@seriousme/opifex 1.9.3 → 1.10.1

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 (304) hide show
  1. package/README.md +37 -26
  2. package/bin/conformanceServer.ts +3 -2
  3. package/bin/demoServer.ts +3 -2
  4. package/bin/mqtt.ts +126 -117
  5. package/client/client.ts +35 -15
  6. package/client/context.ts +42 -22
  7. package/client/deps.ts +5 -0
  8. package/client/handlers/handleConnack.ts +17 -5
  9. package/client/handlers/handlePublish.ts +4 -1
  10. package/client/handlers/handlePubrec.ts +3 -1
  11. package/client/handlers/handlePubrel.ts +3 -1
  12. package/client/handlers/handleSuback.ts +3 -1
  13. package/client/mod.ts +8 -1
  14. package/client/store/memoryStore.ts +2 -1
  15. package/dev_utils/dummyConn.ts +17 -2
  16. package/dist/bin/conformanceServer.js +3 -2
  17. package/dist/bin/conformanceServer.js.map +1 -1
  18. package/dist/bin/demoServer.js +3 -2
  19. package/dist/bin/demoServer.js.map +1 -1
  20. package/dist/bin/mqtt.d.ts +29 -0
  21. package/dist/bin/mqtt.d.ts.map +1 -1
  22. package/dist/bin/mqtt.js +101 -96
  23. package/dist/bin/mqtt.js.map +1 -1
  24. package/dist/client/client.d.ts +7 -4
  25. package/dist/client/client.d.ts.map +1 -1
  26. package/dist/client/client.js +17 -9
  27. package/dist/client/client.js.map +1 -1
  28. package/dist/client/context.d.ts +3 -1
  29. package/dist/client/context.d.ts.map +1 -1
  30. package/dist/client/context.js +27 -13
  31. package/dist/client/context.js.map +1 -1
  32. package/dist/client/deps.d.ts +3 -2
  33. package/dist/client/deps.d.ts.map +1 -1
  34. package/dist/client/deps.js +2 -1
  35. package/dist/client/deps.js.map +1 -1
  36. package/dist/client/handlers/handleConnack.d.ts +1 -1
  37. package/dist/client/handlers/handleConnack.d.ts.map +1 -1
  38. package/dist/client/handlers/handleConnack.js +14 -5
  39. package/dist/client/handlers/handleConnack.js.map +1 -1
  40. package/dist/client/handlers/handlePublish.d.ts +1 -1
  41. package/dist/client/handlers/handlePublish.d.ts.map +1 -1
  42. package/dist/client/handlers/handlePublish.js +2 -0
  43. package/dist/client/handlers/handlePublish.js.map +1 -1
  44. package/dist/client/handlers/handlePubrec.d.ts +1 -1
  45. package/dist/client/handlers/handlePubrec.d.ts.map +1 -1
  46. package/dist/client/handlers/handlePubrec.js +1 -0
  47. package/dist/client/handlers/handlePubrec.js.map +1 -1
  48. package/dist/client/handlers/handlePubrel.d.ts +1 -1
  49. package/dist/client/handlers/handlePubrel.d.ts.map +1 -1
  50. package/dist/client/handlers/handlePubrel.js +1 -0
  51. package/dist/client/handlers/handlePubrel.js.map +1 -1
  52. package/dist/client/handlers/handleSuback.d.ts.map +1 -1
  53. package/dist/client/handlers/handleSuback.js +3 -1
  54. package/dist/client/handlers/handleSuback.js.map +1 -1
  55. package/dist/client/mod.d.ts +3 -1
  56. package/dist/client/mod.d.ts.map +1 -1
  57. package/dist/client/mod.js +2 -1
  58. package/dist/client/mod.js.map +1 -1
  59. package/dist/client/store/memoryStore.d.ts +1 -1
  60. package/dist/client/store/memoryStore.d.ts.map +1 -1
  61. package/dist/client/store/memoryStore.js.map +1 -1
  62. package/dist/mqttConn/mqttConn.d.ts +13 -8
  63. package/dist/mqttConn/mqttConn.d.ts.map +1 -1
  64. package/dist/mqttConn/mqttConn.js +27 -12
  65. package/dist/mqttConn/mqttConn.js.map +1 -1
  66. package/dist/mqttPacket/PacketType.d.ts +1 -0
  67. package/dist/mqttPacket/PacketType.d.ts.map +1 -1
  68. package/dist/mqttPacket/PacketType.js +1 -0
  69. package/dist/mqttPacket/PacketType.js.map +1 -1
  70. package/dist/mqttPacket/Properties.d.ts +157 -0
  71. package/dist/mqttPacket/Properties.d.ts.map +1 -0
  72. package/dist/mqttPacket/Properties.js +177 -0
  73. package/dist/mqttPacket/Properties.js.map +1 -0
  74. package/dist/mqttPacket/ReasonCode.d.ts +74 -0
  75. package/dist/mqttPacket/ReasonCode.d.ts.map +1 -0
  76. package/dist/mqttPacket/ReasonCode.js +230 -0
  77. package/dist/mqttPacket/ReasonCode.js.map +1 -0
  78. package/dist/mqttPacket/RetainHandling.d.ts +12 -0
  79. package/dist/mqttPacket/RetainHandling.d.ts.map +1 -0
  80. package/dist/mqttPacket/RetainHandling.js +12 -0
  81. package/dist/mqttPacket/RetainHandling.js.map +1 -0
  82. package/dist/mqttPacket/auth.d.ts +21 -0
  83. package/dist/mqttPacket/auth.d.ts.map +1 -0
  84. package/dist/mqttPacket/auth.js +34 -0
  85. package/dist/mqttPacket/auth.js.map +1 -0
  86. package/dist/mqttPacket/connack.d.ts +15 -7
  87. package/dist/mqttPacket/connack.d.ts.map +1 -1
  88. package/dist/mqttPacket/connack.js +43 -15
  89. package/dist/mqttPacket/connack.js.map +1 -1
  90. package/dist/mqttPacket/connect.d.ts +27 -8
  91. package/dist/mqttPacket/connect.d.ts.map +1 -1
  92. package/dist/mqttPacket/connect.js +106 -30
  93. package/dist/mqttPacket/connect.js.map +1 -1
  94. package/dist/mqttPacket/decoder.d.ts +42 -3
  95. package/dist/mqttPacket/decoder.d.ts.map +1 -1
  96. package/dist/mqttPacket/decoder.js +135 -4
  97. package/dist/mqttPacket/decoder.js.map +1 -1
  98. package/dist/mqttPacket/disconnect.d.ts +13 -7
  99. package/dist/mqttPacket/disconnect.d.ts.map +1 -1
  100. package/dist/mqttPacket/disconnect.js +45 -6
  101. package/dist/mqttPacket/disconnect.js.map +1 -1
  102. package/dist/mqttPacket/encoder.d.ts +57 -8
  103. package/dist/mqttPacket/encoder.d.ts.map +1 -1
  104. package/dist/mqttPacket/encoder.js +185 -13
  105. package/dist/mqttPacket/encoder.js.map +1 -1
  106. package/dist/mqttPacket/length.d.ts.map +1 -1
  107. package/dist/mqttPacket/length.js +3 -2
  108. package/dist/mqttPacket/length.js.map +1 -1
  109. package/dist/mqttPacket/mod.d.ts +56 -91
  110. package/dist/mqttPacket/mod.d.ts.map +1 -1
  111. package/dist/mqttPacket/mod.js +22 -22
  112. package/dist/mqttPacket/mod.js.map +1 -1
  113. package/dist/mqttPacket/pingreq.d.ts +4 -6
  114. package/dist/mqttPacket/pingreq.d.ts.map +1 -1
  115. package/dist/mqttPacket/pingreq.js +5 -4
  116. package/dist/mqttPacket/pingreq.js.map +1 -1
  117. package/dist/mqttPacket/pingres.d.ts +4 -6
  118. package/dist/mqttPacket/pingres.d.ts.map +1 -1
  119. package/dist/mqttPacket/pingres.js +7 -5
  120. package/dist/mqttPacket/pingres.js.map +1 -1
  121. package/dist/mqttPacket/protocolLevels.d.ts +11 -0
  122. package/dist/mqttPacket/protocolLevels.d.ts.map +1 -0
  123. package/dist/mqttPacket/protocolLevels.js +11 -0
  124. package/dist/mqttPacket/protocolLevels.js.map +1 -0
  125. package/dist/mqttPacket/pubblishAcks.d.ts +35 -0
  126. package/dist/mqttPacket/pubblishAcks.d.ts.map +1 -0
  127. package/dist/mqttPacket/pubblishAcks.js +56 -0
  128. package/dist/mqttPacket/pubblishAcks.js.map +1 -0
  129. package/dist/mqttPacket/publish.d.ts +19 -8
  130. package/dist/mqttPacket/publish.d.ts.map +1 -1
  131. package/dist/mqttPacket/publish.js +26 -7
  132. package/dist/mqttPacket/publish.js.map +1 -1
  133. package/dist/mqttPacket/suback.d.ts +14 -7
  134. package/dist/mqttPacket/suback.d.ts.map +1 -1
  135. package/dist/mqttPacket/suback.js +41 -20
  136. package/dist/mqttPacket/suback.js.map +1 -1
  137. package/dist/mqttPacket/subscribe.d.ts +24 -9
  138. package/dist/mqttPacket/subscribe.d.ts.map +1 -1
  139. package/dist/mqttPacket/subscribe.js +71 -15
  140. package/dist/mqttPacket/subscribe.js.map +1 -1
  141. package/dist/mqttPacket/types.d.ts +33 -0
  142. package/dist/mqttPacket/types.d.ts.map +1 -1
  143. package/dist/mqttPacket/unsuback.d.ts +14 -7
  144. package/dist/mqttPacket/unsuback.d.ts.map +1 -1
  145. package/dist/mqttPacket/unsuback.js +29 -6
  146. package/dist/mqttPacket/unsuback.js.map +1 -1
  147. package/dist/mqttPacket/unsubscribe.d.ts +14 -7
  148. package/dist/mqttPacket/unsubscribe.d.ts.map +1 -1
  149. package/dist/mqttPacket/unsubscribe.js +24 -8
  150. package/dist/mqttPacket/unsubscribe.js.map +1 -1
  151. package/dist/node/wrapNodeSocket.d.ts.map +1 -1
  152. package/dist/node/wrapNodeSocket.js.map +1 -1
  153. package/dist/persistence/deps.d.ts +1 -1
  154. package/dist/persistence/deps.d.ts.map +1 -1
  155. package/dist/persistence/deps.js +1 -1
  156. package/dist/persistence/deps.js.map +1 -1
  157. package/dist/server/context.d.ts +3 -1
  158. package/dist/server/context.d.ts.map +1 -1
  159. package/dist/server/context.js +8 -2
  160. package/dist/server/context.js.map +1 -1
  161. package/dist/server/deps.d.ts +2 -2
  162. package/dist/server/deps.d.ts.map +1 -1
  163. package/dist/server/deps.js +1 -1
  164. package/dist/server/deps.js.map +1 -1
  165. package/dist/server/handlers/handleConnect.d.ts +1 -1
  166. package/dist/server/handlers/handleConnect.d.ts.map +1 -1
  167. package/dist/server/handlers/handleConnect.js +9 -1
  168. package/dist/server/handlers/handleConnect.js.map +1 -1
  169. package/dist/server/handlers/handlePacket.d.ts +1 -1
  170. package/dist/server/handlers/handlePacket.d.ts.map +1 -1
  171. package/dist/server/handlers/handlePacket.js +1 -1
  172. package/dist/server/handlers/handlePacket.js.map +1 -1
  173. package/dist/server/handlers/handlePingreq.d.ts.map +1 -1
  174. package/dist/server/handlers/handlePingreq.js +1 -0
  175. package/dist/server/handlers/handlePingreq.js.map +1 -1
  176. package/dist/server/handlers/handlePublish.d.ts +2 -2
  177. package/dist/server/handlers/handlePublish.d.ts.map +1 -1
  178. package/dist/server/handlers/handlePublish.js +2 -0
  179. package/dist/server/handlers/handlePublish.js.map +1 -1
  180. package/dist/server/handlers/handlePubrec.d.ts +1 -1
  181. package/dist/server/handlers/handlePubrec.d.ts.map +1 -1
  182. package/dist/server/handlers/handlePubrec.js +1 -0
  183. package/dist/server/handlers/handlePubrec.js.map +1 -1
  184. package/dist/server/handlers/handlePubrel.d.ts +1 -1
  185. package/dist/server/handlers/handlePubrel.d.ts.map +1 -1
  186. package/dist/server/handlers/handlePubrel.js +1 -0
  187. package/dist/server/handlers/handlePubrel.js.map +1 -1
  188. package/dist/server/handlers/handleSubscribe.d.ts +1 -1
  189. package/dist/server/handlers/handleSubscribe.d.ts.map +1 -1
  190. package/dist/server/handlers/handleSubscribe.js +2 -1
  191. package/dist/server/handlers/handleSubscribe.js.map +1 -1
  192. package/dist/server/handlers/handleUnsubscribe.d.ts +1 -1
  193. package/dist/server/handlers/handleUnsubscribe.d.ts.map +1 -1
  194. package/dist/server/handlers/handleUnsubscribe.js +1 -0
  195. package/dist/server/handlers/handleUnsubscribe.js.map +1 -1
  196. package/dist/server/server.d.ts +2 -2
  197. package/dist/server/server.d.ts.map +1 -1
  198. package/dist/server/server.js +5 -3
  199. package/dist/server/server.js.map +1 -1
  200. package/dist/socket/socket.d.ts.map +1 -1
  201. package/dist/socket/socket.js +6 -1
  202. package/dist/socket/socket.js.map +1 -1
  203. package/dist/utils/assert.d.ts +0 -3
  204. package/dist/utils/assert.d.ts.map +1 -1
  205. package/dist/utils/assert.js +0 -7
  206. package/dist/utils/assert.js.map +1 -1
  207. package/dist/utils/mod.d.ts +0 -3
  208. package/dist/utils/mod.d.ts.map +1 -1
  209. package/dist/utils/mod.js +0 -2
  210. package/dist/utils/mod.js.map +1 -1
  211. package/mqttConn/mqttConn.test.ts +27 -12
  212. package/mqttConn/mqttConn.ts +45 -14
  213. package/mqttPacket/PacketType.ts +1 -0
  214. package/mqttPacket/Properties.ts +276 -0
  215. package/mqttPacket/ReasonCode.test.ts +22 -0
  216. package/mqttPacket/ReasonCode.ts +256 -0
  217. package/mqttPacket/RetainHandling.ts +11 -0
  218. package/mqttPacket/auth.test.ts +112 -0
  219. package/mqttPacket/auth.ts +72 -0
  220. package/mqttPacket/connack.test.ts +84 -64
  221. package/mqttPacket/connack.ts +84 -20
  222. package/mqttPacket/connect.test.ts +497 -18
  223. package/mqttPacket/connect.ts +167 -36
  224. package/mqttPacket/decoder.test.ts +33 -16
  225. package/mqttPacket/decoder.ts +173 -5
  226. package/mqttPacket/disconnect.test.ts +97 -18
  227. package/mqttPacket/disconnect.ts +82 -10
  228. package/mqttPacket/encoder.test.ts +32 -8
  229. package/mqttPacket/encoder.ts +236 -11
  230. package/mqttPacket/length.ts +3 -2
  231. package/mqttPacket/mod.ts +75 -32
  232. package/mqttPacket/pingreq.test.ts +52 -4
  233. package/mqttPacket/pingreq.ts +20 -7
  234. package/mqttPacket/pingres.test.ts +52 -4
  235. package/mqttPacket/pingres.ts +22 -8
  236. package/mqttPacket/properties.test.ts +193 -0
  237. package/mqttPacket/protocolLevels.ts +13 -0
  238. package/mqttPacket/pubblishAcks.ts +117 -0
  239. package/mqttPacket/publish.test.ts +212 -133
  240. package/mqttPacket/publish.ts +69 -14
  241. package/mqttPacket/publishAcks.test.ts +128 -0
  242. package/mqttPacket/suback.test.ts +71 -27
  243. package/mqttPacket/suback.ts +78 -26
  244. package/mqttPacket/subscribe.test.ts +132 -43
  245. package/mqttPacket/subscribe.ts +125 -22
  246. package/mqttPacket/types.ts +40 -0
  247. package/mqttPacket/unsuback.test.ts +80 -30
  248. package/mqttPacket/unsuback.ts +65 -10
  249. package/mqttPacket/unsubscribe.test.ts +59 -34
  250. package/mqttPacket/unsubscribe.ts +61 -14
  251. package/node/wrapNodeSocket.ts +2 -1
  252. package/package.json +2 -2
  253. package/persistence/deps.ts +1 -1
  254. package/persistence/memory/memoryPersistence.test.ts +5 -1
  255. package/server/context.ts +23 -10
  256. package/server/deps.ts +2 -0
  257. package/server/handlers/handleConnect.ts +12 -9
  258. package/server/handlers/handlePacket.ts +10 -11
  259. package/server/handlers/handlePingreq.ts +1 -0
  260. package/server/handlers/handlePublish.ts +6 -2
  261. package/server/handlers/handlePubrec.ts +3 -1
  262. package/server/handlers/handlePubrel.ts +3 -1
  263. package/server/handlers/handleSubscribe.ts +3 -6
  264. package/server/handlers/handleUnsubscribe.ts +3 -1
  265. package/server/server.ts +8 -12
  266. package/server/test/handleConnect.test.ts +2 -1
  267. package/server/test/test-handlers.ts +2 -1
  268. package/socket/socket.ts +5 -1
  269. package/utils/assert.ts +0 -18
  270. package/utils/mod.ts +0 -3
  271. package/dist/mqttPacket/puback.d.ts +0 -16
  272. package/dist/mqttPacket/puback.d.ts.map +0 -1
  273. package/dist/mqttPacket/puback.js +0 -21
  274. package/dist/mqttPacket/puback.js.map +0 -1
  275. package/dist/mqttPacket/pubcomp.d.ts +0 -17
  276. package/dist/mqttPacket/pubcomp.d.ts.map +0 -1
  277. package/dist/mqttPacket/pubcomp.js +0 -21
  278. package/dist/mqttPacket/pubcomp.js.map +0 -1
  279. package/dist/mqttPacket/pubrec.d.ts +0 -17
  280. package/dist/mqttPacket/pubrec.d.ts.map +0 -1
  281. package/dist/mqttPacket/pubrec.js +0 -21
  282. package/dist/mqttPacket/pubrec.js.map +0 -1
  283. package/dist/mqttPacket/pubrel.d.ts +0 -17
  284. package/dist/mqttPacket/pubrel.d.ts.map +0 -1
  285. package/dist/mqttPacket/pubrel.js +0 -21
  286. package/dist/mqttPacket/pubrel.js.map +0 -1
  287. package/dist/utils/args.d.ts +0 -28
  288. package/dist/utils/args.d.ts.map +0 -1
  289. package/dist/utils/args.js +0 -76
  290. package/dist/utils/args.js.map +0 -1
  291. package/dist/utils/platform.d.ts +0 -5
  292. package/dist/utils/platform.d.ts.map +0 -1
  293. package/dist/utils/platform.js +0 -8
  294. package/dist/utils/platform.js.map +0 -1
  295. package/mqttPacket/puback.test.ts +0 -55
  296. package/mqttPacket/puback.ts +0 -34
  297. package/mqttPacket/pubcomp.test.ts +0 -55
  298. package/mqttPacket/pubcomp.ts +0 -35
  299. package/mqttPacket/pubrec.test.ts +0 -55
  300. package/mqttPacket/pubrec.ts +0 -35
  301. package/mqttPacket/pubrel.test.ts +0 -55
  302. package/mqttPacket/pubrel.ts +0 -35
  303. package/utils/args.ts +0 -103
  304. package/utils/platform.ts +0 -8
