Type-safe everywhere
Define one event map; both the main thread and the worker get the same typed `on / emit` API. Rename a field, both sides break at compile time.
Inline-function workers
No more separate worker files for simple jobs. Pass a function — hurried serializes it, spawns the worker, and gives you a typed `Promise<T>`.
A bus across the boundary
Streaming progress, cooperative cancellation, state-machine workers — all with five methods: `emit / on / once / off / waitFor`.
Pools with queue + backpressure
`new Pool({ size: 4, task })` and you have parallel CPU-bound throughput with bounded resource use. Events from any worker, broadcasts to all.
AbortSignal & timeouts
Every primitive accepts a per-call `timeout` and an `AbortSignal`. Structured error hierarchy means you can catch exactly what went wrong.
Zero deps, ESM + CJS
Dual build, full `.d.ts` generation, Node 18+. The whole library is ~20kB minified.
One event map. Two endpoints. Zero any.
Declare a single type Events contract and both sides of the worker boundary speak the same typed language. No protocol buffers, no schemas — just TypeScript doing its job.
Main thread
const thread = Thread.fromFunction<Events, number, number>(
(bus, n) => {
bus.emit('progress', { done: n, total: n });
return n;
},
);
thread.on('progress', (p) => {
// p: { done: number; total: number }
render(p.done / p.total);
});
await thread.run(10_000_000);
Shared event map
export type Events = {
progress: { done: number; total: number };
log: string;
cancel: void; // void event
};
Worker file (optional)
import { defineWorker, workerBus } from 'hurried';
import type { Events } from './events.js';
const bus = workerBus<Events>();
export default defineWorker({
process(items: string[]) {
items.forEach((it, i) =>
bus.emit('progress', { done: i + 1, total: items.length }),
);
return items.length;
},
});
Ready to stop blocking the event loop?
One install, two lines of code, every CPU core in your machine.
npm install hurried