@vex-chat/libvex
v10.0.0
Published
Library for communicating with xchat server.
Downloads
1,909
Readme
@vex-chat/libvex
Reference TypeScript client for the Vex protocol. Use it to build a chat client, a bot, or between two clients that need encrypted comms via spire server.
What's in the box
The client implements an X3DH-style handshake (X25519 DH + KDF), XSalsa20-Poly1305 (xSecretbox) for payloads, and HMAC over mail objects for integrity on the wire. Message payloads are intended to be end-to-end encrypted; the server still sees ciphertext, routing metadata, timing, and who talks to whom, and controls key-bundle distribution—so a malicious or compromised Spire can mount impersonation unless users verify sessions out-of-band.
- End-to-end encrypted messaging with X3DH key agreement — sessions, prekeys, and one-time keys handled internally.
- Tree-shakable subpath exports for platform-specific code:
./preset/node,./preset/test,./storage/node,./storage/sqlite,./storage/schema,./keystore/node,./keystore/memory. Browser bundles never pull inbetter-sqlite3or other native modules. - Pluggable storage backend via Kysely so node consumers can use SQLite and browser/tauri/expo consumers can wire their own.
- Pluggable key store so secrets can live in memory (tests), passphrase-encrypted files on disk (
./keystore/node), or wherever the embedding app keeps them.
Install
npm install @vex-chat/libvex@vex-chat/types, @vex-chat/crypto, eventemitter3, kysely, msgpackr, uuid, and zod are required runtime dependencies and install automatically. HTTP calls use the native fetch runtime API.
better-sqlite3 is an optional peer dependency — install it explicitly only if you plan to use the SQLite storage backend on Node:
npm install @vex-chat/libvex better-sqlite3Browser, Tauri, and Expo consumers should leave better-sqlite3 out and supply their own storage adapter via ./storage/schema.
Quickstart
import { Client } from "@vex-chat/libvex";
// Generate or load a long-lived secret key.
const secretKey = Client.generateSecretKey();
const client = await Client.create(secretKey);
// First-time devices must register before logging in.
await client.register("myUsername", "myPassword");
await client.login("myUsername", "myPassword");
// connect() authenticates the WebSocket and fires "ready" when done.
await client.connect();
client.on("ready", async () => {
const me = client.me.user();
await client.messages.send(me.userID, "Hello world!");
});
client.on("message", (message) => {
console.log("message:", message);
});Platform presets
libvex ships per-platform "presets" that wire together the appropriate storage and keystore:
// Node — sqlite storage + encrypted file keystore
import { nodePreset } from "@vex-chat/libvex/preset/node";
// Tests / ephemeral — in-memory storage, no persistence
import { testPreset } from "@vex-chat/libvex/preset/test";Presets return a PlatformPreset with a createStorage() factory and a deviceName. For a custom platform (browser, tauri, expo), import Client from @vex-chat/libvex directly and supply your own Storage (implementing the schema in @vex-chat/libvex/storage/schema) and KeyStore to Client.create.
Development
From the monorepo root:
pnpm install # install workspace deps
pnpm --filter @vex-chat/libvex build # rimraf dist && tsc -p tsconfig.build.json
pnpm --filter @vex-chat/libvex lint # eslint
pnpm --filter @vex-chat/libvex lint:fix # eslint --fix
pnpm --filter @vex-chat/libvex test # vitest unit suite (browser-safe, no spire required)
pnpm --filter @vex-chat/libvex test:e2e # vitest node + browser e2e — needs a running spire
pnpm --filter @vex-chat/libvex lint:pkg # publint --strict
pnpm --filter @vex-chat/libvex lint:types # @arethetypeswrong/cli
pnpm --filter @vex-chat/libvex lint:api # api-extractor — regenerates api/libvex.api.md
pnpm --filter @vex-chat/libvex license:check # license allowlist gate
pnpm --filter @vex-chat/libvex docs # typedoc — writes ./docsOr run from this directory directly with pnpm <script>.
The unit suite runs browser-safe and offline. The e2e suite needs a running Spire when you point tests at it.
Local Spire (dev): pnpm --filter @vex-chat/libvex test:local-spire runs the e2e suite against an instance of apps/spire/ brought up locally; see scripts/test-local-spire.mjs. Bring spire up via pnpm --filter @vex-chat/spire start (or docker compose up in apps/spire/) before running.
Applications using @vex-chat/libvex configure the client with ClientOptions only (for example host, unsafeHttp, and devApiKey); the library does not read .env or any environment variables. This repository's e2e tests can use API_URL / DEV_API_KEY in the shell or CI. There is no separate .env contract for the npm package.
See the root AGENTS.md and this package's AGENTS.md for the release flow (changesets → publish via OIDC) and the rules for writing changesets.
Outside contributors should follow the root CONTRIBUTING.md (including the CLA).
License
Default public license: AGPL-3.0 (see package.json for SPDX). Commercial licenses from Vex Heavy Industries LLC: LICENSE-COMMERCIAL, LICENSING.md.
