aedes 0.51.3 → 1.0.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.
Files changed (67) hide show
  1. package/.github/actions/sticky-pr-comment/action.yml +55 -0
  2. package/.github/workflows/benchmark-compare-serial.yml +60 -0
  3. package/.github/workflows/ci.yml +12 -17
  4. package/.release-it.json +18 -0
  5. package/.taprc +15 -6
  6. package/README.md +6 -4
  7. package/aedes.d.ts +0 -6
  8. package/aedes.js +270 -242
  9. package/benchmarks/README.md +33 -0
  10. package/benchmarks/pingpong.js +94 -25
  11. package/benchmarks/receiver.js +77 -0
  12. package/benchmarks/report.js +150 -0
  13. package/benchmarks/runBenchmarks.js +118 -0
  14. package/benchmarks/sender.js +86 -0
  15. package/benchmarks/server.js +19 -18
  16. package/checkVersion.js +20 -0
  17. package/docs/Aedes.md +66 -8
  18. package/docs/Client.md +3 -4
  19. package/docs/Examples.md +39 -22
  20. package/docs/MIGRATION.md +50 -0
  21. package/eslint.config.js +8 -0
  22. package/example.js +51 -40
  23. package/examples/clusters/index.js +28 -23
  24. package/examples/clusters/package.json +10 -6
  25. package/lib/client.js +405 -306
  26. package/lib/handlers/connect.js +42 -38
  27. package/lib/handlers/index.js +9 -11
  28. package/lib/handlers/ping.js +2 -3
  29. package/lib/handlers/puback.js +5 -5
  30. package/lib/handlers/publish.js +29 -14
  31. package/lib/handlers/pubrec.js +9 -17
  32. package/lib/handlers/pubrel.js +34 -25
  33. package/lib/handlers/subscribe.js +47 -43
  34. package/lib/handlers/unsubscribe.js +16 -19
  35. package/lib/qos-packet.js +14 -17
  36. package/lib/utils.js +5 -12
  37. package/lib/write.js +4 -5
  38. package/package.json +134 -136
  39. package/test/auth.js +468 -804
  40. package/test/basic.js +613 -575
  41. package/test/bridge.js +44 -40
  42. package/test/client-pub-sub.js +531 -504
  43. package/test/close_socket_by_other_party.js +137 -102
  44. package/test/connect.js +487 -484
  45. package/test/drain-timeout.js +593 -0
  46. package/test/drain-toxiproxy.js +620 -0
  47. package/test/events.js +173 -145
  48. package/test/helper.js +351 -73
  49. package/test/keep-alive.js +40 -67
  50. package/test/meta.js +257 -210
  51. package/test/not-blocking.js +93 -197
  52. package/test/qos1.js +464 -554
  53. package/test/qos2.js +308 -393
  54. package/test/regr-21.js +39 -21
  55. package/test/require.cjs +22 -0
  56. package/test/retain.js +349 -398
  57. package/test/topics.js +176 -183
  58. package/test/types/aedes.test-d.ts +4 -8
  59. package/test/will.js +310 -428
  60. package/types/instance.d.ts +40 -35
  61. package/types/packet.d.ts +10 -10
  62. package/.coveralls.yml +0 -1
  63. package/benchmarks/bombing.js +0 -34
  64. package/benchmarks/bombingQoS1.js +0 -36
  65. package/benchmarks/throughputCounter.js +0 -23
  66. package/benchmarks/throughputCounterQoS1.js +0 -33
  67. package/types/.eslintrc.json +0 -47
package/docs/Aedes.md CHANGED
@@ -2,7 +2,9 @@
2
2
  # Aedes
3
3
 
