Skip to main content

hurried

Modern, type-safe parallel execution for Node.js — workers, pools, and a typed event bus.

import { Thread } from 'hurried';

type Events = { progress: { done: number; total: number } };

const thread = Thread.fromFunction<Events, number, number>((bus, n) => {
for (let i = 0; i < n; i++) {
if (i % 1_000_000 === 0) bus.emit('progress', { done: i, total: n });
}
return n;
});

thread.on('progress', (p) => console.log(`${p.done}/${p.total}`));

await thread.run(50_000_000);
await thread.terminate();
🧠

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.

The hurried difference

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

main.ts
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

events.ts
export type Events = {
progress: { done: number; total: number };
log: string;
cancel: void; // void event
};

Worker file (optional)

worker.ts
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