https://github.com/dark1zinn/libunix
A Unix Socket handler for Javascript/TypeScript ecosystems with great DX!
https://github.com/dark1zinn/libunix
bun javascript lib package socket typescript uds unix unix-sockets
Last synced: 3 days ago
JSON representation
A Unix Socket handler for Javascript/TypeScript ecosystems with great DX!
- Host: GitHub
- URL: https://github.com/dark1zinn/libunix
- Owner: dark1zinn
- License: mit
- Created: 2026-06-03T16:40:49.000Z (17 days ago)
- Default Branch: main
- Last Pushed: 2026-06-03T22:48:35.000Z (17 days ago)
- Last Synced: 2026-06-03T23:12:52.380Z (17 days ago)
- Topics: bun, javascript, lib, package, socket, typescript, uds, unix, unix-sockets
- Language: TypeScript
- Homepage:
- Size: 74.2 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# libunix
Unix domain socket (UDS) IPC for [Bun](https://bun.com) and **Node.js 20+**: framed messages, `Server` / `Client`, correlation-based request/response, and lifecycle helpers. **Linux and macOS only**.
## Install
```bash
bun add libunix
# or
npm install libunix
```
## Usage
Typed event maps mirror the integration tests: define the events your app exchanges, then wire handlers on each connected `RemotePeer`.
```ts
import { Client, Server } from 'libunix';
type EchoEvents = {
echo: { msg: string };
[key: string]: unknown;
};
const server = await Server.create({ id: 'my-app', adapter: 'bun' });
const ready = Promise.withResolvers();
server.on('connection', (peer) => {
peer.onRequest('echo', (data) => ({ echo: data.msg }));
ready.resolve();
});
const client = await Client.connect({ id: 'my-app', adapter: 'bun' });
await ready.promise;
const result = await client.request('echo', { msg: 'hello' });
// { echo: 'hello' }
await client.disconnect();
await server.close();
```
### Socket `id`
- **Logical id** (e.g. `'my-app'`): resolved to `$TMPDIR/my-app.sock` (letters, digits, `.`, `_`, `-` only).
- **Filesystem path**: pass a path containing `/` or ending in `.sock` (e.g. `/run/myapp.sock`).
On **Bun**, omit `adapter` (defaults to `Bun.listen` / `Bun.connect`). On **Node**, omit `adapter` (auto-detects `node:net`) or pass `adapter: 'node'` explicitly.
### Node.js 20+
Same API; use the `node:net` transport (no extra dependencies):
```ts
import { Client, Server } from 'libunix';
const server = await Server.create({ id: 'my-app', adapter: 'node' });
// ... same handler wiring as above
const client = await Client.connect({ id: 'my-app', adapter: 'node' });
```
Verify on Node after build: `bun run test:node`.
### One-way events (emit)
```ts
type LoopEvents = {
ping: null;
tick: { n: number };
[key: string]: unknown;
};
const server = await Server.create({ id: 'my-app', adapter: 'bun' });
const ready = Promise.withResolvers();
server.on('connection', (peer) => {
peer.onRequest('ping', () => 'pong');
peer.on('tick', () => {});
ready.resolve();
});
const client = await Client.connect({ id: 'my-app', adapter: 'bun' });
await ready.promise;
await client.emit('tick', { n: 0 });
const pong = await client.request('ping', null);
await client.disconnect();
await server.close();
```
### Errors
```ts
import { LibunixError, isLibunixError } from 'libunix';
try {
await Server.create({ id: socketPath, adapter: 'bun' });
} catch (err) {
if (isLibunixError(err) && err.code === 'EADDRINUSE') {
// socket already in use
}
}
```
## Development
```bash
bun install
bun test
bun run build # tsdown → dist/
```
Benchmarks (hyperfine, requires Nix dev shell): `bun run bench`. Tracked baselines live in [docs/benchmarks/](docs/benchmarks/).
## Security / trust model
libunix targets **local Unix domain socket IPC** between processes on the same machine. Any process that can connect to the socket path is treated as a trusted peer (similar to any local service bound to a world-readable socket file).
- Inbound envelopes always use **safe JSON parsing** (`__proto__` / `constructor` / `prototype` keys are dropped).
- Optional **`strictEnvelope: true`** on `Server.create` / `Client.connect` rejects oversized or deeply nested JSON (`maxEnvelopeBytes`, `maxEnvelopeDepth`).
- This is **not** authentication or encryption; do not expose UDS endpoints to untrusted networks.
Publish tarball is built with [tsdown](https://tsdown.dev/guide/getting-started); `prepublishOnly` runs format check, tests, and build.
## License
[MIT](./LICENSE)