npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@redboltz/mqtt-client-wasm

v0.2.1

Published

MQTT v3.1.1/v5.0 client for browsers and Node.js using WebSocket/TCP/TLS transport, compiled to WebAssembly

Readme

mqtt-client-wasm

CI codecov

MQTT client library compiled to WebAssembly, supporting both browsers and Node.js.

Supported Transports

| Transport | Browser | Node.js | |-----------|---------|---------| | WebSocket (ws://) | Yes | Yes | | WebSocket Secure (wss://) | Yes | Yes | | TCP | - | Yes | | TLS | - | Yes |

Features

  • MQTT v3.1.1 and v5.0: Full support for both protocol versions
  • Multiple Transports: WebSocket for both platforms, TCP/TLS for Node.js
  • Protocol State Machine: Internal state machine automatically handles protocol behavior based on packet exchange
    • e.g., KeepAlive in CONNECT triggers automatic PINGREQ transmission
    • e.g., MQTT v5.0 properties (receiveMaximum, maximumPacketSize, topicAliasMaximum, etc.) are internally tracked and enforced
    • See mqtt-protocol-core for details (Rust)
  • Low-level Endpoint API: Direct packet send/recv operations for full control
  • Auto Response Options: Configurable automatic handling of PUBACK, PUBREC, PUBREL, PUBCOMP, and PINGRESP
  • Interactive Client Tool: Ready-to-use HTML client for testing and debugging (browser)

Protocol State Machine Details

MQTT v3.1.1

Sending CONNECT Packet:

  • If keepAlive is set to a value greater than 0, automatic PINGREQ transmission is enabled. A PINGREQ packet is sent when no other packet has been transmitted within keepAlive seconds.
  • If cleanSession is set to true, the endpoint's Session State is cleared.

Receiving CONNACK Packet:

  • If sessionPresent is false, the endpoint's Session State is cleared. However, the session state configuration is retained, so subsequent PUBLISH packets with QoS 1 or QoS 2 will be stored.
  • If sessionPresent is true, any stored PUBLISH and PUBREL packets are retransmitted.

MQTT v5.0

Sending CONNECT Packet:

  • If cleanStart is set to true, the endpoint's Session State is cleared.
  • If topicAliasMaximum is set, a topic name to topic alias mapping is prepared for outgoing packets.
  • If receiveMaximum is set, the receive quota for incoming packets is configured.
  • If maximumPacketSize is set, the maximum packet size for incoming packets is configured.
  • If sessionExpiryInterval is set to a value greater than 0, session state persistence is enabled.

Receiving CONNACK Packet:

  • If sessionPresent is false, the endpoint's Session State is cleared. However, the session state configuration is retained, so subsequent PUBLISH packets with QoS 1 or QoS 2 will be stored.
  • If sessionPresent is true, any stored PUBLISH and PUBREL packets are retransmitted.
  • If topicAliasMaximum is set, a topic alias to topic name mapping is prepared for incoming packets.
  • If receiveMaximum is set, the send quota for outgoing packets is configured.
  • If maximumPacketSize is set, the maximum packet size for outgoing packets is configured.
  • If serverKeepAlive is set, it overrides the client's keepAlive value. A PINGREQ packet is sent when no other packet has been transmitted within serverKeepAlive seconds.

Topic Alias

Topic Alias is an MQTT v5.0 feature that reduces PUBLISH packet size by mapping topic names to numeric identifiers. The mapping operates independently in two directions: broker-to-client and client-to-broker.

Capacity Negotiation:

  • Client to Broker: The broker declares a topicAliasMaximum value in the CONNACK packet, allowing the client to use topic aliases up to that limit when sending PUBLISH packets.
  • Broker to Client: The client declares a topicAliasMaximum value in the CONNECT packet, allowing the broker to use topic aliases up to that limit when sending PUBLISH packets.

How Topic Alias Works:

  1. Registering a mapping: A PUBLISH packet containing both a topic name and a topicAlias property establishes the mapping. If the alias was already mapped to a different topic, the mapping is updated.

  2. Using a mapping: A PUBLISH packet with an empty topic name and a topicAlias property signals the receiver to look up the topic name from the established mapping. This reduces packet size, especially for long topic names.

Automatic Topic Alias Handling:

The client provides two configuration options to automate topic alias management:

  • autoMapTopicAliasSend: true - Automatically assigns topic aliases when sending PUBLISH packets. When all available aliases are in use, the least recently used mapping is replaced.

  • autoReplaceTopicAliasSend: true - Automatically uses existing mappings when sending PUBLISH packets. If a topic name already has an alias registered, the client sends an empty topic name with the alias instead.

These options can be used together for fully automatic topic alias management.

Receiving PUBLISH with Topic Alias:

When the client receives a PUBLISH packet with an empty topic name and a topic alias, the library automatically restores the topic name from the mapping. You can check whether the topic name was restored by reading the topicNameExtracted property:

const pub = client.asPublish(packet);
console.log(`Topic: ${pub.topicName}`);
if (pub.topicNameExtracted) {
    console.log('(topic name was restored from alias mapping)');
}

Important: Topic Alias and Reconnection

According to the MQTT specification, topic alias mappings are not part of Session State. This means all mappings are discarded when the connection closes. However, Session State (which includes unacknowledged QoS 1/2 PUBLISH packets) can persist across connections.

This creates a potential issue: if a QoS 1 or QoS 2 PUBLISH packet was sent with an empty topic name (using a topic alias), and the client reconnects before receiving acknowledgment, the stored packet cannot be resent as-is because the alias mapping no longer exists.

The library handles this automatically: When retransmitting stored packets after reconnection, the library reconstructs each packet with the original topic name and removes the topic alias property. This ensures protocol compliance without requiring any user intervention.


Installation

npm

npm install @redboltz/mqtt-client-wasm

For WebSocket transport in Node.js, also install the ws package:

npm install ws

Setup by Platform

Browser Setup

import init, {
    WasmMqttClient,
    WasmMqttConfig,
    WasmPacketType
} from '@redboltz/mqtt-client-wasm';

// Initialize WASM module (required once)
await init();

// Create client
const config = new WasmMqttConfig({
    version: '5.0',           // '3.1.1' or '5.0'
    autoPubResponse: true,    // Auto handle QoS acknowledgments
    autoPingResponse: true,   // Auto respond to PINGREQ
});
const client = new WasmMqttClient(config);

// Connect via WebSocket
await client.connect('wss://broker.example.com:8884/');

Direct Script Include (No Bundler)

<script type="module">
    import init, { WasmMqttClient, WasmMqttConfig } from './pkg/mqtt_client_wasm.js';
    await init();
    // ... use the client
</script>

Node.js Setup

const {
    WasmMqttClient,
    WasmMqttConfig,
    WasmMqttPacket,
    WasmPacketType,
    init,
    createClientWithTransport,
    NodeWebSocketTransport,
    NodeTcpTransport,
    NodeTlsTransport
} = require('@redboltz/mqtt-client-wasm');

// Initialize WASM module (required once)
init();

Usage

Use createClientWithTransport() to create a client with a transport. The WASM client handles state machine, timers, and automatic responses (same API as browser).

const fs = require('fs');

// Create transport and client
const transport = new NodeTcpTransport();
const config = new WasmMqttConfig({ version: '5.0' });
const client = createClientWithTransport(config, transport);

// Connect transport AFTER creating client
await transport.connect('broker.example.com', 1883);

// Use the same API as browser
const connectPacket = client.newConnectPacket({
    clientId: 'my-node-client',
    keepAlive: 60,
    cleanSession: true,
});
await client.send(connectPacket);

const connack = await client.recv();
console.log('Connected:', client.asConnack(connack).sessionPresent);

// Subscribe
const packetId = await client.acquirePacketId();
const subPacket = client.newSubscribePacket({
    packetId,
    subscriptions: [{ topic: 'test/#', qos: 1 }],
});
await client.send(subPacket);
const suback = await client.recv();

// Receive messages
while (true) {
    const packet = await client.recv();
    if (packet.packetType() === WasmPacketType.Publish) {
        const pub = client.asPublish(packet);
        console.log(`Received: ${pub.topicName} = ${pub.payload}`);
    }
}

Transport Types

TCP Transport:

const transport = new NodeTcpTransport();
await transport.connect('broker.example.com', 1883);

TLS Transport:

const transport = new NodeTlsTransport({
    ca: fs.readFileSync('ca.pem'),
});
await transport.connect('broker.example.com', 8883);

WebSocket Transport (ws://):

const transport = new NodeWebSocketTransport();
await transport.connect('ws://broker.example.com:8080/');

WebSocket Secure Transport (wss://):

const transport = new NodeWebSocketTransport({
    ca: fs.readFileSync('ca.pem'),
});
await transport.connect('wss://broker.example.com:8884/');

TLS Options (for NodeTlsTransport and NodeWebSocketTransport)

Both NodeTlsTransport and NodeWebSocketTransport accept a TLS options object in their constructor. These options are passed directly to Node.js TLS module.

| Option | Type | Description | |--------|------|-------------| | ca | Buffer/string | CA certificate(s) for server verification | | cert | Buffer/string | Client certificate for mutual TLS | | key | Buffer/string | Client private key for mutual TLS | | passphrase | string | Passphrase for encrypted private key | | rejectUnauthorized | boolean | Reject connections with unverified certificates (default: true) | | servername | string | Server name for SNI (Server Name Indication) | | minVersion | string | Minimum TLS version ('TLSv1.2', 'TLSv1.3') | | maxVersion | string | Maximum TLS version | | ciphers | string | Cipher suites to use |

Example: Mutual TLS Authentication

const transport = new NodeTlsTransport({
    ca: fs.readFileSync('ca.pem'),
    cert: fs.readFileSync('client.crt'),
    key: fs.readFileSync('client.key'),
    passphrase: 'optional-key-passphrase',
});

Example: Custom TLS Configuration

const transport = new NodeWebSocketTransport({
    ca: fs.readFileSync('ca.pem'),
    minVersion: 'TLSv1.2',
    servername: 'broker.example.com',
});

Common API (Both Platforms)

The following sections apply to both browser and Node.js environments.

Configuration Options

const config = new WasmMqttConfig({
    version: '5.0',
    autoPubResponse: true,
    autoPingResponse: true,
});

| Option | Type | Default | Description | |--------|------|---------|-------------| | version | string | '3.1.1' | MQTT version ('3.1.1' or '5.0') | | pingreqSendIntervalMs | number | (auto) | Ping interval in ms (omit for auto from keepAlive) | | autoPubResponse | boolean | true | Auto handle QoS acknowledgments | | autoPingResponse | boolean | true | Auto respond to PINGREQ | | autoMapTopicAliasSend | boolean | false | Auto map topic aliases (v5.0) | | autoReplaceTopicAliasSend | boolean | false | Auto replace topic with alias (v5.0) | | pingrespRecvTimeoutMs | number | (disabled) | PINGRESP timeout in ms | | connectionEstablishTimeoutMs | number | (disabled) | Connection timeout in ms | | shutdownTimeoutMs | number | (disabled) | Shutdown timeout in ms |


Packet Reference

Connect

const connectPacket = client.newConnectPacket({
    clientId: 'my-client',
    keepAlive: 60,
    cleanSession: true,
    userName: 'user',
    password: 'pass',
    // Will message
    willTopic: 'client/status',
    willPayload: 'offline',
    willQos: 1,
    willRetain: true,
    // v5.0 Properties
    sessionExpiryInterval: 3600,
    receiveMaximum: 65535,
    maximumPacketSize: 1048576,
    topicAliasMaximum: 10,
    requestResponseInformation: true,
    requestProblemInformation: true,
    userProperties: [{ key: 'app', value: 'myapp' }],
    authenticationMethod: 'SCRAM-SHA-256',
    authenticationData: [0x01, 0x02, 0x03],
});

await client.send(connectPacket);

Connect Options

| Option | Type | Required | Description | |--------|------|----------|-------------| | clientId | string | Yes | Client identifier | | keepAlive | number | No | Keep alive interval in seconds (default: 0) | | cleanSession | boolean | No | Clean session (v3.1.1) / Clean start (v5.0) | | userName | string | No | Username for authentication | | password | string | No | Password for authentication | | willTopic | string | No | Will message topic | | willPayload | string | No | Will message payload | | willQos | number | No | Will message QoS (0, 1, 2) | | willRetain | boolean | No | Will message retain flag |

Connect Properties (v5.0 only)

| Property | Type | Description | |----------|------|-------------| | sessionExpiryInterval | number | Session expiry interval in seconds | | receiveMaximum | number | Maximum concurrent QoS 1/2 messages | | maximumPacketSize | number | Maximum packet size in bytes | | topicAliasMaximum | number | Maximum topic aliases | | requestResponseInformation | boolean | Request response information from broker | | requestProblemInformation | boolean | Request problem information from broker | | userProperties | array | User properties [{key, value}, ...] | | authenticationMethod | string | Authentication method name | | authenticationData | array | Authentication data (byte array) |


Subscribe

const packetId = await client.acquirePacketId();
const subscribePacket = client.newSubscribePacket({
    packetId: packetId,
    subscriptions: [{
        topic: 'sensor/#',
        qos: 2,
        // v5.0 options
        noLocal: true,
        retainAsPublished: true,
        retainHandling: 1,
    }],
    // v5.0 Properties
    subscriptionIdentifier: 12345,
    userProperties: [{ key: 'source', value: 'web' }],
});

await client.send(subscribePacket);

Subscribe Options

| Option | Type | Required | Description | |--------|------|----------|-------------| | packetId | number | Yes | Packet identifier | | subscriptions | array | Yes | Array of subscription entries |

Subscription Entry

| Option | Type | Required | Description | |--------|------|----------|-------------| | topic | string | Yes | Topic filter | | qos | number | No | Maximum QoS (0, 1, 2, default: 0) | | noLocal | boolean | No | (v5.0) Don't receive own messages | | retainAsPublished | boolean | No | (v5.0) Keep retain flag as published | | retainHandling | number | No | (v5.0) Retain handling: 0=send, 1=send if new, 2=don't send |

Subscribe Properties (v5.0 only)

| Property | Type | Description | |----------|------|-------------| | subscriptionIdentifier | number | Subscription identifier (1-268435455) | | userProperties | array | User properties [{key, value}, ...] |


Unsubscribe

const packetId = await client.acquirePacketId();
const unsubscribePacket = client.newUnsubscribePacket({
    packetId: packetId,
    topics: ['sensor/#', 'device/+/status'],
    // v5.0 Properties
    userProperties: [{ key: 'reason', value: 'cleanup' }],
});

await client.send(unsubscribePacket);

Unsubscribe Options

| Option | Type | Required | Description | |--------|------|----------|-------------| | packetId | number | Yes | Packet identifier | | topics | array | Yes | Array of topic filters to unsubscribe |

Unsubscribe Properties (v5.0 only)

| Property | Type | Description | |----------|------|-------------| | userProperties | array | User properties [{key, value}, ...] |


Publish

const publishPacket = client.newPublishPacket({
    topicName: 'sensor/temperature',
    payload: '25.5',
    qos: 1,
    retain: false,
    dup: false,
    packetId: await client.acquirePacketId(),  // Required for QoS > 0
    // v5.0 Properties
    payloadFormatIndicator: 1,
    messageExpiryInterval: 3600,
    topicAlias: 1,
    responseTopic: 'response/sensor',
    correlationData: [0x01, 0x02, 0x03],
    contentType: 'application/json',
    userProperties: [{ key: 'unit', value: 'celsius' }],
});

await client.send(publishPacket);

Publish Options

| Option | Type | Required | Description | |--------|------|----------|-------------| | topicName | string | Yes | Topic name | | payload | string | No | Payload as UTF-8 string | | payloadBytes | array | No | Payload as byte array (takes precedence over payload) | | qos | number | No | QoS level (0, 1, 2, default: 0) | | retain | boolean | No | Retain flag | | dup | boolean | No | Duplicate flag | | packetId | number | No* | Packet identifier (*Required for QoS 1 or 2) |

Publish Properties (v5.0 only)

| Property | Type | Description | |----------|------|-------------| | payloadFormatIndicator | number | Payload format: 0=unspecified, 1=UTF-8 | | messageExpiryInterval | number | Message expiry interval in seconds | | topicAlias | number | Topic alias (1-65535) | | responseTopic | string | Response topic for request/response | | correlationData | array | Correlation data (byte array) | | contentType | string | Content type (MIME type) | | userProperties | array | User properties [{key, value}, ...] |


Disconnect

const disconnectPacket = client.newDisconnectPacket({
    // v5.0 only options
    reasonCode: 0,
    reasonString: 'Normal disconnection',
    sessionExpiryInterval: 0,
    userProperties: [{ key: 'client', value: 'web' }],
});

await client.send(disconnectPacket);

Disconnect Options (v5.0 only)

| Option | Type | Description | |--------|------|-------------| | reasonCode | number | Disconnect reason code (default: 0 = Normal) | | reasonString | string | Human-readable reason string | | sessionExpiryInterval | number | Override session expiry interval | | userProperties | array | User properties [{key, value}, ...] |

Note: v3.1.1 DISCONNECT has no options - just call client.newDisconnectPacket({}).


QoS Response Packets (PUBACK, PUBREC, PUBREL, PUBCOMP)

When autoPubResponse: false, you need to manually send QoS responses:

// v3.1.1 - only packet_id
const pubackPacket = client.newPubackPacket({ packetId: 1 });

// v5.0 - with optional properties
const pubackPacket = client.newPubackPacket({
    packetId: 1,
    reasonCode: 0,
    reasonString: 'Success',
    userProperties: [{ key: 'info', value: 'processed' }],
});

QoS Response Options

| Option | Type | Required | Description | |--------|------|----------|-------------| | packetId | number | Yes | Packet identifier |

QoS Response Properties (v5.0 only)

| Property | Type | Description | |----------|------|-------------| | reasonCode | number | Reason code | | reasonString | string | Human-readable reason | | userProperties | array | User properties [{key, value}, ...] |

Available methods:

  • newPubackPacket(options) - QoS 1 acknowledgment
  • newPubrecPacket(options) - QoS 2 received
  • newPubrelPacket(options) - QoS 2 release
  • newPubcompPacket(options) - QoS 2 complete

Auth (v5.0 only)

const authPacket = client.newAuthPacket({
    reasonCode: 0x18,  // Continue authentication
    authenticationMethod: 'SCRAM-SHA-256',
    authenticationData: [0x01, 0x02, 0x03],
    reasonString: 'Continue',
    userProperties: [{ key: 'step', value: '2' }],
});

await client.send(authPacket);

Auth Options (v5.0 only)

| Option | Type | Description | |--------|------|-------------| | reasonCode | number | Auth reason code | | authenticationMethod | string | Authentication method name | | authenticationData | array | Authentication data (byte array) | | reasonString | string | Human-readable reason | | userProperties | array | User properties [{key, value}, ...] |


Receive Messages

The client.recv() API works identically on both browser and Node.js:

while (true) {
    const packet = await client.recv();

    switch (packet.packetType()) {
        case WasmPacketType.Connack: {
            const connack = client.asConnack(packet);
            console.log('Connected:', connack.sessionPresent);
            break;
        }
        case WasmPacketType.Publish: {
            const pub = client.asPublish(packet);
            console.log(`Topic: ${pub.topicName}, Payload: ${pub.payload}`);
            break;
        }
        case WasmPacketType.Suback: {
            const suback = client.asSuback(packet);
            console.log(`SUBACK: packetId=${suback.packetId}`);
            break;
        }
        // ... handle other packet types
    }
}

Received Packet Fields Reference

When receiving packets via client.recv(), you can access fields using the client.asXxx(packet) methods. The following sections document all available fields for each packet type.

Received CONNACK

const connack = client.asConnack(packet);

| Field | Type | Description | |-------|------|-------------| | sessionPresent | boolean | Whether a session from a previous connection exists | | returnCode (v3.1.1) | number | Connect return code | | reasonCode (v5.0) | number | Connect reason code | | isSuccess() | boolean | Returns true if connection was accepted |

CONNACK Properties (v5.0 only)

| Property | Type | Description | |----------|------|-------------| | sessionExpiryInterval | number? | Session expiry interval from server | | receiveMaximum | number? | Maximum concurrent QoS 1/2 receives | | maximumQos | number? | Maximum QoS level supported by server | | retainAvailable | boolean? | Whether retain is available | | maximumPacketSize | number? | Maximum packet size | | assignedClientIdentifier | string? | Client ID assigned by server | | topicAliasMaximum | number? | Maximum topic aliases | | reasonString | string? | Human-readable reason | | wildcardSubscriptionAvailable | boolean? | Whether wildcard subscriptions are available | | subscriptionIdentifiersAvailable | boolean? | Whether subscription identifiers are available | | sharedSubscriptionAvailable | boolean? | Whether shared subscriptions are available | | serverKeepAlive | number? | Server-specified keep alive | | responseInformation | string? | Response information | | serverReference | string? | Server reference for redirect | | authenticationMethod | string? | Authentication method | | authenticationData | Uint8Array? | Authentication data | | userProperties() | Array | User properties [{key, value}, ...] |


Received PUBLISH

const pub = client.asPublish(packet);

| Field | Type | Description | |-------|------|-------------| | topicName | string | Topic name | | payload | string? | Payload as UTF-8 string (null if not valid UTF-8) | | payloadBytes() | Uint8Array | Payload as byte array | | qos | number | QoS level (0, 1, 2) | | retain | boolean | Retain flag | | dup | boolean | Duplicate flag | | packetId | number? | Packet identifier (for QoS > 0) |

PUBLISH Properties (v5.0 only)

| Property | Type | Description | |----------|------|-------------| | payloadFormatIndicator | number? | 0=binary, 1=UTF-8 | | messageExpiryInterval | number? | Message expiry in seconds | | topicAlias | number? | Topic alias used | | responseTopic | string? | Response topic for request/response | | correlationData | Uint8Array? | Correlation data | | contentType | string? | Content type (MIME type) | | subscriptionIdentifiers() | number[] | Subscription identifiers matching this message | | userProperties() | Array | User properties [{key, value}, ...] | | topicNameExtracted | boolean | True if topic name was restored from topic alias mapping |

Note: topicNameExtracted indicates that the received PUBLISH packet had an empty topic name with a topic alias, and the library automatically restored the topic name from the alias mapping.


Received SUBACK

const suback = client.asSuback(packet);

| Field | Type | Description | |-------|------|-------------| | packetId | number | Packet identifier | | returnCodes() (v3.1.1) | number[] | Return codes for each subscription | | reasonCodes() (v5.0) | number[] | Reason codes for each subscription |

SUBACK Properties (v5.0 only)

| Property | Type | Description | |----------|------|-------------| | reasonString | string? | Human-readable reason | | userProperties() | Array | User properties [{key, value}, ...] |


Received UNSUBACK

const unsuback = client.asUnsuback(packet);

| Field | Type | Description | |-------|------|-------------| | packetId | number | Packet identifier | | reasonCodes() (v5.0) | number[] | Reason codes for each topic |

UNSUBACK Properties (v5.0 only)

| Property | Type | Description | |----------|------|-------------| | reasonString | string? | Human-readable reason | | userProperties() | Array | User properties [{key, value}, ...] |


Received PUBACK/PUBREC/PUBREL/PUBCOMP

const puback = client.asPuback(packet);
const pubrec = client.asPubrec(packet);
const pubrel = client.asPubrel(packet);
const pubcomp = client.asPubcomp(packet);

| Field | Type | Description | |-------|------|-------------| | packetId | number | Packet identifier | | reasonCode (v5.0) | number | Reason code |

QoS Response Properties (v5.0 only)

| Property | Type | Description | |----------|------|-------------| | reasonString | string? | Human-readable reason | | userProperties() | Array | User properties [{key, value}, ...] |


Received DISCONNECT (v5.0 only)

const disconnect = client.asDisconnect(packet);

| Field | Type | Description | |-------|------|-------------| | reasonCode | number | Disconnect reason code | | sessionExpiryInterval | number? | Session expiry interval | | reasonString | string? | Human-readable reason | | serverReference | string? | Server reference for redirect | | userProperties() | Array | User properties [{key, value}, ...] |


Received AUTH (v5.0 only)

const auth = client.asAuth(packet);

| Field | Type | Description | |-------|------|-------------| | reasonCode | number | Auth reason code | | authenticationMethod | string? | Authentication method | | authenticationData | Uint8Array? | Authentication data | | reasonString | string? | Human-readable reason | | userProperties() | Array | User properties [{key, value}, ...] |


Browser Demo Tools

1. Build WASM Package

wasm-pack build --target web

2. Start Web Server

./start_web_server.sh        # Default port 8080
./start_web_server.sh 9000   # Custom port

3. Open in Browser

Access http://localhost:8080 to see available tools:

  • Client Tool (client.html): Interactive MQTT client with Connect, Subscribe, Publish UI
  • Sequence Test (sequence_test.html): Automated MQTT packet sequence testing

Browser Requirements

  • Modern browser with WebSocket support
  • For wss:// (secure WebSocket): HTTPS page or localhost
  • For ws:// (plain WebSocket): HTTP page (note: some ports like 10080 are blocked by browsers)

Development

Build

# Browser (ES modules)
wasm-pack build --target web

# Node.js (CommonJS)
wasm-pack build --target nodejs --out-dir pkg-nodejs

# Bundlers (npm-style)
wasm-pack build --target bundler

Run Tests

# Native tests (mock underlying layer)
cargo test --features native

# WASM tests
wasm-pack test --node

# Node.js integration tests
node nodejs/test/integration.test.js

# Full check (fmt, clippy, build, test)
./check.sh

License

MIT