4
4
  - [Aedes](#aedes)
5
- - [new Aedes([options]) / new Aedes.Server([options])](#new-aedesoptions--new-aedesserveroptions)
5
+ - [new Aedes(\[options\])](#new-aedesoptions)
6
+ - [Aedes.createBroker(\[options\])](#aedescreatebrokeroptions)
7
+ - [aedes.listen()](#aedeslisten)
6
8
  - [aedes.id](#aedesid)
7
9
  - [aedes.connectedClients](#aedesconnectedclients)
8
10
  - [aedes.closed](#aedesclosed)
@@ -23,7 +25,7 @@
23
25
  - [aedes.subscribe (topic, deliverfunc, callback)](#aedessubscribe-topic-deliverfunc-callback)
24
26
  - [aedes.unsubscribe (topic, deliverfunc, callback)](#aedesunsubscribe-topic-deliverfunc-callback)
25
27
  - [aedes.publish (packet, callback)](#aedespublish-packet-callback)
26
- - [aedes.close ([callback])](#aedesclose-callback)
28
+ - [aedes.close (\[callback\])](#aedesclose-callback)
27
29
  - [Handler: preConnect (client, packet, callback)](#handler-preconnect-client-packet-callback)
28
30
  - [Handler: authenticate (client, username, password, callback)](#handler-authenticate-client-username-password-callback)
29
31
  - [Handler: authorizePublish (client, packet, callback)](#handler-authorizepublish-client-packet-callback)
@@ -31,23 +33,75 @@
31
33
  - [Handler: authorizeForward (client, packet)](#handler-authorizeforward-client-packet)
32
34
  - [Handler: published (packet, client, callback)](#handler-published-packet-client-callback)
33
35
 
34
- ## new Aedes([options]) / new Aedes.Server([options])
36
+ ## new Aedes([options])
35
37
 
36
38
  - options `<object>`
37
39
  - `mq` [`<MQEmitter>`](../README.md#mqemitter) middleware used to deliver messages to subscribed clients. In a cluster environment it is used also to share messages between brokers instances. __Default__: `mqemitter`
38
- - `concurrency` `<number>` maximum number of concurrent messages delivered by `mq`. __Default__: `100`
40
+ - `concurrency` `<number>` maximum number of concurrent messages that can be processed simultaneously by `mq`. __Default__: `100`
41
+
42
+ __Note:__ Concurrency determines how many messages can be "in-flight" at once. When a slow client blocks (socket buffer full), the message delivery hangs waiting for the `drain` event. With `N` concurrency slots and ANY frozen subscriber on a topic, fast clients will receive at most `N` messages before complete deadlock. Higher concurrency = larger buffer before freeze, but without `drainTimeout`, deadlock is __inevitable__. Use `drainTimeout` to protect against this.
39
43
  - `persistence` [`<Persistence>`](../README.md#persistence) middleware that stores _QoS > 0, retained, will_ packets and _subscriptions_. __Default__: `aedes-persistence` (_in memory_)
44
+ Versions 1.x and above require persistence to support async access,see [MIGRATION.md][MIGRATION] for details.
40
45
  - `queueLimit` `<number>` maximum number of queued messages before client session is established. If number of queued items exceeds, `connectionError` throws an error `Client queue limit reached`. __Default__: `42`
41
46
  - `maxClientsIdLength` option to override MQTT 3.1.0 clients Id length limit. __Default__: `23`
42
47
  - `heartbeatInterval` `<number>` an interval in millisconds at which server beats its health signal in `$SYS/<aedes.id>/heartbeat` topic. __Default__: `60000`
43
48
  - `id` `<string>` aedes broker unique identifier. __Default__: `uuidv4()`
44
49
  - `connectTimeout` `<number>` maximum waiting time in milliseconds waiting for a [`CONNECT`][CONNECT] packet. __Default__: `30000`
45
50
  - `keepaliveLimit` `<number>` maximum client keep alive time allowed, 0 means no limit. __Default__: `0`
51
+ - `drainTimeout` `<number>` maximum time in milliseconds to wait for a slow client's socket to drain before disconnecting it. When a client's socket buffer fills up (e.g., slow network, unresponsive client), the broker waits for the `drain` event. Without a timeout, one slow client can block message delivery to all other clients. Set to `0` to disable and wait indefinitely (not recommended). __Default__: `60000` (60 seconds)
52
+
53
+ __Why use drainTimeout?__ When publishing messages, if a client's TCP buffer is full, `socket.write()` returns `false` and the broker waits for the `drain` event before continuing. If the client stops reading (slow 3G, crashed app, malicious client), `drain` never fires and that message hangs forever. Even with high `concurrency`, a single frozen subscriber will eventually exhaust all slots and cause __complete deadlock__ - no more messages can be delivered to ANY client. This is a DoS vulnerability.
54
+
55
+ __Recommended settings:__
56
+ - Production: `10000` - `60000` ms (10-60 seconds)
57
+ - High-latency networks: Higher values to avoid disconnecting legitimate slow clients
58
+ - IoT/embedded devices: Consider client capabilities when setting timeout
59
+
60
+ ```js
61
+ // Recommended for production
62
+ const broker = await Aedes.createBroker({
63
+ drainTimeout: 30000 // Disconnect unresponsive clients after 30 seconds (default: 60000)
64
+ // drainTimeout: 0 // Disable timeout - NOT RECOMMENDED: vulnerable to DoS
65
+ })
66
+
67
+ // Monitor disconnections (optional)
68
+ broker.on('clientDisconnect', (client) => {
69
+ console.log(`Client ${client.id} disconnected`)
70
+ })
71
+ ```
72
+
46
73
  - Returns `<Aedes>`
47
74
 
48
- Create a new Aedes server.
75
+ Create a new Aedes server instance.
76
+
77
+ Aedes is the class exported by this module.
78
+ The instance will only start listening after [aedes.listen()](#aedeslisten) is called.
79
+ The recommended way to start an Aedes server is to use [Aedes.createBroker([options])](#aedescreatebrokeroptions) instead.
80
+
81
+ ## Aedes.createBroker([options])
82
+
83
+ An async static method in the Aedes class which creates the instance and automatically awaits `listen()`.
84
+
85
+ Using `Aedes.createBroker([options])` is the recommended way to start Aedes, example:
49
86
 
50
- Aedes is the class and function exposed by this module. It can be created by `Aedes()` or using `new Aedes()`. An variant `aedes.Server` is for TypeScript or ES modules.
87
+ ```js
88
+ const aedes = await Aedes.createBroker([options])
89
+ ```
90
+
91
+ It uses the same options as [new Aedes([options])](#new-aedesoptions)
92
+
93
+ ## aedes.listen()
94
+
95
+ Async method to make the aedes instance start listening.
96
+ Example:
97
+
98
+ ```js
99
+ const aedes = new Aedes([options])
100
+ await aedes.listen()
101
+ ```
102
+
103
+ You should typically not need to use this as it is more compact to use
104
+ [Aedes.createBroker([options])](#aedescreatebrokeroptions) instead.
51
105
 
52
106
  ## aedes.id
53
107
 
@@ -173,8 +227,11 @@ Emitted when server is closed.
173
227
  A connection listener that pipe stream to aedes.
174
228
 
175
229
  ```js
176
- const aedes = require('./aedes')()
177
- const server = require('net').createServer(aedes.handle)
230
+ import { createServer } from 'node:net'
231
+ import { Aedes } from 'aedes'
232
+
233
+ const aedes = await Aedes.createBroker()
234
+ const server = createServer(aedes.handle)
178
235
  ```
179
236
 
180
237
  ## aedes.subscribe (topic, deliverfunc, callback)
@@ -414,3 +471,4 @@ same as [`Event: publish`](#event-publish), but provides a backpressure function
414
471
  [PINGREQ]: https://github.com/mqttjs/mqtt-packet#pingreq
415
472
  [PUBLISH]: https://github.com/mqttjs/mqtt-packet#publish
416
473
  [PUBREL]: https://github.com/mqttjs/mqtt-packet#pubrel
474
+ [MIGRATION]: MIGRATION.md
package/docs/Client.md CHANGED
@@ -34,13 +34,13 @@ Client connection stream object.
34
34
 
35
35
  In the case of `net.createServer`, `conn` passed to the `connectionlistener` function by node's [net.createServer](https://nodejs.org/api/net.html#net_net_createserver_options_connectionlistener) API.
36
36
 
37
- In the case of [`websocket-stream`][websocket-stream], it's the `stream` argument passed to the websocket `handle` function in [`websocket-stream #on-the-server`][websocket-stream-doc-on-the-server]].
37
+ In the case of [`ws`][ws], it's the `stream.Duplex` argument passed to the `handle` function.
38
38
 
39
39
  ## client.req
40
40
 
41
41
  - `<http.IncomingMessage>`
42
42
 
43
- only for [`websocket-stream`][websocket-stream]. It is a HTTP Websocket upgrade request object passed to websocket `handle` function in [`websocket-stream #on-the-server`][websocket-stream-doc-on-the-server]. It gives an option for accessing headers or cookies.
43
+ only for [`ws`][ws]. It is a HTTP Websocket upgrade request object passed to the `handle` function. It gives an option for accessing headers or cookies.
44
44
 
45
45
  ## client.connecting
46
46
 
@@ -152,5 +152,4 @@ Clear all outgoing messages (QoS > 1) related to this client from persistence
152
152
  [SUBSCRIBE]: https://github.com/mqttjs/mqtt-packet#subscribe
153
153
  [UNSUBSCRIBE]: https://github.com/mqttjs/mqtt-packet#unsubscribe
154
154
 
155
- [websocket-stream]: https://www.npmjs.com/websocket-stream
156
- [websocket-stream-doc-on-the-server]: https://github.com/maxogden/websocket-stream/blob/master/readme.md#on-the-server
155
+ [ws]: https://www.npmjs.com/package/ws
package/docs/Examples.md CHANGED
@@ -4,24 +4,27 @@
4
4
  ## Simple plain MQTT server
5
5
 
6
6
  ```js
7
- const aedes = require('aedes')()
8
- const server = require('net').createServer(aedes.handle)
7
+ import { createServer } from 'node:net'
8
+ import Aedes from 'aedes'
9
+
9
10
  const port = 1883
10
11
 
12
+ const aedes = await Aedes.createBroker()
13
+ const server = createServer(aedes.handle)
14
+
11
15
  server.listen(port, function () {
12
16
  console.log('server started and listening on port ', port)
13
17
  })
14
18
  ```
15
19
 
16
- ## Typescript
20
+ ## CommonJS
17
21
 
18
- ```ts
19
- import Aedes from 'aedes'
20
- import { createServer } from 'net'
22
+ ```js
23
+ const { createServer } = require('node:net')
24
+ const { Aedes } = require('aedes')
21
25
 
26
+ const aedes = await Aedes.createBroker()
22
27
  const port = 1883
23
-
24
- const aedes = new Aedes()
25
28
  const server = createServer(aedes.handle)
26
29
 
27
30
  server.listen(port, function () {
@@ -32,10 +35,11 @@ server.listen(port, function () {
32
35
  ## Simple plain MQTT server using server-factory
33
36
 
34
37
  ```js
35
- const aedes = require('aedes')()
36
- const { createServer } = require('aedes-server-factory')
38
+ import { Aedes } from 'aedes'
39
+ import { createServer } from 'aedes-server-factory'
37
40
  const port = 1883
38
41
 
42
+ const aedes = await Aedes.createBroker()
39
43
  const server = createServer(aedes)
40
44
 
41
45
  server.listen(port, function () {
@@ -46,16 +50,18 @@ server.listen(port, function () {
46
50
  ## MQTT over TLS / MQTTS
47
51
 
48
52
  ```js
49
- const fs = require('fs')
50
- const aedes = require('aedes')()
53
+ import { createServer } from 'node:tls'
54
+ import { readFileSync } from 'node:fs'
55
+ import { Aedes } from 'aedes'
56
+
51
57
  const port = 8883
52
58
 
53
59
  const options = {
54
- key: fs.readFileSync('YOUR_PRIVATE_KEY_FILE.pem'),
55
- cert: fs.readFileSync('YOUR_PUBLIC_CERT_FILE.pem')
60
+ key: readFileSync('YOUR_PRIVATE_KEY_FILE.pem'),
61
+ cert: readFileSync('YOUR_PUBLIC_CERT_FILE.pem')
56
62
  }
57
-
58
- const server = require('tls').createServer(options, aedes.handle)
63
+ const aedes = await Aedes.createBroker()
64
+ const server = createServer(options, aedes.handle)
59
65
 
60
66
  server.listen(port, function () {
61
67
  console.log('server started and listening on port ', port)
@@ -65,12 +71,22 @@ server.listen(port, function () {
65
71
  ## MQTT server over WebSocket
66
72
 
67
73
  ```js
68
- const aedes = require('aedes')()
69
- const httpServer = require('http').createServer()
70
- const ws = require('websocket-stream')
74
+ import { createServer } from 'node:http'
75
+ import { Aedes } from 'aedes'
76
+ import { WebSocketServer, createWebSocketStream } from 'ws'
77
+
71
78
  const port = 8888
72
79
 
73
- ws.createServer({ server: httpServer }, aedes.handle)
80
+ const aedes = await Aedes.createBroker()
81
+ const httpServer = createServer()
82
+ const wss = new WebSocketServer({
83
+ server:httpServer
84
+ })
85
+
86
+ wss.on('connection', (websocket, req) => {
87
+ const stream = createWebSocketStream(websocket)
88
+ aedes.handle(stream, req)
89
+ })
74
90
 
75
91
  httpServer.listen(port, function () {
76
92
  console.log('websocket server listening on port ', port)
@@ -80,10 +96,11 @@ httpServer.listen(port, function () {
80
96
  ## MQTT server over WebSocket using server-factory
81
97
 
82
98
  ```js
83
- const aedes = require('aedes')()
84
- const { createServer } = require('aedes-server-factory')
99
+ import { Aedes } from 'aedes'
100
+ import { createServer } from 'aedes-server-factory'
85
101
  const port = 8888
86
102
 
103
+ const aedes = await Aedes.createBroker()
87
104
  const httpServer = createServer(aedes, { ws: true })
88
105
 
89
106
  httpServer.listen(port, function () {
@@ -0,0 +1,50 @@
1
+ # Migration
2
+
3
+ ## From 0.x to 1.x
4
+
5
+ Version 1.x changes the persistence interface from callback to async/await.
6
+ This also means that the startup of Aedes needs to be awaited to avoid race
7
+ conditions. 1.x also removed the default export to avoid mixups between old
8
+ and new behaviour.
9
+
10
+ ### ESM/Typescript
11
+
12
+ If you previously had code that looks like:
13
+
14
+ ```js
15
+ import aedes from 'aedes'
16
+ const broker = aedes(opts)
17
+ ```
18
+
19
+ You should replace it by:
20
+
21
+ ```js
22
+ import { Aedes } from 'aedes'
23
+ const broker = await Aedes.createBroker(opts)
24
+ ```
25
+
26
+ ### Commonjs
27
+
28
+ If you previously had code that looks like:
29
+
30
+ ```js
31
+ const aedes = require('aedes')
32
+ const broker = aedes(opts)
33
+ ```
34
+
35
+ You should replace it by:
36
+
37
+ ```js
38
+ const { Aedes } = require('aedes')
39
+ const broker = await Aedes.createBroker(opts)
40
+ ```
41
+
42
+ Make sure that the persistence interface that you use is recent enough so that
43
+ it supports the new async interface. Aedes will exit if it does not find an
44
+ async persistence interface.
45
+ The following versions are the minimum versions to use:
46
+
47
+ - aedes-persistence: 10.2.2
48
+ - aedes-persistence-level: 9.1.2
49
+ - aedes-persistence-mongodb: 9.3.1
50
+ - aedes-persistence-redis: 11.2.1
@@ -0,0 +1,8 @@
1
+ import neostandard from 'neostandard'
2
+ const ns = neostandard({ ts: true })
3
+ for (const item of ns) {
4
+ if (item?.languageOptions?.ecmaVersion < 2025) {
5
+ item.languageOptions.ecmaVersion = 2025
6
+ }
7
+ }
8
+ export default ns
package/example.js CHANGED
@@ -1,44 +1,55 @@
1
- 'use strict'
1
+ import net from 'node:net'
2
+ import http from 'node:http'
3
+ import { Aedes } from './aedes.js'
4
+ import ws from 'ws'
2
5
 
3
- const aedes = require('./aedes')()
4
- const server = require('net').createServer(aedes.handle)
5
- const httpServer = require('http').createServer()
6
- const ws = require('websocket-stream')
7
6
  const port = 1883
8
7
  const wsPort = 8888
9
8
 
10
- server.listen(port, function () {
11
- console.log('server listening on port', port)
12
- })
13
-
14
- ws.createServer({
15
- server: httpServer
16
- }, aedes.handle)
17
-
18
- httpServer.listen(wsPort, function () {
19
- console.log('websocket server listening on port', wsPort)
20
- })
21
-
22
- aedes.on('clientError', function (client, err) {
23
- console.log('client error', client.id, err.message, err.stack)
24
- })
25
-
26
- aedes.on('connectionError', function (client, err) {
27
- console.log('client error', client, err.message, err.stack)
28
- })
29
-
30
- aedes.on('publish', function (packet, client) {
31
- if (client) {
32
- console.log('message from client', client.id)
33
- }
34
- })
35
-
36
- aedes.on('subscribe', function (subscriptions, client) {
37
- if (client) {
38
- console.log('subscribe from client', subscriptions, client.id)
39
- }
40
- })
41
-
42
- aedes.on('client', function (client) {
43
- console.log('new client', client.id)
44
- })
9
+ async function startAedes () {
10
+ const aedes = await Aedes.createBroker()
11
+ const server = net.createServer(aedes.handle)
12
+ const httpServer = http.createServer()
13
+ server.listen(port, function () {
14
+ console.log('server listening on port', port)
15
+ })
16
+
17
+ const wss = new ws.WebSocketServer({
18
+ server: httpServer
19
+ })
20
+
21
+ wss.on('connection', (websocket, req) => {
22
+ const stream = ws.createWebSocketStream(websocket)
23
+ aedes.handle(stream, req)
24
+ })
25
+
26
+ httpServer.listen(wsPort, function () {
27
+ console.log('websocket server listening on port', wsPort)
28
+ })
29
+
30
+ aedes.on('clientError', function (client, err) {
31
+ console.log('client error', client.id, err.message, err.stack)
32
+ })
33
+
34
+ aedes.on('connectionError', function (client, err) {
35
+ console.log('client error', client, err.message, err.stack)
36
+ })
37
+
38
+ aedes.on('publish', function (packet, client) {
39
+ if (client) {
40
+ console.log('message from client', client.id)
41
+ }
42
+ })
43
+
44
+ aedes.on('subscribe', function (subscriptions, client) {
45
+ if (client) {
46
+ console.log('subscribe from client', subscriptions, client.id)
47
+ }
48
+ })
49
+
50
+ aedes.on('client', function (client) {
51
+ console.log('new client', client.id)
52
+ })
53
+ }
54
+
55
+ startAedes()
@@ -1,29 +1,34 @@
1
- const cluster = require('cluster')
2
- const Aedes = require('aedes')
3
- const { createServer } = require('net')
4
- const { cpus } = require('os')
1
+ import cluster from 'node:cluster'
2
+ import { createServer } from 'node:net'
3
+ import { cpus } from 'node:os'
4
+ import { Aedes } from '../../aedes.js'
5
5
  const MONGO_URL = 'mongodb://127.0.0.1/aedes-clusters'
6
6
 
7
- const mq = process.env.MQ === 'redis'
8
- ? require('mqemitter-redis')({
9
- port: process.env.REDIS_PORT || 6379
10
- })
11
- : require('mqemitter-mongodb')({
12
- url: MONGO_URL
13
- })
14
-
15
- const persistence = process.env.PERSISTENCE === 'redis'
16
- ? require('aedes-persistence-redis')({
17
- port: process.env.REDIS_PORT || 6379
18
- })
19
- : require('aedes-persistence-mongodb')({
20
- url: MONGO_URL
21
- })
7
+ async function importAndCall (mod, params) {
8
+ const imported = await import(mod)
9
+ return imported.default(params)
10
+ }
22
11
 
23
- function startAedes () {
12
+ async function startAedes () {
24
13
  const port = 1883
25
14
 
26
- const aedes = Aedes({
15
+ const mq = process.env.MQ === 'redis'
16
+ ? await importAndCall('mqemitter-redis', {
17
+ port: process.env.REDIS_PORT || 6379
18
+ })
19
+ : await importAndCall('mqemitter-mongodb', {
20
+ url: MONGO_URL
21
+ })
22
+
23
+ const persistence = process.env.PERSISTENCE === 'redis'
24
+ ? await importAndCall('aedes-persistence-redis', {
25
+ port: process.env.REDIS_PORT || 6379
26
+ })
27
+ : await importAndCall('aedes-persistence-mongodb', {
28
+ url: MONGO_URL
29
+ })
30
+
31
+ const aedes = await Aedes.createBroker({
27
32
  id: 'BROKER_' + cluster.worker.id,
28
33
  mq,
29
34
  persistence
@@ -43,12 +48,12 @@ function startAedes () {
43
48
 
44
49
  aedes.on('subscribe', function (subscriptions, client) {
45
50
  console.log('MQTT client \x1b[32m' + (client ? client.id : client) +
46
- '\x1b[0m subscribed to topics: ' + subscriptions.map(s => s.topic).join('\n'), 'from broker', aedes.id)
51
+ '\x1b[0m subscribed to topics: ' + subscriptions.map(s => s.topic).join('\n'), 'from broker', aedes.id)
47
52
  })
48
53
 
49
54
  aedes.on('unsubscribe', function (subscriptions, client) {
50
55
  console.log('MQTT client \x1b[32m' + (client ? client.id : client) +
51
- '\x1b[0m unsubscribed to topics: ' + subscriptions.join('\n'), 'from broker', aedes.id)
56
+ '\x1b[0m unsubscribed to topics: ' + subscriptions.join('\n'), 'from broker', aedes.id)
52
57
  })
53
58
 
54
59
  // fired when a client connects
@@ -2,17 +2,21 @@
2
2
  "name": "aedes_clusters",
3
3
  "version": "1.0.0",
4
4
  "description": "Testing Aedes Broker with clusters",
5
- "main": "index.js",
5
+ "type": "module",
6
+ "exports": "./index.js",
7
+ "engines": {
8
+ "node": ">=20"
9
+ },
6
10
  "scripts": {
7
11
  "test": "echo \"Error: no test specified\" && exit 1"
8
12
  },
9
13
  "author": "robertsLando",
10
14
  "license": "MIT",
11
15
  "dependencies": {
12
- "aedes": "^0.48.1",
13
- "aedes-persistence-mongodb": "^9.1.0",
14
- "aedes-persistence-redis": "^9.0.1",
15
- "mqemitter-mongodb": "^8.1.0",
16
- "mqemitter-redis": "^5.0.0"
16
+ "aedes": "^0.51.3",
17
+ "aedes-persistence-mongodb": "^9.3.1",
18
+ "aedes-persistence-redis": "^11.2.1",
19
+ "mqemitter-mongodb": "^9.0.1",
20
+ "mqemitter-redis": "^7.1.0"
17
21
  }
18
22
  }