@orkestrel/pool 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["#create","#destroy","#validate","#max","#emitter","#idle","#waiters","#active","#destroyed","#reuse","#grow","#wait","#release","#valid","#token","#ignore","#createAbort","#createClear","#createRelease","#return","#handoff","#serve"],"sources":["../../../src/core/Pool.ts","../../../src/core/factories.ts"],"sourcesContent":["import type { EmitterInterface } from '@orkestrel/emitter'\nimport type { PoolEventMap, PoolInterface, PoolOptions, PoolToken, PoolWaiter } from './types.js'\nimport { Emitter } from '@orkestrel/emitter'\n\n/**\n * A bounded resource pool with idle reuse + FIFO waiting.\n *\n * @remarks\n * - **Idle reuse.** `acquire` first takes an idle resource (validating it when a\n * `validate` hook is set — an invalid one is destroyed and the next idle / a fresh\n * one is tried). When no usable idle resource exists and the pool is below `max`, it\n * `create`s a new one. At `max` with none idle, the acquire PARKS on a FIFO waiter\n * list until a `release` hands it a resource.\n * - **FIFO handoff (validated).** `release` (on the token) hands the resource to the next\n * parked waiter (oldest first) — the resource stays leased, the lessee just changes —\n * or returns it to idle when no one is waiting. With a waiter parked the resource is\n * re-validated first (the same `validate` hook the idle path uses), so a resource that\n * went invalid WHILE leased (e.g. a terminated worker thread) is destroyed and the\n * waiter is served a fresh/valid one instead — a dead resource is never handed on. The\n * no-waiter path stays synchronous; releasing the same token twice is a no-op (an\n * idempotent token guard).\n * - **`validate` is total.** A `validate` hook that THROWS is treated exactly like one\n * returning `false` — the resource is \"not usable\", so it is destroyed and replaced —\n * rather than escaping. This holds on both the idle reuse and the FIFO handoff paths, so\n * a throwing validator can never strand a parked waiter on an unhandled rejection.\n * - **Abort-cancellable waiting.** A parked `acquire` given an `AbortSignal` rejects\n * when that signal fires and removes its waiter from the queue — no leaked waiter, so\n * a later `release` still serves the next live waiter. The signal is supplied by the\n * caller (a worker, for example, passes its per-attempt execution signal); the pool adds no abort\n * of its own.\n * - **Counts.** `size` = idle + leased; `idle` = available now; `active` = leased out.\n * - **Teardown.** `clear` destroys every IDLE resource (leased ones keep running);\n * `destroy` destroys ALL resources and rejects any parked waiters. Both await the\n * `destroy` hook.\n * - **Observable (§13).** The owned {@link emitter} ({@link PoolEventMap}) carries the\n * resource lifecycle — `create` / `acquire` / `release` / `destroy` — for fire-and-forget\n * observers. Every event is emitted directly, strictly AFTER the relevant transition —\n * OUTSIDE the `#handoff` / `#serve` await-chain, never across a waiter's resolve; the\n * emitter isolates a listener throw and routes it to its `error` handler (the `error`\n * option), so a buggy observer can NEVER corrupt the validated FIFO handoff-eviction\n * machinery (it cannot strand a parked waiter or unbalance the lease count). Observation is\n * purely a side-channel.\n * - **De-bloated.** No warm-floor / `min`, no eviction timers — lean.\n */\nexport class Pool<T> implements PoolInterface<T> {\n\treadonly #create: () => Promise<T> | T\n\treadonly #destroy: ((value: T) => Promise<void> | void) | undefined\n\treadonly #validate: ((value: T) => Promise<boolean> | boolean) | undefined\n\treadonly #max: number\n\t// The PUSH observation surface (§13) — owned, never inherited. The emitter isolates a\n\t// listener throw (routing it to the `error` handler), so it can never escape into the\n\t// validated FIFO handoff-eviction path.\n\treadonly #emitter: Emitter<PoolEventMap>\n\n\treadonly #idle: T[] = []\n\treadonly #waiters: PoolWaiter<T>[] = []\n\t#active = 0\n\t#destroyed = false\n\n\tconstructor(options: PoolOptions<T>) {\n\t\tthis.#create = options.create\n\t\tthis.#destroy = options.destroy\n\t\tthis.#validate = options.validate\n\t\tthis.#max = Math.max(1, options.max ?? Number.POSITIVE_INFINITY)\n\t\tthis.#emitter = new Emitter<PoolEventMap>({\n\t\t\t...(options.on !== undefined ? { on: options.on } : {}),\n\t\t\t...(options.error !== undefined ? { error: options.error } : {}),\n\t\t})\n\t}\n\n\tget emitter(): EmitterInterface<PoolEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget size(): number {\n\t\treturn this.#idle.length + this.#active\n\t}\n\n\tget idle(): number {\n\t\treturn this.#idle.length\n\t}\n\n\tget active(): number {\n\t\treturn this.#active\n\t}\n\n\tasync acquire(signal?: AbortSignal): Promise<PoolToken<T>> {\n\t\tif (this.#destroyed) throw new Error('pool is destroyed')\n\t\tif (signal?.aborted === true) throw signal.reason\n\t\t// Reuse a validated idle resource if one is available.\n\t\tconst reused = await this.#reuse()\n\t\tif (reused !== undefined) {\n\t\t\t// Observe the lease — AFTER `#reuse` resolved the token (the resource is already\n\t\t\t// leased; emit only OBSERVES it).\n\t\t\tthis.#emitter.emit('acquire')\n\t\t\treturn reused\n\t\t}\n\t\t// Otherwise grow the pool when below the cap.\n\t\tif (this.size < this.#max) {\n\t\t\tconst grown = await this.#grow()\n\t\t\t// Observe the lease — AFTER `#grow` resolved the fresh token.\n\t\t\tthis.#emitter.emit('acquire')\n\t\t\treturn grown\n\t\t}\n\t\t// At capacity with nothing idle — park until a release hands us a resource. The\n\t\t// `acquire` for THIS lease is emitted by `#serve` once a `release` hands it a resource\n\t\t// (after `waiter.resolve`), NOT here — so a served waiter emits `acquire` exactly once.\n\t\treturn await this.#wait(signal)\n\t}\n\n\tasync clear(): Promise<void> {\n\t\tconst resources = this.#idle.splice(0)\n\t\tawait Promise.all(resources.map((resource) => this.#release(resource)))\n\t}\n\n\tasync destroy(): Promise<void> {\n\t\tif (this.#destroyed) return\n\t\tthis.#destroyed = true\n\t\tconst waiters = this.#waiters.splice(0)\n\t\tconst error = new Error('pool is destroyed')\n\t\tfor (const waiter of waiters) {\n\t\t\twaiter.clear()\n\t\t\twaiter.reject(error)\n\t\t}\n\t\tconst resources = this.#idle.splice(0)\n\t\tawait Promise.all(resources.map((resource) => this.#release(resource)))\n\t}\n\n\t// Take + validate the next idle resource; destroy + skip invalid ones. Returns a\n\t// token for the first valid idle resource, or `undefined` when none is usable.\n\tasync #reuse(): Promise<PoolToken<T> | undefined> {\n\t\twhile (this.#idle.length > 0) {\n\t\t\tconst resource = this.#idle.shift()\n\t\t\tif (resource === undefined) continue\n\t\t\tif (await this.#valid(resource)) {\n\t\t\t\tthis.#active += 1\n\t\t\t\treturn this.#token(resource)\n\t\t\t}\n\t\t\tawait this.#release(resource)\n\t\t}\n\t\treturn undefined\n\t}\n\n\t// Create a fresh resource and lease it. Reserve the active slot before awaiting\n\t// `create` so a concurrent acquire sees the pool at capacity (no overshoot of `max`).\n\tasync #grow(): Promise<PoolToken<T>> {\n\t\tthis.#active += 1\n\t\tlet resource: T\n\t\ttry {\n\t\t\tresource = await this.#create()\n\t\t} catch (error: unknown) {\n\t\t\tthis.#active -= 1\n\t\t\tthrow error instanceof Error ? error : new Error(String(error))\n\t\t}\n\t\t// The pool may have been destroyed during `create` — never hand a live resource into\n\t\t// a torn-down pool. Free the active slot, destroy the just-created resource, and throw.\n\t\tif (this.#destroyed) {\n\t\t\tthis.#active -= 1\n\t\t\tawait this.#release(resource)\n\t\t\tthrow new Error('pool is destroyed')\n\t\t}\n\t\t// Observe the fresh resource — AFTER `create` resolved and the not-destroyed re-check\n\t\t// passed (the resource is here to stay), BEFORE the token is built.\n\t\tthis.#emitter.emit('create')\n\t\treturn this.#token(resource)\n\t}\n\n\t// Park a resolver on the FIFO waiter list until a release hands it a resource; an\n\t// abort on `signal` rejects the acquire and removes its waiter (no leak).\n\t#wait(signal: AbortSignal | undefined): Promise<PoolToken<T>> {\n\t\treturn new Promise<PoolToken<T>>((resolve, reject) => {\n\t\t\tconst waiter: PoolWaiter<T> = { resolve, reject, clear: this.#ignore }\n\t\t\tthis.#waiters.push(waiter)\n\t\t\tif (signal !== undefined) {\n\t\t\t\tconst onAbort = this.#createAbort(signal, waiter)\n\t\t\t\tsignal.addEventListener('abort', onAbort, { once: true })\n\t\t\t\twaiter.clear = this.#createClear(signal, onAbort)\n\t\t\t}\n\t\t})\n\t}\n\n\t// Build an idempotent token; its `release` returns the resource exactly once.\n\t#token(resource: T): PoolToken<T> {\n\t\treturn { value: resource, release: this.#createRelease(resource) }\n\t}\n\n\t#ignore(): void {}\n\n\t#createAbort(signal: AbortSignal, waiter: PoolWaiter<T>): () => void {\n\t\treturn (): void => {\n\t\t\tconst index = this.#waiters.indexOf(waiter)\n\t\t\tif (index >= 0) this.#waiters.splice(index, 1)\n\t\t\twaiter.reject(signal.reason)\n\t\t}\n\t}\n\n\t#createClear(signal: AbortSignal, onAbort: () => void): () => void {\n\t\treturn (): void => signal.removeEventListener('abort', onAbort)\n\t}\n\n\t#createRelease(resource: T): () => void {\n\t\tlet released = false\n\t\treturn (): void => {\n\t\t\tif (released) return\n\t\t\treleased = true\n\t\t\tthis.#return(resource)\n\t\t}\n\t}\n\n\t// Return a leased resource. No waiter parked → synchronously drop it to idle (or destroy\n\t// it if torn down), `#active -= 1`. A waiter IS parked → hand off asynchronously, after\n\t// re-validating the resource so an invalid one (e.g. a terminated thread) is never served.\n\t#return(resource: T): void {\n\t\tif (this.#waiters.length === 0) {\n\t\t\tthis.#active -= 1\n\t\t\tif (this.#destroyed) {\n\t\t\t\tvoid this.#release(resource)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.#idle.push(resource)\n\t\t\t// Observe the resource dropping to idle — AFTER `#active` was balanced down and it\n\t\t\t// is back on the idle list (the synchronous no-waiter path). A waiter-handoff\n\t\t\t// instead keeps the resource LEASED, so it emits no `release` here.\n\t\t\tthis.#emitter.emit('release')\n\t\t\treturn\n\t\t}\n\t\tvoid this.#handoff(resource)\n\t}\n\n\t// Hand a released resource to the oldest parked waiter, re-validating it first. A VALID\n\t// resource is served as-is (it stays leased — `#active` unchanged). An INVALID one is\n\t// destroyed and the waiter is served a fresh resource that REUSES the dead one's `#active`\n\t// slot (the count never dips below the lease, so a concurrent acquire can't overshoot\n\t// `max`). The waiter is re-shifted after every `await` (the queue can change underneath\n\t// us), and the pool is re-checked for teardown — so no waiter is leaked or double-settled\n\t// and no resource is handed into a destroyed pool.\n\tasync #handoff(resource: T): Promise<void> {\n\t\t// VALID release → serve the released resource directly (the common, unchanged path).\n\t\tif (await this.#valid(resource)) {\n\t\t\tthis.#serve(resource)\n\t\t\treturn\n\t\t}\n\t\t// INVALID release → destroy it and replace it, holding its `#active` slot steady.\n\t\tvoid this.#release(resource)\n\t\tlet replacement: T\n\t\ttry {\n\t\t\treplacement = await this.#create()\n\t\t} catch (error: unknown) {\n\t\t\t// The dead resource cannot be replaced — free its slot and reject the oldest waiter\n\t\t\t// (it can't be served), or drop the error if the queue raced empty.\n\t\t\tthis.#active -= 1\n\t\t\tconst waiter = this.#waiters.shift()\n\t\t\twaiter?.clear()\n\t\t\twaiter?.reject(error instanceof Error ? error : new Error(String(error)))\n\t\t\treturn\n\t\t}\n\t\t// Observe the fresh replacement — AFTER `create` resolved, BEFORE it is served.\n\t\tthis.#emitter.emit('create')\n\t\tthis.#serve(replacement)\n\t}\n\n\t// Hand a validated resource (the released one, or its fresh replacement) to the oldest\n\t// live waiter, holding its `#active` slot. If the queue raced empty across the awaits, the\n\t// resource is idle (or destroyed when torn down) and its slot is freed.\n\t#serve(resource: T): void {\n\t\tconst waiter = this.#destroyed ? undefined : this.#waiters.shift()\n\t\tif (waiter !== undefined) {\n\t\t\twaiter.clear()\n\t\t\twaiter.resolve(this.#token(resource))\n\t\t\t// Observe the served-waiter lease — strictly AFTER `waiter.resolve(...)` (the token\n\t\t\t// is already handed off; the emit only OBSERVES it and cannot sit across the resolve\n\t\t\t// or perturb the served acquirer's continuation). This is the `acquire` for a parked\n\t\t\t// `acquire`, so the public `acquire` deliberately does NOT emit on its `#wait` branch.\n\t\t\tthis.#emitter.emit('acquire')\n\t\t\treturn\n\t\t}\n\t\tthis.#active -= 1\n\t\tif (this.#destroyed) {\n\t\t\tvoid this.#release(resource)\n\t\t\treturn\n\t\t}\n\t\tthis.#idle.push(resource)\n\t\t// The waiter queue raced empty across the handoff awaits — the resource lands back on\n\t\t// idle instead of being leased. Observe that as a `release` (the return-to-idle that\n\t\t// `#return` would have emitted had no waiter been parked when the token was released).\n\t\tthis.#emitter.emit('release')\n\t}\n\n\t// Is this resource usable? No validator trusts it; otherwise run the hook. A validator\n\t// that THROWS is treated exactly like one returning `false` — the resource is \"not\n\t// usable\", so it is destroyed + replaced rather than escaping as an unhandled rejection\n\t// that would strand a parked waiter on the handoff path (the same total-function spirit\n\t// as a guard, AGENTS §12 / §14). The single gate for both the idle (`#reuse`) and the\n\t// handoff (`#handoff`) validation, so the two paths can never diverge.\n\tasync #valid(resource: T): Promise<boolean> {\n\t\tif (this.#validate === undefined) return true\n\t\ttry {\n\t\t\treturn await this.#validate(resource)\n\t\t} catch {\n\t\t\treturn false\n\t\t}\n\t}\n\n\t// Destroy one resource via the optional hook, swallowing destruction failures. Observe the\n\t// drop with a `destroy` event AFTER the hook ran (or after the no-hook drop) — the resource\n\t// is gone from the pool either way; a swallowed `destroy`-hook failure still emits (the pool\n\t// abandoned it). The emit is the LAST thing here, strictly after the teardown transition.\n\tasync #release(resource: T): Promise<void> {\n\t\tif (this.#destroy === undefined) {\n\t\t\tthis.#emitter.emit('destroy')\n\t\t\treturn\n\t\t}\n\t\ttry {\n\t\t\tawait this.#destroy(resource)\n\t\t} catch {\n\t\t\t// A destroy failure abandons the resource — there is nothing to recover.\n\t\t}\n\t\tthis.#emitter.emit('destroy')\n\t}\n}\n","import type { PoolInterface, PoolOptions } from './types.js'\nimport { Pool } from './Pool.js'\n\n/**\n * Create a bounded resource pool with idle reuse and FIFO waiting — `acquire` leases a\n * resource (reusing a validated idle one, growing up to `max`, or parking until a\n * `release` frees one) and the returned token's `release` returns it for reuse.\n *\n * @remarks\n * A parked `acquire` given an `AbortSignal` rejects + de-queues itself when the signal\n * fires (no leaked waiter). `clear` destroys idle resources (leased ones keep running);\n * `destroy` destroys all and rejects waiters. The pool is lean — no warm-floor (`min`),\n * no eviction timers — and observable (§13): a typed `emitter` surfaces\n * `create` / `acquire` / `release` / `destroy`.\n *\n * @typeParam T - The pooled resource type\n * @param options - The `create` hook plus optional `destroy` / `validate` / `max`\n * @returns A working {@link PoolInterface}\n *\n * @example\n * ```ts\n * import { createPool } from '@src/core'\n *\n * const pool = createPool<Connection>({\n * \tcreate: () => connect(),\n * \tdestroy: (connection) => connection.close(),\n * \tvalidate: (connection) => connection.alive,\n * \tmax: 8,\n * })\n *\n * const token = await pool.acquire()\n * try {\n * \tawait token.value.query('select 1')\n * } finally {\n * \ttoken.release()\n * }\n * ```\n */\nexport function createPool<T>(options: PoolOptions<T>): PoolInterface<T> {\n\treturn new Pool(options)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["#create","#cleanup","#validate","#max","#emitter","#resources","#available","#validating","#leased","#readyRecords","#destroying","#waiters","#assigned","#reservations","#signals","#ready","#operations","#owned","#failures","#ending","#state","#createAbort","#abort","#pump","#dispose","#settleClear","#detach","#own","#finish","#release","#createRelease","#recycle","#commit","#pumping","#repump","#startValidation","#startCreate","#createResource","#completeOperation","#failOperation","#prepare","#validateResource","#token","#record","#clean","#cleanupError","#completeCleanup","#failCleanup"],"sources":["../../../src/core/errors.ts","../../../src/core/validators.ts","../../../src/core/Pool.ts","../../../src/core/factories.ts"],"sourcesContent":["import type { PoolErrorOptions } from './types.js'\n\n/**\n * A stable, machine-readable pool failure with the original cause and structured context.\n *\n * @example\n * ```ts\n * import { PoolError, isPoolError } from '@orkestrel/pool'\n *\n * try {\n * \tawait pool.acquire()\n * } catch (error: unknown) {\n * \tif (isPoolError(error)) console.error(error.code, error.cause)\n * }\n * ```\n */\nexport class PoolError extends Error {\n\t/** Stable machine-readable failure category. */\n\treadonly code\n\t/** Optional structured input or aggregate-cleanup details. */\n\treadonly context\n\n\t/**\n\t * Create a pool failure without coercing a hostile thrown value.\n\t *\n\t * @param options - Stable code plus optional cause and structured context\n\t */\n\tconstructor(options: PoolErrorOptions) {\n\t\tlet message = 'pool input is invalid'\n\t\tif (options.code === 'destroyed') message = 'pool is destroyed'\n\t\tif (options.code === 'create') message = 'pool create failed'\n\t\tif (options.code === 'cleanup') message = 'pool cleanup failed'\n\t\ttry {\n\t\t\tif (\n\t\t\t\toptions.cause instanceof Error &&\n\t\t\t\ttypeof options.cause.message === 'string' &&\n\t\t\t\toptions.cause.message.length > 0\n\t\t\t) {\n\t\t\t\tmessage = `${message}: ${options.cause.message}`\n\t\t\t}\n\t\t} catch {}\n\t\tsuper(message, options.cause === undefined ? undefined : { cause: options.cause })\n\t\tthis.name = 'PoolError'\n\t\tthis.code = options.code\n\t\tthis.context = options.context\n\t}\n}\n\n/**\n * Test whether an unknown value is a {@link PoolError}, returning `false` for hostile proxies.\n *\n * @param value - The unknown boundary value\n * @returns Whether the value is a real `PoolError` instance\n *\n * @example\n * ```ts\n * isPoolError(new PoolError({ code: 'destroyed' })) // true\n * isPoolError(new Error('other')) // false\n * ```\n */\nexport function isPoolError(value: unknown): value is PoolError {\n\ttry {\n\t\treturn value instanceof PoolError\n\t} catch {\n\t\treturn false\n\t}\n}\n","/**\n * Test whether a value is a valid finite pool maximum.\n *\n * @param value - The unknown maximum candidate\n * @returns Whether the value is a positive safe integer\n *\n * @example\n * ```ts\n * isPoolMax(8) // true\n * isPoolMax(Infinity) // false\n * ```\n */\nexport function isPoolMax(value: unknown): value is number {\n\treturn typeof value === 'number' && Number.isSafeInteger(value) && value > 0\n}\n\n/**\n * Test whether a value is a native `AbortSignal`, returning `false` for hostile proxies.\n *\n * @param value - The unknown signal candidate\n * @returns Whether the value is a native `AbortSignal`\n *\n * @example\n * ```ts\n * isPoolSignal(new AbortController().signal) // true\n * isPoolSignal({ aborted: false }) // false\n * ```\n */\nexport function isPoolSignal(value: unknown): value is AbortSignal {\n\ttry {\n\t\tconst getter = Object.getOwnPropertyDescriptor(AbortSignal.prototype, 'aborted')?.get\n\t\tif (getter === undefined) return false\n\t\tReflect.apply(getter, value, [])\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type { PoolCode, PoolEventMap, PoolInterface, PoolOptions, PoolToken } from './types.js'\nimport { Emitter } from '@orkestrel/emitter'\nimport { PoolError } from './errors.js'\nimport { isPoolMax, isPoolSignal } from './validators.js'\n\n/**\n * A capacity-aware resource pool whose opaque ownership records preserve FIFO settlement,\n * cancellation, exact lease release, and deterministic teardown under concurrent hooks.\n *\n * @typeParam T - The pooled resource value\n *\n * @example\n * ```ts\n * import { Pool } from '@orkestrel/pool'\n *\n * const pool = new Pool({ create: () => new Uint8Array(64), max: 2 })\n * const token = await pool.acquire()\n * try {\n * \tconsume(token.value)\n * } finally {\n * \ttoken.release()\n * }\n * await pool.destroy()\n * ```\n */\nexport class Pool<T> implements PoolInterface<T> {\n\treadonly #create: () => Promise<T> | T\n\treadonly #cleanup: ((value: T) => Promise<void> | void) | undefined\n\treadonly #validate: ((value: T) => Promise<boolean> | boolean) | undefined\n\treadonly #max: number | undefined\n\treadonly #emitter: Emitter<PoolEventMap>\n\treadonly #resources = new Map<object, T>()\n\treadonly #available: object[] = []\n\treadonly #validating = new Set<object>()\n\treadonly #leased = new Set<object>()\n\treadonly #readyRecords = new Set<object>()\n\treadonly #destroying = new Map<object, Promise<void>>()\n\treadonly #waiters: PromiseWithResolvers<PoolToken<T>>[] = []\n\treadonly #assigned = new Set<PromiseWithResolvers<PoolToken<T>>>()\n\treadonly #reservations = new Set<PromiseWithResolvers<PoolToken<T>>>()\n\treadonly #signals = new Map<\n\t\tPromiseWithResolvers<PoolToken<T>>,\n\t\t{ readonly signal: AbortSignal; readonly listener: () => void }\n\t>()\n\treadonly #ready = new Map<\n\t\tPromiseWithResolvers<PoolToken<T>>,\n\t\t| { readonly success: true; readonly record: object; readonly token: PoolToken<T> }\n\t\t| { readonly success: false; readonly error: unknown }\n\t>()\n\treadonly #operations = new Set<Promise<void>>()\n\treadonly #owned = new Set<Promise<void>>()\n\treadonly #failures: unknown[] = []\n\t#ending: PromiseWithResolvers<void> | undefined\n\t#pumping = false\n\t#repump = false\n\n\t/**\n\t * Construct a pool and synchronously validate its capacity contract.\n\t *\n\t * @param options - Resource hooks, observation hooks, and optional positive safe `max`\n\t */\n\tconstructor(options: PoolOptions<T>) {\n\t\tif (options.max !== undefined && !isPoolMax(options.max)) {\n\t\t\tthrow new PoolError({ code: 'invalid', context: { value: options.max } })\n\t\t}\n\t\tthis.#create = options.create\n\t\tthis.#cleanup = options.destroy\n\t\tthis.#validate = options.validate\n\t\tthis.#max = options.max\n\t\tthis.#emitter = new Emitter({\n\t\t\t...(options.on === undefined ? {} : { on: options.on }),\n\t\t\t...(options.error === undefined ? {} : { error: options.error }),\n\t\t})\n\t}\n\n\t/** The typed synchronous lifecycle observation surface. */\n\tget emitter(): EmitterInterface<PoolEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\t/** All owned records, including records validating or destroying. */\n\tget size(): number {\n\t\treturn this.#resources.size\n\t}\n\n\t/** Records immediately available without validation work. */\n\tget idle(): number {\n\t\treturn this.#available.length\n\t}\n\n\t/** Records represented by unsettled released-once lease tokens. */\n\tget active(): number {\n\t\treturn this.#leased.size\n\t}\n\n\t/**\n\t * Queue and lease one resource in FIFO settlement order.\n\t *\n\t * @param signal - Optional native cancellation signal\n\t * @returns A promise for the unique resource lease\n\t */\n\tacquire(signal?: AbortSignal): Promise<PoolToken<T>> {\n\t\tif (signal !== undefined && !isPoolSignal(signal)) {\n\t\t\tthrow new PoolError({ code: 'invalid', context: { value: signal } })\n\t\t}\n\t\tif (this.#ending !== undefined) return Promise.reject(new PoolError({ code: 'destroyed' }))\n\t\tif (signal !== undefined) {\n\t\t\tconst state = this.#state(signal)\n\t\t\tif (state[0]) return Promise.reject(state[1])\n\t\t}\n\n\t\tconst waiter = Promise.withResolvers<PoolToken<T>>()\n\t\tthis.#waiters.push(waiter)\n\t\tif (signal !== undefined) {\n\t\t\tconst listener = this.#createAbort(waiter, signal)\n\t\t\tAbortSignal.prototype.addEventListener.call(signal, 'abort', listener, { once: true })\n\t\t\tthis.#signals.set(waiter, { signal, listener })\n\t\t\tconst state = this.#state(signal)\n\t\t\tif (state[0]) this.#abort(waiter, state[1])\n\t\t}\n\t\tthis.#pump()\n\t\treturn waiter.promise\n\t}\n\n\t/**\n\t * Destroy the records that are idle at this call's synchronous snapshot.\n\t *\n\t * @returns A promise that settles after every snapshot cleanup attempt\n\t */\n\tclear(): Promise<void> {\n\t\tif (this.#ending !== undefined) return Promise.reject(new PoolError({ code: 'destroyed' }))\n\t\tconst records = this.#available.splice(0)\n\t\tconst cleanups: Promise<void>[] = []\n\t\tfor (const record of records) cleanups.push(this.#dispose(record))\n\t\treturn this.#settleClear(cleanups)\n\t}\n\n\t/**\n\t * Permanently tear down the pool and return its stable completion barrier.\n\t *\n\t * @returns The exact promise shared by every destroy call\n\t */\n\tdestroy(): Promise<void> {\n\t\tif (this.#ending !== undefined) return this.#ending.promise\n\n\t\tconst ending = Promise.withResolvers<void>()\n\t\tthis.#ending = ending\n\t\tconst waiters = this.#waiters.splice(0)\n\t\tfor (const waiter of waiters) {\n\t\t\tthis.#detach(waiter)\n\t\t\twaiter.reject(new PoolError({ code: 'destroyed' }))\n\t\t}\n\t\tthis.#ready.clear()\n\t\tthis.#assigned.clear()\n\t\tthis.#available.splice(0)\n\t\tfor (const cleanup of this.#destroying.values()) this.#own(cleanup)\n\t\tfor (const record of this.#resources.keys()) {\n\t\t\tif (!this.#validating.has(record)) this.#own(this.#dispose(record))\n\t\t}\n\t\tthis.#finish()\n\t\treturn ending.promise\n\t}\n\n\t#createAbort(waiter: PromiseWithResolvers<PoolToken<T>>, signal: AbortSignal): () => void {\n\t\treturn (): void => {\n\t\t\tlet reason: unknown\n\t\t\ttry {\n\t\t\t\treason = this.#state(signal)[1]\n\t\t\t} catch (error: unknown) {\n\t\t\t\treason = error\n\t\t\t}\n\t\t\tthis.#abort(waiter, reason)\n\t\t}\n\t}\n\n\t#state(signal: AbortSignal): readonly [aborted: boolean, reason: unknown] {\n\t\tconst aborted = Object.getOwnPropertyDescriptor(AbortSignal.prototype, 'aborted')?.get\n\t\tconst reason = Object.getOwnPropertyDescriptor(AbortSignal.prototype, 'reason')?.get\n\t\tif (aborted === undefined || reason === undefined) {\n\t\t\tthrow new PoolError({ code: 'invalid', context: { value: signal } })\n\t\t}\n\t\ttry {\n\t\t\tconst stopped = Reflect.apply(aborted, signal, []) === true\n\t\t\treturn [stopped, stopped ? Reflect.apply(reason, signal, []) : undefined]\n\t\t} catch (error: unknown) {\n\t\t\tthrow new PoolError({ code: 'invalid', cause: error, context: { value: signal } })\n\t\t}\n\t}\n\n\t#createRelease(record: object): () => void {\n\t\tlet released = false\n\t\treturn (): void => {\n\t\t\tif (released) return\n\t\t\treleased = true\n\t\t\tthis.#release(record)\n\t\t}\n\t}\n\n\t#token(record: object, value: T): PoolToken<T> {\n\t\treturn { value, release: this.#createRelease(record) }\n\t}\n\n\t#abort(waiter: PromiseWithResolvers<PoolToken<T>>, reason: unknown): void {\n\t\tconst index = this.#waiters.indexOf(waiter)\n\t\tif (index < 0) return\n\t\tthis.#waiters.splice(index, 1)\n\t\tthis.#detach(waiter)\n\t\tconst ready = this.#ready.get(waiter)\n\t\tthis.#ready.delete(waiter)\n\t\tthis.#assigned.delete(waiter)\n\t\tif (ready?.success === true) {\n\t\t\tthis.#readyRecords.delete(ready.record)\n\t\t\tthis.#recycle(ready.record)\n\t\t}\n\t\twaiter.reject(reason)\n\t\tthis.#commit()\n\t\tthis.#pump()\n\t}\n\n\t#detach(waiter: PromiseWithResolvers<PoolToken<T>>): void {\n\t\tconst entry = this.#signals.get(waiter)\n\t\tif (entry === undefined) return\n\t\tAbortSignal.prototype.removeEventListener.call(entry.signal, 'abort', entry.listener)\n\t\tthis.#signals.delete(waiter)\n\t}\n\n\t#pump(): void {\n\t\tif (this.#ending !== undefined) return\n\t\tif (this.#pumping) {\n\t\t\tthis.#repump = true\n\t\t\treturn\n\t\t}\n\n\t\tthis.#pumping = true\n\t\tdo {\n\t\t\tthis.#repump = false\n\t\t\tfor (const waiter of this.#waiters) {\n\t\t\t\tif (this.#assigned.has(waiter) || this.#ready.has(waiter)) continue\n\t\t\t\tconst record = this.#available.shift()\n\t\t\t\tif (record !== undefined) {\n\t\t\t\t\tthis.#assigned.add(waiter)\n\t\t\t\t\tthis.#validating.add(record)\n\t\t\t\t\tthis.#startValidation(waiter, record)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (this.#max === undefined || this.#resources.size + this.#reservations.size < this.#max) {\n\t\t\t\t\tthis.#assigned.add(waiter)\n\t\t\t\t\tthis.#reservations.add(waiter)\n\t\t\t\t\tthis.#startCreate(waiter)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t} while (this.#repump)\n\t\tthis.#pumping = false\n\t}\n\n\t#startCreate(waiter: PromiseWithResolvers<PoolToken<T>>): void {\n\t\tconst operation = Promise.resolve().then(() => this.#createResource(waiter))\n\t\tthis.#operations.add(operation)\n\t\tvoid operation.then(\n\t\t\t() => this.#completeOperation(operation),\n\t\t\t(error: unknown) => this.#failOperation(operation, waiter, error, 'create'),\n\t\t)\n\t}\n\n\t#startValidation(waiter: PromiseWithResolvers<PoolToken<T>>, record: object): void {\n\t\tfor (const [owned, value] of this.#resources) {\n\t\t\tif (owned !== record) continue\n\t\t\tif (this.#validate === undefined) {\n\t\t\t\tthis.#validating.delete(record)\n\t\t\t\tthis.#prepare(waiter, record, value)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst operation = Promise.resolve().then(() => this.#validateResource(waiter, record, value))\n\t\t\tthis.#operations.add(operation)\n\t\t\tvoid operation.then(\n\t\t\t\t() => this.#completeOperation(operation),\n\t\t\t\t(error: unknown) => this.#failOperation(operation, waiter, error, 'invalid'),\n\t\t\t)\n\t\t\treturn\n\t\t}\n\t\tthis.#validating.delete(record)\n\t\tthis.#assigned.delete(waiter)\n\t\tthis.#repump = true\n\t}\n\n\tasync #createResource(waiter: PromiseWithResolvers<PoolToken<T>>): Promise<void> {\n\t\tlet value: T\n\t\ttry {\n\t\t\tvalue = await this.#create()\n\t\t} catch (error: unknown) {\n\t\t\tthis.#reservations.delete(waiter)\n\t\t\tif (this.#waiters.includes(waiter)) {\n\t\t\t\tthis.#ready.set(waiter, {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: new PoolError({ code: 'create', cause: error }),\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tthis.#assigned.delete(waiter)\n\t\t\t}\n\t\t\tthis.#commit()\n\t\t\treturn\n\t\t}\n\n\t\tthis.#reservations.delete(waiter)\n\t\tconst record = {}\n\t\tthis.#resources.set(record, value)\n\t\tthis.#readyRecords.add(record)\n\t\tthis.#emitter.emit('create')\n\t\tif (this.#ending !== undefined) {\n\t\t\tthis.#readyRecords.delete(record)\n\t\t\tthis.#assigned.delete(waiter)\n\t\t\ttry {\n\t\t\t\tawait this.#dispose(record)\n\t\t\t} catch {}\n\t\t\treturn\n\t\t}\n\t\tif (!this.#waiters.includes(waiter)) {\n\t\t\tthis.#readyRecords.delete(record)\n\t\t\tthis.#assigned.delete(waiter)\n\t\t\tthis.#recycle(record)\n\t\t\treturn\n\t\t}\n\t\tthis.#ready.set(waiter, {\n\t\t\tsuccess: true,\n\t\t\trecord,\n\t\t\ttoken: this.#token(record, value),\n\t\t})\n\t\tthis.#commit()\n\t}\n\n\tasync #validateResource(\n\t\twaiter: PromiseWithResolvers<PoolToken<T>>,\n\t\trecord: object,\n\t\tvalue: T,\n\t): Promise<void> {\n\t\tlet valid = false\n\t\ttry {\n\t\t\tvalid = (await this.#validate?.(value)) === true\n\t\t} catch {}\n\t\tthis.#validating.delete(record)\n\n\t\tif (this.#ending !== undefined) {\n\t\t\tthis.#assigned.delete(waiter)\n\t\t\ttry {\n\t\t\t\tawait this.#dispose(record)\n\t\t\t} catch {}\n\t\t\treturn\n\t\t}\n\t\tif (!this.#waiters.includes(waiter)) {\n\t\t\tthis.#assigned.delete(waiter)\n\t\t\tif (valid) this.#recycle(record)\n\t\t\telse {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.#dispose(record)\n\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\tthis.#record(error)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tif (valid) {\n\t\t\tthis.#prepare(waiter, record, value)\n\t\t\treturn\n\t\t}\n\n\t\ttry {\n\t\t\tawait this.#dispose(record)\n\t\t} catch (error: unknown) {\n\t\t\tif (this.#waiters.includes(waiter)) {\n\t\t\t\tthis.#ready.set(waiter, {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: new PoolError({ code: 'cleanup', cause: error }),\n\t\t\t\t})\n\t\t\t\tthis.#commit()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.#record(error)\n\t\t}\n\t\tthis.#assigned.delete(waiter)\n\t\tthis.#pump()\n\t}\n\n\t#prepare(waiter: PromiseWithResolvers<PoolToken<T>>, record: object, value: T): void {\n\t\tif (!this.#waiters.includes(waiter) || this.#ending !== undefined) {\n\t\t\tthis.#assigned.delete(waiter)\n\t\t\tthis.#recycle(record)\n\t\t\treturn\n\t\t}\n\t\tthis.#readyRecords.add(record)\n\t\tthis.#ready.set(waiter, {\n\t\t\tsuccess: true,\n\t\t\trecord,\n\t\t\ttoken: this.#token(record, value),\n\t\t})\n\t\tthis.#commit()\n\t}\n\n\t#commit(): void {\n\t\twhile (this.#ending === undefined) {\n\t\t\tconst waiter = this.#waiters[0]\n\t\t\tif (waiter === undefined) return\n\t\t\tconst result = this.#ready.get(waiter)\n\t\t\tif (result === undefined) return\n\t\t\tthis.#waiters.shift()\n\t\t\tthis.#ready.delete(waiter)\n\t\t\tthis.#assigned.delete(waiter)\n\t\t\tthis.#detach(waiter)\n\t\t\tif (!result.success) {\n\t\t\t\twaiter.reject(result.error)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tthis.#readyRecords.delete(result.record)\n\t\t\tthis.#leased.add(result.record)\n\t\t\twaiter.resolve(result.token)\n\t\t\tthis.#emitter.emit('acquire')\n\t\t}\n\t}\n\n\t#completeOperation(operation: Promise<void>): void {\n\t\tthis.#operations.delete(operation)\n\t\tthis.#commit()\n\t\tthis.#pump()\n\t\tthis.#finish()\n\t}\n\n\t#failOperation(\n\t\toperation: Promise<void>,\n\t\twaiter: PromiseWithResolvers<PoolToken<T>>,\n\t\terror: unknown,\n\t\tcode: PoolCode,\n\t): void {\n\t\tthis.#operations.delete(operation)\n\t\tthis.#reservations.delete(waiter)\n\t\tthis.#assigned.delete(waiter)\n\t\tif (this.#waiters.includes(waiter)) {\n\t\t\tthis.#ready.set(waiter, { success: false, error: new PoolError({ code, cause: error }) })\n\t\t}\n\t\tthis.#commit()\n\t\tthis.#pump()\n\t\tthis.#finish()\n\t}\n\n\t#release(record: object): void {\n\t\tif (!this.#leased.delete(record)) return\n\t\tif (this.#ending !== undefined) {\n\t\t\tthis.#own(this.#dispose(record))\n\t\t\treturn\n\t\t}\n\t\tthis.#available.push(record)\n\t\tthis.#pump()\n\t\tif (this.#available.includes(record)) this.#emitter.emit('release')\n\t}\n\n\t#recycle(record: object): void {\n\t\tif (this.#ending !== undefined) {\n\t\t\tthis.#own(this.#dispose(record))\n\t\t\treturn\n\t\t}\n\t\tthis.#available.push(record)\n\t\tthis.#pump()\n\t\tif (this.#available.includes(record)) this.#emitter.emit('release')\n\t}\n\n\t#dispose(record: object): Promise<void> {\n\t\tconst existing = this.#destroying.get(record)\n\t\tif (existing !== undefined) return existing\n\t\tfor (const [owned, value] of this.#resources) {\n\t\t\tif (owned !== record) continue\n\t\t\tconst cleanup = Promise.withResolvers<void>()\n\t\t\tthis.#destroying.set(record, cleanup.promise)\n\t\t\tconst index = this.#available.indexOf(record)\n\t\t\tif (index >= 0) this.#available.splice(index, 1)\n\t\t\tthis.#validating.delete(record)\n\t\t\tthis.#leased.delete(record)\n\t\t\tthis.#readyRecords.delete(record)\n\t\t\tif (this.#ending !== undefined) this.#own(cleanup.promise)\n\t\t\tvoid this.#clean(record, value, cleanup)\n\t\t\treturn cleanup.promise\n\t\t}\n\t\treturn Promise.resolve()\n\t}\n\n\tasync #clean(record: object, value: T, cleanup: PromiseWithResolvers<void>): Promise<void> {\n\t\tlet failure: unknown\n\t\tlet failed = false\n\t\ttry {\n\t\t\tawait this.#cleanup?.(value)\n\t\t} catch (error: unknown) {\n\t\t\tfailure = error\n\t\t\tfailed = true\n\t\t}\n\t\tthis.#resources.delete(record)\n\t\tthis.#emitter.emit('destroy')\n\t\tthis.#destroying.delete(record)\n\t\tthis.#pump()\n\t\tif (failed) cleanup.reject(failure)\n\t\telse cleanup.resolve()\n\t\tthis.#finish()\n\t}\n\n\tasync #settleClear(cleanups: readonly Promise<void>[]): Promise<void> {\n\t\tconst settled = await Promise.allSettled(cleanups)\n\t\tconst failures: unknown[] = []\n\t\tfor (const result of settled) {\n\t\t\tif (\n\t\t\t\tresult.status === 'rejected' &&\n\t\t\t\t!failures.some((failure) => Object.is(failure, result.reason))\n\t\t\t) {\n\t\t\t\tfailures.push(result.reason)\n\t\t\t}\n\t\t}\n\t\tif (failures.length > 0) throw this.#cleanupError(failures)\n\t}\n\n\t#own(cleanup: Promise<void>): void {\n\t\tif (this.#owned.has(cleanup)) return\n\t\tthis.#owned.add(cleanup)\n\t\tvoid cleanup.then(\n\t\t\t() => this.#completeCleanup(cleanup),\n\t\t\t(error: unknown) => this.#failCleanup(cleanup, error),\n\t\t)\n\t}\n\n\t#completeCleanup(cleanup: Promise<void>): void {\n\t\tthis.#owned.delete(cleanup)\n\t\tthis.#finish()\n\t}\n\n\t#failCleanup(cleanup: Promise<void>, error: unknown): void {\n\t\tthis.#owned.delete(cleanup)\n\t\tthis.#record(error)\n\t\tthis.#finish()\n\t}\n\n\t#record(error: unknown): void {\n\t\tif (!this.#failures.some((failure) => Object.is(failure, error))) this.#failures.push(error)\n\t}\n\n\t#cleanupError(failures: readonly unknown[]): PoolError {\n\t\treturn new PoolError({\n\t\t\tcode: 'cleanup',\n\t\t\t...(failures[0] === undefined ? {} : { cause: failures[0] }),\n\t\t\tcontext: { failures: [...failures] },\n\t\t})\n\t}\n\n\t#finish(): void {\n\t\tconst ending = this.#ending\n\t\tif (ending === undefined || this.#operations.size > 0 || this.#owned.size > 0) return\n\t\tlet claimed = false\n\t\tfor (const record of this.#resources.keys()) {\n\t\t\tif (this.#validating.has(record) || this.#destroying.has(record)) continue\n\t\t\tclaimed = true\n\t\t\tthis.#own(this.#dispose(record))\n\t\t}\n\t\tif (claimed || this.#resources.size > 0 || this.#destroying.size > 0) return\n\t\tthis.#emitter.destroy()\n\t\tif (this.#failures.length > 0) ending.reject(this.#cleanupError(this.#failures))\n\t\telse ending.resolve()\n\t}\n}\n","import type { PoolInterface, PoolOptions } from './types.js'\nimport { Pool } from './Pool.js'\n\n/**\n * Create a resource pool with optional bounded capacity, unique ownership, and FIFO settlement.\n *\n * @remarks\n * Concurrent create and validation hooks may overlap, while acquire promises settle in\n * request order. `clear` owns its idle snapshot; `destroy` returns one stable barrier and\n * waits for every in-flight hook and cleanup before destroying the emitter last.\n *\n * @typeParam T - The pooled resource type\n * @param options - Lifecycle hooks, optional positive safe `max`, and observation hooks\n * @returns A working {@link PoolInterface}\n *\n * @example\n * ```ts\n * import { createPool } from '@orkestrel/pool'\n *\n * const pool = createPool<Connection>({\n * \tcreate: () => connect(),\n * \tdestroy: (connection) => connection.close(),\n * \tvalidate: (connection) => connection.alive,\n * \tmax: 8,\n * })\n *\n * const token = await pool.acquire()\n * try {\n * \tawait token.value.query('select 1')\n * } finally {\n * \ttoken.release()\n * }\n * ```\n */\nexport function createPool<T>(options: PoolOptions<T>): PoolInterface<T> {\n\treturn new Pool(options)\n}\n"],"mappings":"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"}
@@ -3,24 +3,20 @@ import { EmitterHooks } from '@orkestrel/emitter';
3
3
  import { EmitterInterface } from '@orkestrel/emitter';
4
4
 
5
5
  /**
6
- * Create a bounded resource pool with idle reuse and FIFO waiting `acquire` leases a
7
- * resource (reusing a validated idle one, growing up to `max`, or parking until a
8
- * `release` frees one) and the returned token's `release` returns it for reuse.
6
+ * Create a resource pool with optional bounded capacity, unique ownership, and FIFO settlement.
9
7
  *
10
8
  * @remarks
11
- * A parked `acquire` given an `AbortSignal` rejects + de-queues itself when the signal
12
- * fires (no leaked waiter). `clear` destroys idle resources (leased ones keep running);
13
- * `destroy` destroys all and rejects waiters. The pool is lean no warm-floor (`min`),
14
- * no eviction timers — and observable (§13): a typed `emitter` surfaces
15
- * `create` / `acquire` / `release` / `destroy`.
9
+ * Concurrent create and validation hooks may overlap, while acquire promises settle in
10
+ * request order. `clear` owns its idle snapshot; `destroy` returns one stable barrier and
11
+ * waits for every in-flight hook and cleanup before destroying the emitter last.
16
12
  *
17
13
  * @typeParam T - The pooled resource type
18
- * @param options - The `create` hook plus optional `destroy` / `validate` / `max`
14
+ * @param options - Lifecycle hooks, optional positive safe `max`, and observation hooks
19
15
  * @returns A working {@link PoolInterface}
20
16
  *
21
17
  * @example
22
18
  * ```ts
23
- * import { createPool } from '@src/core'
19
+ * import { createPool } from '@orkestrel/pool'
24
20
  *
25
21
  * const pool = createPool<Connection>({
26
22
  * create: () => connect(),
@@ -40,120 +36,206 @@ import { EmitterInterface } from '@orkestrel/emitter';
40
36
  export declare function createPool<T>(options: PoolOptions<T>): PoolInterface<T>;
41
37
 
42
38
  /**
43
- * A bounded resource pool with idle reuse + FIFO waiting.
39
+ * Test whether an unknown value is a {@link PoolError}, returning `false` for hostile proxies.
44
40
  *
45
- * @remarks
46
- * - **Idle reuse.** `acquire` first takes an idle resource (validating it when a
47
- * `validate` hook is set — an invalid one is destroyed and the next idle / a fresh
48
- * one is tried). When no usable idle resource exists and the pool is below `max`, it
49
- * `create`s a new one. At `max` with none idle, the acquire PARKS on a FIFO waiter
50
- * list until a `release` hands it a resource.
51
- * - **FIFO handoff (validated).** `release` (on the token) hands the resource to the next
52
- * parked waiter (oldest first) — the resource stays leased, the lessee just changes —
53
- * or returns it to idle when no one is waiting. With a waiter parked the resource is
54
- * re-validated first (the same `validate` hook the idle path uses), so a resource that
55
- * went invalid WHILE leased (e.g. a terminated worker thread) is destroyed and the
56
- * waiter is served a fresh/valid one instead — a dead resource is never handed on. The
57
- * no-waiter path stays synchronous; releasing the same token twice is a no-op (an
58
- * idempotent token guard).
59
- * - **`validate` is total.** A `validate` hook that THROWS is treated exactly like one
60
- * returning `false` the resource is "not usable", so it is destroyed and replaced —
61
- * rather than escaping. This holds on both the idle reuse and the FIFO handoff paths, so
62
- * a throwing validator can never strand a parked waiter on an unhandled rejection.
63
- * - **Abort-cancellable waiting.** A parked `acquire` given an `AbortSignal` rejects
64
- * when that signal fires and removes its waiter from the queue — no leaked waiter, so
65
- * a later `release` still serves the next live waiter. The signal is supplied by the
66
- * caller (a worker, for example, passes its per-attempt execution signal); the pool adds no abort
67
- * of its own.
68
- * - **Counts.** `size` = idle + leased; `idle` = available now; `active` = leased out.
69
- * - **Teardown.** `clear` destroys every IDLE resource (leased ones keep running);
70
- * `destroy` destroys ALL resources and rejects any parked waiters. Both await the
71
- * `destroy` hook.
72
- * - **Observable (§13).** The owned {@link emitter} ({@link PoolEventMap}) carries the
73
- * resource lifecycle `create` / `acquire` / `release` / `destroy` — for fire-and-forget
74
- * observers. Every event is emitted directly, strictly AFTER the relevant transition —
75
- * OUTSIDE the `#handoff` / `#serve` await-chain, never across a waiter's resolve; the
76
- * emitter isolates a listener throw and routes it to its `error` handler (the `error`
77
- * option), so a buggy observer can NEVER corrupt the validated FIFO handoff-eviction
78
- * machinery (it cannot strand a parked waiter or unbalance the lease count). Observation is
79
- * purely a side-channel.
80
- * - **De-bloated.** No warm-floor / `min`, no eviction timers — lean.
41
+ * @param value - The unknown boundary value
42
+ * @returns Whether the value is a real `PoolError` instance
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * isPoolError(new PoolError({ code: 'destroyed' })) // true
47
+ * isPoolError(new Error('other')) // false
48
+ * ```
49
+ */
50
+ export declare function isPoolError(value: unknown): value is PoolError;
51
+
52
+ /**
53
+ * Test whether a value is a valid finite pool maximum.
54
+ *
55
+ * @param value - The unknown maximum candidate
56
+ * @returns Whether the value is a positive safe integer
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * isPoolMax(8) // true
61
+ * isPoolMax(Infinity) // false
62
+ * ```
63
+ */
64
+ export declare function isPoolMax(value: unknown): value is number;
65
+
66
+ /**
67
+ * Test whether a value is a native `AbortSignal`, returning `false` for hostile proxies.
68
+ *
69
+ * @param value - The unknown signal candidate
70
+ * @returns Whether the value is a native `AbortSignal`
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * isPoolSignal(new AbortController().signal) // true
75
+ * isPoolSignal({ aborted: false }) // false
76
+ * ```
77
+ */
78
+ export declare function isPoolSignal(value: unknown): value is AbortSignal;
79
+
80
+ /**
81
+ * A capacity-aware resource pool whose opaque ownership records preserve FIFO settlement,
82
+ * cancellation, exact lease release, and deterministic teardown under concurrent hooks.
83
+ *
84
+ * @typeParam T - The pooled resource value
85
+ *
86
+ * @example
87
+ * ```ts
88
+ * import { Pool } from '@orkestrel/pool'
89
+ *
90
+ * const pool = new Pool({ create: () => new Uint8Array(64), max: 2 })
91
+ * const token = await pool.acquire()
92
+ * try {
93
+ * consume(token.value)
94
+ * } finally {
95
+ * token.release()
96
+ * }
97
+ * await pool.destroy()
98
+ * ```
81
99
  */
82
100
  export declare class Pool<T> implements PoolInterface<T> {
83
101
  #private;
102
+ /**
103
+ * Construct a pool and synchronously validate its capacity contract.
104
+ *
105
+ * @param options - Resource hooks, observation hooks, and optional positive safe `max`
106
+ */
84
107
  constructor(options: PoolOptions<T>);
108
+ /** The typed synchronous lifecycle observation surface. */
85
109
  get emitter(): EmitterInterface<PoolEventMap>;
110
+ /** All owned records, including records validating or destroying. */
86
111
  get size(): number;
112
+ /** Records immediately available without validation work. */
87
113
  get idle(): number;
114
+ /** Records represented by unsettled released-once lease tokens. */
88
115
  get active(): number;
116
+ /**
117
+ * Queue and lease one resource in FIFO settlement order.
118
+ *
119
+ * @param signal - Optional native cancellation signal
120
+ * @returns A promise for the unique resource lease
121
+ */
89
122
  acquire(signal?: AbortSignal): Promise<PoolToken<T>>;
123
+ /**
124
+ * Destroy the records that are idle at this call's synchronous snapshot.
125
+ *
126
+ * @returns A promise that settles after every snapshot cleanup attempt
127
+ */
90
128
  clear(): Promise<void>;
129
+ /**
130
+ * Permanently tear down the pool and return its stable completion barrier.
131
+ *
132
+ * @returns The exact promise shared by every destroy call
133
+ */
91
134
  destroy(): Promise<void>;
92
135
  }
93
136
 
137
+ /** Machine-readable failure codes produced by {@link PoolError}. */
138
+ export declare type PoolCode = 'invalid' | 'destroyed' | 'create' | 'cleanup';
139
+
140
+ /** Structured context attached to a {@link PoolError}. */
141
+ export declare interface PoolContext {
142
+ /** The rejected public input, when the failure is an input-validation error. */
143
+ readonly value?: unknown;
144
+ /** Distinct cleanup failures collected by `clear()` or `destroy()`. */
145
+ readonly failures?: readonly unknown[];
146
+ }
147
+
94
148
  /**
95
- * The push observation surface of a {@link PoolInterface} (AGENTS §13) the resource
96
- * lifecycle moments a fire-and-forget observer subscribes to.
149
+ * A stable, machine-readable pool failure with the original cause and structured context.
97
150
  *
98
- * @remarks
99
- * Pure signals (no `T` payload — `Pool<T>` carries no resource value on its events, so a
100
- * non-generic map stays lean). Listener isolation is the emitter's (AGENTS §13): every event
101
- * is emitted directly and a listener throw is routed to the emitter's `error` handler (the
102
- * `error` option), never onto this map, and sits AFTER the relevant create / acquire /
103
- * release / destroy transition — so a throwing observer can never corrupt the FIFO
104
- * handoff-eviction machinery (it cannot strand a parked waiter or unbalance the lease count).
105
- * Subscribe via `pool.emitter.on(...)`. Declared as a `type` alias (§4.5 — `EventMap` is a
106
- * `type` kind).
151
+ * @example
152
+ * ```ts
153
+ * import { PoolError, isPoolError } from '@orkestrel/pool'
154
+ *
155
+ * try {
156
+ * await pool.acquire()
157
+ * } catch (error: unknown) {
158
+ * if (isPoolError(error)) console.error(error.code, error.cause)
159
+ * }
160
+ * ```
107
161
  */
162
+ export declare class PoolError extends Error {
163
+ /** Stable machine-readable failure category. */
164
+ readonly code: PoolCode;
165
+ /** Optional structured input or aggregate-cleanup details. */
166
+ readonly context: PoolContext | undefined;
167
+ /**
168
+ * Create a pool failure without coercing a hostile thrown value.
169
+ *
170
+ * @param options - Stable code plus optional cause and structured context
171
+ */
172
+ constructor(options: PoolErrorOptions);
173
+ }
174
+
175
+ /** Construction options for {@link PoolError}. */
176
+ export declare interface PoolErrorOptions {
177
+ /** The stable machine-readable failure category. */
178
+ readonly code: PoolCode;
179
+ /** The original thrown value, retained without unsafe string coercion. */
180
+ readonly cause?: unknown;
181
+ /** Optional structured failure details. */
182
+ readonly context?: PoolContext;
183
+ }
184
+
185
+ /** Observable resource lifecycle events emitted by a {@link PoolInterface}. */
108
186
  export declare type PoolEventMap = {
109
- /** A fresh resource was created (`create` resolved) and leased. */
187
+ /** A created resource entered pool ownership. */
110
188
  readonly create: readonly [];
111
- /** A token was handed to a lessee (a reused idle one, a fresh one, or a served waiter). */
189
+ /** A token settled successfully and its exact resource became leased. */
112
190
  readonly acquire: readonly [];
113
- /** A leased resource returned to idle (no waiter was parked). */
191
+ /** A released resource became immediately idle. */
114
192
  readonly release: readonly [];
115
- /** A resource was destroyed (`clear` / `destroy`, or a failed `validate`). */
193
+ /** A resource cleanup hook completed or was attempted when absent. */
116
194
  readonly destroy: readonly [];
117
195
  };
118
196
 
119
- /**
120
- * A bounded resource pool with idle reuse + FIFO waiting.
121
- *
122
- * @remarks
123
- * Exposes a typed {@link emitter} (AGENTS §13) carrying its resource lifecycle moments
124
- * ({@link PoolEventMap}) for fire-and-forget observers. Emitting is observation-only —
125
- * every event fires AFTER the relevant create / acquire / release / destroy transition, so a
126
- * buggy observer can never corrupt the FIFO handoff-eviction machinery: the emitter isolates
127
- * a listener throw and routes it to its `error` handler (the `error` option), never the pool.
128
- */
197
+ /** A FIFO resource pool with optional bounded capacity and deterministic teardown. */
129
198
  export declare interface PoolInterface<T> {
199
+ /** The typed synchronous lifecycle observation surface. */
130
200
  readonly emitter: EmitterInterface<PoolEventMap>;
201
+ /** All owned records, including records validating or destroying. */
131
202
  readonly size: number;
203
+ /** Records immediately available without validation work. */
132
204
  readonly idle: number;
205
+ /** Records represented by unsettled released-once lease tokens. */
133
206
  readonly active: number;
207
+ /**
208
+ * Queue and lease one resource in FIFO settlement order.
209
+ *
210
+ * @param signal - Optional native cancellation signal
211
+ * @returns A promise for the unique resource lease
212
+ */
134
213
  acquire(signal?: AbortSignal): Promise<PoolToken<T>>;
214
+ /**
215
+ * Destroy the records that are idle at this call's synchronous snapshot.
216
+ *
217
+ * @returns A promise that settles after every snapshot cleanup attempt
218
+ */
135
219
  clear(): Promise<void>;
220
+ /**
221
+ * Permanently tear down the pool and return its stable completion barrier.
222
+ *
223
+ * @returns The exact promise shared by every destroy call
224
+ */
136
225
  destroy(): Promise<void>;
137
226
  }
138
227
 
139
228
  /**
140
- * Options for `createPool` the resource lifecycle hooks.
229
+ * Resource lifecycle options for {@link Pool} and `createPool`.
141
230
  *
142
231
  * @remarks
143
- * - `create` make a fresh resource; called when no idle resource is reusable and
144
- * the pool is below `max`. May be async.
145
- * - `destroy` tear a resource down when the pool drops it (`clear` / `destroy`, or
146
- * a failed `validate`); optional and awaited.
147
- * - `validate` — check an idle resource is still usable before leasing it; an invalid
148
- * resource is destroyed and replaced. Optional (an absent validator trusts idle).
149
- * - `max` — the most resources that may exist at once (idle + leased); defaults to
150
- * unbounded. A surplus `acquire` waits (FIFO) for a `release`.
151
- * - `on` — the reserved {@link EmitterHooks} key (§8): initial listeners for the pool's
152
- * {@link PoolEventMap}, wired at construction (e.g. `{ create: () => count() }`).
232
+ * `create` lazily produces resources. `destroy` tears down a claimed resource.
233
+ * `validate` checks a previously owned resource before reuse. `max` is a positive
234
+ * safe integer; omission is the only unbounded form. `on` installs initial emitter
235
+ * listeners and `error` receives isolated listener failures.
153
236
  */
154
237
  export declare interface PoolOptions<T> {
155
238
  readonly on?: EmitterHooks<PoolEventMap>;
156
- /** The emitter's listener-error handler (AGENTS §13) — a listener throw routes here, not to a domain event. */
157
239
  readonly error?: EmitterErrorHandler;
158
240
  readonly create: () => Promise<T> | T;
159
241
  readonly destroy?: (value: T) => Promise<void> | void;
@@ -161,34 +243,12 @@ export declare interface PoolOptions<T> {
161
243
  readonly max?: number;
162
244
  }
163
245
 
164
- /**
165
- * A leased resource from a {@link PoolInterface} — `value` is the live resource and
166
- * `release()` returns it to the pool for reuse (or hands it to the next waiter).
167
- */
246
+ /** A unique lease over one pool-owned resource record. */
168
247
  export declare interface PoolToken<T> {
169
- /** The leased resource. */
248
+ /** The leased value. Duplicate values still belong to independent records. */
170
249
  readonly value: T;
171
- /** Return the resource to the pool; calling more than once is a no-op. */
250
+ /** Return this exact lease once; subsequent calls are no-ops. */
172
251
  release(): void;
173
252
  }
174
253
 
175
- /**
176
- * A parked acquirer on a {@link PoolInterface}'s FIFO waiter list — its promise resolvers
177
- * plus the cleanup that detaches its abort listener.
178
- *
179
- * @remarks
180
- * Held only inside the {@link PoolInterface} engine (a resource at `max` parks the acquirer
181
- * here until a `release` hands it a token); not part of the public call surface, but
182
- * centralized here per AGENTS §5. `resolve` hands the waiter its leased {@link PoolToken};
183
- * `reject` fails its `acquire` (a teardown or an aborted wait); `clear` detaches the abort
184
- * listener so a settled waiter leaks nothing.
185
- *
186
- * @typeParam T - The resource the pool leases
187
- */
188
- export declare interface PoolWaiter<T> {
189
- readonly resolve: (token: PoolToken<T>) => void;
190
- readonly reject: (error: unknown) => void;
191
- clear(): void;
192
- }
193
-
194
254
  export { }