@aellopus/client
The official Node.js and Bun client for Aellopus, a key–value server speaking the Aellopus Wire Protocol (AWP/1) over TCP.
- Zero runtime dependencies — only Node/Bun built-ins (
node:net). - ESM-only, TypeScript-first — ships type declarations; runs on Node 18+ and Bun.
- Binary-safe — values are bytes; keys and values may contain CR, LF, or NUL.
- Promise-based with per-call timeouts and
AbortSignalcancellation. - Pipelining-safe — one connection is shared across concurrent callers, replies correlated in FIFO order.
Validated against the AWP/1 conformance vectors and end-to-end against the reference Rust server.
Install
npm install @aellopus/client
# or: pnpm add @aellopus/client / yarn add @aellopus/client / bun add @aellopus/clientQuick start
import { connect, NotFoundError } from '@aellopus/client';
const client = await connect('127.0.0.1:6969');
try {
await client.set('greeting', 'hello world');
console.log(await client.getString('greeting')); // "hello world"
await client.set('session:42', 'token', { expiresSeconds: 60 });
console.log((await client.ttl('session:42')).seconds); // ~60
try {
await client.get('missing');
} catch (err) {
if (err instanceof NotFoundError) console.log('no such key');
}
} finally {
await client.close();
}A Client is safe to share across concurrent work — hold one rather than pooling.
Running a server
The client talks to an Aellopus server. The quickest way to get one for local development:
docker run --rm -p 6969:6969 adibhauzan/aellopus:latestThe server listens on 127.0.0.1:6969 by default. See the server repository for other options.
API
connect(addr, options?): Promise<Client>
Opens a client to addr, a host:port TCP address with no scheme (IPv6 hosts are bracketed, e.g. [::1]:6969). options ({ timeoutMs?, signal? }) bound establishing the connection only.
Values
| Method | Returns | Notes |
|---|---|---|
get(key) |
Promise<Uint8Array> |
Throws NotFoundError on a miss. An empty value is a present zero-length array. |
getString(key) |
Promise<string> |
UTF-8 convenience over get. |
set(key, value, options?) |
Promise<void> |
value is Uint8Array | string; options.expiresSeconds attaches a TTL. |
del(key) |
Promise<boolean> |
true if the key existed. |
exists(key) |
Promise<boolean> |
|
incr(key) / decr(key) |
Promise<number> |
Post-operation value. |
TTL
| Method | Returns | Notes |
|---|---|---|
ttl(key) |
Promise<TTL> |
Throws NotFoundError if the key is absent. |
expire(key, seconds) |
Promise<boolean> |
true if the key existed. |
TTL exposes hasExpiry: boolean and seconds: number \| undefined (undefined when the key persists with no expiry).
Keys & scanning
| Method | Returns | Notes |
|---|---|---|
keys(pattern) |
Promise<string[]> |
Glob match; may block the server on a large keyspace. |
scanPage(cursor, options?) |
Promise<ScanResult> |
One page. Pass '' to begin; options accepts match / count. |
scan(options?) |
AsyncIterableIterator<string> |
Incremental walk; hides cursor bookkeeping. |
for await (const key of client.scan({ match: 'user:*' })) {
console.log(key);
}Health & metadata
| Method | Returns |
|---|---|
ping() |
Promise<void> |
version() |
Promise<string> — server semver |
stats() |
Promise<string> — server stats text |
Maintenance & lifecycle
| Method | Returns |
|---|---|
flushAll() |
Promise<void> — remove every key |
close() |
Promise<void> — idempotent |
Per-call options
Every method takes an optional final options argument:
const ac = new AbortController();
const value = await client.get('key', { timeoutMs: 250, signal: ac.signal });A timed-out or aborted call rejects but leaves the connection usable — its eventual reply is discarded and later calls stay correctly correlated.
Errors
All thrown errors extend AellopusError, so you can catch the family and discriminate the case:
| Error | Meaning | Recoverable? |
|---|---|---|
NotFoundError |
Key absent (get, getString, ttl) |
Yes |
ServerError |
Well-formed server error; has .code (e.g. NOTINT, TTLRANGE) |
Yes |
TimeoutError |
Call exceeded timeoutMs |
Yes |
ProtocolError |
Malformed or wrong-shaped reply | No — connection is closed |
ClosedError |
Client closed or connection ended | No — reconnect |
A cancelled call rejects with a Web-standard DOMException named AbortError.
Compatibility
- Runtimes: Node.js 18+ and Bun. ESM only.
- Protocol: AWP/1. Tested against Aellopus server
0.1.0.