### Deno MQTT Server Setup Source: https://github.com/seriousme/opifex/blob/main/README.md A basic example demonstrating how to set up an MQTT server using Deno. It listens for incoming connections and serves them using the MqttServer. ```typescript import { MqttServer } from "./server/mod.ts"; const listener = Deno.listen(); const mqttServer = new MqttServer(mqttOptions); for await (const conn of this.listener) { mqttServer.serve(conn); } ``` -------------------------------- ### TcpServer - Start a TCP MQTT broker (NodeJS / Bun) Source: https://context7.com/seriousme/opifex/llms.txt This example demonstrates how to start a TCP MQTT broker using the `TcpServer` class in Node.js or Bun. It includes custom authentication and authorization handlers. ```APIDOC ## TcpServer - Start a TCP MQTT broker (NodeJS / Bun) ### Description This example demonstrates how to start a TCP MQTT broker using the `TcpServer` class in Node.js or Bun. It includes custom authentication and authorization handlers. ### Usage ```typescript import { TcpServer } from "@seriousme/opifex/tcpServer"; import type { Context, TAuthenticationResult, Topic } from "@seriousme/opifex/server"; import { AuthenticationResult } from "@seriousme/opifex/server"; // Custom authentication handler function isAuthenticated( _ctx: Context, clientId: string, username: string, password: Uint8Array, ): TAuthenticationResult { const pwd = new TextDecoder().decode(password); if (username === "admin" && pwd === "secret") { return AuthenticationResult.ok; } return AuthenticationResult.badUsernameOrPassword; } // Topic-level authorization function isAuthorizedToPublish(_ctx: Context, topic: Topic): boolean { return !topic.startsWith("readonly/"); } function isAuthorizedToSubscribe(_ctx: Context, _topic: Topic): boolean { return true; } const server = new TcpServer( { port: 1883, hostname: "0.0.0.0" }, { handlers: { isAuthenticated, isAuthorizedToPublish, isAuthorizedToSubscribe }, }, ); await server.start(); console.log(`Broker listening on ${server.address}:${server.port}`); // → Broker listening on 0.0.0.0:1883 // Later: // server.stop(); ``` ``` -------------------------------- ### MqttServer Setup Source: https://context7.com/seriousme/opifex/llms.txt Instantiate and configure the MqttServer with custom authentication and authorization handlers. ```APIDOC ## MqttServer — Transport-agnostic MQTT server `MqttServer` is the protocol-layer server. Given any `SockConn` (readable/writable streams), `serve(conn)` handles the full MQTT state machine: connect/auth, publish, subscribe, QoS 0/1/2 acknowledgements, will messages, keep-alive timers, and clean vs. persistent sessions. Authentication and authorization are provided as pluggable `Handlers`. ```typescript import { MqttServer, AuthenticationResult } from "@seriousme/opifex/server"; import type { Handlers } from "@seriousme/opifex/server"; const handlers: Handlers = { isAuthenticated: (_ctx, clientId, _username, _password) => { console.log(`Client connecting: ${clientId}`); return AuthenticationResult.ok; // allow all }, isAuthorizedToPublish: (_ctx, topic) => { // Block publishing to system topics return !topic.startsWith("$SYS/"); }, isAuthorizedToSubscribe: (_ctx, _topic) => true, }; const mqttServer = new MqttServer({ handlers }); // Integrate with any socket source — e.g., a Unix socket: // import { createServer } from "node:net"; // const netServer = createServer((sock) => mqttServer.serve(wrapNodeSocket(sock))); // netServer.listen(1883); ``` ``` -------------------------------- ### Start a Deno TCP MQTT Broker with Custom Auth Source: https://context7.com/seriousme/opifex/llms.txt Set up and run a TCP MQTT broker in Deno using Opifex. This example demonstrates custom authentication logic. ```typescript // deno run -A myServer.ts import { MqttServer } from "jsr:@seriousme/opifex/server"; import { AuthenticationResult } from "jsr:@seriousme/opifex/server"; const mqttServer = new MqttServer({ handlers: { isAuthenticated: (_ctx, _clientId, username, password) => { const pwd = new TextDecoder().decode(password); return username === "deno" && pwd === "rocks" ? AuthenticationResult.ok : AuthenticationResult.notAuthorized; }, }, }); const listener = Deno.listen({ port: 1883 }); console.log("Deno MQTT broker on :1883"); for await (const conn of listener) { mqttServer.serve(conn); // non-blocking: serve each client concurrently } ``` -------------------------------- ### Show Opifex Demo Server Help Source: https://github.com/seriousme/opifex/blob/main/node/README.md Use this command to view the help information for the Opifex demo server. Ensure NodeJS and npx are installed and accessible. ```bash npx -p @seriousme/opifex demoserver --help ``` -------------------------------- ### TcpServer (Deno) Source: https://context7.com/seriousme/opifex/llms.txt This example shows how to set up a TCP MQTT broker using `MqttServer` with a Deno runtime. It utilizes Deno's built-in networking capabilities. ```APIDOC ## TcpServer (Deno) ### Description This example shows how to set up a TCP MQTT broker using `MqttServer` with a Deno runtime. It utilizes Deno's built-in networking capabilities. ### Usage ```typescript // deno run -A myServer.ts import { MqttServer } from "jsr:@seriousme/opifex/server"; import { AuthenticationResult } from "jsr:@seriousme/opifex/server"; const mqttServer = new MqttServer({ handlers: { isAuthenticated: (_ctx, _clientId, username, password) => { const pwd = new TextDecoder().decode(password); return username === "deno" && pwd === "rocks" ? AuthenticationResult.ok : AuthenticationResult.notAuthorized; }, }, }); const listener = Deno.listen({ port: 1883 }); console.log("Deno MQTT broker on :1883"); for await (const conn of listener) { mqttServer.serve(conn); // non-blocking: serve each client concurrently } ``` ``` -------------------------------- ### Show Opifex MQTT Client Help Source: https://github.com/seriousme/opifex/blob/main/node/README.md Use this command to view the help information for the Opifex MQTT client. Ensure NodeJS and npx are installed and accessible. ```bash npx @seriousme/opifex mqtt --help ``` -------------------------------- ### Full Publish/Subscribe Example (Node.js) Source: https://context7.com/seriousme/opifex/llms.txt This example combines TcpServer and TcpClient in a single process to demonstrate QoS levels, wildcards, retained messages, and clean disconnection. It requires setting up a server, a publisher client, and a subscriber client. ```typescript import { TcpServer } from "@seriousme/opifex/tcpServer"; import { TcpClient } from "@seriousme/opifex/tcpClient"; import { logger, LogLevel } from "@seriousme/opifex/utils"; logger.level(LogLevel.info); // ── Server ──────────────────────────────────────────────────────────────── const server = new TcpServer({ port: 0 }, {}); // port: 0 → OS assigns a free port await server.start(); console.log(`Broker on ${server.address}:${server.port}`); // ── Publisher client ────────────────────────────────────────────────────── const publisher = new TcpClient(); await publisher.connect({ url: new URL(`mqtt://${server.address}:${server.port}`), numberOfRetries: 0, options: { clientId: "publisher", clean: true, keepAlive: 10 }, }); // ── Subscriber client ───────────────────────────────────────────────────── const subscriber = new TcpClient(); await subscriber.connect({ url: new URL(`mqtt://${server.address}:${server.port}`), numberOfRetries: 0, options: { clientId: "subscriber", clean: true, keepAlive: 10 }, }); await subscriber.subscribe({ subscriptions: [ { topicFilter: "sensors/#", qos: 1 }, { topicFilter: "alerts/+", qos: 2 }, ], }); // Collect incoming messages const received: string[] = []; (async () => { for await (const msg of subscriber.messages()) { received.push(`[${msg.topic}] ${new TextDecoder().decode(msg.payload)}`); } })(); // Publish messages at different QoS levels const enc = new TextEncoder(); await publisher.publish({ topic: "sensors/temp", payload: enc.encode("22.5"), qos: 0 }); await publisher.publish({ topic: "sensors/humidity", payload: enc.encode("60"), qos: 1 }); await publisher.publish({ topic: "alerts/fire", payload: enc.encode("!"), qos: 2 }); await new Promise((r) => setTimeout(r, 100)); // let messages propagate console.log("Received:", received); // → Received: [ // "[sensors/temp] 22.5", // "[sensors/humidity] 60", // "[alerts/fire] !" // ] await subscriber.disconnect(); await publisher.disconnect(); server.stop(); ``` -------------------------------- ### Configure MqttServer with Handlers Source: https://context7.com/seriousme/opifex/llms.txt Set up the MqttServer with authentication and authorization handlers. This example allows all clients to connect and permits publishing to any topic except system topics. ```typescript import { MqttServer, AuthenticationResult } from "@seriousme/opifex/server"; import type { Handlers } from "@seriousme/opifex/server"; const handlers: Handlers = { isAuthenticated: (_ctx, clientId, _username, _password) => { console.log(`Client connecting: ${clientId}`); return AuthenticationResult.ok; // allow all }, isAuthorizedToPublish: (_ctx, topic) => { // Block publishing to system topics return !topic.startsWith("$SYS/"); }, isAuthorizedToSubscribe: (_ctx, _topic) => true, }; const mqttServer = new MqttServer({ handlers }); // Integrate with any socket source — e.g., a Unix socket: // import { createServer } from "node:net"; // const netServer = createServer((sock) => mqttServer.serve(wrapNodeSocket(sock))); // netServer.listen(1883); ``` -------------------------------- ### Start a NodeJS/Bun TCP MQTT Broker with Custom Auth Source: https://context7.com/seriousme/opifex/llms.txt Configure and start a TCP MQTT server using Opifex in a NodeJS or Bun environment. Includes custom authentication and authorization handlers. ```typescript import { TcpServer } from "@seriousme/opifex/tcpServer"; import type { Context, TAuthenticationResult, Topic } from "@seriousme/opifex/server"; import { AuthenticationResult } from "@seriousme/opifex/server"; // Custom authentication handler function isAuthenticated( _ctx: Context, clientId: string, username: string, password: Uint8Array, ): TAuthenticationResult { const pwd = new TextDecoder().decode(password); if (username === "admin" && pwd === "secret") { return AuthenticationResult.ok; } return AuthenticationResult.badUsernameOrPassword; } // Topic-level authorization function isAuthorizedToPublish(_ctx: Context, topic: Topic): boolean { return !topic.startsWith("readonly/"); } function isAuthorizedToSubscribe(_ctx: Context, _topic: Topic): boolean { return true; } const server = new TcpServer( { port: 1883, hostname: "0.0.0.0" }, { handlers: { isAuthenticated, isAuthorizedToPublish, isAuthorizedToSubscribe }, }, ); await server.start(); console.log(`Broker listening on ${server.address}:${server.port}`); // → Broker listening on 0.0.0.0:1883 // Later: // server.stop(); ``` -------------------------------- ### Install Opifex Package Source: https://github.com/seriousme/opifex/blob/main/node/README.md Install the Opifex package locally using npm. This command is used for local deployment of Opifex. ```bash npm install @seriousme/opifex ``` -------------------------------- ### Consume Incoming MQTT Publish Packets with messages() Source: https://context7.com/seriousme/opifex/llms.txt Use the `messages()` method to get an async iterable for incoming `PublishPacket`s. This ensures no messages are lost, even if they arrive before you start consuming them with a `for await` loop. ```typescript import { TcpClient } from "@seriousme/opifex/tcpClient"; import type { PublishPacket } from "@seriousme/opifex/mqttPacket"; const client = new TcpClient(); await client.connect({ url: new URL("mqtt://localhost:1883") }); await client.subscribe({ subscriptions: [{ topicFilter: "telemetry/+/data", qos: 1 }], }); // Start consuming BEFORE the publisher sends anything — no messages dropped const iterable = client.messages(); // Process messages concurrently with the publish loop: (async () => { for await (const pkt: PublishPacket of iterable) { const payload = JSON.parse(new TextDecoder().decode(pkt.payload)); console.log(`Device ${pkt.topic.split("/")[1]}:`, payload); // → Device sensor-42: { temp: 20.1 } } })(); ``` -------------------------------- ### Clone Opifex Repository Source: https://github.com/seriousme/opifex/blob/main/node/README.md Clone the Opifex repository from GitHub to your local machine. This is an alternative to installing via npm for local development. ```bash git clone https://github.com/seriousme/opifex.git ``` -------------------------------- ### Show Demo Server Help from Local Clone Source: https://github.com/seriousme/opifex/blob/main/node/README.md Execute the demo server script directly from a local clone of the Opifex repository to view its help information. Requires the repository to be cloned first. ```bash ./bin/demoServer.ts --help ``` -------------------------------- ### Show MQTT Client Help from Local Clone Source: https://github.com/seriousme/opifex/blob/main/node/README.md Execute the MQTT client script directly from a local clone of the Opifex repository to view its help information. Requires the repository to be cloned first. ```bash ./bin/mqtt.ts --help ``` -------------------------------- ### Run Opifex MQTT Server with Deno Source: https://github.com/seriousme/opifex/blob/main/deno/README.md Execute the Opifex demo server script using Deno. Deno will download dependencies on the first run and may prompt for network access. ```bash deno run https://deno.land/x/opifex/bin/demoServer.ts ``` -------------------------------- ### Local Deployment: Run Opifex Server with Deno Source: https://github.com/seriousme/opifex/blob/main/deno/README.md Run the Opifex demo server locally using Deno with the -A flag for full permissions. ```bash deno run -A bin/demoServer.ts ``` -------------------------------- ### Local Deployment: Run Opifex Client with Deno Source: https://github.com/seriousme/opifex/blob/main/deno/README.md Run the Opifex MQTT client locally using Deno with the -A flag for full permissions. ```bash deno run -A bin/mqtt.ts ``` -------------------------------- ### CLI — `mqtt` command-line client Source: https://context7.com/seriousme/opifex/llms.txt The `mqtt` binary provides `publish` and `subscribe` sub-commands with full TLS, authentication, QoS, retain, and session options. ```APIDOC ## CLI — `mqtt` command-line client The `mqtt` binary (installed as `npx @seriousme/opifex mqtt`) provides `publish` and `subscribe` sub-commands with full TLS, auth, QoS, retain, and session options. ``` -------------------------------- ### Run Opifex MQTT Client with Deno Source: https://github.com/seriousme/opifex/blob/main/deno/README.md Execute the Opifex MQTT client script using Deno. Deno will download dependencies on the first run and may prompt for network access. ```bash deno run https://deno.land/x/opifex/bin/mqtt.ts ``` -------------------------------- ### Connect, Publish, and Subscribe with TcpClient (NodeJS/Bun) Source: https://context7.com/seriousme/opifex/llms.txt Connect to an MQTT broker using TcpClient, subscribe to topics, publish messages, and consume incoming messages. Handles connection lifecycle callbacks and retries. ```typescript import { TcpClient } from "@seriousme/opifex/tcpClient"; import type { PublishPacket } from "@seriousme/opifex/mqttPacket"; const client = new TcpClient(); const encoder = new TextEncoder(); const decoder = new TextDecoder(); // Connection lifecycle callbacks client.onConnected = () => console.log("Connected!"); client.onDisconnected = () => console.log("Disconnected."); client.onReconnecting = () => console.log("Reconnecting…"); client.onError = (err) => console.error("Error:", err.message); await client.connect({ url: new URL("mqtt://localhost:1883"), numberOfRetries: 3, options: { clientId: "my-sensor-01", username: "admin", password: encoder.encode("secret"), keepAlive: 30, clean: true, }, }); // Subscribe to a wildcard topic await client.subscribe({ subscriptions: [ { topicFilter: "sensors/#", qos: 1 }, { topicFilter: "alerts/+/critical", qos: 2 }, ], }); // Publish a retained message with QoS 1 await client.publish({ topic: "sensors/temperature", payload: encoder.encode(JSON.stringify({ value: 22.5, unit: "C" })), qos: 1, retain: true, }); // Consume incoming messages via async iterable (async () => { for await (const msg: PublishPacket of client.messages()) { console.log(`[${msg.topic}] ${decoder.decode(msg.payload)}`); // → [sensors/temperature] {"value":22.5,"unit":"C"} } })(); // Disconnect cleanly // await client.disconnect(); ``` -------------------------------- ### TcpClient Connection and Basic Usage (NodeJS/Bun) Source: https://context7.com/seriousme/opifex/llms.txt Connect a TCP client to an MQTT broker, subscribe to topics, publish messages, and consume incoming messages. ```APIDOC ## TcpClient — Connect, publish, subscribe (NodeJS / Bun) `TcpClient` extends the base `Client` class with Node TCP socket support for `mqtt://` and `mqtts://` (TLS) protocols. The `connect()` method returns a promise that resolves to `TAuthenticationResult`. After connecting, use `publish()`, `subscribe()`, and the `messages()` async iterable. ```typescript import { TcpClient } from "@seriousme/opifex/tcpClient"; import type { PublishPacket } from "@seriousme/opifex/mqttPacket"; const client = new TcpClient(); const encoder = new TextEncoder(); const decoder = new TextDecoder(); // Connection lifecycle callbacks client.onConnected = () => console.log("Connected!"); client.onDisconnected = () => console.log("Disconnected."); client.onReconnecting = () => console.log("Reconnecting…"); client.onError = (err) => console.error("Error:", err.message); await client.connect({ url: new URL("mqtt://localhost:1883"), numberOfRetries: 3, options: { clientId: "my-sensor-01", username: "admin", password: encoder.encode("secret"), keepAlive: 30, clean: true, }, }); // Subscribe to a wildcard topic await client.subscribe({ subscriptions: [ { topicFilter: "sensors/#", qos: 1 }, { topicFilter: "alerts/+/critical", qos: 2 }, ], }); // Publish a retained message with QoS 1 await client.publish({ topic: "sensors/temperature", payload: encoder.encode(JSON.stringify({ value: 22.5, unit: "C" })), qos: 1, retain: true, }); // Consume incoming messages via async iterable (async () => { for await (const msg: PublishPacket of client.messages()) { console.log(`[${msg.topic}] ${decoder.decode(msg.payload)}`); // → [sensors/temperature] {"value":22.5,"unit":"C"} } })(); // Disconnect cleanly // await client.disconnect(); ``` ``` -------------------------------- ### Import Opifex TCP Adapters in Deno Source: https://context7.com/seriousme/opifex/llms.txt Import the TCP client and server adapters for Deno from the JSR registry. ```typescript import { TcpClient } from "jsr:@seriousme/opifex/tcpClient"; import { TcpServer } from "jsr:@seriousme/opifex/tcpServer"; ``` -------------------------------- ### MQTT CLI Publish Command Source: https://context7.com/seriousme/opifex/llms.txt Publish MQTT messages using the `mqtt` CLI. Supports options for retained messages, QoS, authentication, and TLS. ```bash # Publish a retained message with QoS 2 npx @seriousme/opifex mqtt publish \ -u mqtt://localhost:1883 \ -t "home/lights" \ -m "on" \ -q 2 \ -r ``` ```bash # Authenticate with username and password npx @seriousme/opifex mqtt publish \ -u mqtt://localhost:1883 \ -U admin \ -P secret \ -t "status" \ -m "online" ``` ```bash # Use MQTT v5 protocol npx @seriousme/opifex mqtt publish \ -u mqtt://localhost:1883 \ -V 5 \ -t "v5/test" \ -m "hello v5" ``` -------------------------------- ### MQTT CLI Subscribe Command Source: https://context7.com/seriousme/opifex/llms.txt Subscribe to MQTT topics using the `mqtt` CLI. Supports various options for connection URLs, topics, QoS, and TLS. ```bash # Start the demo broker npx -p @seriousme/opifex demoServer 1883 # Subscribe to all messages under "home/#" with QoS 1 npx @seriousme/opifex mqtt subscribe \ -u mqtt://localhost:1883 \ -t "home/#" \ -q 1 ``` ```bash # Connect over TLS with a custom CA cert npx @seriousme/opifex mqtt subscribe \ -u mqtts://broker.example.com:8883 \ -C ./ca.pem \ -c ./client.pem \ -k ./client.key \ -t "secure/#" ``` -------------------------------- ### Implement Custom MQTT Persistence Backend Source: https://context7.com/seriousme/opifex/llms.txt Implement the `IPersistence` interface to provide custom message storage for subscriptions, retained messages, and QoS packets. This allows integration with various databases for durability and clustering. ```typescript import type { IPersistence, IStore, ClientId, Handler, Topic, TopicFilter, QoS, PublishPacket, } from "@seriousme/opifex/persistence"; import { MqttServer } from "@seriousme/opifex/server"; import { TcpServer } from "@seriousme/opifex/tcpServer"; // Minimal in-memory persistence (mirrors MemoryPersistence structure) class MyCustomPersistence implements IPersistence { clientList = new Map(); retained = new Map(); registerClient(clientId: ClientId, handler: Handler, clean: boolean): IStore { // Return or create a session store for clientId throw new Error("Implement with your DB"); } deregisterClient(clientId: ClientId): void { /* ... */ } publish(topic: Topic, packet: PublishPacket): void { /* fan-out to subscribers */ } subscribe(store: IStore, topic: TopicFilter, qos: QoS): void { /* ... */ } unsubscribe(store: IStore, topic: TopicFilter): void { /* ... */ } handleRetained(clientId: ClientId): void { /* deliver retained messages */ } } // Wire a custom persistence backend into the server import { MemoryPersistence } from "@seriousme/opifex/persistence"; const server = new TcpServer( { port: 1883 }, { persistence: new MemoryPersistence() }, // swap with MyCustomPersistence ); await server.start(); console.log("Server with custom persistence started on port", server.port); ``` -------------------------------- ### TcpClient for Deno Environment Source: https://context7.com/seriousme/opifex/llms.txt Utilize the Deno-compatible TcpClient, which uses Deno.connect and Deno.connectTls for establishing connections. The API remains consistent with the NodeJS version. ```typescript // deno run --allow-net --allow-read myClient.ts import { TcpClient } from "jsr:@seriousme/opifex/tcpClient"; const client = new TcpClient(); await client.connect({ url: new URL("mqtt://localhost:1883"), options: { clientId: "deno-client", keepAlive: 60, clean: true }, }); await client.subscribe({ subscriptions: [{ topicFilter: "news/#", qos: 0 }], }); for await (const msg of client.messages()) { console.log(new TextDecoder().decode(msg.payload)); } ``` -------------------------------- ### MqttConn - Low-level packet streaming Source: https://context7.com/seriousme/opifex/llms.txt The `MqttConn` class wraps a `SockConn` to provide methods for sending MQTT packets and an `AsyncIterable` for receiving decoded packets. It handles low-level details like variable-length headers and partial reads. ```APIDOC ## MqttConn — Low-level packet streaming `MqttConn` wraps a `SockConn` and provides `send(packet)` plus an `AsyncIterable` that reads MQTT packets from the wire, handling variable-length headers, partial reads, and oversized packets automatically. It closes automatically on any error and exposes `isClosed` / `reason` for diagnostics. ```typescript import { MqttConn } from "@seriousme/opifex/mqttConn"; import { PacketType, MQTTLevel } from "@seriousme/opifex/mqttPacket"; import type { AnyPacket } from "@seriousme/opifex/mqttPacket"; // conn is any SockConn (e.g., from Deno.connect or wrapNodeSocket) declare const conn: import("@seriousme/opifex/mqttConn").SockConn; const mqttConn = new MqttConn({ conn, maxIncomingPacketSize: 1 * 1024 * 1024, // 1 MB protocolLevel: MQTTLevel.v4, // MQTT 3.1.1 }); // Send a CONNECT packet await mqttConn.send({ type: PacketType.connect, protocolLevel: MQTTLevel.v4, clientId: "raw-client", keepAlive: 60, clean: true, }); // Iterate over decoded packets for await (const packet: AnyPacket of mqttConn) { if (packet.type === PacketType.connack) { console.log("CONNACK received, returnCode:", packet.returnCode); // → CONNACK received, returnCode: 0 break; } } if (!mqttConn.isClosed) { mqttConn.close(); } console.log("Connection closed, reason:", mqttConn.reason ?? "normal"); ``` ``` -------------------------------- ### TcpClient Usage in Deno Source: https://context7.com/seriousme/opifex/llms.txt Utilize the TcpClient in a Deno environment, leveraging Deno's native networking capabilities. ```APIDOC ## TcpClient (Deno) The Deno `TcpClient` in `/deno/tcpClient.ts` overrides `createConn()` to use `Deno.connect` and `Deno.connectTls`, providing the same API surface as the NodeJS variant. ```typescript // deno run --allow-net --allow-read myClient.ts import { TcpClient } from "jsr:@seriousme/opifex/tcpClient"; const client = new TcpClient(); await client.connect({ url: new URL("mqtt://localhost:1883"), options: { clientId: "deno-client", keepAlive: 60, clean: true }, }); await client.subscribe({ subscriptions: [{ topicFilter: "news/#", qos: 0 }], }); for await (const msg of client.messages()) { console.log(new TextDecoder().decode(msg.payload)); } ``` ``` -------------------------------- ### TcpClient TLS Connection (mqtts://) Source: https://context7.com/seriousme/opifex/llms.txt Establish a secure TLS connection using client certificates for mutual authentication. ```APIDOC ## TcpClient — TLS (mqtts://) with client certificates `TcpClient.connectMQTTS` accepts CA cert bundles, client cert, and private key as strings (file contents), enabling mutual TLS authentication against brokers that require it. ```typescript import { TcpClient, getFileData } from "@seriousme/opifex/tcpClient"; const client = new TcpClient(); const caCert = await getFileData("./certs/ca.pem"); // CA bundle const cert = await getFileData("./certs/client.pem"); // client cert const key = await getFileData("./certs/client.key"); // private key await client.connect({ url: new URL("mqtts://broker.example.com:8883"), caCerts: caCert ? [caCert] : undefined, cert, key, options: { clientId: "secure-device-01", keepAlive: 60, clean: true, }, }); console.log("Securely connected over mqtts://"); await client.publish({ topic: "secure/data", payload: new TextEncoder().encode("hello over TLS"), qos: 1, }); await client.disconnect(); ``` ``` -------------------------------- ### Client Event Hooks Source: https://context7.com/seriousme/opifex/llms.txt The base Client class provides connection state tracking and event hooks for lifecycle notifications. Users can subclass Client and override `createConn` for custom transports. ```APIDOC ## Client — Base class / connection state and event hooks `Client` is the transport-agnostic MQTT client base class. Subclass it and override `createConn()` to support custom transports (e.g., WebSocket streams, Unix sockets). The `connectionState` getter reflects the live state machine state. Five event callbacks provide lifecycle notifications. ```typescript import { Client } from "@seriousme/opifex/client"; import { ConnectionState } from "@seriousme/opifex/client"; import type { SockConn } from "@seriousme/opifex/mqttConn"; class WebSocketClient extends Client { protected override async createConn( _protocol: string, hostname: string, port = 1883, ): Promise { // Return any object with { read, write, close, remoteAddr } throw new Error("WebSocket transport not implemented in this example"); } } const client = new WebSocketClient(); client.onConnected = () => console.log("state:", client.connectionState); // → state: connected client.onDisconnected = () => console.log("state:", client.connectionState); // → state: disconnected client.onReconnecting = () => console.log("Attempting reconnect…"); client.onError = (err) => console.error("Client error:", err); // Use client.connect(), client.publish(), client.subscribe(), client.disconnect() // the same way as TcpClient ``` ``` -------------------------------- ### Low-level MQTT Packet Streaming with MqttConn Source: https://context7.com/seriousme/opifex/llms.txt Use `MqttConn` to wrap a `SockConn` for sending and receiving MQTT packets. It handles packet framing, partial reads, and oversized packets automatically, providing an async iterable for incoming packets. ```typescript import { MqttConn } from "@seriousme/opifex/mqttConn"; import { PacketType, MQTTLevel } from "@seriousme/opifex/mqttPacket"; import type { AnyPacket } from "@seriousme/opifex/mqttPacket"; // conn is any SockConn (e.g., from Deno.connect or wrapNodeSocket) declare const conn: import("@seriousme/opifex/mqttConn").SockConn; const mqttConn = new MqttConn({ conn, maxIncomingPacketSize: 1 * 1024 * 1024, // 1 MB protocolLevel: MQTTLevel.v4, // MQTT 3.1.1 }); // Send a CONNECT packet await mqttConn.send({ type: PacketType.connect, protocolLevel: MQTTLevel.v4, clientId: "raw-client", keepAlive: 60, clean: true, }); // Iterate over decoded packets for await (const packet: AnyPacket of mqttConn) { if (packet.type === PacketType.connack) { console.log("CONNACK received, returnCode:", packet.returnCode); // → CONNACK received, returnCode: 0 break; } } if (!mqttConn.isClosed) { mqttConn.close(); } console.log("Connection closed, reason:", mqttConn.reason ?? "normal"); ``` -------------------------------- ### IPersistence — Custom Persistence Backend Source: https://context7.com/seriousme/opifex/llms.txt Interface for pluggable message storage. Implement this to back subscriptions, retained messages, and in-flight QoS packets with a custom database. ```APIDOC ## IPersistence — Custom persistence backend `IPersistence` is the interface for pluggable message storage. Implement it to back subscriptions, retained messages, and in-flight QoS packets with any database. The built-in `MemoryPersistence` is suitable for single-process brokers; replace it for clustering or durability. ``` -------------------------------- ### Secure TcpClient Connection with TLS and Client Certificates Source: https://context7.com/seriousme/opifex/llms.txt Establish a secure connection using mqtts:// by providing CA certificates, client certificate, and private key. This enables mutual TLS authentication. ```typescript import { TcpClient, getFileData } from "@seriousme/opifex/tcpClient"; const client = new TcpClient(); const caCert = await getFileData("./certs/ca.pem"); // CA bundle const cert = await getFileData("./certs/client.pem"); // client cert const key = await getFileData("./certs/client.key"); // private key await client.connect({ url: new URL("mqtts://broker.example.com:8883"), caCerts: caCert ? [caCert] : undefined, cert, key, options: { clientId: "secure-device-01", keepAlive: 60, clean: true, }, }); console.log("Securely connected over mqtts://"); await client.publish({ topic: "secure/data", payload: new TextEncoder().encode("hello over TLS"), qos: 1, }); await client.disconnect(); ``` -------------------------------- ### Client.messages() - Async iterable for incoming packets Source: https://context7.com/seriousme/opifex/llms.txt The `messages()` method returns an `AsyncIterable` that yields incoming `PublishPacket` objects. This allows for efficient and ordered consumption of messages, even if they arrive before the iterable is fully set up. ```APIDOC ## Client.messages() — Async iterable for incoming packets `messages()` wires the internal `onPacket` callback to a `BufferedAsyncIterable` and returns it as an `AsyncIterable`. Awaiting this iterable delivers all incoming publish packets in order without losing messages that arrive between `subscribe()` and the start of the `for await` loop. ```typescript import { TcpClient } from "@seriousme/opifex/tcpClient"; import type { PublishPacket } from "@seriousme/opifex/mqttPacket"; const client = new TcpClient(); await client.connect({ url: new URL("mqtt://localhost:1883") }); await client.subscribe({ subscriptions: [{ topicFilter: "telemetry/+/data", qos: 1 }], }); // Start consuming BEFORE the publisher sends anything — no messages dropped const iterable = client.messages(); // Process messages concurrently with the publish loop: (async () => { for await (const pkt: PublishPacket of iterable) { const payload = JSON.parse(new TextDecoder().decode(pkt.payload)); console.log(`Device ${pkt.topic.split("/")[1]}:`, payload); // → Device sensor-42: { temp: 20.1 } } })(); ``` ``` -------------------------------- ### Extend Opifex Client for Custom Transports Source: https://context7.com/seriousme/opifex/llms.txt Subclass `Client` and override `createConn` to implement custom network transports like WebSockets. The `connectionState` getter provides the current state, and event callbacks offer lifecycle notifications. ```typescript import { Client } from "@seriousme/opifex/client"; import { ConnectionState } from "@seriousme/opifex/client"; import type { SockConn } from "@seriousme/opifex/mqttConn"; class WebSocketClient extends Client { protected override async createConn( _protocol: string, hostname: string, port = 1883, ): Promise { // Return any object with { read, write, close, remoteAddr } throw new Error("WebSocket transport not implemented in this example"); } } const client = new WebSocketClient(); client.onConnected = () => console.log("state:", client.connectionState); // → state: connected client.onDisconnected = () => console.log("state:", client.connectionState); // → state: disconnected client.onReconnecting = () => console.log("Attempting reconnect…"); client.onError = (err) => console.error("Client error:", err); // Use client.connect(), client.publish(), client.subscribe(), client.disconnect() // the same way as TcpClient ``` -------------------------------- ### MQTT Packet Codec (encode/decode) Source: https://context7.com/seriousme/opifex/llms.txt Serializes MQTT packets to binary and deserializes binary data back into packet objects. Supports various MQTT packet types and options. ```APIDOC ## encode / decode — MQTT packet codec (`mqttPacket`) `encode(packet, codecOpts)` serializes any `AnyPacket` object to a `Uint8Array`. `decode(buffer, codecOpts)` parses a complete binary MQTT packet back into a typed packet object. `decodePayload(firstByte, buffer, codecOpts)` decodes just the payload portion when the first byte and length have already been consumed (used internally by `MqttConn`). ``` -------------------------------- ### Encode and Decode MQTT Packets with mqttPacket Source: https://context7.com/seriousme/opifex/llms.txt Use `encode` to serialize packets to `Uint8Array` and `decode` to parse them back. Ensure `codecOpts` are correctly configured for protocol level and packet size limits. ```typescript import { encode, decode, PacketType, MQTTLevel, } from "@seriousme/opifex/mqttPacket"; import type { ConnectPacket, ConnackPacket, CodecOpts } from "@seriousme/opifex/mqttPacket"; const codecOpts: CodecOpts = { protocolLevel: MQTTLevel.v4, maxIncomingPacketSize: 2 * 1024 * 1024, maxOutgoingPacketSize: 2 * 1024 * 1024, }; // Encode a CONNECT packet const connectPacket: ConnectPacket = { type: PacketType.connect, protocolLevel: MQTTLevel.v4, clientId: "test-codec", keepAlive: 30, clean: true, username: "user", password: new TextEncoder().encode("pass"), }; const binary: Uint8Array = encode(connectPacket, codecOpts); console.log("Encoded bytes:", binary.length); // → Encoded bytes: 38 (approx) // Round-trip: decode the binary back to a packet object const decoded = decode(binary, codecOpts) as ConnectPacket; console.log("Packet type:", decoded.type); // → 1 (PacketType.connect) console.log("Client ID:", decoded.clientId); // → test-codec console.log("Keep-alive:", decoded.keepAlive); // → 30 // Encode a PUBLISH packet with QoS 1 const publishBinary = encode({ type: PacketType.publish, protocolLevel: MQTTLevel.v4, topic: "home/lights", payload: new TextEncoder().encode("on"), qos: 1, id: 42, dup: false, retain: false, }, codecOpts); console.log("PUBLISH bytes:", publishBinary.length); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.