sikiopipe
v0.1.0
Published
Zero‑copy‑ish IPC & RPC between Web Workers and Node.js worker_threads with SAB+Atomics fast path and postMessage fallback.
Readme
SikioPipe
Zero‑copy‑ish IPC & RPC between Web Workers and Node.js worker_threads with a SharedArrayBuffer + Atomics fast path and postMessage fallback.
Features
- SAB + Atomics fast path: Uses SharedArrayBuffer-backed SPSC rings with a pooled block allocator when eligible.
- Fallback transport: Falls back to
postMessagewhen SAB isn’t available or allowed. - Channels: Send raw
Uint8Arrayframes, with borrowed receives for low-copy hot paths. - RPC: Type-safe-ish remote proxies (
rpc(conn).wrap<T>()) with a tiny server (rpc(conn).expose(...)). - Streaming RPC:
AsyncIterable<Uint8Array>arguments and return values are streamed with backpressure. - Configurable:
mode,blockSize,blockCount, handshake timeout, ping intervals.
Installation
npm i sikiopipeor
pnpm add sikiopipeor
yarn add sikiopipeQuick Start
Node.js (worker_threads)
main.ts
import { spawnWorker, rpc } from "sikiopipe/node";
type Api = {
add(a: number, b: number): number;
};
const conn = await spawnWorker(new URL("./worker.js", import.meta.url));
const api = rpc(conn).wrap<Api>();
console.log(await api.add(1, 2));
conn.close();
await conn.terminate();worker.js
import { acceptConnection, rpc } from "sikiopipe/node";
const conn = await acceptConnection();
rpc(conn).expose({
add(a: number, b: number) {
return a + b;
},
});Browser (Web Workers)
main.ts
import { getSabEligibility, rpc, spawnWorker } from "sikiopipe/browser";
console.log(getSabEligibility());
type Api = {
ping(): string;
};
const conn = await spawnWorker(new URL("./worker.js", import.meta.url));
const api = rpc(conn).wrap<Api>();
console.log(await api.ping());
conn.close();
await conn.terminate();worker.js
import { acceptConnection, rpc } from "sikiopipe/browser";
const conn = await acceptConnection();
rpc(conn).expose({
ping() {
return "pong";
},
});Transports
| Mode | Behavior | Notes |
|------|----------|-------|
| auto | Selects SAB when eligible, otherwise postMessage | Default |
| sab | Forces SAB transport | In browsers requires COOP/COEP (cross-origin isolation) |
| postMessage | Forces postMessage transport | Always available |
Zero-copy-ish data path
Borrowed receive (avoid per-message slice() allocations):
import { channel } from "sikiopipe";
const ch = channel(conn);
for await (const chunk of ch.recvBorrowed()) {
try {
onBytes(chunk.bytes);
} finally {
chunk.release();
}
}Transfer-backed send (only on postMessage transport):
import { channel, createTransferPayload } from "sikiopipe";
const ch = channel(conn);
const data = new Uint8Array([1, 2, 3]);
const { payload } = createTransferPayload(data.byteLength);
payload.set(data);
await ch.sendTransfer(payload);Building from Source
npm install
npm run buildContributing
Found a bug or have a feature request? Open an Issue. PRs are welcome!
License
This project is licensed under AGPLv3 (AGPL-3.0-only).
