@nadrif/thread 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.
package/src/types.js ADDED
@@ -0,0 +1,1354 @@
1
+ /**
2
+ * @file Central type definitions for the thread library.
3
+ *
4
+ * Import these types in TypeScript projects for full editor intellisense:
5
+ *
6
+ * ```ts
7
+ * import type {
8
+ * // Thread & Pool
9
+ * ThreadDefinition,
10
+ * ThreadOptions,
11
+ * ThreadRunOptions,
12
+ * PoolOptions,
13
+ * PoolRunOptions,
14
+ * PoolTaskResult,
15
+ * PoolStatus,
16
+ * // GPU
17
+ * GPUComputeOptions,
18
+ * GPUComputeInput,
19
+ * GPUComputeSnapshot,
20
+ * OpDeclaration,
21
+ * // Hooks
22
+ * UseThreadReturn,
23
+ * UsePoolReturn,
24
+ * UseGPUReturn,
25
+ * UseGPURunReturn,
26
+ * // Adapters
27
+ * ZustandBinderOptions,
28
+ * SignalBinderOptions,
29
+ * StoreBinderOptions,
30
+ * BinderHandle,
31
+ * Signal,
32
+ * // Common
33
+ * MetricsSnapshot,
34
+ * ThreadEventName,
35
+ * } from 'thread/types';
36
+ * ```
37
+ *
38
+ * @module types
39
+ */
40
+
41
+ // ---------------------------------------------------------------------------
42
+ // Thread definition (what the worker executes)
43
+ // ---------------------------------------------------------------------------
44
+
45
+ /**
46
+ * An object describing the worker's lifecycle and execution logic.
47
+ *
48
+ * Use this form when you need **persistent state** that survives across task
49
+ * invocations. The `setup` function runs exactly once when the worker starts,
50
+ * and its return value becomes `state` – the first argument to every `exec`
51
+ * call. `cleanup` runs right before the worker is terminated.
52
+ *
53
+ * @example
54
+ * // A counter that remembers its count between calls.
55
+ * const definition = {
56
+ * setup() {
57
+ * return { count: 0 };
58
+ * },
59
+ * exec(state, delta) {
60
+ * state.count += delta;
61
+ * return state.count;
62
+ * },
63
+ * cleanup(state) {
64
+ * console.log('Final count:', state.count);
65
+ * },
66
+ * };
67
+ *
68
+ * @typedef {Object} ThreadDefinition
69
+ * @property {((state: any) => any | Promise<any>) | null} [setup]
70
+ * Runs once when the worker starts. Return value is stored as `state`
71
+ * and passed as the first argument to every `exec` call.
72
+ * @property {(state: any, ...args: any[]) => any | Promise<any>} exec
73
+ * Runs on every task invocation. Receives `state` (from `setup`),
74
+ * then any arguments supplied to `thread.run(...)`, and finally a
75
+ * `ctx` context object for reporting progress and logs.
76
+ * @property {((state: any) => void | Promise<void>) | null} [cleanup]
77
+ * Runs once before the worker is terminated. Useful for flushing
78
+ * buffers, closing connections, etc.
79
+ */
80
+
81
+ /**
82
+ * Context object passed as the **last** argument to every `exec` call.
83
+ * Provides the worker-side API for communicating back to the host.
84
+ *
85
+ * @example
86
+ * exec(state, items, ctx) {
87
+ * for (let i = 0; i < items.length; i++) {
88
+ * ctx.reportProgress(i / items.length);
89
+ * ctx.log(`Processing item ${i}`);
90
+ * }
91
+ * ctx.reportMemory();
92
+ * return items.length;
93
+ * }
94
+ *
95
+ * @typedef {Object} ThreadContext
96
+ * @property {(value: number) => void} reportProgress
97
+ * Report a progress value (0–1) back to the host. Only delivered
98
+ * if the caller registered a `progress` listener or passed
99
+ * `hasProgress: true`.
100
+ * @property {(message: string) => void} log
101
+ * Send a log message back to the host. Delivered to every `log`
102
+ * listener registered on the Thread.
103
+ * @property {() => void} reportMemory
104
+ * Request a memory report from the worker. Delivered to every
105
+ * `memory` listener (browser-only, requires `performance.memory`).
106
+ */
107
+
108
+ // ---------------------------------------------------------------------------
109
+ // Thread options
110
+ // ---------------------------------------------------------------------------
111
+
112
+ /**
113
+ * Configuration for a {@link Thread} instance.
114
+ *
115
+ * @example
116
+ * const thread = createThread((x) => x * 2, {
117
+ * timeout: 5000, // reject if task takes >5s
118
+ * idleTimeout: 60_000, // auto-terminate after 60s idle
119
+ * concurrency: 2, // allow 2 concurrent tasks
120
+ * healthCheckInterval: 10_000,
121
+ * onLog: (msg) => console.log('[worker]', msg),
122
+ * onTiming: (ms) => console.log(`Task took ${ms.toFixed(1)}ms`),
123
+ * });
124
+ *
125
+ * @typedef {Object} ThreadOptions
126
+ * @property {number} [timeout=30000]
127
+ * Default timeout in milliseconds. If a task does not resolve within
128
+ * this period, the promise rejects with a {@link ThreadTimeoutError}.
129
+ * Pass `{ timeout: n }` per-task to override.
130
+ * @property {number} [idleTimeout=0]
131
+ * Automatically terminate the worker after this many milliseconds of
132
+ * inactivity. `0` means **never** auto-terminate (the default).
133
+ * @property {string[]} [imports]
134
+ * Script URLs to load via `importScripts()` inside the worker before
135
+ * any tasks run. Useful for loading shared libraries.
136
+ * @property {any[]} [initArgs]
137
+ * Arguments for a silent one-time initialisation run executed
138
+ * immediately after the worker starts. The result is discarded.
139
+ * Useful for warming up WASM modules or opening IndexedDB stores.
140
+ * @property {Transferable[]} [initTransfer]
141
+ * Transferables for the `initArgs` run.
142
+ * @property {number} [healthCheckInterval=0]
143
+ * How often (in ms) to ping the worker to verify it is alive.
144
+ * `0` disables health checks.
145
+ * @property {number} [healthCheckTimeout=5000]
146
+ * Max ms to wait for a health-check pong before declaring the
147
+ * worker unhealthy.
148
+ * @property {number} [concurrency=1]
149
+ * Maximum number of tasks this worker can execute concurrently.
150
+ * Setting this >1 turns the single worker into a small N-worker.
151
+ * @property {((args: any[]) => any[]) | null} [onBeforeRun]
152
+ * Hook called before each task. Receives the argument array; return
153
+ * a new array to replace the arguments, or `undefined` to keep them.
154
+ * @property {((result: any) => any) | null} [onAfterRun]
155
+ * Hook called after each successful task. Return a new value to
156
+ * replace the result, or `undefined` to keep it.
157
+ * @property {((result: any, event: MessageEvent) => void) | null} [onResult]
158
+ * Global listener invoked on every successful result.
159
+ * @property {((info: {error: string, stack?: string}, event: MessageEvent) => void) | null} [onError]
160
+ * Global listener invoked on every error.
161
+ * @property {((value: any, event: MessageEvent) => void) | null} [onProgress]
162
+ * Global listener invoked on every progress update.
163
+ * @property {((durationMs: number, args: any[]) => void) | null} [onTiming]
164
+ * Listener invoked with the wall-clock duration of each task.
165
+ * @property {((message: string, event: MessageEvent) => void) | null} [onLog]
166
+ * Listener invoked when the worker calls `ctx.log(msg)`.
167
+ * @property {((memory: any, event: MessageEvent) => void) | null} [onMemory]
168
+ * Listener invoked when the worker calls `ctx.reportMemory()`.
169
+ * @property {((snapshot: MetricsSnapshot) => void) | null} [onMetrics]
170
+ * Listener invoked after every completed task with the latest
171
+ * metrics snapshot.
172
+ */
173
+
174
+ // ---------------------------------------------------------------------------
175
+ // Thread run options (per-task overrides)
176
+ // ---------------------------------------------------------------------------
177
+
178
+ /**
179
+ * Per-task options passed as the **last** argument to `thread.run()`.
180
+ *
181
+ * @example
182
+ * const controller = new AbortController();
183
+ * const result = await thread.run(largeData, {
184
+ * timeout: 10_000,
185
+ * signal: controller.signal,
186
+ * retries: 2,
187
+ * transfer: [largeData.buffer],
188
+ * cacheTTL: 30_000,
189
+ * });
190
+ *
191
+ * @typedef {Object} ThreadRunOptions
192
+ * @property {number} [timeout]
193
+ * Override the thread's default timeout for this task (ms).
194
+ * @property {Transferable[]} [transfer]
195
+ * Array of `Transferable` objects (e.g. `ArrayBuffer`) to transfer
196
+ * to the worker instead of copying. Dramatically improves speed
197
+ * for large binary data.
198
+ * @property {AbortSignal} [signal]
199
+ * An `AbortSignal` to cancel the task. When `signal.abort()` fires,
200
+ * the task promise rejects with a {@link ThreadAbortError}.
201
+ * @property {number} [retries]
202
+ * Number of times to retry the task if the worker crashes or the
203
+ * `postMessage` call fails.
204
+ * @property {number} [cacheTTL]
205
+ * Cache the result for this many milliseconds. Subsequent calls
206
+ * with identical arguments return the cached value instantly.
207
+ * `0` disables caching (the default).
208
+ */
209
+
210
+ // ---------------------------------------------------------------------------
211
+ // Pool types
212
+ // ---------------------------------------------------------------------------
213
+
214
+ /**
215
+ * Configuration for a {@link ThreadPool}.
216
+ *
217
+ * @example
218
+ * const pool = createPool(4, heavyComputation, {
219
+ * timeout: 30_000,
220
+ * autoRestart: true,
221
+ * maxSize: 8,
222
+ * healthCheckInterval: 5_000,
223
+ * enableStealing: true,
224
+ * keyHasher: (args) => String(args[0].id), // route by entity id
225
+ * });
226
+ *
227
+ * @typedef {Object} PoolOptions
228
+ * @property {number} [timeout]
229
+ * Default timeout applied to every task (ms). Individual tasks can
230
+ * override this via their own options.
231
+ * @property {number} [idleTimeout]
232
+ * Idle timeout forwarded to each thread.
233
+ * @property {string[]} [imports]
234
+ * Script URLs forwarded to each thread.
235
+ * @property {boolean} [autoRestart=true]
236
+ * When a worker crashes, automatically replace it with a fresh
237
+ * worker and move any queued tasks back into the global queue.
238
+ * @property {number} [maxSize=Infinity]
239
+ * Hard upper limit on the number of threads. `scaleTo()` and
240
+ * auto-restart will never exceed this.
241
+ * @property {number} [healthCheckInterval]
242
+ * Health-check interval forwarded to each thread.
243
+ * @property {number} [healthCheckTimeout]
244
+ * Health-check timeout forwarded to each thread.
245
+ * @property {((args: any[]) => string) | null} [keyHasher]
246
+ * Function that maps task arguments to a string key for affinity
247
+ * routing. Tasks with the same key are preferentially routed to
248
+ * the same thread (useful for caches and connection pools).
249
+ * @property {boolean} [enableStealing=true]
250
+ * Enable work-stealing: idle threads can steal queued tasks from
251
+ * busy threads' local queues.
252
+ * @property {number} [concurrency]
253
+ * Max parallel tasks per worker (forwarded to each thread).
254
+ */
255
+
256
+ /**
257
+ * Options for a single {@link ThreadPool.run} call.
258
+ *
259
+ * @example
260
+ * const { id, promise } = pool.run(data, {
261
+ * priority: 1, // lower = higher priority
262
+ * dependsOn: [a, b], // wait for tasks a and b to finish first
263
+ * timeout: 5000,
264
+ * retries: 1,
265
+ * });
266
+ *
267
+ * @typedef {Object} PoolRunOptions
268
+ * @property {number} [priority=0]
269
+ * Task priority. Lower numbers are dequeued first. Default is `0`.
270
+ * @property {number[]} [dependsOn]
271
+ * Array of task IDs that must complete before this task starts.
272
+ * If any dependency fails, this task is rejected with a
273
+ * {@link ThreadDependencyError}.
274
+ * @property {string} [key]
275
+ * Affinity key. If a `keyHasher` is configured, this overrides it.
276
+ * @property {number} [timeout]
277
+ * Per-task timeout (ms). Overrides the pool default.
278
+ * @property {Transferable[]} [transfer]
279
+ * Transferables for this task.
280
+ * @property {AbortSignal} [signal]
281
+ * AbortSignal for this task.
282
+ * @property {number} [retries]
283
+ * Retry count for this task.
284
+ */
285
+
286
+ /**
287
+ * The object returned by {@link ThreadPool.run}. Contains both the
288
+ * auto-generated task ID and the result promise.
289
+ *
290
+ * @example
291
+ * const { id, promise } = pool.run(42);
292
+ * const result = await promise; // 43
293
+ *
294
+ * // Use the id to set up dependencies:
295
+ * const child = pool.run(100, { dependsOn: [id] });
296
+ *
297
+ * @typedef {Object} PoolTaskResult
298
+ * @property {number} id
299
+ * Auto-incrementing task ID. Used for dependency tracking and
300
+ * cancellation via `pool.cancel(id)`.
301
+ * @property {Promise<any>} promise
302
+ * Resolves with the task result, or rejects with one of:
303
+ * - {@link ThreadTimeoutError} if the task exceeds its timeout
304
+ * - {@link ThreadAbortError} if the task was cancelled or aborted
305
+ * - {@link ThreadTerminatedError} if the pool was terminated
306
+ * - {@link ThreadDependencyError} if a dependency failed
307
+ * - {@link ThreadError} for worker-side errors
308
+ */
309
+
310
+ /**
311
+ * Snapshot of pool state returned by {@link ThreadPool.status}.
312
+ *
313
+ * @typedef {Object} PoolStatus
314
+ * @property {number} total
315
+ * Total number of threads (including busy ones).
316
+ * @property {number} busy
317
+ * Number of threads currently executing a task.
318
+ * @property {number} idle
319
+ * `total - busy`.
320
+ * @property {number} queued
321
+ * Number of tasks waiting in the global queue + blocked tasks
322
+ * waiting on dependencies.
323
+ * @property {number} localQueued
324
+ * Sum of all threads' local queues (work-stealing candidates).
325
+ */
326
+
327
+ // ---------------------------------------------------------------------------
328
+ // Metrics
329
+ // ---------------------------------------------------------------------------
330
+
331
+ /**
332
+ * Point-in-time metrics snapshot returned by {@link Metrics.snapshot}.
333
+ *
334
+ * **Note:** `avg`, `min`, `max`, and `throughput` are computed from
335
+ * **successful** tasks only. Errors are counted separately and do not
336
+ * skew the averages.
337
+ *
338
+ * @example
339
+ * const snap = thread.metrics;
340
+ * console.log(`${snap.count} tasks, ${snap.avg.toFixed(1)}ms avg`);
341
+ * console.log(`${(snap.errorRate * 100).toFixed(1)}% error rate`);
342
+ *
343
+ * @typedef {Object} MetricsSnapshot
344
+ * @property {number} count
345
+ * Total number of recorded tasks (successes + errors).
346
+ * @property {number} errors
347
+ * Number of failed tasks.
348
+ * @property {number} avg
349
+ * Average duration of successful tasks in ms. `0` if no successes.
350
+ * @property {number} min
351
+ * Minimum duration of successful tasks in ms. `0` if no successes.
352
+ * @property {number} max
353
+ * Maximum duration of successful tasks in ms. `0` if no successes.
354
+ * @property {number} throughput
355
+ * Successful tasks per second. `0` if no successes.
356
+ * @property {number} errorRate
357
+ * Fraction of tasks that failed (0–1). `0` if no tasks recorded.
358
+ */
359
+
360
+ // ---------------------------------------------------------------------------
361
+ // Serializer
362
+ // ---------------------------------------------------------------------------
363
+
364
+ /**
365
+ * A value that has been serialized by {@link Serializer.serialize}.
366
+ * Functions are converted into `{ __type: 'function', __value: string }`
367
+ * objects; all other values pass through unchanged.
368
+ *
369
+ * @typedef {*} SerializedValue
370
+ */
371
+
372
+ // ---------------------------------------------------------------------------
373
+ // Thread events
374
+ // ---------------------------------------------------------------------------
375
+
376
+ /**
377
+ * Valid event names for {@link Thread.on} and {@link Thread.off}.
378
+ *
379
+ * | Event | Callback signature | Description |
380
+ * |-------------|--------------------------------------------|-------------|
381
+ * | `result` | `(result, event) => void` | Task succeeded |
382
+ * | `error` | `({error, stack}, event) => void` | Task or worker error |
383
+ * | `progress` | `(value, event) => void` | Progress update |
384
+ * | `terminate` | `() => void` | Thread terminated |
385
+ * | `idle` | `() => void` | Thread went idle |
386
+ * | `timing` | `(durationMs, args) => void` | Task timing |
387
+ * | `beforeRun` | `(args) => args \| undefined` | Pre-task hook |
388
+ * | `afterRun` | `(result) => result \| undefined` | Post-task hook |
389
+ * | `log` | `(message, event) => void` | Worker log |
390
+ * | `memory` | `(memory, event) => void` | Memory report |
391
+ * | `health` | `({status: 'ready'}) => void` | Worker ready |
392
+ * | `metrics` | `(snapshot: MetricsSnapshot) => void` | Metrics update |
393
+ *
394
+ * @typedef {'result'|'error'|'progress'|'terminate'|'idle'|'timing'|'beforeRun'|'afterRun'|'log'|'memory'|'health'|'metrics'} ThreadEventName
395
+ */
396
+
397
+ // ---------------------------------------------------------------------------
398
+ // Thread instance shape (for consumers who use createThread)
399
+ // ---------------------------------------------------------------------------
400
+
401
+ /**
402
+ * The public interface of a {@link Thread} instance.
403
+ *
404
+ * @typedef {Object} ThreadInstance
405
+ * @property {(args: ...any) => Promise<any>} run
406
+ * Execute a task and return its result.
407
+ * @property {(tasks: any[][], options?: ThreadRunOptions) => Promise<any[]>} runBatch
408
+ * Execute multiple argument sets in one worker call.
409
+ * @property {(args: ...any) => void} runAsync
410
+ * Fire-and-forget: send a task without waiting.
411
+ * @property {(initialValue: any, ...fns: Function[]) => Promise<any>} runChain
412
+ * Pipe a value through a sequence of functions, each in its own worker.
413
+ * @property {(array: any[], chunkSize: number, processor: Function, options?: ThreadRunOptions) => AsyncGenerator<any>} runStreaming
414
+ * Process an array in chunks, yielding results as they complete.
415
+ * @property {(newExec: Function) => void} reload
416
+ * Hot-swap the worker's exec function and restart.
417
+ * @property {(timeout?: number) => Promise<void>} warmup
418
+ * Warm up the worker with a no-op task.
419
+ * @property {() => Promise<void>} terminateGracefully
420
+ * Wait for pending tasks, run cleanup, then terminate.
421
+ * @property {() => void} terminate
422
+ * Immediately terminate the worker and reject all pending tasks.
423
+ * @property {(event: ThreadEventName, handler: Function) => ThreadInstance} on
424
+ * Register an event listener (chainable).
425
+ * @property {(event: ThreadEventName, handler: Function) => ThreadInstance} off
426
+ * Remove an event listener (chainable).
427
+ * @property {MetricsSnapshot} metrics
428
+ * Current metrics snapshot (getter).
429
+ * @property {boolean} busy
430
+ * `true` if the thread has pending tasks (getter).
431
+ * @property {boolean} terminated
432
+ * `true` if `terminate()` has been called (getter).
433
+ */
434
+
435
+ // ---------------------------------------------------------------------------
436
+ // ThreadPool instance shape
437
+ // ---------------------------------------------------------------------------
438
+
439
+ /**
440
+ * The public interface of a {@link ThreadPool} instance.
441
+ *
442
+ * @typedef {Object} ThreadPoolInstance
443
+ * @property {(args: ...any) => PoolTaskResult} run
444
+ * Submit a task. Returns `{ id, promise }`.
445
+ * @property {(taskId: number) => boolean} cancel
446
+ * Cancel a queued task by ID.
447
+ * @property {(newSize: number) => void} scaleTo
448
+ * Dynamically resize the pool.
449
+ * @property {() => Promise<void>} terminateGracefully
450
+ * Wait for all tasks to finish, then terminate every thread.
451
+ * @property {() => void} terminateAll
452
+ * Immediately terminate all threads and reject queued tasks.
453
+ * @property {() => PoolStatus} status
454
+ * Return current pool status.
455
+ * @property {() => Promise<void>} drain
456
+ * Wait for all tasks to finish (without terminating).
457
+ * @property {(timeout?: number) => Promise<void>} warmup
458
+ * Warm up every thread.
459
+ * @property {MetricsSnapshot} metrics
460
+ * Cumulative pool-wide metrics snapshot (getter).
461
+ */
462
+
463
+ // ---------------------------------------------------------------------------
464
+ // Hook return types (Preact / React)
465
+ // ---------------------------------------------------------------------------
466
+
467
+ /**
468
+ * Return value of the {@link useThread} hook.
469
+ *
470
+ * @typedef {Object} UseThreadReturn
471
+ * @property {ThreadInstance} thread
472
+ * The underlying thread instance. Use for direct access to
473
+ * `thread.metrics`, `thread.busy`, etc.
474
+ * @property {(args: ...any) => Promise<any>} run
475
+ * Execute a task and update reactive state (`result`, `error`,
476
+ * `loading`). Returns a promise with the result.
477
+ * @property {(args: ...any) => void} runAsync
478
+ * Fire-and-forget: send a task without waiting or updating state.
479
+ * @property {any} result
480
+ * The result of the most recent successful `run()` call.
481
+ * `null` initially and after errors.
482
+ * @property {string | null} error
483
+ * Error message from the most recent failed `run()` call.
484
+ * `null` when there is no error.
485
+ * @property {boolean} loading
486
+ * `true` while a task is in flight.
487
+ * @property {boolean} terminated
488
+ * `true` after the thread has been terminated (on unmount).
489
+ */
490
+
491
+ /**
492
+ * Return value of the {@link usePool} hook.
493
+ *
494
+ * @typedef {Object} UsePoolReturn
495
+ * @property {ThreadPoolInstance} pool
496
+ * The underlying pool instance.
497
+ * @property {(args: ...any) => PoolTaskResult} run
498
+ * Submit a task. Returns `{ id, promise }`.
499
+ * @property {(taskId: number) => boolean} cancel
500
+ * Cancel a queued task by ID.
501
+ * @property {() => PoolStatus} status
502
+ * Get current pool status.
503
+ * @property {MetricsSnapshot} metrics
504
+ * Live metrics snapshot, updated at the polling interval.
505
+ * @property {boolean} terminated
506
+ * `true` after the pool has been terminated (on unmount).
507
+ */
508
+
509
+ // ---------------------------------------------------------------------------
510
+ // Adapter types
511
+ // ---------------------------------------------------------------------------
512
+
513
+ /**
514
+ * Configuration for {@link createZustandBinder}.
515
+ *
516
+ * @typedef {Object} ZustandBinderOptions
517
+ * @property {string} [errorAction]
518
+ * Store action name to call on error. Receives `(errorMessage)`.
519
+ * @property {boolean} [append=false]
520
+ * If `true`, results are passed to the action expecting to append
521
+ * to an existing array.
522
+ * @property {string} [metricsAction]
523
+ * Store action name to call with metrics snapshots.
524
+ */
525
+
526
+ /**
527
+ * Configuration for {@link createSignalBinder}.
528
+ *
529
+ * @typedef {Object} SignalBinderOptions
530
+ * @property {Object} [errorSignal]
531
+ * A Preact Signal to write error messages into.
532
+ * @property {(result: any) => any} [transform]
533
+ * Transform the result before writing to the signal.
534
+ */
535
+
536
+ /**
537
+ * Configuration for {@link createStoreBinder}.
538
+ *
539
+ * @typedef {Object} StoreBinderOptions
540
+ * @property {(error: string) => void} [onError]
541
+ * Called with the error message on failure.
542
+ * @property {(result: any) => any} [transform]
543
+ * Transform the result before passing to the setter.
544
+ * @property {(snapshot: MetricsSnapshot) => void} [onMetrics]
545
+ * Called with every metrics snapshot.
546
+ */
547
+
548
+ /**
549
+ * Configuration for {@link createPoolBinder}.
550
+ *
551
+ * @typedef {Object} PoolBinderOptions
552
+ * @property {(error: string) => void} [onError]
553
+ * Called with the error message on failure.
554
+ * @property {(snapshot: MetricsSnapshot) => void} [onMetrics]
555
+ * Called with every metrics snapshot.
556
+ * @property {number} [batchInterval]
557
+ * If set, results are accumulated for this many ms and flushed as
558
+ * an array to the setter.
559
+ */
560
+
561
+ /**
562
+ * Return value of all binder/adapter functions.
563
+ *
564
+ * @typedef {Object} BinderHandle
565
+ * @property {Function} run
566
+ * Execute a task and push the result to the bound state.
567
+ * @property {Function} [destroy]
568
+ * Remove all event listeners. Call on cleanup / unmount.
569
+ * @property {Function} [flush]
570
+ * Manually flush accumulated batch results (pool binder only).
571
+ */
572
+
573
+ // ---------------------------------------------------------------------------
574
+ // Signal compatibility (Preact Signals, Solid signals, etc.)
575
+ // ---------------------------------------------------------------------------
576
+
577
+ /**
578
+ * A reactive signal with a readable/writable `.value` property.
579
+ * Compatible with `@preact/signals`, Solid.js signals, and similar.
580
+ *
581
+ * @typedef {Object} Signal
582
+ * @property {any} value
583
+ * The current value. Reading triggers tracking; writing triggers
584
+ * reactivity updates.
585
+ */
586
+
587
+ // ---------------------------------------------------------------------------
588
+ // GPU Compute types
589
+ // ---------------------------------------------------------------------------
590
+
591
+ /**
592
+ * Configuration for a {@link GPUCompute} instance.
593
+ *
594
+ * @example
595
+ * ```js
596
+ * // Option A: provide a raw WGSL shader
597
+ * const gpu = new GPUCompute({
598
+ * shader: `@compute @workgroup_size(256) fn main(...) { ... }`,
599
+ * });
600
+ *
601
+ * // Option B: no shader — use run() with built-in ops
602
+ * const gpu = new GPUCompute();
603
+ * ```
604
+ *
605
+ * @typedef {Object} GPUComputeOptions
606
+ * @property {string} [shader]
607
+ * WGSL compute shader source code. Optional if you only use
608
+ * `run()` with built-in or user-defined ops.
609
+ * @property {number} [workgroupSize=256]
610
+ * Workgroup size matching `@workgroup_size(N)` in the shader.
611
+ * Used to auto-calculate dispatch dimensions.
612
+ * @property {number} [maxBufferSize=268435456]
613
+ * Maximum buffer size in bytes (default 256 MB). Buffers exceeding
614
+ * this are rejected.
615
+ * @property {Object} [adapterOptions]
616
+ * Options passed to `navigator.gpu.requestAdapter()`.
617
+ * @property {'low-power'|'high-performance'|undefined} [powerPreference]
618
+ * GPU power preference. Default is `'high-performance'`.
619
+ * @property {Function} [cpuFallback]
620
+ * Optional CPU fallback function. Called with {@link GPUComputeInput}
621
+ * when WebGPU is unavailable or the GPU fails.
622
+ * @property {string} [entryPoint]
623
+ * Shader entry point function name. Default is `'main'`.
624
+ */
625
+
626
+ /**
627
+ * Input specification for {@link GPUCompute.compute}.
628
+ *
629
+ * @example
630
+ * ```js
631
+ * await gpu.compute({
632
+ * inputs: { data: new Float32Array([1, 2, 3, 4]) },
633
+ * uniforms: { scale: new Float32Array([2.0]) },
634
+ * outputBuffers: { result: 4 },
635
+ * outputType: 'f32',
636
+ * workgroups: 1,
637
+ * });
638
+ * ```
639
+ *
640
+ * @typedef {Object} GPUComputeInput
641
+ * @property {Object<string, TypedArray>} [inputs={}]
642
+ * Map of binding names to TypedArray data. Each entry becomes a
643
+ * `storage` buffer bound at incrementing binding indices starting
644
+ * from `bindingStart`.
645
+ * @property {Object<string, TypedArray>} [uniforms={}]
646
+ * Map of binding names to TypedArray data for uniform buffers.
647
+ * Uniforms are bound after inputs at incrementing indices.
648
+ * @property {Object<string, number>} [outputBuffers={}]
649
+ * Map of output binding names to element counts (not bytes). Each
650
+ * entry creates a `storage + copy_src` buffer.
651
+ * @property {string|typeof TypedArray} [outputType='f32']
652
+ * TypedArray constructor or name for output buffers. Accepts:
653
+ * `'f32'`, `'i32'`, `'u32'`, `'f64'`, or a constructor like
654
+ * `Float32Array`.
655
+ * @property {number|null} [workgroups=null]
656
+ * Number of workgroups to dispatch. If `null`, calculated
657
+ * automatically from the largest input/output length.
658
+ * @property {number} [bindingStart=0]
659
+ * First binding index. Useful when multiple compute passes share a
660
+ * bind group layout.
661
+ */
662
+
663
+ /**
664
+ * A named pipeline step for {@link GPUCompute.computeSequential}.
665
+ *
666
+ * @typedef {Object} GPUComputeStep
667
+ * @property {string} [pipeline]
668
+ * Pipeline name to switch to (omit to keep the current active pipeline).
669
+ * @property {Object<string, TypedArray>} [inputs]
670
+ * Additional inputs for this step. Previous outputs with matching
671
+ * names are merged automatically.
672
+ * @property {Object<string, TypedArray>} [uniforms]
673
+ * Uniform buffers for this step.
674
+ * @property {Object<string, number>} outputBuffers
675
+ * Output buffer specifications (name -> element count).
676
+ * @property {string|typeof TypedArray} [outputType='f32']
677
+ * Output type for this step.
678
+ */
679
+
680
+ /**
681
+ * Diagnostic snapshot returned by {@link GPUCompute.inspect}.
682
+ *
683
+ * @typedef {Object} GPUComputeSnapshot
684
+ * @property {'idle'|'running'|'error'|'unavailable'} status
685
+ * Current operational status.
686
+ * @property {boolean} available
687
+ * Whether WebGPU is available in this environment.
688
+ * @property {boolean} ready
689
+ * Whether the GPU device and pipelines are compiled.
690
+ * @property {string} activePipeline
691
+ * Name of the currently active pipeline.
692
+ * @property {string[]} pipelines
693
+ * Names of all registered pipelines.
694
+ * @property {string[]} ops
695
+ * Names of all defined operations (built-in + custom).
696
+ * @property {MetricsSnapshot} metrics
697
+ * Performance metrics snapshot.
698
+ * @property {number} dispatchCount
699
+ * Total number of dispatches (successes + failures).
700
+ * @property {number} bytesTransferred
701
+ * Approximate total bytes read/written to the GPU.
702
+ * @property {number} bufferPoolEntries
703
+ * Number of pooled buffers available for reuse.
704
+ * @property {number} workgroupSize
705
+ * Workgroup size configured on this instance.
706
+ * @property {number} maxBufferSize
707
+ * Maximum buffer size in bytes.
708
+ * @property {'low-power'|'high-performance'|undefined} powerPreference
709
+ * GPU power preference.
710
+ */
711
+
712
+ /**
713
+ * Declaration for a custom GPU operation passed to
714
+ * {@link GPUCompute.define}. Describes inputs, outputs, uniforms,
715
+ * and the loop body that generates WGSL automatically.
716
+ *
717
+ * @example
718
+ * ```js
719
+ * gpu.define('scaleClamp', {
720
+ * inputs: ['data'],
721
+ * outputs: ['result'],
722
+ * uniforms: ['factor', 'maxVal'],
723
+ * body: `result[i] = min(data[i] * factor, maxVal);`,
724
+ * type: 'f32',
725
+ * fn: (input) => {
726
+ * const data = input.inputs.data;
727
+ * const factor = input.uniforms.factor[0];
728
+ * const maxVal = input.uniforms.maxVal[0];
729
+ * const result = new Float32Array(data.length);
730
+ * for (let i = 0; i < data.length; i++)
731
+ * result[i] = Math.min(data[i] * factor, maxVal);
732
+ * return { result };
733
+ * },
734
+ * });
735
+ * ```
736
+ *
737
+ * @typedef {Object} OpDeclaration
738
+ * @property {string[]} [inputs=[]]
739
+ * Names of input storage bindings. These become WGSL variables
740
+ * you reference in the body.
741
+ * @property {string[]} [outputs=['result']]
742
+ * Names of output storage bindings.
743
+ * @property {string[]} [uniforms=[]]
744
+ * Names of uniform bindings.
745
+ * @property {string} body
746
+ * WGSL loop body. The variable `i` (the element index) is
747
+ * pre-declared. Reference binding names directly as variables.
748
+ * @property {string} [type='f32']
749
+ * Element type: `'f32'`, `'i32'`, or `'u32'`.
750
+ * @property {Function} [fn]
751
+ * Optional CPU fallback function. Used when WebGPU is
752
+ * unavailable. Receives `{ inputs, uniforms, outputs }` and
753
+ * should return `{ outputName: TypedArray }`.
754
+ * @property {number} [workgroupSize]
755
+ * Override the instance's default workgroup size for this op.
756
+ */
757
+
758
+ /**
759
+ * A built-in operation definition (stored in `BUILT_IN_OPS`).
760
+ *
761
+ * @typedef {Object} BuiltInOp
762
+ * @property {string[]} [inputs]
763
+ * Input binding names.
764
+ * @property {string[]} [uniforms]
765
+ * Uniform binding names.
766
+ * @property {string[]} outputs
767
+ * Output binding names.
768
+ * @property {string} body
769
+ * WGSL loop body.
770
+ */
771
+
772
+ /**
773
+ * Low-level shader build declaration passed to {@link buildShader}.
774
+ *
775
+ * @typedef {Object} ShaderDeclaration
776
+ * @property {string[]} [inputs=[]]
777
+ * Input binding names.
778
+ * @property {string[]} [outputs=[]]
779
+ * Output binding names.
780
+ * @property {string[]} [uniforms=[]]
781
+ * Uniform binding names.
782
+ * @property {string} body
783
+ * WGSL loop body.
784
+ * @property {string} [type='f32']
785
+ * Element type.
786
+ * @property {number} [workgroupSize=256]
787
+ * Workgroup size.
788
+ * @property {string} [name='main']
789
+ * Entry point function name.
790
+ */
791
+
792
+ /**
793
+ * Snapshot of GPU compute state returned by {@link GPUCompute.metrics}.
794
+ *
795
+ * @typedef {Object} GPUComputeMetrics
796
+ * @property {number} count
797
+ * Total number of dispatches.
798
+ * @property {number} errors
799
+ * Number of failed dispatches.
800
+ * @property {number} avg
801
+ * Average dispatch duration in ms (successes only).
802
+ * @property {number} min
803
+ * Minimum dispatch duration in ms (successes only).
804
+ * @property {number} max
805
+ * Maximum dispatch duration in ms (successes only).
806
+ * @property {number} throughput
807
+ * Dispatches per second (successes only).
808
+ * @property {number} errorRate
809
+ * Fraction of dispatches that failed (0–1).
810
+ */
811
+
812
+ // ---------------------------------------------------------------------------
813
+ // GPU Hook return types
814
+ // ---------------------------------------------------------------------------
815
+
816
+ /**
817
+ * Return value of the {@link useGPU} hook.
818
+ *
819
+ * @typedef {Object} UseGPUReturn
820
+ * @property {GPUCompute} gpu
821
+ * The underlying GPU instance.
822
+ * @property {(args: ...any) => Promise<any>} run
823
+ * Execute a GPU operation and update reactive state.
824
+ * @property {(name?: string, count?: number) => DataPipelineChain} pipe
825
+ * Start a fluent pipeline chain.
826
+ * @property {(name: string, fn: Function) => void} define
827
+ * Register a new operation on the GPU instance.
828
+ * @property {any} result
829
+ * The result of the most recent successful `run()` call.
830
+ * @property {boolean} loading
831
+ * `true` while a GPU operation is in flight.
832
+ * @property {string|null} error
833
+ * Error message from the most recent failed `run()` call.
834
+ * @property {string} status
835
+ * Current GPU status: `'idle'`, `'running'`, `'error'`, or `'unavailable'`.
836
+ * @property {MetricsSnapshot} metrics
837
+ * Live metrics snapshot, updated at the polling interval.
838
+ */
839
+
840
+ /**
841
+ * Return value of the {@link useGPURun} hook.
842
+ *
843
+ * @typedef {Object} UseGPURunReturn
844
+ * @property {(args: ...any) => Promise<any>} run
845
+ * Execute a GPU operation and update reactive state.
846
+ * @property {any} result
847
+ * The result of the most recent successful `run()` call.
848
+ * @property {boolean} loading
849
+ * `true` while a GPU operation is in flight.
850
+ * @property {string|null} error
851
+ * Error message from the most recent failed `run()` call.
852
+ */
853
+
854
+ // ---------------------------------------------------------------------------
855
+ // GPU Adapter option types
856
+ // ---------------------------------------------------------------------------
857
+
858
+ /**
859
+ * Configuration for {@link createGPUBinder}.
860
+ *
861
+ * @typedef {Object} GPUBinderOptions
862
+ * @property {string} [errorAction]
863
+ * Store action name to call on error. Receives `(errorMessage)`.
864
+ * @property {Function} [transform]
865
+ * Transform the result before writing to the store.
866
+ * @property {string} [metricsAction]
867
+ * Store action name to call with metrics snapshots.
868
+ */
869
+
870
+ /**
871
+ * Configuration for {@link createGPUSignalBinder}.
872
+ *
873
+ * @typedef {Object} GPUSignalBinderOptions
874
+ * @property {Object} [errorSignal]
875
+ * A Preact Signal to write error messages into.
876
+ * @property {Function} [transform]
877
+ * Transform the result before writing to the signal.
878
+ * @property {Object} [loadingSignal]
879
+ * A Preact Signal to write loading state (boolean) into.
880
+ */
881
+
882
+ /**
883
+ * Configuration for {@link createGPUStoreBinder}.
884
+ *
885
+ * @typedef {Object} GPUStoreBinderOptions
886
+ * @property {Function} [onError]
887
+ * Called with the error message on failure.
888
+ * @property {Function} [transform]
889
+ * Transform the result before passing to the setter.
890
+ * @property {Function} [onMetrics]
891
+ * Called with metrics snapshots after each run.
892
+ */
893
+
894
+ // ---------------------------------------------------------------------------
895
+ // Factory option types
896
+ // ---------------------------------------------------------------------------
897
+
898
+ /**
899
+ * Options for {@link createManagedThread}.
900
+ *
901
+ * @typedef {Object} ManagedThreadOptions
902
+ * @property {number} [timeout=30000]
903
+ * Task timeout in ms.
904
+ * @property {boolean} [healthChecks=true]
905
+ * Enable automatic health checks.
906
+ * @property {number} [healthCheckInterval=10000]
907
+ * Health check interval in ms.
908
+ * @property {Function} [onMetrics]
909
+ * Callback for live metrics snapshots.
910
+ * @property {Function} [onLog]
911
+ * Callback for worker log messages.
912
+ * @property {ThreadOptions} [thread]
913
+ * Additional options forwarded to the Thread constructor.
914
+ */
915
+
916
+ /**
917
+ * Options for {@link createGPUOp}.
918
+ *
919
+ * @typedef {GPUComputeOptions} GPUOpOptions
920
+ */
921
+
922
+ /**
923
+ * Options for {@link createGPUPipeline}.
924
+ *
925
+ * @typedef {GPUComputeOptions} GPUPipelineOptions
926
+ */
927
+
928
+ /**
929
+ * Options for {@link createGPUReducer}.
930
+ *
931
+ * @typedef {GPUComputeOptions} GPUReducerOptions
932
+ */
933
+
934
+ // ---------------------------------------------------------------------------
935
+ // Configuration types
936
+ // ---------------------------------------------------------------------------
937
+
938
+ /**
939
+ * Top-level thread configuration object.
940
+ *
941
+ * Created via {@link defineConfig} in `thread.config.js`. All fields are
942
+ * optional — omitted values use built-in defaults.
943
+ *
944
+ * The config is **frozen** (immutable) after creation. Mutating it
945
+ * has no effect.
946
+ *
947
+ * @typedef {Object} threadConfig
948
+ *
949
+ * @property {'preact'|'react'|'svelte'|'vue'|'solid'|'angular'|'custom'} [framework='preact']
950
+ * UI framework. Determines which hooks (`useState`, `useEffect`, etc.)
951
+ * are imported at module load time.
952
+ *
953
+ * The framework is resolved via dynamic `import()` — no hardcoded
954
+ * dependency. Supported values:
955
+ *
956
+ * | Value | Import path | Status |
957
+ * |-------|------------|--------|
958
+ * | `'preact'` | `preact/hooks` | Supported |
959
+ * | `'react'` | `react` | Supported |
960
+ * | `'svelte'` | `svelte/reactivity` | Supported (partial) |
961
+ * | `'vue'` | `vue` | Supported (partial) |
962
+ * | `'solid'` | `solid-js` | Supported |
963
+ * | `'angular'` | — | Coming soon |
964
+ * | `'custom'` | — | User provides `customHookSource` |
965
+ *
966
+ * @property {'zustand'|'signals'|'redux'|'jotai'|'mobx'|'vanilla'|'custom'} [stateManager='zustand']
967
+ * State manager. Determines which adapter constructors are available
968
+ * for binding threads/GPUs to your store.
969
+ *
970
+ * | Value | Adapter type | Thread adapter | GPU adapter |
971
+ * |-------|-------------|---------------|-------------|
972
+ * | `'zustand'` | action | `createZustandBinder` | `createGPUBinder` |
973
+ * | `'signals'` | signal | `createSignalBinder` | `createGPUSignalBinder` |
974
+ * | `'redux'` | setter | `createStoreBinder` | `createGPUStoreBinder` |
975
+ * | `'jotai'` | setter | `createStoreBinder` | `createGPUStoreBinder` |
976
+ * | `'mobx'` | setter | `createStoreBinder` | `createGPUStoreBinder` |
977
+ * | `'vanilla'` | setter | `createStoreBinder` | `createGPUStoreBinder` |
978
+ * | `'custom'` | — | User provides `customAdapter` | — |
979
+ *
980
+ * @property {Function|null} [customHookSource=null]
981
+ * Custom hook source function. When `framework: 'custom'`, this
982
+ * function is called and must return an object with:
983
+ * `{ useState, useEffect, useRef, useCallback, useMemo }`.
984
+ *
985
+ * @example
986
+ * ```js
987
+ * customHookSource: async () => {
988
+ * const mod = await import('my-framework/hooks');
989
+ * return {
990
+ * useState: mod.useState,
991
+ * useEffect: mod.useEffect,
992
+ * useRef: mod.useRef,
993
+ * useCallback: mod.useCallback,
994
+ * useMemo: mod.useMemo,
995
+ * };
996
+ * }
997
+ * ```
998
+ *
999
+ * @property {Function|null} [customAdapter=null]
1000
+ * Custom adapter factory. When `stateManager: 'custom'`, this
1001
+ * function receives `(instance, store, action, options)` and must
1002
+ * return `{ run: Function, destroy: Function }`.
1003
+ *
1004
+ * @example
1005
+ * ```js
1006
+ * customAdapter: (instance, store, action) => ({
1007
+ * run: async (...args) => {
1008
+ * const result = await instance.run(...args);
1009
+ * store.dispatch({ type: action, payload: result });
1010
+ * },
1011
+ * destroy: () => {},
1012
+ * })
1013
+ * ```
1014
+ *
1015
+ * @property {threadGPUConfig} [gpu={}]
1016
+ * GPU compute defaults. Applied to all `GPUCompute` instances created
1017
+ * after the config is loaded.
1018
+ *
1019
+ * @property {threadThreadConfig} [thread={}]
1020
+ * Thread defaults. Applied to all threads created via factory functions.
1021
+ *
1022
+ * @property {threadPoolConfig} [pool={}]
1023
+ * Pool defaults. Applied to all thread pools created via factory functions.
1024
+ *
1025
+ * @property {threadDevConfig} [dev={}]
1026
+ * Development options. Controls logging, metrics, and debugging.
1027
+ *
1028
+ * @example
1029
+ * ```js
1030
+ * // thread.config.js
1031
+ * import { defineConfig } from 'thread/config';
1032
+ *
1033
+ * export default defineConfig({
1034
+ * framework: 'react',
1035
+ * stateManager: 'zustand',
1036
+ * gpu: {
1037
+ * workgroupSize: 256,
1038
+ * powerPreference: 'high-performance',
1039
+ * },
1040
+ * thread: { timeout: 30_000 },
1041
+ * pool: { autoRestart: true },
1042
+ * dev: { log: true },
1043
+ * });
1044
+ * ```
1045
+ */
1046
+
1047
+ /**
1048
+ * GPU compute configuration section.
1049
+ *
1050
+ * These defaults are applied to all `GPUCompute` instances created
1051
+ * after the config is loaded. Individual instances can override
1052
+ * these via their constructor options.
1053
+ *
1054
+ * @typedef {Object} threadGPUConfig
1055
+ *
1056
+ * @property {number} [workgroupSize=256]
1057
+ * Workgroup size for compute shaders. Must match the
1058
+ * `@workgroup_size(N)` declaration in your WGSL shaders.
1059
+ * Higher values use more GPU resources but may improve throughput
1060
+ * for large datasets.
1061
+ *
1062
+ * @property {number} [maxBufferSize=268435456]
1063
+ * Maximum buffer size in bytes (default 256 MB). Buffers
1064
+ * exceeding this limit are rejected. Increase for large datasets.
1065
+ *
1066
+ * @property {string} [entryPoint='main']
1067
+ * Shader entry point function name. Must match the function
1068
+ * name in your WGSL shader (e.g. `@compute @workgroup_size(256) fn main(…)`)
1069
+ *
1070
+ * @property {'low-power'|'high-performance'} [powerPreference='high-performance']
1071
+ * GPU power preference. `'high-performance'` uses the discrete GPU
1072
+ * if available. `'low-power'` uses the integrated GPU.
1073
+ *
1074
+ * @property {Function|null} [cpuFallback=null]
1075
+ * CPU fallback function. Called with the compute input when WebGPU
1076
+ * is unavailable or the GPU fails. Useful for development on
1077
+ * machines without WebGPU support.
1078
+ *
1079
+ * @property {Object} [adapterOptions={}]
1080
+ * Options passed to `navigator.gpu.requestAdapter()`. Use this
1081
+ * to select a specific GPU adapter.
1082
+ *
1083
+ * @property {string|null} [shader=null]
1084
+ * Default WGSL compute shader source. Optional if you only use
1085
+ * `run()` with built-in ops.
1086
+ *
1087
+ * @example
1088
+ * ```js
1089
+ * gpu: {
1090
+ * workgroupSize: 256, // Match @workgroup_size(256) in shaders
1091
+ * maxBufferSize: 512 * 1024 * 1024, // 512 MB for large datasets
1092
+ * powerPreference: 'low-power', // Prefer integrated GPU
1093
+ * cpuFallback: (input) => { // Fallback for no WebGPU
1094
+ * return input.inputs.data.reduce((a, b) => a + b, 0);
1095
+ * },
1096
+ * }
1097
+ * ```
1098
+ */
1099
+
1100
+ /**
1101
+ * Thread configuration section.
1102
+ *
1103
+ * These defaults are applied to all threads created via factory
1104
+ * functions (`createThread`, `createPool`, `createWorker`, etc.).
1105
+ * Individual threads can override these via their options.
1106
+ *
1107
+ * @typedef {Object} threadThreadConfig
1108
+ *
1109
+ * @property {number} [timeout=30000]
1110
+ * Task timeout in milliseconds. If a task runs longer than this,
1111
+ * it is automatically aborted and a `ThreadTimeoutError` is thrown.
1112
+ *
1113
+ * @property {number} [idleTimeout]
1114
+ * Idle timeout in milliseconds. If a thread has no tasks for this
1115
+ * duration, it is automatically terminated. `undefined` = never idle timeout.
1116
+ *
1117
+ * @property {number} [healthCheckInterval]
1118
+ * Health check interval in milliseconds. The pool periodically
1119
+ * pings each thread to ensure it's responsive. `undefined` = no health checks.
1120
+ *
1121
+ * @property {number} [healthCheckTimeout]
1122
+ * Health check timeout in milliseconds. If a thread doesn't respond
1123
+ * to a health check within this time, it's considered crashed.
1124
+ *
1125
+ * @property {number} [concurrency]
1126
+ * Maximum concurrent tasks per thread. Default is `1` (one task at a time).
1127
+ *
1128
+ * @example
1129
+ * ```js
1130
+ * thread: {
1131
+ * timeout: 10_000, // 10 second task timeout
1132
+ * idleTimeout: 60_000, // Kill idle threads after 60s
1133
+ * healthCheckInterval: 5_000, // Ping threads every 5s
1134
+ * healthCheckTimeout: 2_000, // Kill unresponsive threads after 2s
1135
+ * }
1136
+ * ```
1137
+ */
1138
+
1139
+ /**
1140
+ * Pool configuration section.
1141
+ *
1142
+ * These defaults are applied to all thread pools created via factory
1143
+ * functions. Individual pools can override these via their options.
1144
+ *
1145
+ * @typedef {Object} threadPoolConfig
1146
+ *
1147
+ * @property {boolean} [autoRestart=true]
1148
+ * Automatically restart crashed workers. When a worker crashes,
1149
+ * a replacement is spawned and pending tasks are re-queued.
1150
+ *
1151
+ * @property {boolean} [enableStealing=true]
1152
+ * Enable work-stealing. Idle threads can steal tasks from busy
1153
+ * threads' queues, improving load balancing.
1154
+ *
1155
+ * @property {number} [maxSize]
1156
+ * Maximum number of threads in the pool. `undefined` = unlimited.
1157
+ *
1158
+ * @property {Function} [keyHasher]
1159
+ * Function that maps task arguments to an affinity key. Tasks with
1160
+ * the same key are routed to the same thread (useful for stateful
1161
+ * workers). Default is `JSON.stringify`.
1162
+ *
1163
+ * @example
1164
+ * ```js
1165
+ * pool: {
1166
+ * autoRestart: true, // Replace crashed workers
1167
+ * enableStealing: true, // Allow work-stealing
1168
+ * maxSize: 8, // Cap at 8 threads
1169
+ * keyHasher: (args) => args[0]?.id ?? 'default', // Route by ID
1170
+ * }
1171
+ * ```
1172
+ */
1173
+
1174
+ /**
1175
+ * Development configuration section.
1176
+ *
1177
+ * Controls logging, metrics, and debugging features. These are
1178
+ * typically `false` in production.
1179
+ *
1180
+ * @typedef {Object} threadDevConfig
1181
+ *
1182
+ * @property {boolean} [log=false]
1183
+ * Forward worker `console.log` messages to the main thread.
1184
+ * Useful for debugging but noisy in production.
1185
+ *
1186
+ * @property {boolean} [metrics=false]
1187
+ * Enable metrics collection. When `true`, thread and pool instances
1188
+ * track timing, throughput, and error rates. Has a small performance
1189
+ * overhead.
1190
+ *
1191
+ * @property {number} [warnOnLongTask=0]
1192
+ * Warn if a task exceeds N milliseconds. Set to `0` to disable.
1193
+ * Useful for finding performance bottlenecks during development.
1194
+ *
1195
+ * @example
1196
+ * ```js
1197
+ * dev: {
1198
+ * log: true, // See worker logs in console
1199
+ * metrics: true, // Track performance
1200
+ * warnOnLongTask: 1_000, // Warn if task > 1 second
1201
+ * }
1202
+ * ```
1203
+ */
1204
+
1205
+ // ---------------------------------------------------------------------------
1206
+ // Environment detection types
1207
+ // ---------------------------------------------------------------------------
1208
+
1209
+ /**
1210
+ * Environment detection result.
1211
+ *
1212
+ * Returned by {@link env} and used internally for cross-platform
1213
+ * compatibility decisions.
1214
+ *
1215
+ * @typedef {Object} threadEnv
1216
+ *
1217
+ * @property {'browser'|'node'|'bun'|'deno'|'edge'|'unknown'} runtime
1218
+ * Detected JavaScript runtime.
1219
+ *
1220
+ * @property {'main'|'worker'|'service-worker'|'unknown'} context
1221
+ * Current execution context (main thread vs worker).
1222
+ *
1223
+ * @property {boolean} isBrowser
1224
+ * `true` if running in a browser environment (including Web Workers).
1225
+ *
1226
+ * @property {boolean} isNode
1227
+ * `true` if running in Node.js.
1228
+ *
1229
+ * @property {boolean} isBun
1230
+ * `true` if running in Bun.
1231
+ *
1232
+ * @property {boolean} isDeno
1233
+ * `true` if running in Deno.
1234
+ *
1235
+ * @property {boolean} isEdge
1236
+ * `true` if running in an edge runtime (Cloudflare Workers, Vercel Edge).
1237
+ *
1238
+ * @property {boolean} isWorker
1239
+ * `true` if running in a worker context (not main thread).
1240
+ *
1241
+ * @property {boolean} isMainThread
1242
+ * `true` if running on the main thread.
1243
+ *
1244
+ * @property {boolean} hasWorker
1245
+ * `true` if the Worker API is available.
1246
+ *
1247
+ * @property {boolean} hasGPU
1248
+ * `true` if WebGPU is available.
1249
+ *
1250
+ * @property {boolean} hasFS
1251
+ * `true` if the `fs` module is available (Node/Bun).
1252
+ *
1253
+ * @property {boolean} hasPath
1254
+ * `true` if the `path` module is available (Node/Bun).
1255
+ *
1256
+ * @property {boolean} hasMemoryAPI
1257
+ * `true` if `performance.memory` is available (Chrome).
1258
+ *
1259
+ * @property {boolean} hasBlob
1260
+ * `true` if `Blob` and `URL.createObjectURL` are available.
1261
+ *
1262
+ * @property {boolean} hasDynamicImport
1263
+ * `true` if dynamic `import()` is available.
1264
+ *
1265
+ * @property {function(string): any|null} requireModule
1266
+ * Safely require a Node.js built-in module. Returns `null` if unavailable.
1267
+ *
1268
+ * @property {function(): string} getCwd
1269
+ * Get the current working directory across environments.
1270
+ *
1271
+ * @property {function(string): string|null} readFileSync
1272
+ * Read a file synchronously. Returns `null` in browser environments.
1273
+ *
1274
+ * @property {function(string): boolean} fileExists
1275
+ * Check if a file exists on disk.
1276
+ *
1277
+ * @property {function(...string): string} resolvePath
1278
+ * Resolve a file path relative to the current working directory.
1279
+ */
1280
+
1281
+ /**
1282
+ * GPU environment detection result.
1283
+ *
1284
+ * Returned by {@link gpuEnv} and used for GPU availability checks.
1285
+ *
1286
+ * @typedef {Object} threadGPUEnv
1287
+ *
1288
+ * @property {Promise<boolean>} available
1289
+ * Async GPU availability check (cached after first call).
1290
+ *
1291
+ * @property {boolean} sync
1292
+ * Synchronous check for `navigator.gpu` presence.
1293
+ *
1294
+ * @property {string} runtime
1295
+ * Current runtime identifier.
1296
+ *
1297
+ * @property {boolean} isBrowser
1298
+ * `true` if in a browser environment.
1299
+ *
1300
+ * @property {boolean} isNode
1301
+ * `true` if in Node.js or Bun.
1302
+ *
1303
+ * @property {boolean} isDeno
1304
+ * `true` if in Deno.
1305
+ *
1306
+ * @property {function(Object=): Promise<GPUAdapter|null>} requestAdapter
1307
+ * Request a GPU adapter from the current environment.
1308
+ *
1309
+ * @property {function(Object=): Promise<{adapter: GPUAdapter, device: GPUDevice}|null>} requestDevice
1310
+ * Request a GPU device (adapter + device).
1311
+ *
1312
+ * @property {function(): Promise<Object>} info
1313
+ * Get diagnostic GPU information.
1314
+ */
1315
+
1316
+ /**
1317
+ * Worker info result.
1318
+ *
1319
+ * Returned by {@link workerInfo} to describe Worker support.
1320
+ *
1321
+ * @typedef {Object} threadWorkerInfo
1322
+ *
1323
+ * @property {boolean} supported
1324
+ * `true` if Worker creation is supported.
1325
+ *
1326
+ * @property {'browser'|'node'|'bun'|'deno'|'none'} type
1327
+ * Type of Worker support detected.
1328
+ *
1329
+ * @property {string} details
1330
+ * Human-readable description of the Worker implementation.
1331
+ */
1332
+
1333
+ /**
1334
+ * Worker interface (cross-platform).
1335
+ *
1336
+ * Unified API that works across browser, Node.js, Bun, and Deno.
1337
+ *
1338
+ * @typedef {Object} threadWorkerInterface
1339
+ *
1340
+ * @property {function(MessageEvent): void} onmessage
1341
+ * Message handler (set by the host).
1342
+ *
1343
+ * @property {function(ErrorEvent): void} onerror
1344
+ * Error handler (set by the host).
1345
+ *
1346
+ * @property {function(MessageEvent): void} onmessageerror
1347
+ * Message error handler (set by the host).
1348
+ *
1349
+ * @property {function(*, Transferable[]=): void} postMessage
1350
+ * Post a message to the worker.
1351
+ *
1352
+ * @property {function(): void} terminate
1353
+ * Terminate the worker and clean up resources.
1354
+ */