@dmop/puru 0.1.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/serialize.ts","../src/configure.ts","../src/runtime.ts","../src/adapters/node.ts","../src/bootstrap.ts","../src/adapters/bun.ts","../src/channel.ts","../src/adapters/inline.ts","../src/pool.ts","../src/spawn.ts","../src/waitgroup.ts","../src/errgroup.ts","../src/mutex.ts","../src/once.ts","../src/select.ts","../src/after.ts","../src/ticker.ts","../src/registry.ts"],"sourcesContent":["const NATIVE_CODE_RE = /\\[native code\\]/\nconst METHOD_RE = /^[a-zA-Z_$][a-zA-Z0-9_$]*\\s*\\(/\n\n// A valid serialized function must start with one of these patterns.\n// This guards against prototype pollution on Function.prototype.toString\n// returning arbitrary strings.\nconst VALID_FN_START_RE = /^(?:function\\b|async\\s+function\\b|async\\s*\\(|\\(|[a-zA-Z_$][a-zA-Z0-9_$]*\\s*=>|async\\s+[a-zA-Z_$])/\n\nexport function serializeFunction(fn: Function): string {\n if (typeof fn !== 'function') {\n throw new TypeError('Expected a function')\n }\n\n const str = fn.toString()\n\n if (typeof str !== 'string' || str.length === 0) {\n throw new TypeError(\n 'Function serialization returned an invalid result. ' +\n 'This may indicate Function.prototype.toString has been tampered with.',\n )\n }\n\n if (NATIVE_CODE_RE.test(str)) {\n throw new TypeError(\n 'Native functions cannot be serialized. Use an arrow function wrapper instead.',\n )\n }\n\n if (!VALID_FN_START_RE.test(str)) {\n throw new TypeError(\n 'Function serialization produced unexpected output. ' +\n 'Only arrow functions, function expressions, and async functions are supported.',\n )\n }\n\n // Detect class methods like \"method() { ... }\" — not valid standalone functions\n if (\n METHOD_RE.test(str) &&\n !str.startsWith('function') &&\n !str.startsWith('async function') &&\n !str.startsWith('async (') &&\n !str.startsWith('async=') &&\n !str.startsWith('(') &&\n !str.includes('=>')\n ) {\n throw new TypeError(\n 'Class methods cannot be serialized. Use an arrow function wrapper instead.',\n )\n }\n\n return str\n}\n","import { availableParallelism } from 'node:os'\nimport type { PuruConfig } from './types.js'\n\nconst DEFAULT_CONFIG: PuruConfig = {\n maxThreads: availableParallelism?.() ?? 4,\n strategy: 'fifo',\n idleTimeout: 30_000,\n adapter: 'auto',\n concurrency: 64,\n}\n\nlet currentConfig: PuruConfig = { ...DEFAULT_CONFIG }\nlet configLocked = false\n\nexport function configure(opts: Partial<PuruConfig>): void {\n if (configLocked) {\n throw new Error(\n 'configure() must be called before the first spawn(). The worker pool has already been initialized.',\n )\n }\n currentConfig = { ...currentConfig, ...opts }\n}\n\nexport function getConfig(): PuruConfig {\n configLocked = true\n return { ...currentConfig }\n}\n\n/** @internal For testing only */\nexport function resetConfig(): void {\n currentConfig = { ...DEFAULT_CONFIG }\n configLocked = false\n}\n","export type Runtime = 'node' | 'deno' | 'bun' | 'browser'\nexport type Capability = 'full-threads' | 'single-thread'\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\nexport function detectRuntime(): Runtime {\n if (typeof (globalThis as any).Bun !== 'undefined') return 'bun'\n if (typeof (globalThis as any).Deno !== 'undefined') return 'deno'\n if (\n typeof globalThis.process !== 'undefined' &&\n globalThis.process.versions?.node\n )\n return 'node'\n return 'browser'\n}\n\nexport function detectCapability(): Capability {\n const runtime = detectRuntime()\n if (runtime === 'node' || runtime === 'bun') return 'full-threads'\n if (typeof (globalThis as any).Worker !== 'undefined') return 'full-threads'\n return 'single-thread'\n}\n","import { Worker } from 'node:worker_threads'\nimport { NODE_BOOTSTRAP_CODE } from '../bootstrap.js'\nimport type { ManagedWorker, WorkerAdapter } from './base.js'\n\nclass NodeManagedWorker implements ManagedWorker {\n private worker: Worker\n\n constructor() {\n this.worker = new Worker(NODE_BOOTSTRAP_CODE, { eval: true })\n }\n\n get id(): number {\n return this.worker.threadId\n }\n\n postMessage(data: unknown): void {\n this.worker.postMessage(data)\n }\n\n terminate(): Promise<number> {\n return this.worker.terminate()\n }\n\n on(event: 'message', handler: (data: unknown) => void): void\n on(event: 'error', handler: (err: Error) => void): void\n on(event: 'exit', handler: (code: number) => void): void\n on(event: string, handler: (...args: any[]) => void): void {\n this.worker.on(event, handler)\n }\n\n unref(): void {\n this.worker.unref()\n }\n\n ref(): void {\n this.worker.ref()\n }\n}\n\nexport class NodeWorkerAdapter implements WorkerAdapter {\n createWorker(): ManagedWorker {\n return new NodeManagedWorker()\n }\n}\n","/**\n * Channel proxy code shared between Node and Web bootstraps.\n * Injected at the top of the worker, inert unless channels are passed.\n */\nconst CHANNEL_PROXY_CODE = `\nconst __chCallbacks = new Map();\nlet __chRpcId = 0;\n\nclass __ChannelProxy {\n constructor(id) {\n this._id = id;\n }\n\n _rpc(op, value) {\n const correlationId = ++__chRpcId;\n return new Promise((resolve, reject) => {\n __chCallbacks.set(correlationId, { resolve, reject });\n __postMsg({\n type: 'channel-op',\n channelId: this._id,\n op,\n correlationId,\n value\n });\n });\n }\n\n send(value) {\n return this._rpc('send', value);\n }\n\n recv() {\n return this._rpc('recv', undefined);\n }\n\n close() {\n __postMsg({\n type: 'channel-op',\n channelId: this._id,\n op: 'close',\n correlationId: ++__chRpcId\n });\n }\n\n [Symbol.asyncIterator]() {\n const proxy = this;\n return {\n async next() {\n const value = await proxy.recv();\n if (value === null) return { done: true, value: undefined };\n return { done: false, value };\n }\n };\n }\n}\n\nfunction __handleChannelResult(msg) {\n if (msg.type === 'channel-result') {\n const cb = __chCallbacks.get(msg.correlationId);\n if (cb) {\n __chCallbacks.delete(msg.correlationId);\n if (msg.error) {\n cb.reject(new Error(msg.error));\n } else {\n cb.resolve(msg.value);\n }\n }\n }\n}\n\nfunction __buildChannelProxies(channels) {\n if (!channels) return undefined;\n const proxies = {};\n for (const name of Object.keys(channels)) {\n proxies[name] = new __ChannelProxy(channels[name]);\n }\n return proxies;\n}\n\nfunction __execFn(fnStr, channels) {\n if (channels) {\n const __ch = __buildChannelProxies(channels);\n const fn = new Function('__ch', 'return (' + fnStr + ')(__ch)');\n return fn(__ch);\n } else {\n const fn = new Function('return (' + fnStr + ')()');\n return fn();\n }\n}\n`\n\n/** Bootstrap code for Node.js workers (eval: true, CJS context) */\nexport const NODE_BOOTSTRAP_CODE = `\n'use strict';\nconst { parentPort } = require('worker_threads');\n\nconst __postMsg = (d) => parentPort.postMessage(d);\n\n${CHANNEL_PROXY_CODE}\n\nconst cancelledTasks = new Set();\n\nparentPort.on('message', (msg) => {\n __handleChannelResult(msg);\n});\n\nparentPort.on('message', async (msg) => {\n if (msg.type === 'execute') {\n if (msg.concurrent) {\n (async () => {\n if (cancelledTasks.has(msg.taskId)) {\n cancelledTasks.delete(msg.taskId);\n return;\n }\n try {\n const result = await __execFn(msg.fnStr, msg.channels);\n if (!cancelledTasks.has(msg.taskId)) {\n parentPort.postMessage({ type: 'result', taskId: msg.taskId, value: result });\n }\n } catch (error) {\n if (!cancelledTasks.has(msg.taskId)) {\n parentPort.postMessage({\n type: 'error',\n taskId: msg.taskId,\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n } finally {\n cancelledTasks.delete(msg.taskId);\n }\n })();\n } else {\n try {\n const result = await __execFn(msg.fnStr, msg.channels);\n parentPort.postMessage({ type: 'result', taskId: msg.taskId, value: result });\n } catch (error) {\n parentPort.postMessage({\n type: 'error',\n taskId: msg.taskId,\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n }\n } else if (msg.type === 'cancel') {\n cancelledTasks.add(msg.taskId);\n } else if (msg.type === 'shutdown') {\n process.exit(0);\n }\n});\n\nparentPort.postMessage({ type: 'ready' });\n`\n\n/** Bootstrap code for Bun/Web Workers (file-based, Web Worker API) */\nexport const WEB_BOOTSTRAP_CODE = `\nconst __postMsg = (d) => self.postMessage(d);\n\n${CHANNEL_PROXY_CODE}\n\nconst cancelledTasks = new Set();\n\nself.addEventListener('message', (event) => {\n __handleChannelResult(event.data);\n});\n\nself.onmessage = async (event) => {\n const msg = event.data;\n if (msg.type === 'execute') {\n if (msg.concurrent) {\n (async () => {\n if (cancelledTasks.has(msg.taskId)) {\n cancelledTasks.delete(msg.taskId);\n return;\n }\n try {\n const result = await __execFn(msg.fnStr, msg.channels);\n if (!cancelledTasks.has(msg.taskId)) {\n self.postMessage({ type: 'result', taskId: msg.taskId, value: result });\n }\n } catch (error) {\n if (!cancelledTasks.has(msg.taskId)) {\n self.postMessage({\n type: 'error',\n taskId: msg.taskId,\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n } finally {\n cancelledTasks.delete(msg.taskId);\n }\n })();\n } else {\n try {\n const result = await __execFn(msg.fnStr, msg.channels);\n self.postMessage({ type: 'result', taskId: msg.taskId, value: result });\n } catch (error) {\n self.postMessage({\n type: 'error',\n taskId: msg.taskId,\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n }\n } else if (msg.type === 'cancel') {\n cancelledTasks.add(msg.taskId);\n } else if (msg.type === 'shutdown') {\n self.close();\n }\n};\n\nself.postMessage({ type: 'ready' });\n`\n\n/** @deprecated Use NODE_BOOTSTRAP_CODE instead */\nexport const BOOTSTRAP_CODE = NODE_BOOTSTRAP_CODE\n","import { WEB_BOOTSTRAP_CODE } from '../bootstrap.js'\nimport type { ManagedWorker, WorkerAdapter } from './base.js'\nimport { writeFileSync, unlinkSync, mkdtempSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { tmpdir } from 'node:os'\n\nlet workerIdCounter = 0\nlet bootstrapFile: string | null = null\n\n/**\n * Returns the path to a temporary JS file containing the bootstrap code.\n * Bun's Blob URL workers break when the URL is revoked before the worker\n * fully initializes its message handler, so we use a file-based worker instead.\n */\nfunction getBootstrapFile(): string {\n if (!bootstrapFile) {\n const dir = mkdtempSync(join(tmpdir(), 'puru-'))\n bootstrapFile = join(dir, 'worker.js')\n writeFileSync(bootstrapFile, WEB_BOOTSTRAP_CODE)\n }\n return bootstrapFile\n}\n\nclass BunManagedWorker implements ManagedWorker {\n private worker: Worker\n readonly id: number\n\n constructor() {\n this.id = ++workerIdCounter\n this.worker = new Worker(getBootstrapFile())\n }\n\n postMessage(data: unknown): void {\n this.worker.postMessage(data)\n }\n\n terminate(): Promise<number> {\n this.worker.terminate()\n // Web Worker terminate() is synchronous and void; return resolved 0\n return Promise.resolve(0)\n }\n\n on(event: 'message', handler: (data: unknown) => void): void\n on(event: 'error', handler: (err: Error) => void): void\n on(event: 'exit', handler: (code: number) => void): void\n on(event: string, handler: (...args: any[]) => void): void {\n if (event === 'message') {\n this.worker.addEventListener('message', (e: MessageEvent) => {\n handler(e.data)\n })\n } else if (event === 'error') {\n this.worker.addEventListener('error', (e: ErrorEvent) => {\n handler(e.error ?? new Error(e.message))\n })\n } else if (event === 'exit') {\n // Bun emits 'close' on worker termination\n this.worker.addEventListener('close', (e: CloseEvent) => {\n handler((e as any).code ?? 0)\n })\n }\n }\n\n unref(): void {\n // Bun Workers support unref()\n if ('unref' in this.worker && typeof this.worker.unref === 'function') {\n ;(this.worker as any).unref()\n }\n }\n\n ref(): void {\n // Bun Workers support ref()\n if ('ref' in this.worker && typeof this.worker.ref === 'function') {\n ;(this.worker as any).ref()\n }\n }\n}\n\nexport class BunWorkerAdapter implements WorkerAdapter {\n createWorker(): ManagedWorker {\n return new BunManagedWorker()\n }\n}\n\n/** Clean up the temporary bootstrap file. Called during pool drain. */\nexport function cleanupBootstrapFile(): void {\n if (bootstrapFile) {\n try { unlinkSync(bootstrapFile) } catch {}\n bootstrapFile = null\n }\n}\n","export interface Channel<T> {\n send(value: T): Promise<void>\n recv(): Promise<T | null>\n close(): void\n [Symbol.asyncIterator](): AsyncIterator<T>\n}\n\ninterface PendingRecv<T> {\n resolve: (value: T | null) => void\n}\n\ninterface PendingSend<T> {\n value: T\n resolve: () => void\n reject: (reason: unknown) => void\n}\n\nlet channelIdCounter = 0\nconst channelRegistry = new Map<string, ChannelImpl<unknown>>()\n\nclass ChannelImpl<T> implements Channel<T> {\n /** @internal */\n readonly _id: string\n private buffer: T[] = []\n private capacity: number\n private closed = false\n private recvQueue: PendingRecv<T>[] = []\n private sendQueue: PendingSend<T>[] = []\n\n constructor(capacity: number) {\n this._id = `__ch_${++channelIdCounter}`\n this.capacity = capacity\n channelRegistry.set(this._id, this as ChannelImpl<unknown>)\n }\n\n send(value: T): Promise<void> {\n if (this.closed) {\n return Promise.reject(new Error('send on closed channel'))\n }\n\n // If there's a waiting receiver, deliver directly\n const receiver = this.recvQueue.shift()\n if (receiver) {\n receiver.resolve(value)\n return Promise.resolve()\n }\n\n // If buffer has room, buffer it\n if (this.buffer.length < this.capacity) {\n this.buffer.push(value)\n return Promise.resolve()\n }\n\n // Block until a receiver is ready\n return new Promise<void>((resolve, reject) => {\n this.sendQueue.push({ value, resolve, reject })\n })\n }\n\n recv(): Promise<T | null> {\n // If buffer has a value, take it and unblock a pending sender\n if (this.buffer.length > 0) {\n const value = this.buffer.shift()!\n const sender = this.sendQueue.shift()\n if (sender) {\n this.buffer.push(sender.value)\n sender.resolve()\n }\n return Promise.resolve(value)\n }\n\n // If there's a pending sender (unbuffered or buffer was empty), take directly\n const sender = this.sendQueue.shift()\n if (sender) {\n sender.resolve()\n return Promise.resolve(sender.value)\n }\n\n // If closed, return null\n if (this.closed) {\n return Promise.resolve(null)\n }\n\n // Block until a sender provides a value or channel closes\n return new Promise<T | null>((resolve) => {\n this.recvQueue.push({ resolve })\n })\n }\n\n close(): void {\n if (this.closed) return\n this.closed = true\n\n // Resolve all pending receivers with null\n for (const receiver of this.recvQueue) {\n receiver.resolve(null)\n }\n this.recvQueue = []\n\n // Reject all pending senders\n for (const sender of this.sendQueue) {\n sender.reject(new Error('send on closed channel'))\n }\n this.sendQueue = []\n }\n\n async *[Symbol.asyncIterator](): AsyncIterator<T> {\n while (true) {\n const value = await this.recv()\n if (value === null) return\n yield value\n }\n }\n}\n\nexport function chan<T>(capacity: number = 0): Channel<T> {\n if (capacity < 0 || !Number.isInteger(capacity)) {\n throw new RangeError('Channel capacity must be a non-negative integer')\n }\n return new ChannelImpl<T>(capacity)\n}\n\n/** @internal */\nexport function getChannelById(id: string): Channel<unknown> | undefined {\n return channelRegistry.get(id)\n}\n\n/** @internal */\nexport function resetChannelRegistry(): void {\n channelRegistry.clear()\n channelIdCounter = 0\n}\n","import type { ManagedWorker, WorkerAdapter } from './base.js'\nimport { getChannelById } from '../channel.js'\n\nlet inlineIdCounter = 0\n\ntype MessageHandler = (data: unknown) => void\ntype ErrorHandler = (err: Error) => void\ntype ExitHandler = (code: number) => void\n\nclass InlineManagedWorker implements ManagedWorker {\n readonly id: number\n private messageHandlers: MessageHandler[] = []\n private errorHandlers: ErrorHandler[] = []\n private exitHandlers: ExitHandler[] = []\n private terminated = false\n private cancelledTasks = new Set<string>()\n\n constructor() {\n this.id = ++inlineIdCounter\n // Emit ready on next microtask (matches real worker timing)\n queueMicrotask(() => {\n this.emit('message', { type: 'ready' })\n })\n }\n\n postMessage(data: unknown): void {\n if (this.terminated) return\n\n const msg = data as { type: string; taskId?: string; fnStr?: string; concurrent?: boolean; channels?: Record<string, string>; correlationId?: number; value?: unknown; error?: string }\n if (msg.type === 'execute') {\n this.executeTask(msg.taskId!, msg.fnStr!, msg.concurrent ?? false, msg.channels)\n } else if (msg.type === 'cancel') {\n this.cancelledTasks.add(msg.taskId!)\n } else if (msg.type === 'channel-result') {\n // Route channel results back to pending RPC callbacks\n this.emit('message', msg)\n } else if (msg.type === 'shutdown') {\n this.terminated = true\n this.emit('exit', 0)\n }\n }\n\n terminate(): Promise<number> {\n this.terminated = true\n this.emit('exit', 1)\n return Promise.resolve(1)\n }\n\n on(event: 'message', handler: MessageHandler): void\n on(event: 'error', handler: ErrorHandler): void\n on(event: 'exit', handler: ExitHandler): void\n on(event: string, handler: (...args: any[]) => void): void {\n if (event === 'message') this.messageHandlers.push(handler as MessageHandler)\n else if (event === 'error') this.errorHandlers.push(handler as ErrorHandler)\n else if (event === 'exit') this.exitHandlers.push(handler as ExitHandler)\n }\n\n unref(): void {}\n ref(): void {}\n\n private emit(event: 'message', data: unknown): void\n private emit(event: 'error', err: Error): void\n private emit(event: 'exit', code: number): void\n private emit(event: string, value: unknown): void {\n if (event === 'message') {\n for (const h of this.messageHandlers) h(value)\n } else if (event === 'error') {\n for (const h of this.errorHandlers) h(value as Error)\n } else if (event === 'exit') {\n for (const h of this.exitHandlers) h(value as number)\n }\n }\n\n private buildChannelProxies(channels: Record<string, string>): Record<string, unknown> {\n const self = this\n const proxies: Record<string, unknown> = {}\n for (const [name, channelId] of Object.entries(channels)) {\n proxies[name] = {\n _id: channelId,\n async send(value: unknown) {\n const ch = getChannelById(channelId)\n if (!ch) throw new Error(`Channel ${channelId} not found`)\n await ch.send(value)\n },\n async recv() {\n const ch = getChannelById(channelId)\n if (!ch) throw new Error(`Channel ${channelId} not found`)\n return ch.recv()\n },\n close() {\n const ch = getChannelById(channelId)\n if (ch) ch.close()\n },\n [Symbol.asyncIterator]() {\n const ch = getChannelById(channelId) as any\n if (!ch) throw new Error(`Channel ${channelId} not found`)\n return {\n async next() {\n const value = await ch.recv()\n if (value === null) return { done: true, value: undefined }\n return { done: false, value }\n }\n }\n }\n }\n }\n return proxies\n }\n\n private executeTask(taskId: string, fnStr: string, concurrent: boolean, channels?: Record<string, string>): void {\n // Run on next microtask to simulate async worker behavior\n queueMicrotask(async () => {\n if (this.terminated) return\n if (concurrent && this.cancelledTasks.has(taskId)) {\n this.cancelledTasks.delete(taskId)\n return\n }\n try {\n let result: unknown\n if (channels) {\n const proxies = this.buildChannelProxies(channels)\n const fn = new Function('__ch', 'return (' + fnStr + ')(__ch)') as (ch: unknown) => unknown\n result = await fn(proxies)\n } else {\n const fn = new Function('return (' + fnStr + ')()') as () => unknown\n result = await fn()\n }\n if (concurrent && this.cancelledTasks.has(taskId)) {\n this.cancelledTasks.delete(taskId)\n return\n }\n this.emit('message', { type: 'result', taskId, value: result })\n } catch (error) {\n if (concurrent && this.cancelledTasks.has(taskId)) {\n this.cancelledTasks.delete(taskId)\n return\n }\n this.emit('message', {\n type: 'error',\n taskId,\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n })\n }\n })\n }\n}\n\nexport class InlineAdapter implements WorkerAdapter {\n createWorker(): ManagedWorker {\n return new InlineManagedWorker()\n }\n}\n","import type { ManagedWorker, WorkerAdapter } from './adapters/base.js'\nimport type { PuruConfig, Task, WorkerMessage, WorkerResponse } from './types.js'\nimport { getConfig } from './configure.js'\nimport { detectRuntime, detectCapability } from './runtime.js'\nimport { NodeWorkerAdapter } from './adapters/node.js'\nimport { BunWorkerAdapter } from './adapters/bun.js'\nimport { InlineAdapter } from './adapters/inline.js'\nimport { getChannelById } from './channel.js'\n\nexport class WorkerPool {\n private config: PuruConfig\n private adapter: WorkerAdapter\n private idleWorkers: ManagedWorker[] = []\n private exclusiveWorkers = new Map<string, ManagedWorker>()\n private sharedWorkers = new Map<ManagedWorker, Set<string>>()\n private queues = {\n high: [] as Task[],\n normal: [] as Task[],\n low: [] as Task[],\n }\n private concurrentQueues = {\n high: [] as Task[],\n normal: [] as Task[],\n low: [] as Task[],\n }\n private allWorkers = new Set<ManagedWorker>()\n private idleTimers = new Map<ManagedWorker, ReturnType<typeof setTimeout>>()\n private pendingWorkerCount = 0\n private pendingTasksForWorkers: Task[] = []\n private draining = false\n private totalCompleted = 0\n private totalFailed = 0\n private taskMap = new Map<string, Task>()\n\n constructor(config: PuruConfig, adapter: WorkerAdapter) {\n this.config = config\n this.adapter = adapter\n }\n\n // --- Queue helpers ---\n\n private enqueue(task: Task): void {\n this.queues[task.priority].push(task)\n }\n\n private dequeue(): Task | undefined {\n return (\n this.queues.high.shift() ??\n this.queues.normal.shift() ??\n this.queues.low.shift()\n )\n }\n\n private enqueueConcurrent(task: Task): void {\n this.concurrentQueues[task.priority].push(task)\n }\n\n private dequeueConcurrent(): Task | undefined {\n return (\n this.concurrentQueues.high.shift() ??\n this.concurrentQueues.normal.shift() ??\n this.concurrentQueues.low.shift()\n )\n }\n\n private removeFromQueue(taskId: string): Task | undefined {\n for (const priority of ['high', 'normal', 'low'] as const) {\n const queue = this.queues[priority]\n const idx = queue.findIndex((t) => t.id === taskId)\n if (idx !== -1) {\n return queue.splice(idx, 1)[0]\n }\n }\n return undefined\n }\n\n private removeFromConcurrentQueue(taskId: string): Task | undefined {\n for (const priority of ['high', 'normal', 'low'] as const) {\n const queue = this.concurrentQueues[priority]\n const idx = queue.findIndex((t) => t.id === taskId)\n if (idx !== -1) {\n return queue.splice(idx, 1)[0]\n }\n }\n return undefined\n }\n\n // --- Submit ---\n\n submit(task: Task): void {\n if (this.draining) {\n task.reject(new Error('Pool is shutting down'))\n return\n }\n\n if (task.concurrent) {\n this.submitConcurrent(task)\n } else {\n this.submitExclusive(task)\n }\n }\n\n private submitExclusive(task: Task): void {\n // Try to assign to an idle worker\n const worker = this.idleWorkers.pop()\n if (worker) {\n this.dispatch(worker, task)\n return\n }\n\n // Try to create a new worker\n const totalWorkers = this.allWorkers.size + this.pendingWorkerCount\n if (totalWorkers < this.config.maxThreads) {\n this.pendingWorkerCount++\n this.pendingTasksForWorkers.push(task)\n this.createAndReadyWorker()\n return\n }\n\n // Queue the task by priority\n this.enqueue(task)\n }\n\n private submitConcurrent(task: Task): void {\n // 1. Find a shared worker under the concurrency limit\n for (const [worker, tasks] of this.sharedWorkers) {\n if (tasks.size < this.config.concurrency) {\n this.dispatchConcurrent(worker, task)\n return\n }\n }\n\n // 2. Grab an idle worker and convert to shared mode\n const idleWorker = this.idleWorkers.pop()\n if (idleWorker) {\n this.dispatchConcurrent(idleWorker, task)\n return\n }\n\n // 3. Spin up a new worker if under limit\n const totalWorkers = this.allWorkers.size + this.pendingWorkerCount\n if (totalWorkers < this.config.maxThreads) {\n this.pendingWorkerCount++\n this.pendingTasksForWorkers.push(task)\n this.createAndReadyWorker()\n return\n }\n\n // 4. All workers busy/saturated — queue it\n this.enqueueConcurrent(task)\n }\n\n // --- Dispatch ---\n\n private dispatch(worker: ManagedWorker, task: Task): void {\n const timer = this.idleTimers.get(worker)\n if (timer) {\n clearTimeout(timer)\n this.idleTimers.delete(worker)\n }\n\n worker.ref()\n this.exclusiveWorkers.set(task.id, worker)\n this.taskMap.set(task.id, task)\n\n const msg: WorkerMessage = {\n type: 'execute',\n taskId: task.id,\n fnStr: task.fnStr,\n concurrent: false,\n channels: task.channels,\n }\n worker.postMessage(msg)\n }\n\n private dispatchConcurrent(worker: ManagedWorker, task: Task): void {\n const timer = this.idleTimers.get(worker)\n if (timer) {\n clearTimeout(timer)\n this.idleTimers.delete(worker)\n }\n\n worker.ref()\n\n if (!this.sharedWorkers.has(worker)) {\n this.sharedWorkers.set(worker, new Set())\n }\n this.sharedWorkers.get(worker)!.add(task.id)\n this.taskMap.set(task.id, task)\n\n const msg: WorkerMessage = {\n type: 'execute',\n taskId: task.id,\n fnStr: task.fnStr,\n concurrent: true,\n channels: task.channels,\n }\n worker.postMessage(msg)\n }\n\n // --- Task completion ---\n\n private handleWorkerMessage(worker: ManagedWorker, response: WorkerResponse): void {\n if (response.type === 'channel-op') {\n this.handleChannelOp(worker, response)\n return\n }\n\n if (response.type === 'result') {\n const taskId = response.taskId\n this.resolveTask(taskId, response.value)\n\n if (this.exclusiveWorkers.has(taskId)) {\n this.exclusiveWorkers.delete(taskId)\n this.assignNextOrIdle(worker)\n } else {\n const taskSet = this.sharedWorkers.get(worker)\n if (taskSet) {\n taskSet.delete(taskId)\n this.assignNextConcurrentOrIdle(worker)\n }\n }\n } else if (response.type === 'error') {\n const taskId = response.taskId\n const err = new Error(response.message)\n if (response.stack) err.stack = response.stack\n this.rejectTask(taskId, err)\n\n if (this.exclusiveWorkers.has(taskId)) {\n this.exclusiveWorkers.delete(taskId)\n this.assignNextOrIdle(worker)\n } else {\n const taskSet = this.sharedWorkers.get(worker)\n if (taskSet) {\n taskSet.delete(taskId)\n this.assignNextConcurrentOrIdle(worker)\n }\n }\n }\n }\n\n private assignNextOrIdle(worker: ManagedWorker): void {\n if (!this.allWorkers.has(worker)) return\n\n // Try exclusive queue first\n const next = this.dequeue()\n if (next) {\n this.dispatch(worker, next)\n return\n }\n\n // Then try concurrent queue\n const concurrentNext = this.dequeueConcurrent()\n if (concurrentNext) {\n this.dispatchConcurrent(worker, concurrentNext)\n return\n }\n\n this.makeIdle(worker)\n }\n\n private assignNextConcurrentOrIdle(worker: ManagedWorker): void {\n if (!this.allWorkers.has(worker)) return\n\n const taskSet = this.sharedWorkers.get(worker)\n const currentCount = taskSet?.size ?? 0\n\n // Fill up to concurrency limit from concurrent queue\n let filled = currentCount\n while (filled < this.config.concurrency) {\n const next = this.dequeueConcurrent()\n if (!next) break\n this.dispatchConcurrent(worker, next)\n filled++\n }\n\n // If no tasks remain, transition back\n const updatedSet = this.sharedWorkers.get(worker)\n if (!updatedSet || updatedSet.size === 0) {\n this.sharedWorkers.delete(worker)\n // Try exclusive queue before going idle\n const exclusiveTask = this.dequeue()\n if (exclusiveTask) {\n this.dispatch(worker, exclusiveTask)\n } else {\n this.makeIdle(worker)\n }\n }\n }\n\n private makeIdle(worker: ManagedWorker): void {\n worker.unref()\n this.idleWorkers.push(worker)\n\n if (this.config.idleTimeout > 0) {\n const timer = setTimeout(() => {\n this.idleTimers.delete(worker)\n const idx = this.idleWorkers.indexOf(worker)\n if (idx !== -1) {\n this.idleWorkers.splice(idx, 1)\n }\n this.allWorkers.delete(worker)\n worker.terminate()\n }, this.config.idleTimeout)\n\n // Don't let the idle timer prevent process exit\n if (timer.unref) timer.unref()\n this.idleTimers.set(worker, timer)\n }\n }\n\n // --- Channel RPC ---\n\n private async handleChannelOp(\n worker: ManagedWorker,\n msg: { channelId: string; op: 'send' | 'recv' | 'close'; correlationId: number; value?: unknown },\n ): Promise<void> {\n const channel = getChannelById(msg.channelId)\n\n if (!channel) {\n worker.postMessage({\n type: 'channel-result',\n correlationId: msg.correlationId,\n error: `Channel ${msg.channelId} not found`,\n })\n return\n }\n\n try {\n if (msg.op === 'send') {\n await channel.send(msg.value)\n worker.postMessage({\n type: 'channel-result',\n correlationId: msg.correlationId,\n })\n } else if (msg.op === 'recv') {\n const value = await channel.recv()\n worker.postMessage({\n type: 'channel-result',\n correlationId: msg.correlationId,\n value,\n })\n } else if (msg.op === 'close') {\n channel.close()\n worker.postMessage({\n type: 'channel-result',\n correlationId: msg.correlationId,\n })\n }\n } catch (err) {\n worker.postMessage({\n type: 'channel-result',\n correlationId: msg.correlationId,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n // --- Task resolution ---\n\n private resolveTask(taskId: string, value: unknown): void {\n const task = this.taskMap.get(taskId)\n if (task) {\n this.taskMap.delete(taskId)\n this.totalCompleted++\n task.resolve(value)\n }\n }\n\n private rejectTask(taskId: string, reason: unknown): void {\n const task = this.taskMap.get(taskId)\n if (task) {\n this.taskMap.delete(taskId)\n this.totalFailed++\n task.reject(reason)\n }\n }\n\n // --- Cancellation ---\n\n cancelTask(taskId: string): void {\n // 1. Check exclusive queues\n const removed = this.removeFromQueue(taskId)\n if (removed) {\n removed.reject(new DOMException('Task was cancelled', 'AbortError'))\n return\n }\n\n // 2. Check concurrent queues\n const removedConcurrent = this.removeFromConcurrentQueue(taskId)\n if (removedConcurrent) {\n removedConcurrent.reject(new DOMException('Task was cancelled', 'AbortError'))\n return\n }\n\n // 3. Check exclusive workers — terminate the worker (existing behavior)\n const exclusiveWorker = this.exclusiveWorkers.get(taskId)\n if (exclusiveWorker) {\n this.exclusiveWorkers.delete(taskId)\n this.allWorkers.delete(exclusiveWorker)\n this.taskMap.delete(taskId)\n exclusiveWorker.terminate()\n return\n }\n\n // 4. Check shared workers — send cancel message, do NOT terminate\n for (const [worker, taskSet] of this.sharedWorkers) {\n if (taskSet.has(taskId)) {\n taskSet.delete(taskId)\n this.taskMap.delete(taskId)\n worker.postMessage({ type: 'cancel', taskId })\n if (taskSet.size === 0) {\n this.sharedWorkers.delete(worker)\n this.assignNextConcurrentOrIdle(worker)\n }\n return\n }\n }\n }\n\n // --- Lifecycle ---\n\n async drain(): Promise<void> {\n this.draining = true\n\n // Reject all queued exclusive tasks\n for (const priority of ['high', 'normal', 'low'] as const) {\n for (const task of this.queues[priority]) {\n task.reject(new Error('Pool is shutting down'))\n }\n this.queues[priority] = []\n }\n\n // Reject all queued concurrent tasks\n for (const priority of ['high', 'normal', 'low'] as const) {\n for (const task of this.concurrentQueues[priority]) {\n task.reject(new Error('Pool is shutting down'))\n }\n this.concurrentQueues[priority] = []\n }\n\n // Clear in-flight concurrent tasks — their workers are about to be terminated.\n // We don't reject them here because the caller may not be listening, which\n // would cause unhandled rejection errors. The promises will simply never settle.\n for (const [, taskSet] of this.sharedWorkers) {\n for (const taskId of taskSet) {\n this.taskMap.delete(taskId)\n }\n }\n\n // Terminate all workers\n const terminatePromises: Promise<number>[] = []\n for (const worker of this.allWorkers) {\n const timer = this.idleTimers.get(worker)\n if (timer) clearTimeout(timer)\n terminatePromises.push(worker.terminate())\n }\n\n await Promise.all(terminatePromises)\n\n this.idleWorkers = []\n this.exclusiveWorkers.clear()\n this.sharedWorkers.clear()\n this.allWorkers.clear()\n this.idleTimers.clear()\n }\n\n resize(maxThreads: number): void {\n this.config = { ...this.config, maxThreads }\n\n // If we now have capacity, dequeue tasks and spin up workers\n while (true) {\n const totalWorkers = this.allWorkers.size + this.pendingWorkerCount\n if (totalWorkers >= maxThreads) break\n // Try exclusive queue first, then concurrent\n const task = this.dequeue() ?? this.dequeueConcurrent()\n if (!task) break\n this.pendingWorkerCount++\n this.pendingTasksForWorkers.push(task)\n this.createAndReadyWorker()\n }\n\n // If pool is now oversized, terminate excess idle workers\n while (this.allWorkers.size > maxThreads && this.idleWorkers.length > 0) {\n const worker = this.idleWorkers.pop()!\n const timer = this.idleTimers.get(worker)\n if (timer) {\n clearTimeout(timer)\n this.idleTimers.delete(worker)\n }\n this.allWorkers.delete(worker)\n worker.terminate()\n }\n }\n\n // --- Worker creation ---\n\n private createAndReadyWorker(): void {\n const worker = this.adapter.createWorker()\n\n const onReady = () => {\n this.pendingWorkerCount--\n this.allWorkers.add(worker)\n\n const task = this.pendingTasksForWorkers.shift()\n if (task) {\n if (task.concurrent) {\n this.dispatchConcurrent(worker, task)\n } else {\n this.dispatch(worker, task)\n }\n } else {\n this.makeIdle(worker)\n }\n }\n\n worker.on('message', (msg: unknown) => {\n const response = msg as WorkerResponse\n if (response.type === 'ready') {\n onReady()\n return\n }\n this.handleWorkerMessage(worker, response)\n })\n\n worker.on('error', (err: Error) => {\n // Clean up exclusive task on this worker\n for (const [taskId, w] of this.exclusiveWorkers) {\n if (w === worker) {\n this.exclusiveWorkers.delete(taskId)\n break\n }\n }\n // Clean up concurrent tasks on this worker\n const taskSet = this.sharedWorkers.get(worker)\n if (taskSet) {\n for (const taskId of taskSet) {\n this.rejectTask(taskId, err)\n }\n this.sharedWorkers.delete(worker)\n }\n })\n\n worker.on('exit', (_code: number) => {\n this.allWorkers.delete(worker)\n const timer = this.idleTimers.get(worker)\n if (timer) {\n clearTimeout(timer)\n this.idleTimers.delete(worker)\n }\n\n // Remove from idle if present\n const idleIdx = this.idleWorkers.indexOf(worker)\n if (idleIdx !== -1) {\n this.idleWorkers.splice(idleIdx, 1)\n }\n\n // Clean up exclusive task\n for (const [taskId, w] of this.exclusiveWorkers) {\n if (w === worker) {\n this.exclusiveWorkers.delete(taskId)\n break\n }\n }\n\n // Clean up concurrent tasks\n const taskSet = this.sharedWorkers.get(worker)\n if (taskSet) {\n for (const taskId of taskSet) {\n this.rejectTask(taskId, new Error('Worker exited unexpectedly'))\n }\n this.sharedWorkers.delete(worker)\n }\n })\n }\n\n // --- Stats ---\n\n stats(): PoolStats {\n let concurrentTasks = 0\n for (const taskSet of this.sharedWorkers.values()) {\n concurrentTasks += taskSet.size\n }\n\n return {\n totalWorkers: this.allWorkers.size,\n idleWorkers: this.idleWorkers.length,\n busyWorkers: this.exclusiveWorkers.size,\n sharedWorkers: this.sharedWorkers.size,\n concurrentTasks,\n pendingWorkers: this.pendingWorkerCount,\n queuedTasks: {\n high: this.queues.high.length,\n normal: this.queues.normal.length,\n low: this.queues.low.length,\n total:\n this.queues.high.length +\n this.queues.normal.length +\n this.queues.low.length,\n },\n queuedConcurrentTasks: {\n high: this.concurrentQueues.high.length,\n normal: this.concurrentQueues.normal.length,\n low: this.concurrentQueues.low.length,\n total:\n this.concurrentQueues.high.length +\n this.concurrentQueues.normal.length +\n this.concurrentQueues.low.length,\n },\n totalCompleted: this.totalCompleted,\n totalFailed: this.totalFailed,\n maxThreads: this.config.maxThreads,\n concurrency: this.config.concurrency,\n }\n }\n}\n\nexport interface PoolStats {\n totalWorkers: number\n idleWorkers: number\n busyWorkers: number\n sharedWorkers: number\n concurrentTasks: number\n pendingWorkers: number\n queuedTasks: {\n high: number\n normal: number\n low: number\n total: number\n }\n queuedConcurrentTasks: {\n high: number\n normal: number\n low: number\n total: number\n }\n totalCompleted: number\n totalFailed: number\n maxThreads: number\n concurrency: number\n}\n\n// Pool singleton\nlet poolInstance: WorkerPool | null = null\n\nfunction createAdapter(adapterConfig: string): WorkerAdapter {\n if (adapterConfig === 'inline') return new InlineAdapter()\n if (adapterConfig === 'node') return new NodeWorkerAdapter()\n if (adapterConfig === 'bun') return new BunWorkerAdapter()\n\n // auto — detect runtime\n const capability = detectCapability()\n if (capability === 'single-thread') {\n throw new Error(\n 'puru requires a runtime with thread support (Node.js or Bun). ' +\n 'Current runtime does not support worker threads.',\n )\n }\n const runtime = detectRuntime()\n if (runtime === 'bun') return new BunWorkerAdapter()\n return new NodeWorkerAdapter()\n}\n\nexport function getPool(): WorkerPool {\n if (!poolInstance) {\n const config = getConfig()\n poolInstance = new WorkerPool(config, createAdapter(config.adapter))\n }\n return poolInstance\n}\n\nexport function stats(): PoolStats {\n return getPool().stats()\n}\n\nexport function resize(maxThreads: number): void {\n getPool().resize(maxThreads)\n}\n\nexport async function resetPool(): Promise<void> {\n if (poolInstance) {\n await poolInstance.drain()\n poolInstance = null\n }\n}\n","import { serializeFunction } from './serialize.js'\nimport { getPool } from './pool.js'\nimport type { SpawnResult, Task } from './types.js'\nimport type { Channel } from './channel.js'\n\nlet taskCounter = 0\n\nexport function spawn<T>(\n fn: (() => T | Promise<T>) | ((channels: Record<string, Channel<unknown>>) => T | Promise<T>),\n opts?: {\n priority?: 'low' | 'normal' | 'high'\n concurrent?: boolean\n channels?: Record<string, Channel<unknown>>\n },\n): SpawnResult<T> {\n const fnStr = serializeFunction(fn)\n const taskId = String(++taskCounter)\n\n // Capture the call site stack for better error reporting\n const spawnStack = new Error().stack\n\n let resolveFn!: (value: T) => void\n let rejectFn!: (reason: unknown) => void\n let settled = false\n\n const result = new Promise<T>((resolve, reject) => {\n resolveFn = resolve\n rejectFn = reject\n })\n\n // Extract channel IDs if channels are provided\n let channelMap: Record<string, string> | undefined\n if (opts?.channels) {\n channelMap = {}\n for (const [name, ch] of Object.entries(opts.channels)) {\n const impl = ch as unknown as { _id: string }\n if (!impl._id) {\n throw new Error(`Channel \"${name}\" is not a valid puru channel`)\n }\n channelMap[name] = impl._id\n }\n }\n\n const task: Task = {\n id: taskId,\n fnStr,\n priority: opts?.priority ?? 'normal',\n concurrent: opts?.concurrent ?? false,\n channels: channelMap,\n resolve: (value) => {\n if (!settled) {\n settled = true\n resolveFn(value as T)\n }\n },\n reject: (reason) => {\n if (!settled) {\n settled = true\n // Enrich worker errors with the spawn() call site\n if (reason instanceof Error && spawnStack) {\n const callerLine = spawnStack\n .split('\\n')\n .slice(2)\n .join('\\n')\n reason.stack =\n (reason.stack ?? reason.message) +\n '\\n --- spawned at ---\\n' +\n callerLine\n }\n rejectFn(reason)\n }\n },\n }\n\n getPool().submit(task)\n\n const cancel = () => {\n if (settled) return\n settled = true\n getPool().cancelTask(taskId)\n rejectFn(new DOMException('Task was cancelled', 'AbortError'))\n }\n\n return { result, cancel }\n}\n\n/** @internal For testing only */\nexport function resetTaskCounter(): void {\n taskCounter = 0\n}\n","import { spawn } from './spawn.js'\nimport type { SpawnResult } from './types.js'\nimport type { Channel } from './channel.js'\n\nexport class WaitGroup {\n private tasks: SpawnResult<unknown>[] = []\n private controller = new AbortController()\n\n get signal(): AbortSignal {\n return this.controller.signal\n }\n\n spawn(\n fn: (() => unknown) | ((channels: Record<string, Channel<unknown>>) => unknown),\n opts?: { concurrent?: boolean; channels?: Record<string, Channel<unknown>> },\n ): void {\n if (this.controller.signal.aborted) {\n throw new Error('WaitGroup has been cancelled')\n }\n const handle = spawn(fn, opts)\n this.tasks.push(handle)\n }\n\n async wait(): Promise<unknown[]> {\n return Promise.all(this.tasks.map((t) => t.result))\n }\n\n async waitSettled(): Promise<PromiseSettledResult<unknown>[]> {\n return Promise.allSettled(this.tasks.map((t) => t.result))\n }\n\n cancel(): void {\n this.controller.abort()\n for (const task of this.tasks) {\n task.cancel()\n }\n }\n}\n","import { spawn } from './spawn.js'\nimport type { SpawnResult } from './types.js'\n\nexport class ErrGroup {\n private tasks: SpawnResult<unknown>[] = []\n private controller = new AbortController()\n private firstError: unknown = undefined\n private hasError = false\n\n get signal(): AbortSignal {\n return this.controller.signal\n }\n\n spawn(fn: () => unknown, opts?: { concurrent?: boolean }): void {\n if (this.controller.signal.aborted) {\n throw new Error('ErrGroup has been cancelled')\n }\n const handle = spawn(fn, opts)\n\n // Watch for errors and cancel all tasks on first failure\n handle.result.catch((err) => {\n if (!this.hasError) {\n this.hasError = true\n this.firstError = err\n this.cancel()\n }\n })\n\n this.tasks.push(handle)\n }\n\n async wait(): Promise<unknown[]> {\n const settled = await Promise.allSettled(this.tasks.map((t) => t.result))\n\n if (this.hasError) {\n throw this.firstError\n }\n\n return settled.map((r) => {\n if (r.status === 'fulfilled') return r.value\n throw r.reason\n })\n }\n\n cancel(): void {\n this.controller.abort()\n for (const task of this.tasks) {\n task.cancel()\n }\n }\n}\n","export class Mutex {\n private queue: (() => void)[] = []\n private locked = false\n\n async lock(): Promise<void> {\n if (!this.locked) {\n this.locked = true\n return\n }\n return new Promise<void>((resolve) => {\n this.queue.push(resolve)\n })\n }\n\n unlock(): void {\n if (!this.locked) {\n throw new Error('Cannot unlock a mutex that is not locked')\n }\n const next = this.queue.shift()\n if (next) {\n next()\n } else {\n this.locked = false\n }\n }\n\n async withLock<T>(fn: () => T | Promise<T>): Promise<T> {\n await this.lock()\n try {\n return await fn()\n } finally {\n this.unlock()\n }\n }\n\n get isLocked(): boolean {\n return this.locked\n }\n}\n","export class Once<T = void> {\n private promise: Promise<T> | null = null\n private called = false\n\n async do(fn: () => T | Promise<T>): Promise<T> {\n if (!this.called) {\n this.called = true\n this.promise = Promise.resolve(fn())\n }\n return this.promise!\n }\n\n get done(): boolean {\n return this.called\n }\n\n reset(): void {\n this.called = false\n this.promise = null\n }\n}\n","type SelectCase<T = unknown> = [Promise<T>, (value: T) => void]\n\nexport interface SelectOptions {\n default?: () => void\n}\n\nexport function select(\n cases: SelectCase[],\n opts?: SelectOptions,\n): Promise<void> {\n if (cases.length === 0) {\n if (opts?.default) {\n opts.default()\n }\n return Promise.resolve()\n }\n\n // Non-blocking: if default is provided, check if any promise is already settled\n if (opts?.default) {\n // Race a microtask against the promises to check if any is immediately ready\n return new Promise<void>((resolve, reject) => {\n let settled = false\n\n // Check all promises for immediate resolution\n for (const [promise, handler] of cases) {\n Promise.resolve(promise).then(\n (value) => {\n if (settled) return\n settled = true\n try {\n handler(value)\n resolve()\n } catch (err) {\n reject(err)\n }\n },\n (err) => {\n if (settled) return\n settled = true\n reject(err)\n },\n )\n }\n\n // Schedule default on the next microtask — if no promise resolved synchronously,\n // default wins\n queueMicrotask(() => {\n if (settled) return\n settled = true\n try {\n opts.default!()\n resolve()\n } catch (err) {\n reject(err)\n }\n })\n })\n }\n\n // Blocking: wait for the first promise to settle\n return new Promise<void>((resolve, reject) => {\n let settled = false\n\n cases.forEach(([promise, handler]) => {\n promise.then(\n (value) => {\n if (settled) return\n settled = true\n try {\n handler(value)\n resolve()\n } catch (err) {\n reject(err)\n }\n },\n (err) => {\n if (settled) return\n settled = true\n reject(err)\n },\n )\n })\n })\n}\n","export function after(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n","export class Ticker {\n private interval: ReturnType<typeof setInterval> | null = null\n private resolve: (() => void) | null = null\n private stopped = false\n private ms: number\n\n constructor(ms: number) {\n this.ms = ms\n this.interval = setInterval(() => {\n if (this.resolve) {\n const r = this.resolve\n this.resolve = null\n r()\n }\n }, ms)\n if (this.interval.unref) this.interval.unref()\n }\n\n async tick(): Promise<boolean> {\n if (this.stopped) return false\n return new Promise<boolean>((resolve) => {\n this.resolve = () => resolve(true)\n })\n }\n\n stop(): void {\n this.stopped = true\n if (this.interval) {\n clearInterval(this.interval)\n this.interval = null\n }\n if (this.resolve) {\n const r = this.resolve\n this.resolve = null\n r()\n }\n }\n\n async *[Symbol.asyncIterator](): AsyncIterator<void> {\n while (await this.tick()) {\n yield\n }\n }\n}\n\nexport function ticker(ms: number): Ticker {\n return new Ticker(ms)\n}\n","import { getPool } from './pool.js'\nimport { serializeFunction } from './serialize.js'\nimport type { SpawnResult, Task } from './types.js'\n\ntype TaskFn = (...args: unknown[]) => unknown\n\nconst registry = new Map<string, TaskFn>()\nlet taskCounter = 0\n\nexport function register(name: string, fn: TaskFn): void {\n if (registry.has(name)) {\n throw new Error(`Task \"${name}\" is already registered`)\n }\n registry.set(name, fn)\n}\n\nexport function run<T = unknown>(\n name: string,\n ...args: unknown[]\n): Promise<T> {\n const fn = registry.get(name)\n if (!fn) {\n throw new Error(`Task \"${name}\" is not registered. Call register() first.`)\n }\n\n // Serialize the function and JSON-encode args into a self-contained string\n // that the worker can execute without any closures.\n const fnStr = serializeFunction(fn)\n const serializedArgs = args.map((a) => {\n const json = JSON.stringify(a)\n if (json === undefined) {\n throw new TypeError(\n `Argument of type ${typeof a} is not JSON-serializable. ` +\n 'run() args must be JSON-serializable (no undefined, functions, symbols, or BigInt).',\n )\n }\n return json\n })\n const wrapperStr = `() => (${fnStr})(${serializedArgs.join(', ')})`\n\n const taskId = `reg_${++taskCounter}`\n const spawnStack = new Error().stack\n\n let resolveFn!: (value: T) => void\n let rejectFn!: (reason: unknown) => void\n\n const result = new Promise<T>((resolve, reject) => {\n resolveFn = resolve\n rejectFn = reject\n })\n\n const task: Task = {\n id: taskId,\n fnStr: wrapperStr,\n priority: 'normal',\n concurrent: false,\n resolve: (value) => resolveFn(value as T),\n reject: (reason) => {\n if (reason instanceof Error && spawnStack) {\n const callerLine = spawnStack.split('\\n').slice(2).join('\\n')\n reason.stack =\n (reason.stack ?? reason.message) +\n '\\n --- spawned at ---\\n' +\n callerLine\n }\n rejectFn(reason)\n },\n }\n\n getPool().submit(task)\n\n return result\n}\n\n/** @internal For testing only */\nexport function clearRegistry(): void {\n registry.clear()\n taskCounter = 0\n}\n"],"mappings":"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","names":["Worker","Worker","sender","taskCounter"]}
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@dmop/puru",
3
+ "version": "0.1.0",
4
+ "description": "puru (プール) — Goroutine-style concurrency for JavaScript",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "engines": {
25
+ "node": ">=18.0.0"
26
+ },
27
+ "scripts": {
28
+ "build": "tsup",
29
+ "test": "vitest run",
30
+ "test:watch": "vitest",
31
+ "typecheck": "tsc --noEmit",
32
+ "bench": "npm run build && npx tsx benchmarks/run-all.ts",
33
+ "bench:node": "npm run build && npx tsx benchmarks/run-all.ts",
34
+ "bench:bun": "npm run build && bun benchmarks/run-all.ts",
35
+ "bench:fib": "npx tsx benchmarks/01-fibonacci.ts",
36
+ "bench:primes": "npx tsx benchmarks/02-primes.ts",
37
+ "bench:matrix": "npx tsx benchmarks/03-matrix.ts",
38
+ "bench:data": "npx tsx benchmarks/04-data-processing.ts",
39
+ "bench:overhead": "npx tsx benchmarks/05-overhead.ts",
40
+ "bench:channels": "npx tsx benchmarks/06-channels-pipeline.ts",
41
+ "bench:concurrent": "npx tsx benchmarks/07-concurrent-async.ts",
42
+ "bench:mutex": "npx tsx benchmarks/08-mutex.ts",
43
+ "bench:errgroup": "npx tsx benchmarks/09-errgroup.ts",
44
+ "bench:select": "npx tsx benchmarks/10-select-default.ts",
45
+ "bench:once": "npx tsx benchmarks/11-once-ticker.ts",
46
+ "prepublishOnly": "npm run build"
47
+ },
48
+ "devDependencies": {
49
+ "@types/node": "^22.0.0",
50
+ "bun-types": "^1.3.11",
51
+ "tsup": "^8.5.0",
52
+ "typescript": "^5.7.0",
53
+ "vitest": "^3.1.0"
54
+ },
55
+ "keywords": [
56
+ "concurrency",
57
+ "goroutine",
58
+ "worker",
59
+ "channel",
60
+ "threads",
61
+ "parallel"
62
+ ],
63
+ "license": "MIT",
64
+ "author": "Danilo Pedrosa",
65
+ "repository": {
66
+ "type": "git",
67
+ "url": "git+https://github.com/dmop/puru.git"
68
+ },
69
+ "homepage": "https://github.com/dmop/puru#readme",
70
+ "bugs": {
71
+ "url": "https://github.com/dmop/puru/issues"
72
+ }
73
+ }