@withnen/client
v0.4.0
Published
MIT licensed client SDK for end-to-end encrypted API payloads. ML-KEM-768 key exchange + ChaCha20-Poly1305 encryption.
Readme
Nen Client SDK (@withnen/client)
The browser/frontend SDK for Nen — a drop-in fetch replacement that encrypts
the payload before it leaves the tab, using a post-quantum (ML-KEM-768) handshake.
Install
npm install @withnen/clientQuick use
import { createNenFetch, createNenStream } from '@withnen/client';
const nenFetch = createNenFetch(''); // '' = same-origin
const data = await nenFetch('/api/secure', { // returns the decrypted JSON
method: 'POST',
body: JSON.stringify({ ssn: '412-55-9087' }),
});
for await (const chunk of createNenStream('')('/api/chat', {
method: 'POST',
body: JSON.stringify({ prompt }),
})) {
process.stdout.write(chunk); // decrypted SSE tokens
}Prefer an explicit instance? new NenClient(serverUrl, { identityMode: 'pqc' })
then await client.handshake(), client.nenFetch(), client.nenStream(),
client.rotate(), client.terminate(), client.status().
What it does
- Handshake — generates an ML-KEM keypair in Wasm, posts the public key,
decapsulates the returned ciphertext into the shared secret, and stores the
server-issued HMAC key. With
identityMode: 'pqc'it also signs the ephemeral key with ML-DSA. The ML-KEM secret key is zeroized immediately after. nenFetch— encrypts the JSON body (ChaCha20-Poly1305), sends{ ct, n }base64 with theX-Nen-Session,X-Nen-Timestamp, andX-Nen-Signature(HMAC) headers, and decrypts the JSON response.nenStream— same request leg; yields decrypted SSE chunks as an async generator.- Auto-recovery — on a
401it transparentlyrotate()s (fresh handshake) and retries once.
Coded errors
Failures throw an NenError carrying a stable ISO-xxxx code (e.g.
ISO-2001 SESSION_NOT_INITIALIZED, ISO-1003 HANDSHAKE_NETWORK). The wire/throw
surface never leaks the internal diagnostic hint. Resolve a code with
describeNenCode('ISO-1003'). Full catalog: ../../ERROR_CODES.md.
Build & test
npm run build # tsup → dist/ (CJS + ESM + .d.ts)
npm test # jest (core-crypto mapped to the Node wasm build for tests)Notes
- Session keys live in instance memory only — never
localStorage/cookies — and are lost on refresh (a fresh handshake follows). Each tab handshakes independently. - The wire format is base64-only (
{ ct, n }) as of v0.2.0.
See ../../PROTOCOL.md for the exact protocol.
