# BENNC-JS [![Build Status](https://drone.jacknet.io/api/badges/TerribleCodeClub/bennc-js/status.svg)](https://drone.jacknet.io/TerribleCodeClub/bennc-js) A TypeScript implementation of the [BENNC](https://wiki.jacknet.io/books/simontech/chapter/bennc) (Butlersaurus Ephemeral No NONCEnse Chat) protocol specification. This library provides both low-level protocol utilities and a high-level client for connecting to BENNC chat servers via WebSocket. ## Features - **Complete BENNC Protocol Support**: All message types (0x0000-0xFFFF) including subscribe, basic chat, user data, keepalive, history, and unsubscribe - **High-Level Client**: `BenncClient` class with automatic reconnection and event-driven architecture - **Browser & Node.js Compatible**: Works in modern browsers and Node.js environments - **TypeScript First**: Full type safety with comprehensive TypeScript definitions - **Encryption Support**: Built-in Romulus-M AEAD encryption for secure messaging - **Automatic Reconnection**: Configurable backoff strategies (constant, exponential) - **Small Bundle Size**: Minimal dependencies and efficient implementation ## Installation ```bash npm install @3t/bennc ``` ## Quick Start ### Using the BenncClient (Recommended) ```typescript import { BenncClient, MessageTypes } from "@3t/bennc"; const client = new BenncClient({ url: "wss://your-bennc-server.com", autoReconnect: true, reconnectBackoff: "exponential", reconnectDelay: 1000, }); // Listen for events client.addEventListener("connected", () => { console.log("Connected to BENNC server"); // Subscribe to basic messages client.subscribe(MessageTypes.Basic); }); client.addEventListener("message:1", (event) => { const { senderId, data } = event.detail; console.log(`Message from ${senderId}:`, new TextDecoder().decode(data)); }); client.addEventListener("disconnected", (event) => { console.log("Disconnected:", event.detail); }); // Connect to server await client.connect(); // Send a message client.sendBasicMessage("Hello, BENNC!"); ``` ### Using Low-Level Protocol Functions ```typescript import { packers, unpackers, MessageTypes } from "@3t/bennc"; // Pack a basic message const messageData = new TextEncoder().encode("Hello World"); const packet = packers[MessageTypes.Basic](messageData); // Unpack incoming message const incomingMessage = unpackers[MessageTypes.Basic](receivedData); ``` ## API Reference ### BenncClient #### Constructor Options ```typescript interface BenncClientOptions { url: string; // WebSocket server URL protocols?: string[]; // WebSocket protocols autoReconnect?: boolean; // Enable auto-reconnection (default: true) reconnectBackoff?: "constant" | "exponential"; // Backoff strategy (default: 'exponential') reconnectDelay?: number; // Reconnection delay in ms (default: 1000) maxReconnectAttempts?: number; // Max reconnection attempts (default: 10) } ``` #### Methods - `connect(): Promise` - Connect to the BENNC server - `disconnect(): void` - Disconnect from the server - `isConnected(): boolean` - Check connection status - `subscribe(messageType: MessageTypes): void` - Subscribe to message type - `unsubscribe(messageType: MessageTypes): void` - Unsubscribe from message type - `sendBasicMessage(message: string, key?: Uint8Array): void` - Send encrypted chat message - `sendUserDataRequest(username: string, colour: Color, clientId: string, key?: Uint8Array): void` - Request user data - `sendUserDataResponse(username: string, colour: Color, clientId: string, key?: Uint8Array): void` - Respond with user data - `sendKeepalive(): void` - Send keepalive message - `requestHistory(): void` - Request message history #### Events The client extends `EventTarget` and emits the following events: - `connected` - Successfully connected to server - `disconnected` - Disconnected from server (detail: `{code, reason}`) - `reconnecting` - Attempting to reconnect - `error` - Connection or protocol error (detail: error object) - `packet` - Raw incoming packet (detail: packet object) - `message` - Parsed message (detail: `{messageType, senderId, data}`) - `message:${messageType}` - Specific message type events (detail: `{senderId, data}`) - `unknown-message` - Unknown message type received - `parse-error` - Error parsing incoming message ### Message Types ```typescript enum MessageTypes { Subscribe = 0x0000, Basic = 0x0001, UserDataRequest = 0x0002, UserDataResponse = 0x0003, Keepalive = 0x0005, GetHistory = 0xfffe, Unsubscribe = 0xffff, } ``` ### Protocol Constants ```typescript const MAX_DATA_LENGTH = 1000; // Maximum data payload size const DEFAULT_KEY: Uint8Array; // Default encryption key ``` ## Build To build the BENNC-JS library from source: ```bash $ git clone $ cd bennc-js $ npm install $ npm run build ``` The build output will be saved to the `dist` directory. ## Protocol Details BENNC uses a binary protocol with the following message structure: **Client โ†’ Server**: `[Type(2)|Length(2)|Data(0-1000)]` **Server โ†’ Client**: `[Type(2)|SenderId(4)|Length(2)|Data(0-1000)]` - All integers are big-endian - Maximum data payload is 1000 bytes (including encryption overhead) - Encrypted message types (0x0001, 0x0002, 0x0003) use Romulus-M AEAD with 16-byte nonces - Reserved sender IDs: 0xFFFFFF00-0xFFFFFFFF ## Development Requirements: Node.js LTS and npm ### Commands ```bash # Install dependencies npm install # Run tests npm run test # Lint code npm run lint # Format code npm run format # Build library npm run build ``` ### Visual Studio Code This repository includes VS Code configuration for debugging and testing. Use `Ctrl+Shift+B` (or `โ‡งโŒ˜B`) to run the build task. Unit tests use [Jest](https://jestjs.io/) with VS Code support via the [Jest extension](https://marketplace.visualstudio.com/items?itemName=Orta.vscode-jest). ## License ISC License - see package.json for details. ## Contributing This is part of the BENNC protocol ecosystem. Please refer to the [BENNC specification](https://wiki.jacknet.io/books/simontech/chapter/bennc) for protocol details.