@stomp/stompjs 7.1.1 → 7.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/esm6/client.js CHANGED
@@ -5,16 +5,52 @@ import { Versions } from './versions.js';
5
5
  * STOMP Client Class.
6
6
  *
7
7
  * Part of `@stomp/stompjs`.
8
+ *
9
+ * This class provides a robust implementation for connecting to and interacting with a
10
+ * STOMP-compliant messaging broker over WebSocket. It supports STOMP versions 1.2, 1.1, and 1.0.
11
+ *
12
+ * Features:
13
+ * - Handles automatic reconnections.
14
+ * - Supports heartbeat mechanisms to detect and report communication failures.
15
+ * - Allows customization of connection and WebSocket behaviors through configurations.
16
+ * - Compatible with both browser environments and Node.js with polyfill support for WebSocket.
8
17
  */
9
18
  export class Client {
10
19
  /**
11
- * Underlying WebSocket instance, READONLY.
20
+ * Provides access to the underlying WebSocket instance.
21
+ * This property is **read-only**.
22
+ *
23
+ * Example:
24
+ * ```javascript
25
+ * const webSocket = client.webSocket;
26
+ * if (webSocket) {
27
+ * console.log('WebSocket is connected:', webSocket.readyState === WebSocket.OPEN);
28
+ * }
29
+ * ```
30
+ *
31
+ * **Caution:**
32
+ * Directly interacting with the WebSocket instance (e.g., sending or receiving frames)
33
+ * can interfere with the proper functioning of this library. Such actions may cause
34
+ * unexpected behavior, disconnections, or invalid state in the library's internal mechanisms.
35
+ *
36
+ * Instead, use the library's provided methods to manage STOMP communication.
37
+ *
38
+ * @returns The WebSocket instance used by the STOMP handler, or `undefined` if not connected.
12
39
  */
13
40
  get webSocket() {
14
41
  return this._stompHandler?._webSocket;
15
42
  }
16
43
  /**
17
- * Disconnection headers.
44
+ * Allows customization of the disconnection headers.
45
+ *
46
+ * Any changes made during an active session will also be applied immediately.
47
+ *
48
+ * Example:
49
+ * ```javascript
50
+ * client.disconnectHeaders = {
51
+ * receipt: 'custom-receipt-id'
52
+ * };
53
+ * ```
18
54
  */
19
55
  get disconnectHeaders() {
20
56
  return this._disconnectHeaders;
@@ -26,19 +62,53 @@ export class Client {
26
62
  }
27
63
  }
28
64
  /**
29
- * `true` if there is an active connection to STOMP Broker
65
+ * Indicates whether there is an active connection to the STOMP broker.
66
+ *
67
+ * Usage:
68
+ * ```javascript
69
+ * if (client.connected) {
70
+ * console.log('Client is connected to the broker.');
71
+ * } else {
72
+ * console.log('No connection to the broker.');
73
+ * }
74
+ * ```
75
+ *
76
+ * @returns `true` if the client is currently connected, `false` otherwise.
30
77
  */
31
78
  get connected() {
32
79
  return !!this._stompHandler && this._stompHandler.connected;
33
80
  }
34
81
  /**
35
- * version of STOMP protocol negotiated with the server, READONLY
82
+ * The version of the STOMP protocol negotiated with the server during connection.
83
+ *
84
+ * This is a **read-only** property and reflects the negotiated protocol version after
85
+ * a successful connection.
86
+ *
87
+ * Example:
88
+ * ```javascript
89
+ * console.log('Connected STOMP version:', client.connectedVersion);
90
+ * ```
91
+ *
92
+ * @returns The negotiated STOMP protocol version or `undefined` if not connected.
36
93
  */
37
94
  get connectedVersion() {
38
95
  return this._stompHandler ? this._stompHandler.connectedVersion : undefined;
39
96
  }
40
97
  /**
41
- * if the client is active (connected or going to reconnect)
98
+ * Indicates whether the client is currently active.
99
+ *
100
+ * A client is considered active if it is connected or actively attempting to reconnect.
101
+ *
102
+ * Example:
103
+ * ```javascript
104
+ * if (client.active) {
105
+ * console.log('The client is active.');
106
+ * } else {
107
+ * console.log('The client is inactive.');
108
+ * }
109
+ * ```
110
+ *
111
+ * @returns `true` if the client is active, otherwise `false`.
42
112
  */
43
113
  get active() {
44
114
  return this.state === ActivationState.ACTIVE;
@@ -48,129 +118,217 @@ export class Client {
48
118
  this.onChangeState(state);
49
119
  }
50
120
  /**
51
- * Create an instance.
121
+ * Constructs a new STOMP client instance.
122
+ *
123
+ * The constructor initializes default values and sets up no-op callbacks for all events.
124
+ * Configuration can be passed during construction, or updated later using `configure`.
125
+ *
126
+ * Example:
127
+ * ```javascript
128
+ * const client = new Client({
129
+ * brokerURL: 'wss://broker.example.com',
130
+ * reconnectDelay: 5000
131
+ * });
132
+ * ```
133
+ *
134
+ * @param conf Optional configuration object to initialize the client with.
52
135
  */
53
136
  constructor(conf = {}) {
54
137
  /**
55
- * STOMP versions to attempt during STOMP handshake. By default, versions `1.2`, `1.1`, and `1.0` are attempted.
138
+ * STOMP protocol versions to use during the handshake. By default, the client will attempt
139
+ * versions `1.2`, `1.1`, and `1.0` in descending order of preference.
56
140
  *
57
141
  * Example:
58
142
  * ```javascript
59
- * // Try only versions 1.1 and 1.0
60
- * client.stompVersions = new Versions(['1.1', '1.0'])
143
+ * // Configure the client to only use versions 1.1 and 1.0
144
+ * client.stompVersions = new Versions(['1.1', '1.0']);
61
145
  * ```
62
146
  */
63
147
  this.stompVersions = Versions.default;
64
148
  /**
65
- * Will retry if Stomp connection is not established in specified milliseconds.
66
- * Default 0, which switches off automatic reconnection.
149
+ * Timeout for establishing STOMP connection, in milliseconds.
150
+ *
151
+ * If the connection is not established within this period, the attempt will fail.
152
+ * The default is `0`, meaning no timeout is set for connection attempts.
153
+ *
154
+ * Example:
155
+ * ```javascript
156
+ * client.connectionTimeout = 5000; // Fail connection if not established in 5 seconds
157
+ * ```
67
158
  */
68
159
  this.connectionTimeout = 0;
69
160
  /**
70
- * automatically reconnect with delay in milliseconds, set to 0 to disable.
161
+ * Delay (in milliseconds) between reconnection attempts if the connection drops.
162
+ *
163
+ * Set to `0` to disable automatic reconnections. The default value is `5000` ms (5 seconds).
164
+ *
165
+ * Example:
166
+ * ```javascript
167
+ * client.reconnectDelay = 3000; // Attempt reconnection every 3 seconds
168
+ * client.reconnectDelay = 0; // Disable automatic reconnection
169
+ * ```
71
170
  */
72
171
  this.reconnectDelay = 5000;
73
172
  /**
74
- * tracking the time to the next reconnection. Initialized to [Client#reconnectDelay]{@link Client#reconnectDelay}'s value and it may
75
- * change depending on the [Client#reconnectTimeMode]{@link Client#reconnectTimeMode} setting
173
+ * The next reconnection delay, used internally.
174
+ * Initialized to the value of [Client#reconnectDelay]{@link Client#reconnectDelay}, and it may
175
+ * dynamically change based on [Client#reconnectTimeMode]{@link Client#reconnectTimeMode}.
76
176
  */
77
177
  this._nextReconnectDelay = 0;
78
178
  /**
79
- * Maximum time to wait between reconnects, in milliseconds. Defaults to 15 minutes.
80
- * Only relevant when [Client#reconnectTimeMode]{@link Client#reconnectTimeMode} not LINEAR (e.g., EXPONENTIAL).
81
- * Set to 0 for no limit on wait time.
179
+ * Maximum delay (in milliseconds) between reconnection attempts when using exponential backoff.
180
+ *
181
+ * Default is 15 minutes (`15 * 60 * 1000` milliseconds). If `0`, there will be no upper limit.
182
+ *
183
+ * Example:
184
+ * ```javascript
185
+ * client.maxReconnectDelay = 10000; // Maximum wait time is 10 seconds
186
+ * ```
82
187
  */
83
- this.maxReconnectDelay = 15 * 60 * 1000; // 15 minutes in ms
188
+ this.maxReconnectDelay = 15 * 60 * 1000;
84
189
  /**
85
- * Reconnection wait time mode, either linear (default) or exponential.
86
- * Note: See [Client#maxReconnectDelay]{@link Client#maxReconnectDelay} for setting the maximum delay when exponential
190
+ * Mode for determining the time interval between reconnection attempts.
191
+ *
192
+ * Available modes:
193
+ * - `ReconnectionTimeMode.LINEAR` (default): Fixed delays between reconnection attempts.
194
+ * - `ReconnectionTimeMode.EXPONENTIAL`: Delay doubles after each attempt, capped by [maxReconnectDelay]{@link Client#maxReconnectDelay}.
87
195
  *
196
+ * Example:
88
197
  * ```javascript
89
- * client.configure({
90
- * reconnectTimeMode: ReconnectionTimeMode.EXPONENTIAL,
91
- * reconnectDelay: 200, // It will wait 200, 400, 800 ms...
92
- * maxReconnectDelay: 10000, // Optional, when provided, it will not wait more that these ms
93
- * })
198
+ * client.reconnectTimeMode = ReconnectionTimeMode.EXPONENTIAL;
199
+ * client.reconnectDelay = 200; // Initial delay of 200 ms, doubles with each attempt
200
+ * client.maxReconnectDelay = 2 * 60 * 1000; // Cap delay at 10 minutes
94
201
  * ```
95
202
  */
96
203
  this.reconnectTimeMode = ReconnectionTimeMode.LINEAR;
97
204
  /**
98
- * Incoming heartbeat interval in milliseconds. Set to 0 to disable.
205
+ * Interval (in milliseconds) for receiving heartbeat signals from the server.
206
+ *
207
+ * Specifies the expected frequency of heartbeats sent by the server. Set to `0` to disable.
208
+ *
209
+ * Example:
210
+ * ```javascript
211
+ * client.heartbeatIncoming = 10000; // Expect a heartbeat every 10 seconds
212
+ * ```
99
213
  */
100
214
  this.heartbeatIncoming = 10000;
101
215
  /**
102
- * Outgoing heartbeat interval in milliseconds. Set to 0 to disable.
216
+ * Multiplier for adjusting tolerance when processing heartbeat signals.
217
+ *
218
+ * Tolerance level is calculated using the multiplier:
219
+ * `tolerance = heartbeatIncoming * heartbeatToleranceMultiplier`.
220
+ * This helps account for delays in network communication or variations in timings.
221
+ *
222
+ * Default value is `2`.
223
+ *
224
+ * Example:
225
+ * ```javascript
226
+ * client.heartbeatToleranceMultiplier = 2.5; // Tolerates longer delays
227
+ * ```
228
+ */
229
+ this.heartbeatToleranceMultiplier = 2;
230
+ /**
231
+ * Interval (in milliseconds) for sending heartbeat signals to the server.
232
+ *
233
+ * Specifies how frequently heartbeats should be sent to the server. Set to `0` to disable.
234
+ *
235
+ * Example:
236
+ * ```javascript
237
+ * client.heartbeatOutgoing = 5000; // Send a heartbeat every 5 seconds
238
+ * ```
103
239
  */
104
240
  this.heartbeatOutgoing = 10000;
105
241
  /**
106
- * Outgoing heartbeat strategy.
107
- * See https://github.com/stomp-js/stompjs/pull/579
108
- *
109
- * Can be worker or interval strategy, but will always use `interval`
110
- * if web workers are unavailable, for example, in a non-browser environment.
242
+ * Strategy for sending outgoing heartbeats.
111
243
  *
112
- * Using Web Workers may work better on long-running pages
113
- * and mobile apps, as the browser may suspend Timers in the main page.
114
- * Try the `Worker` mode if you discover disconnects when the browser tab is in the background.
244
+ * Options:
245
+ * - `TickerStrategy.Worker`: Uses Web Workers for sending heartbeats (recommended for long-running or background sessions).
246
+ * - `TickerStrategy.Interval`: Uses standard JavaScript `setInterval` (default).
115
247
  *
116
- * When used in a JS environment, use 'worker' or 'interval' as valid values.
248
+ * Note:
249
+ * - If Web Workers are unavailable (e.g., in Node.js), the `Interval` strategy is used automatically.
250
+ * - Web Workers are preferable in browsers for reducing disconnects when tabs are in the background.
117
251
  *
118
- * Defaults to `interval` strategy.
252
+ * Example:
253
+ * ```javascript
254
+ * client.heartbeatStrategy = TickerStrategy.Worker;
255
+ * ```
119
256
  */
120
257
  this.heartbeatStrategy = TickerStrategy.Interval;
121
258
  /**
122
- * This switches on a non-standard behavior while sending WebSocket packets.
123
- * It splits larger (text) packets into chunks of [maxWebSocketChunkSize]{@link Client#maxWebSocketChunkSize}.
124
- * Only Java Spring brokers seem to support this mode.
259
+ * Enables splitting of large text WebSocket frames into smaller chunks.
125
260
  *
126
- * WebSockets, by itself, split large (text) packets,
127
- * so it is not needed with a truly compliant STOMP/WebSocket broker.
128
- * Setting it for such a broker will cause large messages to fail.
261
+ * This setting is enabled for brokers that support only chunked messages (e.g., Java Spring-based brokers).
262
+ * Default is `false`.
129
263
  *
130
- * `false` by default.
264
+ * Warning:
265
+ * - Should not be used with WebSocket-compliant brokers, as chunking may cause large message failures.
266
+ * - Binary WebSocket frames are never split.
131
267
  *
132
- * Binary frames are never split.
268
+ * Example:
269
+ * ```javascript
270
+ * client.splitLargeFrames = true;
271
+ * client.maxWebSocketChunkSize = 4096; // Allow chunks of 4 KB
272
+ * ```
133
273
  */
134
274
  this.splitLargeFrames = false;
135
275
  /**
136
- * See [splitLargeFrames]{@link Client#splitLargeFrames}.
137
- * This has no effect if [splitLargeFrames]{@link Client#splitLargeFrames} is `false`.
276
+ * Maximum size (in bytes) for individual WebSocket chunks if [splitLargeFrames]{@link Client#splitLargeFrames} is enabled.
277
+ *
278
+ * Default is 8 KB (`8 * 1024` bytes). This value has no effect if [splitLargeFrames]{@link Client#splitLargeFrames} is `false`.
138
279
  */
139
280
  this.maxWebSocketChunkSize = 8 * 1024;
140
281
  /**
141
- * Usually the
142
- * [type of WebSocket frame]{@link https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send#Parameters}
143
- * is automatically decided by type of the payload.
144
- * Default is `false`, which should work with all compliant brokers.
282
+ * Forces all WebSocket frames to use binary transport, irrespective of payload type.
283
+ *
284
+ * Default behavior determines frame type based on payload (e.g., binary data for ArrayBuffers).
145
285
  *
146
- * Set this flag to force binary frames.
286
+ * Example:
287
+ * ```javascript
288
+ * client.forceBinaryWSFrames = true;
289
+ * ```
147
290
  */
148
291
  this.forceBinaryWSFrames = false;
149
292
  /**
150
- * A bug in ReactNative chops a string on occurrence of a NULL.
151
- * See issue [https://github.com/stomp-js/stompjs/issues/89]{@link https://github.com/stomp-js/stompjs/issues/89}.
152
- * This makes incoming WebSocket messages invalid STOMP packets.
153
- * Setting this flag attempts to reverse the damage by appending a NULL.
154
- * If the broker splits a large message into multiple WebSocket messages,
155
- * this flag will cause data loss and abnormal termination of connection.
156
- *
157
- * This is not an ideal solution, but a stop gap until the underlying issue is fixed at ReactNative library.
293
+ * Workaround for a React Native WebSocket bug, where messages containing `NULL` are chopped.
294
+ *
295
+ * Enabling this appends a `NULL` character to incoming frames to ensure they remain valid STOMP packets.
296
+ *
297
+ * Warning:
298
+ * - For brokers that split large messages, this may cause data loss or connection termination.
299
+ *
300
+ * Example:
301
+ * ```javascript
302
+ * client.appendMissingNULLonIncoming = true;
303
+ * ```
158
304
  */
159
305
  this.appendMissingNULLonIncoming = false;
160
306
  /**
161
- * Browsers do not immediately close WebSockets when `.close` is issued.
162
- * This may cause reconnection to take a significantly long time in case
163
- * of some types of failures.
164
- * In case of incoming heartbeat failure, this experimental flag instructs
165
- * the library to discard the socket immediately
166
- * (even before it is actually closed).
307
+ * Instruct the library to immediately terminate the socket on communication failures, even
308
+ * before the WebSocket is completely closed.
309
+ *
310
+ * This is particularly useful in browser environments where WebSocket closure may get delayed,
311
+ * causing prolonged reconnection intervals under certain failure conditions.
312
+ *
313
+ *
314
+ * Example:
315
+ * ```javascript
316
+ * client.discardWebsocketOnCommFailure = true; // Enable aggressive closing of WebSocket
317
+ * ```
318
+ *
319
+ * Default value: `false`.
167
320
  */
168
321
  this.discardWebsocketOnCommFailure = false;
169
322
  /**
170
- * Activation state.
323
+ * Current activation state of the client.
324
+ *
325
+ * Possible states:
326
+ * - `ActivationState.ACTIVE`: Client is connected or actively attempting to connect.
327
+ * - `ActivationState.INACTIVE`: Client is disconnected and not attempting to reconnect.
328
+ * - `ActivationState.DEACTIVATING`: Client is in the process of disconnecting.
171
329
  *
172
- * It will usually be ACTIVE or INACTIVE.
173
- * When deactivating, it may go from ACTIVE to INACTIVE without entering DEACTIVATING.
330
+ * Note: The client may transition directly from `ACTIVE` to `INACTIVE` without entering
331
+ * the `DEACTIVATING` state.
174
332
  */
175
333
  this.state = ActivationState.INACTIVE;
176
334
  // No op callbacks
@@ -182,6 +340,8 @@ export class Client {
182
340
  this.onUnhandledMessage = noOp;
183
341
  this.onUnhandledReceipt = noOp;
184
342
  this.onUnhandledFrame = noOp;
343
+ this.onHeartbeatReceived = noOp;
344
+ this.onHeartbeatLost = noOp;
185
345
  this.onStompError = noOp;
186
346
  this.onWebSocketClose = noOp;
187
347
  this.onWebSocketError = noOp;
@@ -194,7 +354,22 @@ export class Client {
194
354
  this.configure(conf);
195
355
  }
196
356
  /**
197
- * Update configuration.
357
+ * Updates the client's configuration.
358
+ *
359
+ * All properties in the provided configuration object will override the current settings.
360
+ *
361
+ * Additionally, a warning is logged if `maxReconnectDelay` is configured to a
362
+ * value lower than `reconnectDelay`, and `maxReconnectDelay` is adjusted to match `reconnectDelay`.
363
+ *
364
+ * Example:
365
+ * ```javascript
366
+ * client.configure({
367
+ * reconnectDelay: 3000,
368
+ * maxReconnectDelay: 10000
369
+ * });
370
+ * ```
371
+ *
372
+ * @param conf Configuration object containing the new settings.
198
373
  */
199
374
  configure(conf) {
200
375
  // bulk assign all properties to this
@@ -207,12 +382,20 @@ export class Client {
207
382
  }
208
383
  }
209
384
  /**
210
- * Initiate the connection with the broker.
211
- * If the connection breaks, as per [Client#reconnectDelay]{@link Client#reconnectDelay},
212
- * it will keep trying to reconnect. If the [Client#reconnectTimeMode]{@link Client#reconnectTimeMode}
213
- * is set to EXPONENTIAL it will increase the wait time exponentially
385
+ * Activates the client, initiating a connection to the STOMP broker.
386
+ *
387
+ * On activation, the client attempts to connect and sets its state to `ACTIVE`. If the connection
388
+ * is lost, it will automatically retry based on `reconnectDelay` or `maxReconnectDelay`. If
389
+ * `reconnectTimeMode` is set to `EXPONENTIAL`, the reconnect delay increases exponentially.
390
+ *
391
+ * To stop reconnection attempts and disconnect, call [Client#deactivate]{@link Client#deactivate}.
392
+ *
393
+ * Example:
394
+ * ```javascript
395
+ * client.activate(); // Connect to the broker
396
+ * ```
214
397
  *
215
- * Call [Client#deactivate]{@link Client#deactivate} to disconnect and stop reconnection attempts.
398
+ * If the client is currently `DEACTIVATING`, connection is delayed until the deactivation process completes.
216
399
  */
217
400
  activate() {
218
401
  const _activate = () => {
@@ -270,6 +453,7 @@ export class Client {
270
453
  connectHeaders: this.connectHeaders,
271
454
  disconnectHeaders: this._disconnectHeaders,
272
455
  heartbeatIncoming: this.heartbeatIncoming,
456
+ heartbeatGracePeriods: this.heartbeatToleranceMultiplier,
273
457
  heartbeatOutgoing: this.heartbeatOutgoing,
274
458
  heartbeatStrategy: this.heartbeatStrategy,
275
459
  splitLargeFrames: this.splitLargeFrames,
@@ -322,6 +506,12 @@ export class Client {
322
506
  onUnhandledFrame: frame => {
323
507
  this.onUnhandledFrame(frame);
324
508
  },
509
+ onHeartbeatReceived: () => {
510
+ this.onHeartbeatReceived();
511
+ },
512
+ onHeartbeatLost: () => {
513
+ this.onHeartbeatLost();
514
+ },
325
515
  });
326
516
  this._stompHandler.start();
327
517
  }
@@ -355,27 +545,36 @@ export class Client {
355
545
  }
356
546
  }
357
547
  /**
358
- * Disconnect if connected and stop auto reconnect loop.
359
- * Appropriate callbacks will be invoked if there is an underlying STOMP connection.
548
+ * Disconnects the client and stops the automatic reconnection loop.
549
+ *
550
+ * If there is an active STOMP connection at the time of invocation, the appropriate callbacks
551
+ * will be triggered during the shutdown sequence. Once deactivated, the client will enter the
552
+ * `INACTIVE` state, and no further reconnection attempts will be made.
360
553
  *
361
- * This call is async. It will resolve immediately if there is no underlying active websocket,
362
- * otherwise, it will resolve after the underlying websocket is properly disposed of.
554
+ * **Behavior**:
555
+ * - If there is no active WebSocket connection, this method resolves immediately.
556
+ * - If there is an active connection, the method waits for the underlying WebSocket
557
+ * to properly close before resolving.
558
+ * - Multiple calls to this method are safe. Each invocation resolves upon completion.
559
+ * - To reactivate, call [Client#activate]{@link Client#activate}.
363
560
  *
364
- * It is not an error to invoke this method more than once.
365
- * Each of those would resolve on completion of deactivation.
561
+ * **Experimental Option:**
562
+ * - By specifying the `force: true` option, the WebSocket connection is discarded immediately,
563
+ * bypassing both the STOMP and WebSocket shutdown sequences.
564
+ * - **Caution:** Using `force: true` may leave the WebSocket in an inconsistent state,
565
+ * and brokers may not immediately detect the termination.
366
566
  *
367
- * To reactivate, you can call [Client#activate]{@link Client#activate}.
567
+ * Example:
568
+ * ```javascript
569
+ * // Graceful disconnect
570
+ * await client.deactivate();
368
571
  *
369
- * Experimental: pass `force: true` to immediately discard the underlying connection.
370
- * This mode will skip both the STOMP and the Websocket shutdown sequences.
371
- * In some cases, browsers take a long time in the Websocket shutdown
372
- * if the underlying connection had gone stale.
373
- * Using this mode can speed up.
374
- * When this mode is used, the actual Websocket may linger for a while
375
- * and the broker may not realize that the connection is no longer in use.
572
+ * // Forced disconnect to speed up shutdown when the connection is stale
573
+ * await client.deactivate({ force: true });
574
+ * ```
376
575
  *
377
- * It is possible to invoke this method initially without the `force` option
378
- * and subsequently, say after a wait, with the `force` option.
576
+ * @param options Configuration options for deactivation. Use `force: true` for immediate shutdown.
577
+ * @returns A Promise that resolves when the deactivation process completes.
379
578
  */
380
579
  async deactivate(options = {}) {
381
580
  const force = options.force || false;
@@ -420,10 +619,18 @@ export class Client {
420
619
  return retPromise;
421
620
  }
422
621
  /**
423
- * Force disconnect if there is an active connection by directly closing the underlying WebSocket.
424
- * This is different from a normal disconnect where a DISCONNECT sequence is carried out with the broker.
425
- * After forcing disconnect, automatic reconnect will be attempted.
426
- * To stop further reconnects call [Client#deactivate]{@link Client#deactivate} as well.
622
+ * Forces a disconnect by directly closing the WebSocket.
623
+ *
624
+ * Unlike a normal disconnect, this does not send a DISCONNECT sequence to the broker but
625
+ * instead closes the WebSocket connection directly. After forcing a disconnect, the client
626
+ * will automatically attempt to reconnect based on its `reconnectDelay` configuration.
627
+ *
628
+ * **Note:** To prevent further reconnect attempts, call [Client#deactivate]{@link Client#deactivate}.
629
+ *
630
+ * Example:
631
+ * ```javascript
632
+ * client.forceDisconnect();
633
+ * ```
427
634
  */
428
635
  forceDisconnect() {
429
636
  if (this._stompHandler) {
@@ -437,39 +644,38 @@ export class Client {
437
644
  }
438
645
  }
439
646
  /**
440
- * Send a message to a named destination. Refer to your STOMP broker documentation for types
441
- * and naming of destinations.
442
- *
443
- * STOMP protocol specifies and suggests some headers and also allows broker-specific headers.
647
+ * Sends a message to the specified destination on the STOMP broker.
444
648
  *
445
- * `body` must be String.
446
- * You will need to covert the payload to string in case it is not string (e.g. JSON).
649
+ * The `body` must be a `string`. For non-string payloads (e.g., JSON), encode it as a string before sending.
650
+ * If sending binary data, use the `binaryBody` parameter as a [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array).
447
651
  *
448
- * To send a binary message body, use `binaryBody` parameter. It should be a
449
- * [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array).
450
- * Sometimes brokers may not support binary frames out of the box.
451
- * Please check your broker documentation.
652
+ * **Content-Length Behavior**:
653
+ * - For non-binary messages, the `content-length` header is added by default.
654
+ * - The `content-length` header can be skipped for text frames by setting `skipContentLengthHeader: true` in the parameters.
655
+ * - For binary messages, the `content-length` header is always included.
452
656
  *
453
- * `content-length` header is automatically added to the STOMP Frame sent to the broker.
454
- * Set `skipContentLengthHeader` to indicate that `content-length` header should not be added.
455
- * For binary messages, `content-length` header is always added.
456
- *
457
- * Caution: The broker will, most likely, report an error and disconnect
458
- * if the message body has NULL octet(s) and `content-length` header is missing.
657
+ * **Notes**:
658
+ * - Ensure that brokers support binary frames before using `binaryBody`.
659
+ * - Sending messages with NULL octets and missing `content-length` headers can cause brokers to disconnect and throw errors.
459
660
  *
661
+ * Example:
460
662
  * ```javascript
461
- * client.publish({destination: "/queue/test", headers: {priority: 9}, body: "Hello, STOMP"});
462
- *
463
- * // Only destination is mandatory parameter
464
- * client.publish({destination: "/queue/test", body: "Hello, STOMP"});
465
- *
466
- * // Skip content-length header in the frame to the broker
467
- * client.publish({"/queue/test", body: "Hello, STOMP", skipContentLengthHeader: true});
468
- *
469
- * var binaryData = generateBinaryData(); // This need to be of type Uint8Array
470
- * // setting content-type header is not mandatory, however a good practice
471
- * client.publish({destination: '/topic/special', binaryBody: binaryData,
472
- * headers: {'content-type': 'application/octet-stream'}});
663
+ * // Basic text message
664
+ * client.publish({ destination: "/queue/test", body: "Hello, STOMP" });
665
+ *
666
+ * // Text message with additional headers
667
+ * client.publish({ destination: "/queue/test", headers: { priority: 9 }, body: "Hello, STOMP" });
668
+ *
669
+ * // Skip content-length header
670
+ * client.publish({ destination: "/queue/test", body: "Hello, STOMP", skipContentLengthHeader: true });
671
+ *
672
+ * // Binary message
673
+ * const binaryData = new Uint8Array([1, 2, 3, 4]);
674
+ * client.publish({
675
+ * destination: '/topic/special',
676
+ * binaryBody: binaryData,
677
+ * headers: { 'content-type': 'application/octet-stream' }
678
+ * });
473
679
  * ```
474
680
  */
475
681
  publish(params) {
@@ -483,39 +689,27 @@ export class Client {
483
689
  }
484
690
  }
485
691
  /**
486
- * STOMP brokers may carry out operation asynchronously and allow requesting for acknowledgement.
487
- * To request an acknowledgement, a `receipt` header needs to be sent with the actual request.
488
- * The value (say receipt-id) for this header needs to be unique for each use.
489
- * Typically, a sequence, a UUID, a random number or a combination may be used.
692
+ * Monitors for a receipt acknowledgment from the broker for specific operations.
490
693
  *
491
- * A complaint broker will send a RECEIPT frame when an operation has actually been completed.
492
- * The operation needs to be matched based on the value of the receipt-id.
694
+ * Add a `receipt` header to the operation (like subscribe or publish), and use this method with
695
+ * the same receipt ID to detect when the broker has acknowledged the operation's completion.
493
696
  *
494
- * This method allows watching for a receipt and invoking the callback
495
- * when the corresponding receipt has been received.
496
- *
497
- * The actual {@link IFrame} will be passed as parameter to the callback.
697
+ * The callback is invoked with the corresponding {@link IFrame} when the receipt is received.
498
698
  *
499
699
  * Example:
500
700
  * ```javascript
501
- * // Subscribing with acknowledgement
502
- * let receiptId = randomText();
503
- *
504
- * client.watchForReceipt(receiptId, function() {
505
- * // Will be called after server acknowledges
506
- * });
701
+ * const receiptId = "unique-receipt-id";
507
702
  *
508
- * client.subscribe(TEST.destination, onMessage, {receipt: receiptId});
703
+ * client.watchForReceipt(receiptId, (frame) => {
704
+ * console.log("Operation acknowledged by the broker:", frame);
705
+ * });
509
706
  *
510
- *
511
- * // Publishing with acknowledgement
512
- * receiptId = randomText();
513
- *
514
- * client.watchForReceipt(receiptId, function() {
515
- * // Will be called after server acknowledges
516
- * });
517
- * client.publish({destination: TEST.destination, headers: {receipt: receiptId}, body: msg});
707
+ * // Attach the receipt header to an operation
708
+ * client.publish({ destination: "/queue/test", headers: { receipt: receiptId }, body: "Hello" });
518
709
  * ```
710
+ *
711
+ * @param receiptId Unique identifier for the receipt.
712
+ * @param callback Callback function invoked on receiving the RECEIPT frame.
519
713
  */
520
714
  watchForReceipt(receiptId, callback) {
521
715
  this._checkConnection();
@@ -523,28 +717,33 @@ export class Client {
523
717
  this._stompHandler.watchForReceipt(receiptId, callback);
524
718
  }
525
719
  /**
526
- * Subscribe to a STOMP Broker location. The callback will be invoked for each
527
- * received message with the {@link IMessage} as argument.
720
+ * Subscribes to a destination on the STOMP broker.
528
721
  *
529
- * Note: The library will generate a unique ID if there is none provided in the headers.
530
- * To use your own ID, pass it using the `headers` argument.
722
+ * The callback is triggered for each message received from the subscribed destination. The message
723
+ * is passed as an {@link IMessage} instance.
531
724
  *
725
+ * **Subscription ID**:
726
+ * - If no `id` is provided in `headers`, the library generates a unique subscription ID automatically.
727
+ * - Provide an explicit `id` in `headers` if you wish to manage the subscription ID manually.
728
+ *
729
+ * Example:
532
730
  * ```javascript
533
- * callback = function(message) {
534
- * // called when the client receives a STOMP message from the server
535
- * if (message.body) {
536
- * alert("got message with body " + message.body)
537
- * } else {
538
- * alert("got empty message");
539
- * }
540
- * });
541
- *
542
- * var subscription = client.subscribe("/queue/test", callback);
543
- *
544
- * // Explicit subscription id
545
- * var mySubId = 'my-subscription-id-001';
546
- * var subscription = client.subscribe(destination, callback, { id: mySubId });
731
+ * const callback = (message) => {
732
+ * console.log("Received message:", message.body);
733
+ * };
734
+ *
735
+ * // Auto-generated subscription ID
736
+ * const subscription = client.subscribe("/queue/test", callback);
737
+ *
738
+ * // Explicit subscription ID
739
+ * const mySubId = "my-subscription-id";
740
+ * const subscription = client.subscribe("/queue/test", callback, { id: mySubId });
547
741
  * ```
742
+ *
743
+ * @param destination Destination to subscribe to.
744
+ * @param callback Function invoked for each received message.
745
+ * @param headers Optional headers for subscription, such as `id`.
746
+ * @returns A {@link StompSubscription} which can be used to manage the subscription.
548
747
  */
549
748
  subscribe(destination, callback, headers = {}) {
550
749
  this._checkConnection();
@@ -552,16 +751,24 @@ export class Client {
552
751
  return this._stompHandler.subscribe(destination, callback, headers);
553
752
  }
554
753
  /**
555
- * It is preferable to unsubscribe from a subscription by calling
556
- * `unsubscribe()` directly on {@link StompSubscription} returned by `client.subscribe()`:
754
+ * Unsubscribes from a subscription on the STOMP broker.
557
755
  *
756
+ * Prefer using the `unsubscribe` method directly on the {@link StompSubscription} returned from `subscribe` for cleaner management:
558
757
  * ```javascript
559
- * var subscription = client.subscribe(destination, onmessage);
560
- * // ...
561
- * subscription.unsubscribe();
758
+ * const subscription = client.subscribe("/queue/test", callback);
759
+ * // Unsubscribe using the subscription object
760
+ * subscription.unsubscribe();
562
761
  * ```
563
762
  *
564
- * See: https://stomp.github.com/stomp-specification-1.2.html#UNSUBSCRIBE UNSUBSCRIBE Frame
763
+ * This method can also be used directly with the subscription ID.
764
+ *
765
+ * Example:
766
+ * ```javascript
767
+ * client.unsubscribe("my-subscription-id");
768
+ * ```
769
+ *
770
+ * @param id Subscription ID to unsubscribe.
771
+ * @param headers Optional headers to pass for the UNSUBSCRIBE frame.
565
772
  */
566
773
  unsubscribe(id, headers = {}) {
567
774
  this._checkConnection();
@@ -569,10 +776,21 @@ export class Client {
569
776
  this._stompHandler.unsubscribe(id, headers);
570
777
  }
571
778
  /**
572
- * Start a transaction, the returned {@link ITransaction} has methods - [commit]{@link ITransaction#commit}
573
- * and [abort]{@link ITransaction#abort}.
779
+ * Starts a new transaction. The returned {@link ITransaction} object provides
780
+ * methods for [commit]{@link ITransaction#commit} and [abort]{@link ITransaction#abort}.
781
+ *
782
+ * If `transactionId` is not provided, the library generates a unique ID internally.
783
+ *
784
+ * Example:
785
+ * ```javascript
786
+ * const tx = client.begin(); // Auto-generated ID
574
787
  *
575
- * `transactionId` is optional, if not passed the library will generate it internally.
788
+ * // Or explicitly specify a transaction ID
789
+ * const tx = client.begin("my-transaction-id");
790
+ * ```
791
+ *
792
+ * @param transactionId Optional transaction ID.
793
+ * @returns An instance of {@link ITransaction}.
576
794
  */
577
795
  begin(transactionId) {
578
796
  this._checkConnection();
@@ -580,16 +798,19 @@ export class Client {
580
798
  return this._stompHandler.begin(transactionId);
581
799
  }
582
800
  /**
583
- * Commit a transaction.
801
+ * Commits a transaction.
584
802
  *
585
- * It is preferable to commit a transaction by calling [commit]{@link ITransaction#commit} directly on
586
- * {@link ITransaction} returned by [client.begin]{@link Client#begin}.
803
+ * It is strongly recommended to call [commit]{@link ITransaction#commit} on
804
+ * the transaction object returned by [client#begin]{@link Client#begin}.
587
805
  *
806
+ * Example:
588
807
  * ```javascript
589
- * var tx = client.begin(txId);
590
- * //...
591
- * tx.commit();
808
+ * const tx = client.begin();
809
+ * // Perform operations under this transaction
810
+ * tx.commit();
592
811
  * ```
812
+ *
813
+ * @param transactionId The ID of the transaction to commit.
593
814
  */
594
815
  commit(transactionId) {
595
816
  this._checkConnection();
@@ -597,15 +818,19 @@ export class Client {
597
818
  this._stompHandler.commit(transactionId);
598
819
  }
599
820
  /**
600
- * Abort a transaction.
601
- * It is preferable to abort a transaction by calling [abort]{@link ITransaction#abort} directly on
602
- * {@link ITransaction} returned by [client.begin]{@link Client#begin}.
821
+ * Aborts a transaction.
822
+ *
823
+ * It is strongly recommended to call [abort]{@link ITransaction#abort} directly
824
+ * on the transaction object returned by [client#begin]{@link Client#begin}.
603
825
  *
826
+ * Example:
604
827
  * ```javascript
605
- * var tx = client.begin(txId);
606
- * //...
607
- * tx.abort();
828
+ * const tx = client.begin();
829
+ * // Perform operations under this transaction
830
+ * tx.abort(); // Abort the transaction
608
831
  * ```
832
+ *
833
+ * @param transactionId The ID of the transaction to abort.
609
834
  */
610
835
  abort(transactionId) {
611
836
  this._checkConnection();
@@ -613,17 +838,23 @@ export class Client {
613
838
  this._stompHandler.abort(transactionId);
614
839
  }
615
840
  /**
616
- * ACK a message. It is preferable to acknowledge a message by calling [ack]{@link IMessage#ack} directly
617
- * on the {@link IMessage} handled by a subscription callback:
841
+ * Acknowledges receipt of a message. Typically, this should be done by calling
842
+ * [ack]{@link IMessage#ack} directly on the {@link IMessage} instance passed
843
+ * to the subscription callback.
618
844
  *
845
+ * Example:
619
846
  * ```javascript
620
- * var callback = function (message) {
621
- * // process the message
622
- * // acknowledge it
623
- * message.ack();
624
- * };
625
- * client.subscribe(destination, callback, {'ack': 'client'});
847
+ * const callback = (message) => {
848
+ * // Process the message
849
+ * message.ack(); // Acknowledge the message
850
+ * };
851
+ *
852
+ * client.subscribe("/queue/example", callback, { ack: "client" });
626
853
  * ```
854
+ *
855
+ * @param messageId The ID of the message to acknowledge.
856
+ * @param subscriptionId The ID of the subscription.
857
+ * @param headers Optional headers for the acknowledgment frame.
627
858
  */
628
859
  ack(messageId, subscriptionId, headers = {}) {
629
860
  this._checkConnection();
@@ -631,17 +862,25 @@ export class Client {
631
862
  this._stompHandler.ack(messageId, subscriptionId, headers);
632
863
  }
633
864
  /**
634
- * NACK a message. It is preferable to acknowledge a message by calling [nack]{@link IMessage#nack} directly
635
- * on the {@link IMessage} handled by a subscription callback:
865
+ * Rejects a message (negative acknowledgment). Like acknowledgments, this should
866
+ * typically be done by calling [nack]{@link IMessage#nack} directly on the {@link IMessage}
867
+ * instance passed to the subscription callback.
636
868
  *
869
+ * Example:
637
870
  * ```javascript
638
- * var callback = function (message) {
639
- * // process the message
640
- * // an error occurs, nack it
641
- * message.nack();
642
- * };
643
- * client.subscribe(destination, callback, {'ack': 'client'});
871
+ * const callback = (message) => {
872
+ * // Process the message
873
+ * if (isError(message)) {
874
+ * message.nack(); // Reject the message
875
+ * }
876
+ * };
877
+ *
878
+ * client.subscribe("/queue/example", callback, { ack: "client" });
644
879
  * ```
880
+ *
881
+ * @param messageId The ID of the message to negatively acknowledge.
882
+ * @param subscriptionId The ID of the subscription.
883
+ * @param headers Optional headers for the NACK frame.
645
884
  */
646
885
  nack(messageId, subscriptionId, headers = {}) {
647
886
  this._checkConnection();