### Complete Working Example Source: https://context7.com/stomp-js/stompjs/llms.txt A comprehensive Node.js example demonstrating connection, subscription, publishing (transactional and non-transactional), manual acknowledgments, and graceful shutdown. ```APIDOC ## Complete working example — Node.js producer/consumer A full end-to-end example that demonstrates connecting, subscribing, publishing, transactional publishing, manual ACK, and graceful shutdown. ```typescript import { Client, IMessage, ReconnectionTimeMode } from '@stomp/stompjs'; import { WebSocket } from 'ws'; Object.assign(global, { WebSocket }); const DESTINATION = '/queue/example'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws', connectHeaders: { login: 'guest', passcode: 'guest' }, reconnectDelay: 3000, maxReconnectDelay: 30_000, reconnectTimeMode: ReconnectionTimeMode.EXPONENTIAL, heartbeatIncoming: 10_000, heartbeatOutgoing: 10_000, debug: (msg) => console.debug('[DEBUG]', msg), onConnect: async () => { console.log('✓ Connected, version:', client.connectedVersion); // Subscribe with manual ACK const sub = client.subscribe( DESTINATION, (msg: IMessage) => { console.log('← Received:', msg.body); msg.ack(); // acknowledge each message }, { ack: 'client-individual' }, ); // Transactional publish const tx = client.begin(); client.publish({ destination: DESTINATION, headers: { transaction: tx.id }, body: 'Message 1' }); client.publish({ destination: DESTINATION, headers: { transaction: tx.id }, body: 'Message 2' }); tx.commit(); console.log('→ Published 2 messages in transaction', tx.id); // Non-transactional publish with receipt const receiptId = 'rcpt-001'; client.watchForReceipt(receiptId, () => console.log('✓ Broker confirmed receipt', receiptId)); client.publish({ destination: DESTINATION, headers: { receipt: receiptId }, body: 'Message 3' }); // Graceful shutdown after a short delay await new Promise(r => setTimeout(r, 3000)); sub.unsubscribe(); await client.deactivate(); console.log('✓ Deactivated'); }, onStompError: (frame) => console.error('✗ STOMP error:', frame.headers['message'], frame.body), onWebSocketError: (evt) => console.error('✗ WebSocket error:', evt), }); client.activate(); ``` ``` -------------------------------- ### Install and Connect in Node.js Source: https://github.com/stomp-js/stompjs/blob/develop/README.md Steps to install STOMP.js and its WebSocket dependency for Node.js, followed by an example of connecting to a broker, subscribing, and publishing. The 'ws' library needs to be explicitly assigned to the global WebSocket object. ```bash npm install @stomp/stompjs ws ``` ```javascript import { Client } from '@stomp/stompjs'; import { WebSocket } from 'ws'; Object.assign(global, { WebSocket }); const client = new Client({ brokerURL: 'ws://localhost:15674/ws', onConnect: () => { client.subscribe('/topic/test01', message => console.log(`Received: ${message.body}`), ); client.publish({ destination: '/topic/test01', body: 'First Message' }); }, }); client.activate(); ``` -------------------------------- ### Install Dependencies with npm Source: https://github.com/stomp-js/stompjs/blob/develop/Contribute.md Installs project dependencies. Ensure Node.js and npm are installed before running. ```bash $ npm i ``` -------------------------------- ### Node.js Producer/Consumer Example Source: https://context7.com/stomp-js/stompjs/llms.txt A full example demonstrating connection, subscription with manual ACK, transactional publishing, publishing with receipts, and graceful shutdown. Requires `ws` package for Node.js. ```typescript import { Client, IMessage, ReconnectionTimeMode } from '@stomp/stompjs'; import { WebSocket } from 'ws'; Object.assign(global, { WebSocket }); const DESTINATION = '/queue/example'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws', connectHeaders: { login: 'guest', passcode: 'guest' }, reconnectDelay: 3000, maxReconnectDelay: 30_000, reconnectTimeMode: ReconnectionTimeMode.EXPONENTIAL, heartbeatIncoming: 10_000, heartbeatOutgoing: 10_000, debug: (msg) => console.debug('[DEBUG]', msg), onConnect: async () => { console.log('✓ Connected, version:', client.connectedVersion); // Subscribe with manual ACK const sub = client.subscribe( DESTINATION, (msg: IMessage) => { console.log('← Received:', msg.body); msg.ack(); // acknowledge each message }, { ack: 'client-individual' }, ); // Transactional publish const tx = client.begin(); client.publish({ destination: DESTINATION, headers: { transaction: tx.id }, body: 'Message 1' }); client.publish({ destination: DESTINATION, headers: { transaction: tx.id }, body: 'Message 2' }); tx.commit(); console.log('→ Published 2 messages in transaction', tx.id); // Non-transactional publish with receipt const receiptId = 'rcpt-001'; client.watchForReceipt(receiptId, () => console.log('✓ Broker confirmed receipt', receiptId)); client.publish({ destination: DESTINATION, headers: { receipt: receiptId }, body: 'Message 3' }); // Graceful shutdown after a short delay await new Promise(r => setTimeout(r, 3000)); sub.unsubscribe(); await client.deactivate(); console.log('✓ Deactivated'); }, onStompError: (frame) => console.error('✗ STOMP error:', frame.headers['message'], frame.body), onWebSocketError: (evt) => console.error('✗ WebSocket error:', evt), }); client.activate(); ``` -------------------------------- ### Install @stomp/stompjs for Node.js and Browser Source: https://context7.com/stomp-js/stompjs/llms.txt Install the library using npm for Node.js environments. For browser usage without a bundler, importmap or CDN can be used. ```bash # Node.js npm install @stomp/stompjs ws ``` ```html ``` -------------------------------- ### Start Transaction with client.begin Source: https://context7.com/stomp-js/stompjs/llms.txt Initiate a transaction using `client.begin()` to group `publish`, `ack`, and `nack` calls atomically. The library generates a unique transaction ID if none is provided. ```typescript import { Client, ITransaction } from '@stomp/stompjs'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws', onConnect: () => { const tx: ITransaction = client.begin(); // auto-generated ID console.log('Transaction ID:', tx.id); try { // All publishes under this transaction are atomic client.publish({ destination: '/queue/ledger', headers: { transaction: tx.id }, body: JSON.stringify({ type: 'debit', account: 'A', amount: 100 }), }); client.publish({ destination: '/queue/ledger', headers: { transaction: tx.id }, body: JSON.stringify({ type: 'credit', account: 'B', amount: 100 }), }); tx.commit(); console.log('Transaction committed'); } catch (err) { tx.abort(); console.error('Transaction aborted:', err); } }, }); client.activate(); ``` -------------------------------- ### Connect and Subscribe in Browser Source: https://github.com/stomp-js/stompjs/blob/develop/README.md Example of connecting to a STOMP broker, subscribing to a topic, and publishing a message in a browser environment. Ensure the script tags for import maps and es-module-shims are included in your HTML. ```html ``` ```javascript import { Client } from '@stomp/stompjs'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws', onConnect: () => { client.subscribe('/topic/test01', message => console.log(`Received: ${message.body}`), ); client.publish({ destination: '/topic/test01', body: 'First Message' }); }, }); client.activate(); ``` -------------------------------- ### client.begin(transactionId?) Source: https://context7.com/stomp-js/stompjs/llms.txt Starts a new transaction, returning an `ITransaction` object with `id`, `commit()`, and `abort()` methods. Operations like `publish`, `ack`, and `nack` can be associated with this transaction ID for atomic execution. ```APIDOC ## `client.begin(transactionId?)` — Start a transaction ### Description Initiates a STOMP transaction. Returns an `ITransaction` object that allows grouping of `publish`, `ack`, and `nack` operations to be committed or aborted atomically. If no `transactionId` is provided, a unique ID is generated. ### Usage ```typescript const tx: ITransaction = client.begin(); // auto-generated ID console.log('Transaction ID:', tx.id); try { // All publishes under this transaction are atomic client.publish({ ... }); client.publish({ ... }); tx.commit(); console.log('Transaction committed'); } catch (err) { tx.abort(); console.error('Transaction aborted:', err); } ``` ### Parameters - `transactionId` (string, optional): A unique identifier for the transaction. If not provided, the library generates one. ``` -------------------------------- ### Run RabbitMQ Docker Container Source: https://github.com/stomp-js/stompjs/blob/develop/Contribute.md Starts a RabbitMQ Docker container in detached mode, exposing the WebStomp port. ```bash docker run -d -p 15674:15674 myrabbitmq ``` -------------------------------- ### Atomic Message Grouping with ITransaction Source: https://context7.com/stomp-js/stompjs/llms.txt Use `client.begin()` to start a transaction. Messages published with the transaction ID will be grouped atomically. Commit or abort the transaction to finalize. ```typescript import { Client, ITransaction } from '@stomp/stompjs'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws', onConnect: () => { const tx: ITransaction = client.begin('my-tx-001'); // Enqueue multiple messages atomically for (const item of ['A', 'B', 'C']) { client.publish({ destination: '/queue/batch', headers: { transaction: tx.id }, body: item, }); } // Acknowledge a message within the transaction // message.ack({ transaction: tx.id }); // Commit or abort const success = true; // application logic if (success) { tx.commit(); console.log('Transaction my-tx-001 committed'); } else { tx.abort(); console.log('Transaction my-tx-001 aborted'); } }, }); client.activate(); ``` -------------------------------- ### Legacy STOMP Client API (Deprecated) Source: https://context7.com/stomp-js/stompjs/llms.txt The `CompatClient` extends `Client` to maintain the pre-v5 API. Use `Stomp.client()` or `Stomp.over()` to create a `CompatClient`. Migration to the modern `Client` API is recommended. This example shows connecting, sending, and subscribing using the legacy API. ```typescript import { Stomp } from '@stomp/stompjs'; // Legacy factory — creates a CompatClient const client = Stomp.over(() => new WebSocket('ws://localhost:15674/ws')); client.connect( { login: 'guest', passcode: 'guest' }, // headers (frame) => { // connectCallback console.log('Connected (legacy API)', frame); // Legacy send() — equivalent to client.publish() client.send('/queue/test', {}, 'Hello from legacy API'); // Legacy subscribe client.subscribe('/queue/test', (msg) => { console.log('Received (legacy):', msg.body); }); }, (error) => console.error('Error:', error), // errorCallback ); // Legacy heartbeat configuration client.heartbeat.incoming = 10_000; client.heartbeat.outgoing = 5_000; ``` -------------------------------- ### Activate STOMP Client Connection Source: https://context7.com/stomp-js/stompjs/llms.txt Call `client.activate()` to initiate the connection lifecycle. This method transitions the client to an active state and starts connection attempts. It handles automatic reconnections if the connection is lost. ```typescript import { Client, ActivationState } from '@stomp/stompjs'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws' }); client.onChangeState = (state: ActivationState) => { console.log('State →', ActivationState[state]); // Logs: State → ACTIVE, State → DEACTIVATING, State → INACTIVE }; client.onConnect = () => { console.log('Broker connected, client.active =', client.active); // true console.log('Negotiated STOMP version:', client.connectedVersion); // "1.2" console.log('Client.connected =', client.connected); // true }; client.activate(); // Output: State → ACTIVE // [STOMP] Opening Web Socket... // Broker connected, client.active = true // Negotiated STOMP version: 1.2 ``` -------------------------------- ### Incoming Subscription Message Interface Source: https://context7.com/stomp-js/stompjs/llms.txt The `IMessage` interface extends `IFrame` and is received in subscription callbacks. It provides `ack()` and `nack()` methods for message acknowledgment. This example shows how to access message details and handle acknowledgments. ```typescript import { Client, IMessage } from '@stomp/stompjs'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws', onConnect: () => { client.subscribe('/queue/items', (msg: IMessage) => { // Frame fields console.log('Destination:', msg.headers['destination']); console.log('Message-id:', msg.headers['message-id']); console.log('Subscription:', msg.headers['subscription']); console.log('Body:', msg.body); // UTF-8 string console.log('Binary body:', msg.binaryBody); // Uint8Array console.log('Is binary:', msg.isBinaryBody); // Parse JSON body if (msg.headers['content-type']?.includes('json')) { const payload = JSON.parse(msg.body); console.log('Parsed payload:', payload); } // ACK when using 'client' or 'client-individual' ack mode // msg.ack(); // msg.nack({ 'requeue': 'false' }); }, { ack: 'auto' }); }, }); client.activate(); ``` -------------------------------- ### Build RabbitMQ Docker Image Source: https://github.com/stomp-js/stompjs/blob/develop/Contribute.md Builds a Docker image for RabbitMQ with necessary plugins and configuration. This command only needs to be run once. ```bash docker build -t myrabbitmq rabbitmq/ ``` -------------------------------- ### Client Class Source: https://context7.com/stomp-js/stompjs/llms.txt The `Client` class is the primary entry point for creating a STOMP client instance. Configuration options can be provided during instantiation or updated later using `client.configure()`. ```APIDOC ## new Client(conf?: StompConfig) — Create a STOMP client instance The `Client` class is the main entry point. All configuration is passed at construction time via a `StompConfig` object, or updated at any time via `client.configure()`. Every field is optional; sensible defaults are provided (5-second reconnect delay, 10-second heartbeats, STOMP 1.2/1.1/1.0 negotiation). ### Parameters - **conf** (StompConfig) - Optional - Configuration object for the STOMP client. - **brokerURL** (string) - WebSocket endpoint. - **connectHeaders** (object) - STOMP CONNECT frame headers. - **login** (string) - Login username. - **passcode** (string) - Login password. - **host** (string) - Virtual host. - **reconnectDelay** (number) - Milliseconds between reconnect attempts. - **maxReconnectDelay** (number) - Cap for exponential backoff. - **reconnectTimeMode** (ReconnectionTimeMode) - Mode for reconnect delay (e.g., EXPONENTIAL). - **heartbeatIncoming** (number) - Incoming heartbeat interval in milliseconds (0 to disable). - **heartbeatOutgoing** (number) - Outgoing heartbeat interval in milliseconds. - **heartbeatToleranceMultiplier** (number) - Multiplier for heartbeat tolerance. - **heartbeatStrategy** (TickerStrategy) - Strategy for heartbeats (e.g., Interval, Worker). - **connectionTimeout** (number) - Timeout in milliseconds to abort a connect attempt. - **debug** (function) - Callback function for debug messages. - **onConnect** (function) - Callback function when connected. - **frame** (IFrame) - The CONNECTED frame. - **onDisconnect** (function) - Callback function when disconnected. - **onStompError** (function) - Callback function for STOMP errors. - **frame** (IFrame) - The ERROR frame. - **onWebSocketClose** (function) - Callback function for WebSocket close events. - **evt** (object) - The close event object. - **onWebSocketError** (function) - Callback function for WebSocket errors. - **evt** (object) - The error event object. ### Request Example ```typescript import { Client, StompConfig, ReconnectionTimeMode, TickerStrategy, IFrame } from '@stomp/stompjs'; // Node.js only: polyfill WebSocket import { WebSocket } from 'ws'; Object.assign(global, { WebSocket }); const client = new Client({ brokerURL: 'ws://localhost:15674/ws', connectHeaders: { login: 'guest', passcode: 'guest', host: '/', }, reconnectDelay: 5000, maxReconnectDelay: 60_000, reconnectTimeMode: ReconnectionTimeMode.EXPONENTIAL, heartbeatIncoming: 10_000, heartbeatOutgoing: 10_000, heartbeatToleranceMultiplier: 2, heartbeatStrategy: TickerStrategy.Interval, connectionTimeout: 5_000, debug: (msg: string) => console.log('[STOMP]', msg), onConnect: (frame: IFrame) => { console.log('Connected, session:', frame.headers['session']); }, onDisconnect: () => console.log('Disconnected'), onStompError: (frame: IFrame) => console.error('STOMP error:', frame.body), onWebSocketClose: (evt) => console.warn('WebSocket closed, code:', evt.code), onWebSocketError: (evt) => console.error('WebSocket error:', evt), }); ``` ``` -------------------------------- ### Create and Configure STOMP Client Instance Source: https://context7.com/stomp-js/stompjs/llms.txt Instantiate the `Client` class with a `StompConfig` object to set up connection details, headers, reconnection logic, and callbacks. For Node.js, polyfill the WebSocket API. ```typescript import { Client, StompConfig, ReconnectionTimeMode, TickerStrategy, IFrame } from '@stomp/stompjs'; // Node.js only: polyfill WebSocket import { WebSocket } from 'ws'; Object.assign(global, { WebSocket }); const client = new Client({ brokerURL: 'ws://localhost:15674/ws', // WebSocket endpoint connectHeaders: { login: 'guest', passcode: 'guest', host: '/', }, reconnectDelay: 5000, // ms between reconnect attempts maxReconnectDelay: 60_000, // cap for exponential backoff reconnectTimeMode: ReconnectionTimeMode.EXPONENTIAL, heartbeatIncoming: 10_000, // ms, 0 = disabled heartbeatOutgoing: 10_000, heartbeatToleranceMultiplier: 2, // tolerance = incoming * multiplier heartbeatStrategy: TickerStrategy.Interval, // or TickerStrategy.Worker connectionTimeout: 5_000, // abort connect attempt after 5s debug: (msg: string) => console.log('[STOMP]', msg), onConnect: (frame: IFrame) => { console.log('Connected, session:', frame.headers['session']); }, onDisconnect: () => console.log('Disconnected'), onStompError: (frame: IFrame) => console.error('STOMP error:', frame.body), onWebSocketClose: (evt) => console.warn('WebSocket closed, code:', evt.code), onWebSocketError: (evt) => console.error('WebSocket error:', evt), }); ``` -------------------------------- ### Configure Client at Runtime Source: https://context7.com/stomp-js/stompjs/llms.txt Merges new configuration onto the client instance. Can be called before or after `activate()`. Useful for rotating credentials before each reconnect via `beforeConnect`. ```typescript import { Client } from '@stomp/stompjs'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws' }); // Dynamically refresh an auth token before every connect attempt client.beforeConnect = async (c: Client) => { const token = await fetch('/api/token').then(r => r.text()); c.configure({ connectHeaders: { login: 'app', passcode: token }, }); }; client.onConnect = () => console.log('Authenticated and connected'); client.activate(); ``` -------------------------------- ### STOMP Frame Interface and Callbacks Source: https://context7.com/stomp-js/stompjs/llms.txt The `IFrame` interface represents a STOMP frame. Lifecycle callbacks like `onConnect`, `onDisconnect`, and `onStompError` receive an `IFrame` object. This example demonstrates accessing frame properties and headers within the `onConnect` and `onStompError` callbacks. ```typescript import { Client, IFrame } from '@stomp/stompjs'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws', onConnect: (frame: IFrame) => { console.log('Command:', frame.command); // "CONNECTED" console.log('Version:', frame.headers['version']); // "1.2" console.log('Session:', frame.headers['session']); // broker session ID console.log('Heart-beat:', frame.headers['heart-beat']); // "0,0" or "10000,10000" console.log('Is binary:', frame.isBinaryBody); // false for CONNECTED frame }, onStompError: (frame: IFrame) => { console.error('STOMP ERROR'); console.error(' command:', frame.command); // "ERROR" console.error(' message:', frame.headers['message']); console.error(' body:', frame.body); }, }); client.activate(); ``` -------------------------------- ### client.activate() Source: https://context7.com/stomp-js/stompjs/llms.txt Initiates the connection lifecycle by transitioning the client to an active state. If the connection is lost, the client will automatically attempt to reconnect. ```APIDOC ## client.activate() — Start the connection lifecycle Transitions the client to `ActivationState.ACTIVE` and initiates a connection attempt. If the connection drops, the client automatically schedules reconnections. Calling `activate()` while already active is a no-op; calling it during deactivation queues activation for after shutdown completes. ### Description This method starts the STOMP client's connection process. It handles the WebSocket connection and STOMP handshake. If the connection is interrupted, it will automatically attempt to re-establish the connection based on the configured reconnection settings. ### Method `client.activate()` ### Parameters This method does not accept any parameters. ### Usage Example ```typescript import { Client, ActivationState } from '@stomp/stompjs'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws' }); client.onChangeState = (state: ActivationState) => { console.log('State →', ActivationState[state]); // Logs: State → ACTIVE, State → DEACTIVATING, State → INACTIVE }; client.onConnect = () => { console.log('Broker connected, client.active =', client.active); // true console.log('Negotiated STOMP version:', client.connectedVersion); // "1.2" console.log('Client.connected =', client.connected); // true }; client.activate(); // Output: // State → ACTIVE // [STOMP] Opening Web Socket... // Broker connected, client.active = true // Negotiated STOMP version: 1.2 ``` ``` -------------------------------- ### client.configure(conf: StompConfig) Source: https://context7.com/stomp-js/stompjs/llms.txt Merges new configuration onto the client instance. This method can be called before or after `activate()`, and is useful for rotating credentials before each reconnect via `beforeConnect`. ```APIDOC ## `client.configure(conf: StompConfig)` — Update client configuration at runtime Merges new configuration onto the client instance. Can be called before or after `activate()`. Useful for rotating credentials before each reconnect via `beforeConnect`. ```typescript import { Client } from '@stomp/stompjs'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws' }); // Dynamically refresh an auth token before every connect attempt client.beforeConnect = async (c: Client) => { const token = await fetch('/api/token').then(r => r.text()); c.configure({ connectHeaders: { login: 'app', passcode: token }, }); }; client.onConnect = () => console.log('Authenticated and connected'); client.activate(); ``` ``` -------------------------------- ### Custom WebSocket Factory with SockJS Source: https://context7.com/stomp-js/stompjs/llms.txt Demonstrates how to use `webSocketFactory` to provide a custom WebSocket implementation, such as SockJS, for environments requiring non-standard WebSocket connections. The factory function must return a new socket instance on each call. ```APIDOC ## `client.webSocketFactory` — Custom WebSocket / SockJS factory An alternative to `brokerURL` for environments that require a non-standard WebSocket (e.g., SockJS, or a custom wrapper). The factory function is called on every connection and reconnection attempt, so each call must return a fresh socket instance. Takes precedence over `brokerURL` when both are set. ```typescript import { Client } from '@stomp/stompjs'; import SockJS from 'sockjs-client'; // npm install sockjs-client const client = new Client({ // No brokerURL — use webSocketFactory instead webSocketFactory: () => new SockJS('http://localhost:15674/stomp'), connectHeaders: { login: 'guest', passcode: 'guest' }, onConnect: () => { console.log('Connected via SockJS'); client.subscribe('/topic/demo', msg => console.log(msg.body)); client.publish({ destination: '/topic/demo', body: 'SockJS message' }); }, }); client.activate(); ``` ``` -------------------------------- ### Configure RabbitMQ for Binary Frames Source: https://github.com/stomp-js/stompjs/blob/develop/Contribute.md Configures RabbitMQ to use binary frames for WebStomp. This is necessary for proper message handling. ```bash echo 'web_stomp.ws_frame = binary' >> /etc/rabbitmq/rabbitmq.conf ``` -------------------------------- ### Build Project Variants Source: https://github.com/stomp-js/stompjs/blob/develop/Contribute.md Builds the project to generate ES Modules and UMD variants. This command is part of the basic development workflow. ```bash $ npm run build ``` -------------------------------- ### Run Tests in NodeJS Source: https://github.com/stomp-js/stompjs/blob/develop/Contribute.md Executes the project's test suite within a NodeJS environment. This is a key step in the development workflow. ```bash $ npm run test ``` -------------------------------- ### client.subscribe(destination, callback, headers?) Source: https://context7.com/stomp-js/stompjs/llms.txt Subscribes to a destination by sending a STOMP SUBSCRIBE frame. A callback is registered to handle incoming messages. Returns a `StompSubscription` object with an `id` and an `unsubscribe()` method. An auto-generated ID is used if `headers.id` is not provided. ```APIDOC ## `client.subscribe(destination, callback, headers?)` — Subscribe to a destination Sends a STOMP SUBSCRIBE frame and registers a callback invoked for every incoming message. Returns a `StompSubscription` with an `id` and an `unsubscribe()` method. An auto-generated subscription ID is used unless `headers.id` is provided. ```typescript import { Client, IMessage, StompSubscription } from '@stomp/stompjs'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws', onConnect: () => { // Auto-id subscription const sub: StompSubscription = client.subscribe( '/topic/prices', (message: IMessage) => { console.log('Headers:', message.headers); console.log('Body:', message.body); // Binary body: message.binaryBody (Uint8Array) // Is binary: message.isBinaryBody }, ); // Explicit subscription ID const sub2 = client.subscribe( '/queue/notifications', (msg) => console.log('Notification:', msg.body), { id: 'my-notification-sub', ack: 'client' }, ); // Later: unsubscribe either way setTimeout(() => { sub.unsubscribe(); // preferred client.unsubscribe(sub2.id); // equivalent }, 30_000); }, }); client.activate(); ``` ``` -------------------------------- ### Run Tests in Browsers with Karma Source: https://github.com/stomp-js/stompjs/blob/develop/Contribute.md Executes the project's test suite in browsers using Karma. Be cautious when running this concurrently with NodeJS tests due to shared resource names. ```bash $ npm run karma ``` -------------------------------- ### Managing Subscriptions with StompSubscription Source: https://context7.com/stomp-js/stompjs/llms.txt Use `client.subscribe()` to receive messages. The returned `StompSubscription` object can be used to `unsubscribe()` later. Store subscriptions to manage them. ```typescript import { Client, StompSubscription } from '@stomp/stompjs'; const subscriptions: Map = new Map(); const client = new Client({ brokerURL: 'ws://localhost:15674/ws', onConnect: () => { const topics = ['/topic/alpha', '/topic/beta', '/topic/gamma']; for (const topic of topics) { const sub: StompSubscription = client.subscribe(topic, (msg) => { console.log(`[${topic}] ${msg.body}`); }); subscriptions.set(topic, sub); console.log(`Subscribed to ${topic} with id: ${sub.id}`); } // Unsubscribe from one topic after 10 seconds setTimeout(() => { const sub = subscriptions.get('/topic/alpha'); if (sub) { sub.unsubscribe(); subscriptions.delete('/topic/alpha'); console.log('Unsubscribed from /topic/alpha'); } }, 10_000); }, }); client.activate(); ``` -------------------------------- ### client.publish(params: IPublishParams) Source: https://context7.com/stomp-js/stompjs/llms.txt Sends a STOMP SEND frame to the specified destination. Supports text or binary payloads via `body` or `binaryBody` respectively. Custom STOMP headers can be provided. Throws `TypeError` if the client is not connected. ```APIDOC ## `client.publish(params: IPublishParams)` — Send a message to the broker Sends a STOMP SEND frame to the specified destination. The `body` must be a `string`; use `binaryBody` (a `Uint8Array`) for binary payloads. Custom STOMP headers are passed via `headers`. Throws `TypeError` if the client is not connected. ```typescript import { Client } from '@stomp/stompjs'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws', onConnect: () => { // 1. Simple text message client.publish({ destination: '/queue/orders', body: 'Hello, broker!', }); // 2. JSON payload with custom headers client.publish({ destination: '/topic/events', headers: { priority: '9', 'content-type': 'application/json' }, body: JSON.stringify({ event: 'user.signup', userId: 42 }), }); // 3. Binary payload const pixels = new Uint8Array([0xff, 0xd8, 0xff, 0xe0]); // JPEG header client.publish({ destination: '/queue/images', binaryBody: pixels, headers: { 'content-type': 'image/jpeg' }, }); // 4. Skip content-length header (e.g. for Spring-compatible brokers) client.publish({ destination: '/queue/legacy', body: 'plain text', skipContentLengthHeader: true, }); }, }); client.activate(); ``` ``` -------------------------------- ### client.subscribe with manual acknowledgement Source: https://context7.com/stomp-js/stompjs/llms.txt When a subscription is created with `ack: 'client'` or `ack: 'client-individual'`, messages must be explicitly acknowledged. Call `message.ack()` on success or `message.nack()` to reject. The broker will redeliver unacknowledged messages according to its policy. ```APIDOC ## `client.subscribe` with manual acknowledgement — ACK / NACK messages ### Description Messages must be explicitly acknowledged when a subscription is created with `ack: 'client'` or `ack: 'client-individual'`. Use `message.ack()` for successful processing or `message.nack()` to indicate failure, allowing the broker to redeliver messages. ### Usage ```typescript client.subscribe( '/queue/tasks', async (message: IMessage) => { try { const task = JSON.parse(message.body); await processTask(task); // application logic message.ack(); // → STOMP ACK frame sent console.log('Task processed and acknowledged'); } catch (err) { console.error('Task failed, sending NACK:', err); message.nack(); // → STOMP NACK frame sent; broker requeues } }, { ack: 'client-individual' }, // each message acknowledged separately ); ``` ### Parameters - `destination` (string): The STOMP destination to subscribe to. - `callback` (function): A function that will be called with the received `IMessage`. - `headers` (object, optional): Headers for the SUBSCRIBE frame. Use `{ ack: 'client' }` or `{ ack: 'client-individual' }` for manual acknowledgements. ``` -------------------------------- ### STOMP Protocol Version Constants Source: https://context7.com/stomp-js/stompjs/llms.txt Use the `Versions` class to access supported STOMP protocol version strings and generate correct WebSocket sub-protocol and CONNECT header values. Import `Versions` from '@stomp/stompjs'. ```typescript import { Versions } from '@stomp/stompjs'; console.log(Versions.V1_0); // "1.0" console.log(Versions.V1_1); // "1.1" console.log(Versions.V1_2); // "1.2" const v = new Versions([Versions.V1_2, Versions.V1_1]); console.log(v.supportedVersions()); // "1.2,1.1" (used in CONNECT frame) console.log(v.protocolVersions()); // ["v12.stomp", "v11.stomp"] (used as WS sub-protocols) ``` -------------------------------- ### client.watchForReceipt(receiptId, callback) Source: https://context7.com/stomp-js/stompjs/llms.txt Registers a callback to be executed when the broker sends a RECEIPT frame matching the specified `receiptId`. This is used to confirm that operations like publish, subscribe, or unsubscribe have been processed by the broker. ```APIDOC ## `client.watchForReceipt(receiptId, callback)` — Wait for broker acknowledgement ### Description Sets up a listener for a specific `receiptId`. When the broker processes an operation that includes this `receiptId` in its headers, it sends back a RECEIPT frame, triggering the provided callback. ### Usage ```typescript const receiptId = `receipt-${Date.now()}`; // Register the watcher BEFORE issuing the operation client.watchForReceipt(receiptId, (frame: IFrame) => { console.log('Broker confirmed message delivery, receipt frame:', frame.command); // Output: Broker confirmed message delivery, receipt frame: RECEIPT }); client.publish({ destination: '/queue/confirmed', headers: { receipt: receiptId }, body: 'This message requires broker confirmation', }); ``` ### Parameters - `receiptId` (string): The unique identifier for the receipt to watch for. - `callback` (function): A function to execute when the corresponding RECEIPT frame is received. It receives the `IFrame` object as an argument. ``` -------------------------------- ### Heartbeat Configuration Source: https://context7.com/stomp-js/stompjs/llms.txt Configures heartbeat settings (`heartbeatIncoming`, `heartbeatOutgoing`, `heartbeatToleranceMultiplier`) to maintain connection liveness and detect broker failures. Heartbeats can be disabled by setting values to 0. ```APIDOC ## Heartbeat configuration — `heartbeatIncoming`, `heartbeatOutgoing`, `heartbeatToleranceMultiplier` Heartbeats keep the connection alive and detect broker failures. `heartbeatOutgoing` controls the ping interval sent to the broker; `heartbeatIncoming` controls the expected ping interval from the broker. The tolerance window is `heartbeatIncoming * heartbeatToleranceMultiplier`. Both can be set to `0` to disable. ```typescript import { Client, TickerStrategy } from '@stomp/stompjs'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws', heartbeatOutgoing: 5_000, // send ping every 5s heartbeatIncoming: 10_000, // expect ping from broker every 10s heartbeatToleranceMultiplier: 2,// tolerate up to 20s before declaring failure heartbeatStrategy: TickerStrategy.Worker, // use Web Worker (avoids tab throttling) onHeartbeatReceived: () => { console.log(`[${new Date().toISOString()}] Heartbeat received`); }, onHeartbeatLost: () => { console.error('Heartbeat lost — broker may be unreachable'); // The library will force-disconnect and attempt reconnection automatically }, onConnect: () => console.log('Connected'), }); client.activate(); ``` ``` -------------------------------- ### Reconnection with Exponential Backoff Source: https://context7.com/stomp-js/stompjs/llms.txt Configures reconnection behavior using `reconnectTimeMode`, `reconnectDelay`, and `maxReconnectDelay`. The client can switch to exponential backoff for increasing delays between reconnection attempts, capped by `maxReconnectDelay`. ```APIDOC ## Reconnection with exponential backoff — `reconnectTimeMode`, `reconnectDelay`, `maxReconnectDelay` By default the client uses linear reconnect delays. Switch to `ReconnectionTimeMode.EXPONENTIAL` to double the delay after each failed attempt, up to `maxReconnectDelay`. ```typescript import { Client, ReconnectionTimeMode } from '@stomp/stompjs'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws', reconnectDelay: 500, // initial delay: 0.5s maxReconnectDelay: 30_000, // cap: 30s reconnectTimeMode: ReconnectionTimeMode.EXPONENTIAL, // Sequence: 500ms → 1000ms → 2000ms → 4000ms → 8000ms → 16000ms → 30000ms → 30000ms ... onConnect: () => console.log('Reconnected successfully'), onWebSocketClose: (evt) => { console.warn(`WebSocket closed (code ${evt.code}), scheduling reconnect...`); }, debug: (msg) => console.debug(msg), }); client.activate(); ``` ``` -------------------------------- ### STOMP Version Negotiation Source: https://context7.com/stomp-js/stompjs/llms.txt Allows control over which STOMP protocol versions are advertised during the connection handshake using `stompVersions`. This is useful for compatibility with brokers that support a limited set of versions. ```APIDOC ## `client.stompVersions` — Control STOMP protocol version negotiation Controls which STOMP versions are advertised in the CONNECT frame. By default all three versions are offered (`1.2`, `1.1`, `1.0`) in preference order. Restrict this when connecting to brokers with limited protocol support. ```typescript import { Client, Versions } from '@stomp/stompjs'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws', // Only offer STOMP 1.1 and 1.0; do not negotiate 1.2 stompVersions: new Versions([Versions.V1_1, Versions.V1_0]), onConnect: (frame) => { console.log('Negotiated version:', client.connectedVersion); // Output: Negotiated version: 1.1 }, }); client.activate(); ``` ``` -------------------------------- ### Custom WebSocket Factory with SockJS Source: https://context7.com/stomp-js/stompjs/llms.txt Use `webSocketFactory` to provide a custom WebSocket implementation, such as SockJS. The factory function must return a new socket instance on each call. This option takes precedence over `brokerURL`. ```typescript import { Client } from '@stomp/stompjs'; import SockJS from 'sockjs-client'; // npm install sockjs-client const client = new Client({ // No brokerURL — use webSocketFactory instead webSocketFactory: () => new SockJS('http://localhost:15674/stomp'), connectHeaders: { login: 'guest', passcode: 'guest' }, onConnect: () => { console.log('Connected via SockJS'); client.subscribe('/topic/demo', msg => console.log(msg.body)); client.publish({ destination: '/topic/demo', body: 'SockJS message' }); }, }); client.activate(); ``` -------------------------------- ### Wait for Receipt with client.watchForReceipt Source: https://context7.com/stomp-js/stompjs/llms.txt Use `client.watchForReceipt(receiptId, callback)` to execute a callback when the broker sends a RECEIPT frame matching the specified `receiptId`. This confirms operations like publish, subscribe, or unsubscribe. ```typescript import { Client, IFrame } from '@stomp/stompjs'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws', onConnect: () => { const receiptId = `receipt-${Date.now()}`; // Register the watcher BEFORE issuing the operation client.watchForReceipt(receiptId, (frame: IFrame) => { console.log('Broker confirmed message delivery, receipt frame:', frame.command); // Output: Broker confirmed message delivery, receipt frame: RECEIPT }); client.publish({ destination: '/queue/confirmed', headers: { receipt: receiptId }, body: 'This message requires broker confirmation', }); }, }); client.activate(); ``` -------------------------------- ### STOMP Protocol Version Negotiation Source: https://context7.com/stomp-js/stompjs/llms.txt Control the STOMP versions offered during connection using `stompVersions`. This is important for brokers with limited protocol support. By default, `1.2`, `1.1`, and `1.0` are offered. ```typescript import { Client, Versions } from '@stomp/stompjs'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws', // Only offer STOMP 1.1 and 1.0; do not negotiate 1.2 stompVersions: new Versions([Versions.V1_1, Versions.V1_0]), onConnect: (frame) => { console.log('Negotiated version:', client.connectedVersion); // Output: Negotiated version: 1.1 }, }); client.activate(); ``` -------------------------------- ### Gracefully Stop the Client Source: https://context7.com/stomp-js/stompjs/llms.txt Sends a STOMP DISCONNECT frame, waits for the WebSocket to close cleanly, then transitions to `ActivationState.INACTIVE`. Pass `{ force: true }` to skip the graceful shutdown sequence and immediately discard the socket. ```typescript import { Client } from '@stomp/stompjs'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws', onConnect: async () => { console.log('Connected'); // Do some work... await new Promise(resolve => setTimeout(resolve, 2000)); // Graceful shutdown — waits for broker RECEIPT await client.deactivate(); console.log('Deactivated gracefully, client.active =', client.active); // false // -- OR -- forced shutdown (skips DISCONNECT handshake) // await client.deactivate({ force: true }); }, }); client.activate(); ``` -------------------------------- ### Heartbeat Configuration for Connection Stability Source: https://context7.com/stomp-js/stompjs/llms.txt Configure `heartbeatIncoming`, `heartbeatOutgoing`, and `heartbeatToleranceMultiplier` to manage connection health and detect broker failures. Set to `0` to disable. `heartbeatStrategy: TickerStrategy.Worker` uses a Web Worker to avoid tab throttling. ```typescript import { Client, TickerStrategy } from '@stomp/stompjs'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws', heartbeatOutgoing: 5_000, // send ping every 5s heartbeatIncoming: 10_000, // expect ping from broker every 10s heartbeatToleranceMultiplier: 2,// tolerate up to 20s before declaring failure heartbeatStrategy: TickerStrategy.Worker, // use Web Worker (avoids tab throttling) onHeartbeatReceived: () => { console.log(`[${new Date().toISOString()}] Heartbeat received`); }, onHeartbeatLost: () => { console.error('Heartbeat lost — broker may be unreachable'); // The library will force-disconnect and attempt reconnection automatically }, onConnect: () => console.log('Connected'), }); client.activate(); ``` -------------------------------- ### Exponential Backoff Reconnection Strategy Source: https://context7.com/stomp-js/stompjs/llms.txt Configure `reconnectTimeMode`, `reconnectDelay`, and `maxReconnectDelay` for exponential backoff reconnection. The delay doubles with each failed attempt, capped by `maxReconnectDelay`. The default is linear backoff. ```typescript import { Client, ReconnectionTimeMode } from '@stomp/stompjs'; const client = new Client({ brokerURL: 'ws://localhost:15674/ws', reconnectDelay: 500, // initial delay: 0.5s maxReconnectDelay: 30_000, // cap: 30s reconnectTimeMode: ReconnectionTimeMode.EXPONENTIAL, // Sequence: 500ms → 1000ms → 2000ms → 4000ms → 8000ms → 16000ms → 30000ms → 30000ms ... onConnect: () => console.log('Reconnected successfully'), onWebSocketClose: (evt) => { console.warn(`WebSocket closed (code ${evt.code}), scheduling reconnect...`); }, debug: (msg) => console.debug(msg), }); client.activate(); ```