@@ -2,12 +2,18 @@
2
2
  * @module mqttConn
3
3
  */
4
4
 
5
+ import type {
6
+ AnyPacket,
7
+ CodecOpts,
8
+ LengthDecoderResult,
9
+ ProtocolLevel,
10
+ } from "../mqttPacket/mod.ts";
11
+
5
12
  import {
6
- type AnyPacket,
7
13
  decodePayload,
8
14
  encode,
9
15
  getLengthDecoder,
10
- type LengthDecoderResult,
16
+ MQTTLevel,
11
17
  } from "../mqttPacket/mod.ts";
12
18
 
13
19
  import { assert } from "../utils/mod.ts";
@@ -23,6 +29,8 @@ export const MqttConnError = {
23
29
  UnexpectedEof: "Unexpected EOF",
24
30
  } as const;
25
31
 
32
+ const DEFAULT_MAX_PACKETSIZE = 2 * 1024 * 1024; // 2MB
33
+
26
34
  /**
27
35
  * Interface for MQTT connection handling
28
36
  */
@@ -74,13 +82,13 @@ async function readFull(conn: Conn, buf: Uint8Array): Promise<void> {
74
82
  /**
75
83
  * Read a complete MQTT packet from the connection
76
84
  * @param conn Connection to read from
77
- * @param maxPacketSize Maximum allowed packet size
85
+ * @param maxIncomingPacketSize Maximum allowed packet size
78
86
  * @returns Decoded MQTT packet
79
87
  * @throws Error if packet is invalid or too large
80
88
  */
81
89
  export async function readPacket(
82
90
  conn: Conn,
83
- maxPacketSize: number,
91
+ codecOpts: CodecOpts,
84
92
  ): Promise<AnyPacket> {
85
93
  // fixed header is 1 byte of type + flags
86
94
  // + a maximum of 4 bytes to encode the remaining length
@@ -93,11 +101,15 @@ export async function readPacket(
93
101
  } while (!result.done);
94
102
 
95
103
  const remainingLength = result.length;
96
- assert(remainingLength < maxPacketSize - 1, MqttConnError.packetTooLarge);
104
+ const maxIncomingPacketSize = codecOpts.maxIncomingPacketSize;
105
+ assert(
106
+ remainingLength < maxIncomingPacketSize - 1,
107
+ MqttConnError.packetTooLarge,
108
+ );
97
109
  const packetBuf = new Uint8Array(remainingLength);
98
110
  // read the rest of the packet
99
111
  await readFull(conn, packetBuf);
100
- const packet = decodePayload(firstByte, packetBuf);
112
+ const packet = decodePayload(firstByte, packetBuf, codecOpts);
101
113
  assert(packet !== null, MqttConnError.UnexpectedEof);
102
114
  return packet;
103
115
  }
@@ -108,8 +120,8 @@ export async function readPacket(
108
120
  export class MqttConn implements IMqttConn {
109
121
  /** Underlying connection */
110
122
  readonly conn: Conn;
111
- /** Maximum allowed packet size */
112
- private readonly maxPacketSize: number;
123
+ /** codecOpts */
124
+ codecOpts: CodecOpts;
113
125
  /** Reason for connection closure if any */
114
126
  private _reason: string | undefined = undefined;
115
127
  /** Whether connection is closed */
@@ -119,17 +131,25 @@ export class MqttConn implements IMqttConn {
119
131
  * Create new MQTT connection
120
132
  * @param options Connection options
121
133
  * @param options.conn Underlying socket connection
122
- * @param options.maxPacketSize Maximum allowed packet size (default 2MB)
134
+ * @param options.maxIncomingPacketSize Maximum allowed incoming packet size (default 2MB)
135
+ * @param options.maxOutGoingPacketSize Maximum allowed outgoing packet size (default 2MB)
136
+ * @param options.protocolLevel Supported protocolLevel
123
137
  */
124
138
  constructor({
125
139
  conn,
126
- maxPacketSize,
140
+ maxIncomingPacketSize = DEFAULT_MAX_PACKETSIZE,
141
+ protocolLevel = MQTTLevel.unknown,
127
142
  }: {
128
143
  conn: SockConn;
129
- maxPacketSize?: number;
144
+ maxIncomingPacketSize?: number;
145
+ protocolLevel?: ProtocolLevel;
130
146
  }) {
131
147
  this.conn = new Conn(conn);
132
- this.maxPacketSize = maxPacketSize || 2 * 1024 * 1024;
148
+ this.codecOpts = {
149
+ maxIncomingPacketSize,
150
+ maxOutgoingPacketSize: maxIncomingPacketSize,
151
+ protocolLevel,
152
+ };
133
153
  }
134
154
 
135
155
  /** Get reason for connection closure */
@@ -137,6 +157,14 @@ export class MqttConn implements IMqttConn {
137
157
  return this._reason;
138
158
  }
139
159
 
160
+ /** Get remoteAdress */
161
+ get remoteAddress(): string {
162
+ if (this.conn.remoteAddr?.transport === "tcp") {
163
+ return this.conn.remoteAddr.hostname;
164
+ }
165
+ return "unknown";
166
+ }
167
+
140
168
  /**
141
169
  * Async iterator for receiving packets
142
170
  * @yields MQTT packets
@@ -144,7 +172,10 @@ export class MqttConn implements IMqttConn {
144
172
  async *[Symbol.asyncIterator](): AsyncIterableIterator<AnyPacket> {
145
173
  while (!this._isClosed) {
146
174
  try {
147
- yield await readPacket(this.conn, this.maxPacketSize);
175
+ yield await readPacket(
176
+ this.conn,
177
+ this.codecOpts,
178
+ );
148
179
  } catch (err) {
149
180
  if (err instanceof Error) {
150
181
  if (err.name === "PartialReadError") {
@@ -165,7 +196,7 @@ export class MqttConn implements IMqttConn {
165
196
  */
166
197
  async send(data: AnyPacket): Promise<void> {
167
198
  try {
168
- await this.conn.write(encode(data));
199
+ await this.conn.write(encode(data, this.codecOpts));
169
200
  } catch (err) {
170
201
  if (err instanceof Error) {
171
202
  this._reason = err.message;
@@ -17,6 +17,7 @@ export const PacketType = {
17
17
  pingreq: 12,
18
18
  pingres: 13,
19
19
  disconnect: 14,
20
+ auth: 15,
20
21
  } as const;
21
22
 
22
23
  /**
@@ -0,0 +1,276 @@
1
+ import { PacketType } from "./PacketType.ts";
2
+ import type { InvertRecord, UTF8StringPair } from "./types.ts";
3
+
4
+ export const PropertySetType = {
5
+ ...PacketType,
6
+ will: 100,
7
+ } as const;
8
+
9
+ export type TPropertySetType =
10
+ typeof PropertySetType[keyof typeof PropertySetType];
11
+
12
+ export const propertyKind = {
13
+ boolean: 0, // its a byte in the MQTT standard, but for convenience we convert to boolean
14
+ byte: 1,
15
+ int16: 2,
16
+ int32: 3,
17
+ varInt: 4,
18
+ byteArray: 5,
19
+ utf8string: 6,
20
+ utf8StringPairs: 7,
21
+ varIntArray: 8,
22
+ } as const;
23
+
24
+ export const propertyToId = {
25
+ payloadFormatIndicator: 0x01,
26
+ messageExpiryInterval: 0x02,
27
+ contentType: 0x03,
28
+ responseTopic: 0x08,
29
+ correlationData: 0x09,
30
+ subscriptionIdentifier: 0x0b,
31
+ // special case,placeholder to encode decode multiple subscription identifiers
32
+ subscriptionIdentifiers: 0xff,
33
+ sessionExpiryInterval: 0x11,
34
+ assignedClientIdentifier: 0x12,
35
+ serverKeepAlive: 0x13,
36
+ authenticationMethod: 0x15,
37
+ authenticationData: 0x16,
38
+ requestProblemInformation: 0x17,
39
+ willDelayInterval: 0x18,
40
+ requestResponseInformation: 0x19,
41
+ responseInformation: 0x1a,
42
+ serverReference: 0x1c,
43
+ reasonString: 0x1f,
44
+ receiveMaximum: 0x21,
45
+ topicAliasMaximum: 0x22,
46
+ topicAlias: 0x23,
47
+ maximumQos: 0x24,
48
+ retainAvailable: 0x25,
49
+ userProperty: 0x26,
50
+ maximumPacketSize: 0x27,
51
+ wildcardSubscriptionAvailable: 0x28,
52
+ subscriptionIdentifierAvailable: 0x29,
53
+ sharedSubscriptionAvailable: 0x2a,
54
+ } as const;
55
+
56
+ type PropertyNames = keyof typeof propertyToId;
57
+ // A helper type to convert a tuple of numbers to a union of strings
58
+
59
+ export const propertyToKind = {
60
+ [propertyToId.payloadFormatIndicator]: propertyKind.boolean,
61
+ [propertyToId.messageExpiryInterval]: propertyKind.int32,
62
+ [propertyToId.contentType]: propertyKind.utf8string,
63
+ [propertyToId.responseTopic]: propertyKind.utf8string,
64
+ [propertyToId.correlationData]: propertyKind.byteArray,
65
+ [propertyToId.subscriptionIdentifier]: propertyKind.varInt,
66
+ [propertyToId.subscriptionIdentifiers]: propertyKind.varIntArray,
67
+ [propertyToId.sessionExpiryInterval]: propertyKind.int32,
68
+ [propertyToId.assignedClientIdentifier]: propertyKind.utf8string,
69
+ [propertyToId.serverKeepAlive]: propertyKind.int16,
70
+ [propertyToId.authenticationMethod]: propertyKind.utf8string,
71
+ [propertyToId.authenticationData]: propertyKind.byteArray,
72
+ [propertyToId.requestProblemInformation]: propertyKind.boolean,
73
+ [propertyToId.willDelayInterval]: propertyKind.int32,
74
+ [propertyToId.requestResponseInformation]: propertyKind.boolean,
75
+ [propertyToId.responseInformation]: propertyKind.utf8string,
76
+ [propertyToId.serverReference]: propertyKind.utf8string,
77
+ [propertyToId.reasonString]: propertyKind.utf8string,
78
+ [propertyToId.receiveMaximum]: propertyKind.int16,
79
+ [propertyToId.topicAliasMaximum]: propertyKind.int16,
80
+ [propertyToId.topicAlias]: propertyKind.int16,
81
+ [propertyToId.maximumQos]: propertyKind.byte,
82
+ [propertyToId.retainAvailable]: propertyKind.boolean,
83
+ [propertyToId.userProperty]: propertyKind.utf8StringPairs,
84
+ [propertyToId.maximumPacketSize]: propertyKind.int32,
85
+ [propertyToId.wildcardSubscriptionAvailable]: propertyKind.boolean,
86
+ [propertyToId.subscriptionIdentifierAvailable]: propertyKind.boolean,
87
+ [propertyToId.sharedSubscriptionAvailable]: propertyKind.boolean,
88
+ } as const;
89
+
90
+ export type UserPropertyType = Array<UTF8StringPair>;
91
+ export type SubscriptionIdentifiersType = Array<number>;
92
+
93
+ type PropertyKindMap = {
94
+ [propertyKind.boolean]: boolean;
95
+ [propertyKind.byte]: number;
96
+ [propertyKind.int16]: number;
97
+ [propertyKind.int32]: number;
98
+ [propertyKind.varInt]: number;
99
+ [propertyKind.byteArray]: Uint8Array;
100
+ [propertyKind.utf8string]: string;
101
+ [propertyKind.utf8StringPairs]: UserPropertyType;
102
+ [propertyKind.varIntArray]: SubscriptionIdentifiersType;
103
+ };
104
+
105
+ type Mqttv5PropertyType<K extends number> = K extends keyof PropertyKindMap
106
+ ? PropertyKindMap[K]
107
+ : never;
108
+
109
+ export type Mqttv5PropertyTypes = PropertyKindMap[keyof PropertyKindMap];
110
+ export type Mqttv5PropertyTypesNoUser = Exclude<
111
+ Mqttv5PropertyTypes,
112
+ UserPropertyType
113
+ >;
114
+
115
+ // First, create a type for all valid property numbers
116
+ export type ValidPropertyNumber =
117
+ (typeof propertyToId)[keyof typeof propertyToId];
118
+ // Then, create a mapped type that iterates over the property names
119
+ // and uses propertyToKind to look up the correct TypeScript type.
120
+
121
+ type AllMqttv5Properties = {
122
+ [K in PropertyNames]?: Mqttv5PropertyType<
123
+ typeof propertyToKind[typeof propertyToId[K]]
124
+ >;
125
+ };
126
+
127
+ type PropertyByNumberType = InvertRecord<typeof propertyToId>;
128
+
129
+ export const propertyByNumber = Object.fromEntries(
130
+ Object.entries(propertyToId).map(
131
+ ([k, v]) => [v, k],
132
+ ),
133
+ ) as PropertyByNumberType;
134
+
135
+ export const PropertyByPropertySetType = {
136
+ [PropertySetType.reserved]: [],
137
+ [PropertySetType.connect]: [
138
+ propertyToId.sessionExpiryInterval,
139
+ propertyToId.authenticationMethod,
140
+ propertyToId.authenticationData,
141
+ propertyToId.requestProblemInformation,
142
+ propertyToId.requestResponseInformation,
143
+ propertyToId.receiveMaximum,
144
+ propertyToId.topicAliasMaximum,
145
+ propertyToId.userProperty,
146
+ propertyToId.maximumPacketSize,
147
+ ],
148
+ [PropertySetType.connack]: [
149
+ propertyToId.sessionExpiryInterval,
150
+ propertyToId.assignedClientIdentifier,
151
+ propertyToId.serverKeepAlive,
152
+ propertyToId.authenticationMethod,
153
+ propertyToId.authenticationData,
154
+ propertyToId.responseInformation,
155
+ propertyToId.serverReference,
156
+ propertyToId.reasonString,
157
+ propertyToId.receiveMaximum,
158
+ propertyToId.topicAliasMaximum,
159
+ propertyToId.maximumQos,
160
+ propertyToId.retainAvailable,
161
+ propertyToId.userProperty,
162
+ propertyToId.maximumPacketSize,
163
+ propertyToId.wildcardSubscriptionAvailable,
164
+ propertyToId.subscriptionIdentifierAvailable,
165
+ propertyToId.sharedSubscriptionAvailable,
166
+ ],
167
+ [PropertySetType.publish]: [
168
+ propertyToId.payloadFormatIndicator,
169
+ propertyToId.messageExpiryInterval,
170
+ propertyToId.contentType,
171
+ propertyToId.responseTopic,
172
+ propertyToId.correlationData,
173
+ propertyToId.subscriptionIdentifiers,
174
+ propertyToId.topicAlias,
175
+ propertyToId.userProperty,
176
+ ],
177
+ [PropertySetType.subscribe]: [
178
+ propertyToId.subscriptionIdentifier,
179
+ propertyToId.userProperty,
180
+ ],
181
+ [PropertySetType.unsubscribe]: [
182
+ propertyToId.userProperty,
183
+ ],
184
+
185
+ [PropertySetType.disconnect]: [
186
+ propertyToId.sessionExpiryInterval,
187
+ propertyToId.serverReference,
188
+ propertyToId.reasonString,
189
+ propertyToId.userProperty,
190
+ ],
191
+ [PropertySetType.auth]: [
192
+ propertyToId.authenticationMethod,
193
+ propertyToId.authenticationData,
194
+ propertyToId.reasonString,
195
+ propertyToId.userProperty,
196
+ ],
197
+ [PropertySetType.puback]: [
198
+ propertyToId.reasonString,
199
+ propertyToId.userProperty,
200
+ ],
201
+ [PropertySetType.pubrec]: [
202
+ propertyToId.reasonString,
203
+ propertyToId.userProperty,
204
+ ],
205
+ [PropertySetType.pubrel]: [
206
+ propertyToId.reasonString,
207
+ propertyToId.userProperty,
208
+ ],
209
+ [PropertySetType.pubcomp]: [
210
+ propertyToId.reasonString,
211
+ propertyToId.userProperty,
212
+ ],
213
+ [PropertySetType.suback]: [
214
+ propertyToId.reasonString,
215
+ propertyToId.userProperty,
216
+ ],
217
+ [PropertySetType.unsuback]: [
218
+ propertyToId.reasonString,
219
+ propertyToId.userProperty,
220
+ ],
221
+ [PropertySetType.pingreq]: [],
222
+ [PropertySetType.pingres]: [],
223
+
224
+ [PropertySetType.will]: [
225
+ propertyToId.payloadFormatIndicator,
226
+ propertyToId.messageExpiryInterval,
227
+ propertyToId.contentType,
228
+ propertyToId.responseTopic,
229
+ propertyToId.correlationData,
230
+ propertyToId.willDelayInterval,
231
+ propertyToId.userProperty,
232
+ ],
233
+ } as const;
234
+
235
+ // helper types
236
+ type PropertyIdsToKeys<T extends readonly ValidPropertyNumber[]> = {
237
+ [K in T[number]]: (typeof propertyByNumber)[K];
238
+ }[T[number]];
239
+
240
+ // from AllMqttv5Properties pick the ones returned by PropertyIdsToKeys for this type
241
+ type GeneratePacketTypeProperties<T extends readonly ValidPropertyNumber[]> =
242
+ Pick<AllMqttv5Properties, PropertyIdsToKeys<T>>;
243
+
244
+ export type PropsByPacketSetType = {
245
+ [K in TPropertySetType]: GeneratePacketTypeProperties<
246
+ typeof PropertyByPropertySetType[K]
247
+ >;
248
+ };
249
+
250
+ // props per PacketType
251
+ export type ConnectProperties =
252
+ PropsByPacketSetType[typeof PropertySetType.connect];
253
+ export type ConnackProperties =
254
+ PropsByPacketSetType[typeof PropertySetType.connack];
255
+ export type PublishProperties =
256
+ PropsByPacketSetType[typeof PropertySetType.publish];
257
+ export type PubackProperties =
258
+ PropsByPacketSetType[typeof PropertySetType.puback];
259
+ export type PubrecProperties =
260
+ PropsByPacketSetType[typeof PropertySetType.pubrec];
261
+ export type PubrelProperties =
262
+ PropsByPacketSetType[typeof PropertySetType.pubrel];
263
+ export type PubcompProperties =
264
+ PropsByPacketSetType[typeof PropertySetType.pubcomp];
265
+ export type SubscribeProperties =
266
+ PropsByPacketSetType[typeof PropertySetType.subscribe];
267
+ export type SubackProperties =
268
+ PropsByPacketSetType[typeof PropertySetType.suback];
269
+ export type UnsubscribeProperties =
270
+ PropsByPacketSetType[typeof PropertySetType.unsubscribe];
271
+ export type UnsubackProperties =
272
+ PropsByPacketSetType[typeof PropertySetType.unsuback];
273
+ export type DisconnectProperties =
274
+ PropsByPacketSetType[typeof PropertySetType.disconnect];
275
+ export type AuthProperties = PropsByPacketSetType[typeof PropertySetType.auth];
276
+ export type WillProperties = PropsByPacketSetType[typeof PropertySetType.will];
@@ -0,0 +1,22 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { ReasonCode, reasonCodeToString } from "./ReasonCode.ts";
4
+ import { PacketType } from "./mod.ts";
5
+
6
+ test("lookup of reason codes works", () => {
7
+ assert.equal(
8
+ reasonCodeToString(PacketType.connect, ReasonCode.success),
9
+ "Success",
10
+ "Succes on Connect works",
11
+ );
12
+ assert.equal(
13
+ reasonCodeToString(PacketType.suback, ReasonCode.success),
14
+ "Granted QoS 0",
15
+ "Granted QoS 0 on Suback works",
16
+ );
17
+ assert.equal(
18
+ reasonCodeToString(PacketType.disconnect, ReasonCode.success),
19
+ "Normal disconnection",
20
+ "Normal disconnection on Disconnect works",
21
+ );
22
+ });
@@ -0,0 +1,256 @@
1
+ /**
2
+ * Possible MQTT V5 reason codes
3
+ */
4
+
5
+ import { PacketType } from "./PacketType.ts";
6
+ import type { InvertRecord } from "./types.ts";
7
+
8
+ export const ReasonCode = {
9
+ success: 0x00,
10
+ normalDisconnection: 0x00,
11
+ grantedQos0: 0x00,
12
+ grantedQos1: 0x01,
13
+ grantedQos2: 0x02,
14
+ disconnectWithWillMessage: 0x04,
15
+ noMatchingSubscribers: 0x10,
16
+ noSubscriptionExisted: 0x11,
17
+ continueAuthentication: 0x18,
18
+ reAuthenticate: 0x19,
19
+ unspecifiedError: 0x80,
20
+ malformedPacket: 0x81,
21
+ protocolError: 0x82,
22
+ implementationSpecificError: 0x83,
23
+ unsupportedProtocolVersion: 0x84,
24
+ clientIdentifierNotValid: 0x85,
25
+ badUserNameOrPassword: 0x86,
26
+ notAuthorized: 0x87,
27
+ serverUnavailable: 0x88,
28
+ serverBusy: 0x89,
29
+ banned: 0x8a,
30
+ serverShuttingDown: 0x8b,
31
+ badAuthenticationMethod: 0x8c,
32
+ keepAliveTimeout: 0x8d,
33
+ sessionTakenOver: 0x8e,
34
+ topicFilterInvalid: 0x8f,
35
+ topicNameInvalid: 0x90,
36
+ packetIdentifierInUse: 0x91,
37
+ packetIdentifierNotFound: 0x92,
38
+ receiveMaximumExceeded: 0x93,
39
+ topicAliasInvalid: 0x94,
40
+ packetTooLarge: 0x95,
41
+ messageRateTooHigh: 0x96,
42
+ quotaExceeded: 0x97,
43
+ administrativeAction: 0x98,
44
+ payloadFormatInvalid: 0x99,
45
+ retainNotSupported: 0x9a,
46
+ qosNotSupported: 0x9b,
47
+ useAnotherServer: 0x9c,
48
+ serverMoved: 0x9d,
49
+ sharedSubscriptionsNotSupported: 0x9e,
50
+ connectionRateExceeded: 0x9f,
51
+ maximumConnectTime: 0xa0,
52
+ subscriptionIdentifiersNotSupported: 0xa1,
53
+ wildcardSubscriptionsNotSupported: 0xa2,
54
+ } as const;
55
+
56
+ /**
57
+ * Reverse lookup for ReasonCode
58
+ */
59
+
60
+ export type ReasonCodeByNumberType = InvertRecord<typeof ReasonCode>;
61
+ export const ReasonCodeByNumber = Object
62
+ .fromEntries(
63
+ Object.entries(ReasonCode).map(([k, v]) => [v, k]),
64
+ ) as ReasonCodeByNumberType;
65
+
66
+ export const ReasonCodebyPacket = {
67
+ [PacketType.connack]: [
68
+ ReasonCode.success,
69
+ ReasonCode.unspecifiedError,
70
+ ReasonCode.malformedPacket,
71
+ ReasonCode.protocolError,
72
+ ReasonCode.implementationSpecificError,
73
+ ReasonCode.unsupportedProtocolVersion,
74
+ ReasonCode.clientIdentifierNotValid,
75
+ ReasonCode.badUserNameOrPassword,
76
+ ReasonCode.notAuthorized,
77
+ ReasonCode.serverUnavailable,
78
+ ReasonCode.serverBusy,
79
+ ReasonCode.banned,
80
+ ReasonCode.badAuthenticationMethod,
81
+ ReasonCode.topicNameInvalid,
82
+ ReasonCode.packetTooLarge,
83
+ ReasonCode.quotaExceeded,
84
+ ReasonCode.payloadFormatInvalid,
85
+ ReasonCode.retainNotSupported,
86
+ ReasonCode.qosNotSupported,
87
+ ReasonCode.useAnotherServer,
88
+ ReasonCode.serverMoved,
89
+ ReasonCode.connectionRateExceeded,
90
+ ],
91
+ [PacketType.puback]: [
92
+ ReasonCode.success,
93
+ ReasonCode.noMatchingSubscribers,
94
+ ReasonCode.unspecifiedError,
95
+ ReasonCode.implementationSpecificError,
96
+ ReasonCode.notAuthorized,
97
+ ReasonCode.topicNameInvalid,
98
+ ReasonCode.packetIdentifierInUse,
99
+ ReasonCode.quotaExceeded,
100
+ ReasonCode.payloadFormatInvalid,
101
+ ],
102
+ [PacketType.pubrec]: [
103
+ ReasonCode.success,
104
+ ReasonCode.noMatchingSubscribers,
105
+ ReasonCode.unspecifiedError,
106
+ ReasonCode.implementationSpecificError,
107
+ ReasonCode.notAuthorized,
108
+ ReasonCode.topicNameInvalid,
109
+ ReasonCode.packetIdentifierInUse,
110
+ ReasonCode.quotaExceeded,
111
+ ReasonCode.payloadFormatInvalid,
112
+ ],
113
+ [PacketType.pubrel]: [
114
+ ReasonCode.success,
115
+ ReasonCode.packetIdentifierNotFound,
116
+ ],
117
+ [PacketType.pubcomp]: [
118
+ ReasonCode.success,
119
+ ReasonCode.packetIdentifierNotFound,
120
+ ],
121
+ [PacketType.unsuback]: [
122
+ ReasonCode.success,
123
+ ReasonCode.noSubscriptionExisted,
124
+ ReasonCode.unspecifiedError,
125
+ ReasonCode.implementationSpecificError,
126
+ ReasonCode.notAuthorized,
127
+ ReasonCode.topicFilterInvalid,
128
+ ReasonCode.packetIdentifierInUse,
129
+ ],
130
+ [PacketType.auth]: [
131
+ ReasonCode.success,
132
+ ReasonCode.continueAuthentication,
133
+ ReasonCode.reAuthenticate,
134
+ ],
135
+ [PacketType.disconnect]: [
136
+ ReasonCode.normalDisconnection,
137
+ ReasonCode.disconnectWithWillMessage,
138
+ ReasonCode.unspecifiedError,
139
+ ReasonCode.malformedPacket,
140
+ ReasonCode.protocolError,
141
+ ReasonCode.implementationSpecificError,
142
+ ReasonCode.notAuthorized,
143
+ ReasonCode.serverBusy,
144
+ ReasonCode.serverShuttingDown,
145
+ ReasonCode.badAuthenticationMethod,
146
+ ReasonCode.keepAliveTimeout,
147
+ ReasonCode.sessionTakenOver,
148
+ ReasonCode.topicFilterInvalid,
149
+ ReasonCode.topicNameInvalid,
150
+ ReasonCode.receiveMaximumExceeded,
151
+ ReasonCode.topicAliasInvalid,
152
+ ReasonCode.packetTooLarge,
153
+ ReasonCode.messageRateTooHigh,
154
+ ReasonCode.quotaExceeded,
155
+ ReasonCode.administrativeAction,
156
+ ReasonCode.payloadFormatInvalid,
157
+ ReasonCode.retainNotSupported,
158
+ ReasonCode.qosNotSupported,
159
+ ReasonCode.useAnotherServer,
160
+ ReasonCode.serverMoved,
161
+ ReasonCode.sharedSubscriptionsNotSupported,
162
+ ReasonCode.connectionRateExceeded,
163
+ ReasonCode.maximumConnectTime,
164
+ ReasonCode.subscriptionIdentifiersNotSupported,
165
+ ReasonCode.wildcardSubscriptionsNotSupported,
166
+ ],
167
+ [PacketType.suback]: [
168
+ ReasonCode.grantedQos0,
169
+ ReasonCode.grantedQos1,
170
+ ReasonCode.grantedQos2,
171
+ ReasonCode.unspecifiedError,
172
+ ReasonCode.implementationSpecificError,
173
+ ReasonCode.notAuthorized,
174
+ ReasonCode.topicFilterInvalid,
175
+ ReasonCode.packetIdentifierInUse,
176
+ ReasonCode.quotaExceeded,
177
+ ReasonCode.sharedSubscriptionsNotSupported,
178
+ ReasonCode.subscriptionIdentifiersNotSupported,
179
+ ReasonCode.wildcardSubscriptionsNotSupported,
180
+ ],
181
+ } as const;
182
+
183
+ const reasonCodesToString = {
184
+ [0x00]: "Success",
185
+ [0x01]: "Granted QoS 1",
186
+ [0x02]: "Granted QoS 2",
187
+ [0x04]: "Disconnect with Will Message",
188
+ [0x10]: "No matching subscribers",
189
+ [0x11]: "No subscription existed",
190
+ [0x18]: "Continue authentication",
191
+ [0x19]: "Re-authenticate",
192
+ [0x80]: "Unspecified error",
193
+ [0x81]: "Malformed Packet",
194
+ [0x82]: "Protocol Error",
195
+ [0x83]: "Implementation specific error",
196
+ [0x84]: "Unsupported Protocol Version",
197
+ [0x85]: "Client Identifier not valid",
198
+ [0x86]: "Bad User Name or Password",
199
+ [0x87]: "Not authorized",
200
+ [0x88]: "Server unavailable",
201
+ [0x89]: "Server busy",
202
+ [0x8a]: "Banned",
203
+ [0x8b]: "Server shutting down",
204
+ [0x8c]: "Bad authentication method",
205
+ [0x8d]: "Keep Alive timeout",
206
+ [0x8e]: "Session taken over",
207
+ [0x8f]: "Topic Filter invalid",
208
+ [0x90]: "Topic Name invalid",
209
+ [0x91]: "Packet Identifier in use",
210
+ [0x92]: "Packet Identifier not found",
211
+ [0x93]: "Receive Maximum exceeded",
212
+ [0x94]: "Topic Alias invalid",
213
+ [0x95]: "Packet too large",
214
+ [0x96]: "Message rate too high",
215
+ [0x97]: "Quota exceeded",
216
+ [0x98]: "Administrative action",
217
+ [0x99]: "Payload format invalid",
218
+ [0x9a]: "Retain not supported",
219
+ [0x9b]: "QoS not supported",
220
+ [0x9c]: "Use another server",
221
+ [0x9d]: "Server moved",
222
+ [0x9e]: "Shared Subscriptions not supported",
223
+ [0x9f]: "Connection rate exceeded",
224
+ [0xa0]: "Maximum connect time",
225
+ [0xa1]: "Subscription Identifiers not supported",
226
+ [0xa2]: "Wildcard Subscriptions not supported",
227
+ } as const;
228
+
229
+ // Can't import this from types as this would create an import loop
230
+ type TPacketType = typeof PacketType[keyof typeof PacketType];
231
+ export type TReasonCode = typeof ReasonCode[keyof typeof ReasonCode];
232
+ type TReasonCodeByPacket = keyof typeof ReasonCodebyPacket;
233
+
234
+ export function reasonCodeToString(
235
+ packetType: TPacketType,
236
+ code: TReasonCode,
237
+ ): string {
238
+ if (code === 0) {
239
+ if (packetType === PacketType.disconnect) {
240
+ return "Normal disconnection";
241
+ }
242
+ if (packetType === PacketType.suback) {
243
+ return "Granted QoS 0";
244
+ }
245
+ }
246
+ return reasonCodesToString[code];
247
+ }
248
+
249
+ export function isValidReasonCode(
250
+ packetType: TPacketType,
251
+ code: number,
252
+ ): boolean {
253
+ const validReasonCodes =
254
+ ReasonCodebyPacket[packetType as TReasonCodeByPacket] as readonly number[];
255
+ return validReasonCodes.includes(code);
256
+ }