@seriousme/opifex 1.11.2 → 2.0.3

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 (538) hide show
  1. package/LICENSE.txt +1 -1
  2. package/README.md +102 -43
  3. package/bin/conformanceServer.ts +45 -13
  4. package/bin/demoServer.ts +38 -13
  5. package/bin/mqtt.ts +52 -30
  6. package/client/ConnectionState.ts +2 -0
  7. package/client/client.ts +57 -47
  8. package/client/context.ts +75 -21
  9. package/client/deps.ts +5 -0
  10. package/client/handlers/handleAuth.test.ts +193 -0
  11. package/client/handlers/handleAuth.ts +89 -0
  12. package/client/handlers/handleConnack.test.ts +173 -0
  13. package/client/handlers/handleConnack.ts +16 -6
  14. package/client/handlers/handleDisconnect.test.ts +22 -0
  15. package/client/handlers/handleDisconnect.ts +17 -0
  16. package/client/handlers/handlePacket.test.ts +242 -0
  17. package/client/handlers/handlePacket.ts +19 -5
  18. package/client/handlers/handlePuback.test.ts +99 -0
  19. package/client/handlers/handlePuback.ts +6 -0
  20. package/client/handlers/handlePubcomp.test.ts +112 -0
  21. package/client/handlers/handlePubcomp.ts +5 -0
  22. package/client/handlers/handlePublish.test.ts +188 -0
  23. package/client/handlers/handlePubrec.test.ts +119 -0
  24. package/client/handlers/handlePubrec.ts +5 -1
  25. package/client/handlers/handlePubrel.test.ts +136 -0
  26. package/client/handlers/handleSuback.test.ts +122 -0
  27. package/client/handlers/handleSuback.ts +3 -0
  28. package/client/handlers/handleUnsuback.test.ts +101 -0
  29. package/client/mod.ts +2 -2
  30. package/client/store/memoryStore.ts +2 -2
  31. package/client/store/store.ts +3 -1
  32. package/deno/README.md +1 -2
  33. package/deno/tcpClient.test.ts +75 -0
  34. package/deno/tcpClient.ts +16 -11
  35. package/deno/tcpServer.test.ts +22 -21
  36. package/deno/tcpServer.ts +5 -0
  37. package/deno/tlsServer.test.ts +97 -0
  38. package/deno/tlsServer.ts +42 -0
  39. package/deno/wsServer.test.ts +93 -0
  40. package/deno/wsServer.ts +73 -0
  41. package/dev_utils/generateCert.ts +95 -0
  42. package/dev_utils/mockConn.ts +36 -0
  43. package/dev_utils/mockServer.ts +28 -0
  44. package/dev_utils/mod.ts +30 -2
  45. package/dev_utils/packetHelpers.ts +404 -0
  46. package/dev_utils/test-handlers.ts +98 -0
  47. package/dev_utils/timers.ts +14 -0
  48. package/dev_utils/webStreamPair.test.ts +171 -0
  49. package/dev_utils/webStreamPair.ts +143 -0
  50. package/dist/bin/conformanceServer.js +17 -12
  51. package/dist/bin/conformanceServer.js.map +1 -1
  52. package/dist/bin/demoServer.js +16 -12
  53. package/dist/bin/demoServer.js.map +1 -1
  54. package/dist/bin/mqtt.js +19 -16
  55. package/dist/bin/mqtt.js.map +1 -1
  56. package/dist/client/ConnectionState.d.ts +2 -0
  57. package/dist/client/ConnectionState.d.ts.map +1 -1
  58. package/dist/client/ConnectionState.js +2 -0
  59. package/dist/client/ConnectionState.js.map +1 -1
  60. package/dist/client/client.d.ts +19 -22
  61. package/dist/client/client.d.ts.map +1 -1
  62. package/dist/client/client.js +34 -20
  63. package/dist/client/client.js.map +1 -1
  64. package/dist/client/context.d.ts +11 -3
  65. package/dist/client/context.d.ts.map +1 -1
  66. package/dist/client/context.js +44 -12
  67. package/dist/client/context.js.map +1 -1
  68. package/dist/client/deps.d.ts +3 -2
  69. package/dist/client/deps.d.ts.map +1 -1
  70. package/dist/client/deps.js +1 -1
  71. package/dist/client/deps.js.map +1 -1
  72. package/dist/client/handlers/handleAuth.d.ts +9 -0
  73. package/dist/client/handlers/handleAuth.d.ts.map +1 -0
  74. package/dist/client/handlers/handleAuth.js +66 -0
  75. package/dist/client/handlers/handleAuth.js.map +1 -0
  76. package/dist/client/handlers/handleConnack.d.ts +2 -2
  77. package/dist/client/handlers/handleConnack.d.ts.map +1 -1
  78. package/dist/client/handlers/handleConnack.js +16 -6
  79. package/dist/client/handlers/handleConnack.js.map +1 -1
  80. package/dist/client/handlers/handleDisconnect.d.ts +11 -0
  81. package/dist/client/handlers/handleDisconnect.d.ts.map +1 -0
  82. package/dist/client/handlers/handleDisconnect.js +15 -0
  83. package/dist/client/handlers/handleDisconnect.js.map +1 -0
  84. package/dist/client/handlers/handlePacket.d.ts.map +1 -1
  85. package/dist/client/handlers/handlePacket.js +14 -3
  86. package/dist/client/handlers/handlePacket.js.map +1 -1
  87. package/dist/client/handlers/handlePuback.d.ts.map +1 -1
  88. package/dist/client/handlers/handlePuback.js +5 -0
  89. package/dist/client/handlers/handlePuback.js.map +1 -1
  90. package/dist/client/handlers/handlePubcomp.d.ts.map +1 -1
  91. package/dist/client/handlers/handlePubcomp.js +5 -0
  92. package/dist/client/handlers/handlePubcomp.js.map +1 -1
  93. package/dist/client/handlers/handlePubrec.d.ts.map +1 -1
  94. package/dist/client/handlers/handlePubrec.js +5 -1
  95. package/dist/client/handlers/handlePubrec.js.map +1 -1
  96. package/dist/client/handlers/handleSuback.d.ts +1 -0
  97. package/dist/client/handlers/handleSuback.d.ts.map +1 -1
  98. package/dist/client/handlers/handleSuback.js +3 -0
  99. package/dist/client/handlers/handleSuback.js.map +1 -1
  100. package/dist/client/mod.d.ts +2 -2
  101. package/dist/client/mod.d.ts.map +1 -1
  102. package/dist/client/mod.js +1 -1
  103. package/dist/client/mod.js.map +1 -1
  104. package/dist/client/store/memoryStore.d.ts.map +1 -1
  105. package/dist/client/store/memoryStore.js +2 -2
  106. package/dist/client/store/memoryStore.js.map +1 -1
  107. package/dist/client/store/store.d.ts +2 -1
  108. package/dist/client/store/store.d.ts.map +1 -1
  109. package/dist/client/store/store.js +1 -1
  110. package/dist/client/store/store.js.map +1 -1
  111. package/dist/dev_utils/generateCert.d.ts +11 -0
  112. package/dist/dev_utils/generateCert.d.ts.map +1 -0
  113. package/dist/dev_utils/generateCert.js +76 -0
  114. package/dist/dev_utils/generateCert.js.map +1 -0
  115. package/dist/examples/authHandler.test.d.ts +2 -0
  116. package/dist/examples/authHandler.test.d.ts.map +1 -0
  117. package/dist/examples/authHandler.test.js +123 -0
  118. package/dist/examples/authHandler.test.js.map +1 -0
  119. package/dist/examples/mqtt.test.d.ts +2 -0
  120. package/dist/examples/mqtt.test.d.ts.map +1 -0
  121. package/dist/examples/mqtt.test.js +70 -0
  122. package/dist/examples/mqtt.test.js.map +1 -0
  123. package/dist/examples/mqtts.test.d.ts +2 -0
  124. package/dist/examples/mqtts.test.d.ts.map +1 -0
  125. package/dist/examples/mqtts.test.js +81 -0
  126. package/dist/examples/mqtts.test.js.map +1 -0
  127. package/dist/mqttConn/mqttConn.d.ts +25 -16
  128. package/dist/mqttConn/mqttConn.d.ts.map +1 -1
  129. package/dist/mqttConn/mqttConn.js +69 -40
  130. package/dist/mqttConn/mqttConn.js.map +1 -1
  131. package/dist/mqttPacket/AuthenticationResult.d.ts.map +1 -1
  132. package/dist/mqttPacket/BitMask.d.ts +12 -11
  133. package/dist/mqttPacket/BitMask.d.ts.map +1 -1
  134. package/dist/mqttPacket/BitMask.js +10 -18
  135. package/dist/mqttPacket/BitMask.js.map +1 -1
  136. package/dist/mqttPacket/PacketType.d.ts.map +1 -1
  137. package/dist/mqttPacket/Properties.d.ts +2 -2
  138. package/dist/mqttPacket/Properties.d.ts.map +1 -1
  139. package/dist/mqttPacket/Properties.js.map +1 -1
  140. package/dist/mqttPacket/ReasonCode.d.ts +1 -0
  141. package/dist/mqttPacket/ReasonCode.d.ts.map +1 -1
  142. package/dist/mqttPacket/ReasonCode.js +1 -0
  143. package/dist/mqttPacket/ReasonCode.js.map +1 -1
  144. package/dist/mqttPacket/RetainHandling.d.ts.map +1 -1
  145. package/dist/mqttPacket/auth.d.ts +3 -5
  146. package/dist/mqttPacket/auth.d.ts.map +1 -1
  147. package/dist/mqttPacket/auth.js +31 -30
  148. package/dist/mqttPacket/auth.js.map +1 -1
  149. package/dist/mqttPacket/codec.d.ts +48 -0
  150. package/dist/mqttPacket/codec.d.ts.map +1 -0
  151. package/dist/mqttPacket/codec.js +93 -0
  152. package/dist/mqttPacket/codec.js.map +1 -0
  153. package/dist/mqttPacket/connack.d.ts +4 -5
  154. package/dist/mqttPacket/connack.d.ts.map +1 -1
  155. package/dist/mqttPacket/connack.js +43 -45
  156. package/dist/mqttPacket/connack.js.map +1 -1
  157. package/dist/mqttPacket/connect.d.ts +26 -27
  158. package/dist/mqttPacket/connect.d.ts.map +1 -1
  159. package/dist/mqttPacket/connect.js +156 -157
  160. package/dist/mqttPacket/connect.js.map +1 -1
  161. package/dist/mqttPacket/decoder.d.ts +1 -13
  162. package/dist/mqttPacket/decoder.d.ts.map +1 -1
  163. package/dist/mqttPacket/decoder.js +7 -28
  164. package/dist/mqttPacket/decoder.js.map +1 -1
  165. package/dist/mqttPacket/disconnect.d.ts +4 -5
  166. package/dist/mqttPacket/disconnect.d.ts.map +1 -1
  167. package/dist/mqttPacket/disconnect.js +41 -43
  168. package/dist/mqttPacket/disconnect.js.map +1 -1
  169. package/dist/mqttPacket/encoder.d.ts +1 -15
  170. package/dist/mqttPacket/encoder.d.ts.map +1 -1
  171. package/dist/mqttPacket/encoder.js +4 -27
  172. package/dist/mqttPacket/encoder.js.map +1 -1
  173. package/dist/mqttPacket/length.js +1 -1
  174. package/dist/mqttPacket/length.js.map +1 -1
  175. package/dist/mqttPacket/mod.d.ts +21 -103
  176. package/dist/mqttPacket/mod.d.ts.map +1 -1
  177. package/dist/mqttPacket/mod.js +5 -94
  178. package/dist/mqttPacket/mod.js.map +1 -1
  179. package/dist/mqttPacket/pingreq.d.ts +4 -5
  180. package/dist/mqttPacket/pingreq.d.ts.map +1 -1
  181. package/dist/mqttPacket/pingreq.js +11 -13
  182. package/dist/mqttPacket/pingreq.js.map +1 -1
  183. package/dist/mqttPacket/pingres.d.ts +4 -5
  184. package/dist/mqttPacket/pingres.d.ts.map +1 -1
  185. package/dist/mqttPacket/pingres.js +11 -13
  186. package/dist/mqttPacket/pingres.js.map +1 -1
  187. package/dist/mqttPacket/protocolLevels.d.ts +11 -6
  188. package/dist/mqttPacket/protocolLevels.d.ts.map +1 -1
  189. package/dist/mqttPacket/protocolLevels.js +5 -1
  190. package/dist/mqttPacket/protocolLevels.js.map +1 -1
  191. package/dist/mqttPacket/pubblishAcks.d.ts +9 -10
  192. package/dist/mqttPacket/pubblishAcks.d.ts.map +1 -1
  193. package/dist/mqttPacket/pubblishAcks.js +43 -45
  194. package/dist/mqttPacket/pubblishAcks.js.map +1 -1
  195. package/dist/mqttPacket/publish.d.ts +14 -14
  196. package/dist/mqttPacket/publish.d.ts.map +1 -1
  197. package/dist/mqttPacket/publish.js +53 -55
  198. package/dist/mqttPacket/publish.js.map +1 -1
  199. package/dist/mqttPacket/suback.d.ts +4 -5
  200. package/dist/mqttPacket/suback.d.ts.map +1 -1
  201. package/dist/mqttPacket/suback.js +38 -40
  202. package/dist/mqttPacket/suback.js.map +1 -1
  203. package/dist/mqttPacket/subscribe.d.ts +36 -7
  204. package/dist/mqttPacket/subscribe.d.ts.map +1 -1
  205. package/dist/mqttPacket/subscribe.js +90 -89
  206. package/dist/mqttPacket/subscribe.js.map +1 -1
  207. package/dist/mqttPacket/types.d.ts +1 -8
  208. package/dist/mqttPacket/types.d.ts.map +1 -1
  209. package/dist/mqttPacket/unsuback.d.ts +4 -5
  210. package/dist/mqttPacket/unsuback.d.ts.map +1 -1
  211. package/dist/mqttPacket/unsuback.js +32 -34
  212. package/dist/mqttPacket/unsuback.js.map +1 -1
  213. package/dist/mqttPacket/unsubscribe.d.ts +23 -6
  214. package/dist/mqttPacket/unsubscribe.d.ts.map +1 -1
  215. package/dist/mqttPacket/unsubscribe.js +45 -44
  216. package/dist/mqttPacket/unsubscribe.js.map +1 -1
  217. package/dist/mqttPacket/validators.d.ts +4 -16
  218. package/dist/mqttPacket/validators.d.ts.map +1 -1
  219. package/dist/mqttPacket/validators.js +5 -26
  220. package/dist/mqttPacket/validators.js.map +1 -1
  221. package/dist/node/tcpClient.d.ts +1 -1
  222. package/dist/node/tcpClient.d.ts.map +1 -1
  223. package/dist/node/tcpClient.js +12 -7
  224. package/dist/node/tcpClient.js.map +1 -1
  225. package/dist/node/tcpServer.d.ts.map +1 -1
  226. package/dist/node/tcpServer.js +4 -0
  227. package/dist/node/tcpServer.js.map +1 -1
  228. package/dist/node/tlsServer.d.ts +19 -0
  229. package/dist/node/tlsServer.d.ts.map +1 -0
  230. package/dist/node/tlsServer.js +58 -0
  231. package/dist/node/tlsServer.js.map +1 -0
  232. package/dist/node/wrapNodeSocket.d.ts.map +1 -1
  233. package/dist/node/wrapNodeSocket.js +6 -28
  234. package/dist/node/wrapNodeSocket.js.map +1 -1
  235. package/dist/persistence/basicPersistence.d.ts +36 -0
  236. package/dist/persistence/basicPersistence.d.ts.map +1 -0
  237. package/dist/persistence/basicPersistence.js +306 -0
  238. package/dist/persistence/basicPersistence.js.map +1 -0
  239. package/dist/persistence/deps.d.ts +3 -2
  240. package/dist/persistence/deps.d.ts.map +1 -1
  241. package/dist/persistence/deps.js +2 -1
  242. package/dist/persistence/deps.js.map +1 -1
  243. package/dist/persistence/memory/memoryPersistence.d.ts +6 -23
  244. package/dist/persistence/memory/memoryPersistence.d.ts.map +1 -1
  245. package/dist/persistence/memory/memoryPersistence.js +12 -115
  246. package/dist/persistence/memory/memoryPersistence.js.map +1 -1
  247. package/dist/persistence/memory/memoryStorage.d.ts +45 -0
  248. package/dist/persistence/memory/memoryStorage.d.ts.map +1 -0
  249. package/dist/persistence/memory/memoryStorage.js +143 -0
  250. package/dist/persistence/memory/memoryStorage.js.map +1 -0
  251. package/dist/persistence/mod.d.ts +3 -3
  252. package/dist/persistence/mod.d.ts.map +1 -1
  253. package/dist/persistence/mod.js +6 -1
  254. package/dist/persistence/mod.js.map +1 -1
  255. package/dist/persistence/persistence.d.ts +44 -69
  256. package/dist/persistence/persistence.d.ts.map +1 -1
  257. package/dist/persistence/persistence.js +1 -2
  258. package/dist/persistence/persistence.js.map +1 -1
  259. package/dist/persistence/sqlite/sqliteDatabase.d.ts +46 -0
  260. package/dist/persistence/sqlite/sqliteDatabase.d.ts.map +1 -0
  261. package/dist/persistence/sqlite/sqliteDatabase.js +215 -0
  262. package/dist/persistence/sqlite/sqliteDatabase.js.map +1 -0
  263. package/dist/persistence/sqlite/sqlitePersistence.d.ts +16 -0
  264. package/dist/persistence/sqlite/sqlitePersistence.d.ts.map +1 -0
  265. package/dist/persistence/sqlite/sqlitePersistence.js +29 -0
  266. package/dist/persistence/sqlite/sqlitePersistence.js.map +1 -0
  267. package/dist/persistence/sqlite/sqliteStorage.d.ts +36 -0
  268. package/dist/persistence/sqlite/sqliteStorage.d.ts.map +1 -0
  269. package/dist/persistence/sqlite/sqliteStorage.js +194 -0
  270. package/dist/persistence/sqlite/sqliteStorage.js.map +1 -0
  271. package/dist/persistence/storage.d.ts +38 -0
  272. package/dist/persistence/storage.d.ts.map +1 -0
  273. package/dist/persistence/storage.js +5 -0
  274. package/dist/persistence/storage.js.map +1 -0
  275. package/dist/server/config.d.ts +47 -0
  276. package/dist/server/config.d.ts.map +1 -0
  277. package/dist/server/config.js +41 -0
  278. package/dist/server/config.js.map +1 -0
  279. package/dist/server/context.d.ts +198 -24
  280. package/dist/server/context.d.ts.map +1 -1
  281. package/dist/server/context.js +432 -53
  282. package/dist/server/context.js.map +1 -1
  283. package/dist/server/deps.d.ts +5 -6
  284. package/dist/server/deps.d.ts.map +1 -1
  285. package/dist/server/deps.js +2 -2
  286. package/dist/server/deps.js.map +1 -1
  287. package/dist/server/handlers/completeConnect.d.ts +8 -0
  288. package/dist/server/handlers/completeConnect.d.ts.map +1 -0
  289. package/dist/server/handlers/completeConnect.js +74 -0
  290. package/dist/server/handlers/completeConnect.js.map +1 -0
  291. package/dist/server/handlers/handleAuth.d.ts +9 -0
  292. package/dist/server/handlers/handleAuth.d.ts.map +1 -0
  293. package/dist/server/handlers/handleAuth.js +69 -0
  294. package/dist/server/handlers/handleAuth.js.map +1 -0
  295. package/dist/server/handlers/handleConnect.d.ts +2 -4
  296. package/dist/server/handlers/handleConnect.d.ts.map +1 -1
  297. package/dist/server/handlers/handleConnect.js +140 -67
  298. package/dist/server/handlers/handleConnect.js.map +1 -1
  299. package/dist/server/handlers/handleDisconnect.d.ts +1 -1
  300. package/dist/server/handlers/handleDisconnect.d.ts.map +1 -1
  301. package/dist/server/handlers/handleDisconnect.js +3 -3
  302. package/dist/server/handlers/handleDisconnect.js.map +1 -1
  303. package/dist/server/handlers/handlePacket.d.ts.map +1 -1
  304. package/dist/server/handlers/handlePacket.js +19 -6
  305. package/dist/server/handlers/handlePacket.js.map +1 -1
  306. package/dist/server/handlers/handlePuback.d.ts +1 -3
  307. package/dist/server/handlers/handlePuback.d.ts.map +1 -1
  308. package/dist/server/handlers/handlePuback.js +2 -8
  309. package/dist/server/handlers/handlePuback.js.map +1 -1
  310. package/dist/server/handlers/handlePubcomp.d.ts +1 -1
  311. package/dist/server/handlers/handlePubcomp.d.ts.map +1 -1
  312. package/dist/server/handlers/handlePubcomp.js +2 -4
  313. package/dist/server/handlers/handlePubcomp.js.map +1 -1
  314. package/dist/server/handlers/handlePublish.d.ts +1 -1
  315. package/dist/server/handlers/handlePublish.d.ts.map +1 -1
  316. package/dist/server/handlers/handlePublish.js +149 -45
  317. package/dist/server/handlers/handlePublish.js.map +1 -1
  318. package/dist/server/handlers/handlePubrec.d.ts.map +1 -1
  319. package/dist/server/handlers/handlePubrec.js +2 -3
  320. package/dist/server/handlers/handlePubrec.js.map +1 -1
  321. package/dist/server/handlers/handlePubrel.d.ts.map +1 -1
  322. package/dist/server/handlers/handlePubrel.js +6 -2
  323. package/dist/server/handlers/handlePubrel.js.map +1 -1
  324. package/dist/server/handlers/handleSubscribe.d.ts +1 -6
  325. package/dist/server/handlers/handleSubscribe.d.ts.map +1 -1
  326. package/dist/server/handlers/handleSubscribe.js +99 -38
  327. package/dist/server/handlers/handleSubscribe.js.map +1 -1
  328. package/dist/server/handlers/handleUnsubscribe.d.ts.map +1 -1
  329. package/dist/server/handlers/handleUnsubscribe.js +19 -4
  330. package/dist/server/handlers/handleUnsubscribe.js.map +1 -1
  331. package/dist/server/mod.d.ts +3 -3
  332. package/dist/server/mod.d.ts.map +1 -1
  333. package/dist/server/mod.js +1 -1
  334. package/dist/server/mod.js.map +1 -1
  335. package/dist/server/server.d.ts +29 -6
  336. package/dist/server/server.d.ts.map +1 -1
  337. package/dist/server/server.js +84 -15
  338. package/dist/server/server.js.map +1 -1
  339. package/dist/socket/socket.d.ts +11 -9
  340. package/dist/socket/socket.d.ts.map +1 -1
  341. package/dist/socket/socket.js +67 -15
  342. package/dist/socket/socket.js.map +1 -1
  343. package/dist/timer/timer.d.ts +32 -0
  344. package/dist/timer/timer.d.ts.map +1 -1
  345. package/dist/timer/timer.js +32 -0
  346. package/dist/timer/timer.js.map +1 -1
  347. package/dist/trie/trie.d.ts +10 -5
  348. package/dist/trie/trie.d.ts.map +1 -1
  349. package/dist/trie/trie.js +47 -17
  350. package/dist/trie/trie.js.map +1 -1
  351. package/dist/utils/assert.d.ts.map +1 -1
  352. package/dist/utils/{BufferedAsyncIterable.d.ts → bufferedAsyncIterable.d.ts} +1 -1
  353. package/dist/utils/bufferedAsyncIterable.d.ts.map +1 -0
  354. package/dist/utils/{BufferedAsyncIterable.js → bufferedAsyncIterable.js} +1 -1
  355. package/dist/utils/bufferedAsyncIterable.js.map +1 -0
  356. package/dist/utils/deferred.d.ts.map +1 -1
  357. package/dist/utils/deferred.js.map +1 -1
  358. package/dist/utils/getOrInsertPolyFill.d.ts +2 -0
  359. package/dist/utils/getOrInsertPolyFill.d.ts.map +1 -0
  360. package/dist/utils/getOrInsertPolyFill.js +12 -0
  361. package/dist/utils/getOrInsertPolyFill.js.map +1 -0
  362. package/dist/utils/logger.d.ts +40 -3
  363. package/dist/utils/logger.d.ts.map +1 -1
  364. package/dist/utils/logger.js +53 -7
  365. package/dist/utils/logger.js.map +1 -1
  366. package/dist/utils/mod.d.ts +6 -1
  367. package/dist/utils/mod.d.ts.map +1 -1
  368. package/dist/utils/mod.js +5 -1
  369. package/dist/utils/mod.js.map +1 -1
  370. package/dist/utils/outboundTopicAliasManager.d.ts +52 -0
  371. package/dist/utils/outboundTopicAliasManager.d.ts.map +1 -0
  372. package/dist/utils/outboundTopicAliasManager.js +74 -0
  373. package/dist/utils/outboundTopicAliasManager.js.map +1 -0
  374. package/dist/utils/queue.d.ts.map +1 -1
  375. package/dist/utils/topicFilter.d.ts +32 -0
  376. package/dist/utils/topicFilter.d.ts.map +1 -0
  377. package/dist/utils/topicFilter.js +52 -0
  378. package/dist/utils/topicFilter.js.map +1 -0
  379. package/dist/utils/utils.d.ts +2 -0
  380. package/dist/utils/utils.d.ts.map +1 -1
  381. package/dist/utils/utils.js +2 -0
  382. package/dist/utils/utils.js.map +1 -1
  383. package/dist/utils/validators.d.ts +34 -0
  384. package/dist/utils/validators.d.ts.map +1 -0
  385. package/dist/utils/validators.js +61 -0
  386. package/dist/utils/validators.js.map +1 -0
  387. package/dist/web/webSocketStream.d.ts +29 -0
  388. package/dist/web/webSocketStream.d.ts.map +1 -0
  389. package/dist/web/webSocketStream.js +69 -0
  390. package/dist/web/webSocketStream.js.map +1 -0
  391. package/dist/web/wrapWebSocket.d.ts +12 -0
  392. package/dist/web/wrapWebSocket.d.ts.map +1 -0
  393. package/dist/web/wrapWebSocket.js +41 -0
  394. package/dist/web/wrapWebSocket.js.map +1 -0
  395. package/dist/web/wsClient.d.ts +7 -0
  396. package/dist/web/wsClient.d.ts.map +1 -0
  397. package/dist/web/wsClient.js +22 -0
  398. package/dist/web/wsClient.js.map +1 -0
  399. package/dist/web/wsClient.test.d.ts +2 -0
  400. package/dist/web/wsClient.test.d.ts.map +1 -0
  401. package/dist/web/wsClient.test.js +20 -0
  402. package/dist/web/wsClient.test.js.map +1 -0
  403. package/examples/authHandler.test.ts +164 -0
  404. package/examples/mqtt.test.ts +89 -0
  405. package/examples/mqtts.test.ts +100 -0
  406. package/examples/webSocket.test.ts +94 -0
  407. package/mqttConn/mqttConn.test.ts +9 -9
  408. package/mqttConn/mqttConn.ts +91 -49
  409. package/mqttPacket/BitMask.ts +11 -19
  410. package/mqttPacket/Properties.ts +6 -3
  411. package/mqttPacket/ReasonCode.ts +2 -1
  412. package/mqttPacket/auth.test.ts +1 -1
  413. package/mqttPacket/auth.ts +41 -48
  414. package/mqttPacket/codec.ts +146 -0
  415. package/mqttPacket/connack.ts +57 -68
  416. package/mqttPacket/connect.test.ts +2 -2
  417. package/mqttPacket/connect.ts +197 -204
  418. package/mqttPacket/decoder.test.ts +0 -39
  419. package/mqttPacket/decoder.ts +9 -36
  420. package/mqttPacket/disconnect.ts +57 -68
  421. package/mqttPacket/encoder.ts +5 -40
  422. package/mqttPacket/length.ts +1 -1
  423. package/mqttPacket/mod.ts +48 -200
  424. package/mqttPacket/pingreq.ts +21 -27
  425. package/mqttPacket/pingres.ts +21 -27
  426. package/mqttPacket/protocolLevels.ts +12 -7
  427. package/mqttPacket/pubblishAcks.ts +68 -77
  428. package/mqttPacket/publish.ts +76 -83
  429. package/mqttPacket/suback.ts +48 -58
  430. package/mqttPacket/subscribe.ts +141 -117
  431. package/mqttPacket/types.ts +1 -9
  432. package/mqttPacket/unsuback.ts +46 -58
  433. package/mqttPacket/unsubscribe.ts +74 -63
  434. package/mqttPacket/validators.ts +5 -31
  435. package/node/socket-node-stream.test.ts +322 -0
  436. package/node/socket-node-stream.ts +174 -0
  437. package/node/tcpClient.test.ts +70 -0
  438. package/node/tcpClient.ts +13 -12
  439. package/node/tcpServer.test.ts +24 -20
  440. package/node/tcpServer.ts +6 -0
  441. package/node/tlsServer.test.ts +94 -0
  442. package/node/tlsServer.ts +81 -0
  443. package/node/wrapNodeSocket.ts +7 -30
  444. package/package.json +73 -45
  445. package/persistence/basicPersistence.ts +495 -0
  446. package/persistence/deps.ts +11 -1
  447. package/persistence/memory/memoryPersistence.ts +12 -152
  448. package/persistence/memory/memoryStorage.ts +232 -0
  449. package/persistence/mod.ts +4 -4
  450. package/persistence/persistence.test.ts +24 -0
  451. package/persistence/persistence.testing.ts +1324 -0
  452. package/persistence/persistence.ts +111 -67
  453. package/persistence/sqlite/sqliteDatabase.ts +294 -0
  454. package/persistence/sqlite/sqlitePersistence.test.ts +48 -0
  455. package/persistence/sqlite/sqlitePersistence.ts +36 -0
  456. package/persistence/sqlite/sqliteStorage.ts +324 -0
  457. package/persistence/storage.ts +84 -0
  458. package/server/config.ts +65 -0
  459. package/server/context.ts +658 -74
  460. package/server/deps.ts +25 -5
  461. package/server/handlers/completeConnect.ts +93 -0
  462. package/server/handlers/duplicate.test.ts +196 -0
  463. package/server/handlers/handleAuth.test.ts +225 -0
  464. package/server/handlers/handleAuth.ts +88 -0
  465. package/server/handlers/handleConnect.test.ts +589 -0
  466. package/server/handlers/handleConnect.ts +201 -86
  467. package/server/handlers/handleConnect.version.test.ts +108 -0
  468. package/server/handlers/handleDisconnect.test.ts +56 -0
  469. package/server/handlers/handleDisconnect.ts +3 -3
  470. package/server/handlers/handlePacket.test.ts +24 -0
  471. package/server/handlers/handlePacket.ts +30 -8
  472. package/server/handlers/handlePingreq.test.ts +29 -0
  473. package/server/handlers/handlePuback.test.ts +28 -0
  474. package/server/handlers/handlePuback.ts +5 -8
  475. package/server/handlers/handlePubcomp.test.ts +28 -0
  476. package/server/handlers/handlePubcomp.ts +5 -4
  477. package/server/handlers/handlePublish.test.ts +471 -0
  478. package/server/handlers/handlePublish.ts +189 -35
  479. package/server/handlers/handlePubrec.test.ts +28 -0
  480. package/server/handlers/handlePubrec.ts +2 -3
  481. package/server/handlers/handlePubrel.test.ts +74 -0
  482. package/server/handlers/handlePubrel.ts +12 -2
  483. package/server/handlers/handleSubscribe.test.ts +971 -0
  484. package/server/handlers/handleSubscribe.ts +158 -39
  485. package/server/handlers/handleUnsubscribe.test.ts +79 -0
  486. package/server/handlers/handleUnsubscribe.ts +29 -5
  487. package/server/handlers/keepalive.test.ts +132 -0
  488. package/server/handlers/session.persistence.test.ts +194 -0
  489. package/server/handlers/will.delivery.test.ts +221 -0
  490. package/server/mod.ts +4 -3
  491. package/server/preconnect.test.ts +151 -0
  492. package/server/server.ts +115 -17
  493. package/socket/socket.test.ts +91 -0
  494. package/socket/socket.ts +81 -31
  495. package/timer/timer.test.ts +4 -7
  496. package/timer/timer.ts +36 -0
  497. package/tools/benchmarks/receiver.ts +51 -0
  498. package/tools/benchmarks/sender.ts +48 -0
  499. package/tools/benchmarks/utils.ts +31 -0
  500. package/tools/mqtt-compat/README.md +130 -0
  501. package/tools/mqtt-compat/broker.ts +52 -0
  502. package/tools/mqtt-compat/paho-mqtt4.test.ts +379 -0
  503. package/tools/mqtt-compat/paho-mqtt5.tests.ts +887 -0
  504. package/trie/trie.test.ts +9 -1
  505. package/trie/trie.ts +57 -22
  506. package/utils/bufferedAsyncIterable.test.ts +92 -0
  507. package/utils/{BufferedAsyncIterable.ts → bufferedAsyncIterable.ts} +1 -1
  508. package/utils/deferred.test.ts +36 -0
  509. package/utils/deferred.ts +0 -1
  510. package/utils/getOrInsertPolyFill.ts +12 -0
  511. package/utils/logger.test.ts +189 -0
  512. package/utils/logger.ts +62 -7
  513. package/utils/mod.ts +15 -1
  514. package/utils/outboundTopicAliasManager.ts +100 -0
  515. package/utils/queue.test.ts +61 -0
  516. package/utils/topicFilter.test.ts +63 -0
  517. package/utils/topicFilter.ts +61 -0
  518. package/utils/utils.ts +3 -0
  519. package/utils/validators.ts +67 -0
  520. package/web/webSocketStream.ts +97 -0
  521. package/web/wrapWebSocket.ts +52 -0
  522. package/web/wsClient.test.ts +26 -0
  523. package/web/wsClient.ts +25 -0
  524. package/benchmarks/receiver.ts +0 -35
  525. package/benchmarks/sender.ts +0 -32
  526. package/benchmarks/utils.ts +0 -9
  527. package/dev_utils/dummyConn.ts +0 -110
  528. package/dist/persistence/store.d.ts +0 -13
  529. package/dist/persistence/store.d.ts.map +0 -1
  530. package/dist/persistence/store.js +0 -2
  531. package/dist/persistence/store.js.map +0 -1
  532. package/dist/utils/BufferedAsyncIterable.d.ts.map +0 -1
  533. package/dist/utils/BufferedAsyncIterable.js.map +0 -1
  534. package/examples/tcpServer.test.ts +0 -148
  535. package/persistence/memory/memoryPersistence.test.ts +0 -156
  536. package/persistence/store.ts +0 -15
  537. package/server/test/handleConnect.test.ts +0 -130
  538. package/server/test/test-handlers.ts +0 -53
@@ -0,0 +1,887 @@
1
+ import assert from "node:assert/strict";
2
+ import { test } from "node:test";
3
+ import type { AnyPacket, QoS } from "../../server/deps.ts";
4
+ import { logger, LogLevel, PacketType } from "../../server/deps.ts";
5
+ import {
6
+ addMockClient,
7
+ connect5,
8
+ delay,
9
+ disconnect5,
10
+ ping,
11
+ publish5,
12
+ receiveMessages5,
13
+ startMockServer,
14
+ subscribe5,
15
+ unsubscribe5,
16
+ } from "../../dev_utils/mod.ts";
17
+ import type {
18
+ ConnectProperties,
19
+ PublishProperties,
20
+ } from "../../mqttPacket/Properties.ts";
21
+
22
+ const txtEncoder = new TextEncoder();
23
+ logger.level(LogLevel.error);
24
+
25
+ // Global-like state setup matching Python suite
26
+ const topicPrefix = "client_test5/";
27
+ const topics = ["TopicA", "TopicA/B", "Topic/C", "TopicA/C", "/TopicA"].map(
28
+ (t) => topicPrefix + t,
29
+ );
30
+ const wildtopics = ["TopicA/+", "+/C", "#", "/#", "/+", "+/+", "TopicA/#"].map(
31
+ (t) => topicPrefix + t,
32
+ );
33
+ const nosubscribeTopics = ["test/nosubscribe"];
34
+
35
+ // --- Original Tests ---
36
+
37
+ test("Basic Connection and Publish Flow", async () => {
38
+ const { mqttConn } = startMockServer();
39
+
40
+ await connect5(mqttConn, { clientId: "myclientid" });
41
+ await disconnect5(mqttConn);
42
+
43
+ const { mqttConn: mqttConn2, mqttServer } = startMockServer();
44
+ await connect5(mqttConn2, { clientId: "myclientid" });
45
+
46
+ await subscribe5(mqttConn2, [{ topicFilter: topics[0], qos: 2 }]);
47
+
48
+ const mqttConn3 = addMockClient(mqttServer);
49
+ await connect5(mqttConn3, { clientId: "publisher" });
50
+
51
+ await publish5(mqttConn3, topics[0], 0, { payload: "qos 0" });
52
+ await publish5(mqttConn3, topics[0], 1, { payload: "qos 1", id: 1 });
53
+ await publish5(mqttConn3, topics[0], 2, { payload: "qos 2", id: 2 });
54
+
55
+ const messages = await receiveMessages5(mqttConn2);
56
+ assert.strictEqual(messages.length, 3);
57
+ });
58
+
59
+ test("Retained Messages with User Properties", async () => {
60
+ const { mqttConn, mqttServer } = startMockServer();
61
+
62
+ await connect5(mqttConn, { clientId: "myclientid" });
63
+
64
+ const properties: PublishProperties = {
65
+ userProperty: [["a", "2"], ["c", "3"]],
66
+ };
67
+
68
+ await publish5(mqttConn, topics[1], 0, { retain: true, properties });
69
+ await publish5(mqttConn, topics[2], 1, { retain: true, properties, id: 3 });
70
+ await publish5(mqttConn, topics[3], 2, { retain: true, properties, id: 4 });
71
+
72
+ await delay(50);
73
+
74
+ const bConn = addMockClient(mqttServer);
75
+ await connect5(bConn, { clientId: "myclientid2" });
76
+ await subscribe5(bConn, [{ topicFilter: wildtopics[5], qos: 2 }]);
77
+
78
+ const packets: AnyPacket[] = await receiveMessages5(bConn);
79
+
80
+ assert.strictEqual(packets.length, 3);
81
+ assert.strictEqual(
82
+ packets.filter((p) => p.type === PacketType.publish).length,
83
+ 3,
84
+ );
85
+ await disconnect5(mqttConn);
86
+ });
87
+
88
+ test("Will Message Configuration", async () => {
89
+ const { mqttConn: aConn, mqttServer } = startMockServer();
90
+
91
+ await connect5(aConn, {
92
+ clientId: "myclientid",
93
+ clean: true,
94
+ keepAlive: 2,
95
+ will: {
96
+ topic: topics[2],
97
+ payload: txtEncoder.encode("will message"),
98
+ qos: 2,
99
+ retain: false,
100
+ properties: {
101
+ willDelayInterval: 0,
102
+ userProperty: [["a", "2"], ["c", "3"]],
103
+ },
104
+ },
105
+ });
106
+
107
+ const bConn = addMockClient(mqttServer);
108
+ await connect5(bConn, { clientId: "myclientid2" });
109
+ await subscribe5(bConn, [{ topicFilter: topics[2], qos: 2 }]);
110
+
111
+ aConn.close();
112
+
113
+ const { value: willPublish } = await bConn.next();
114
+ assert.strictEqual(willPublish.type, PacketType.publish);
115
+ assert.strictEqual(willPublish.topic, topics[2]);
116
+
117
+ await disconnect5(bConn);
118
+ });
119
+
120
+ test("Zero Length Client Identifier Processing", async () => {
121
+ const { mqttConn } = startMockServer();
122
+
123
+ await connect5(mqttConn, { clientId: "" });
124
+ await disconnect5(mqttConn);
125
+ });
126
+
127
+ test("Offline Message Queueing (Session Expiry)", async () => {
128
+ const { mqttConn: aConn, mqttServer } = startMockServer();
129
+
130
+ await connect5(aConn, {
131
+ clientId: "offlineClient",
132
+ properties: { sessionExpiryInterval: 99999 },
133
+ });
134
+ await subscribe5(aConn, [{ topicFilter: wildtopics[5], qos: 2 }]);
135
+ await disconnect5(aConn);
136
+
137
+ const bConn = addMockClient(mqttServer);
138
+ await connect5(bConn, { clientId: "publisher" });
139
+ await publish5(bConn, topics[1], 0, { payload: "qos 0" });
140
+ await publish5(bConn, topics[2], 1, { payload: "qos 1", id: 10 });
141
+ await publish5(bConn, topics[3], 2, { payload: "qos 2", id: 11 });
142
+ await disconnect5(bConn);
143
+
144
+ const aReconnect = addMockClient(mqttServer);
145
+ await connect5(aReconnect, {
146
+ clientId: "offlineClient",
147
+ clean: false,
148
+ properties: { sessionExpiryInterval: 99999 },
149
+ });
150
+
151
+ const packet1 = await aReconnect.next();
152
+ const packet2 = await aReconnect.next();
153
+ assert.strictEqual(packet1.value.type, PacketType.publish);
154
+ assert.strictEqual(packet2.value.type, PacketType.publish);
155
+
156
+ await disconnect5(aReconnect);
157
+ });
158
+
159
+ test("Shared Subscriptions Delivery Single-Instance Verification", async () => {
160
+ const { mqttConn: aConn, mqttServer } = startMockServer();
161
+ const sharedSubTopic = `$share/sharename/${topicPrefix}x`;
162
+ const sharedPubTopic = `${topicPrefix}x`;
163
+
164
+ await connect5(aConn, { clientId: "clientA" });
165
+ await subscribe5(aConn, [{ topicFilter: sharedSubTopic, qos: 2 }]);
166
+
167
+ const bConn = addMockClient(mqttServer);
168
+ await connect5(bConn, { clientId: "clientB" });
169
+ await subscribe5(bConn, [{ topicFilter: sharedSubTopic, qos: 2 }]);
170
+
171
+ const pConn = addMockClient(mqttServer);
172
+ await connect5(pConn, { clientId: "publisher" });
173
+ await publish5(pConn, sharedPubTopic, 0, { payload: "shared content" });
174
+
175
+ await delay(50);
176
+
177
+ await disconnect5(aConn);
178
+ await disconnect5(bConn);
179
+ await disconnect5(pConn);
180
+ });
181
+
182
+ // --- Added Missing Tests (from client_test5.py) ---
183
+
184
+ test("Overlapping Subscriptions", async () => {
185
+ const { mqttConn: aConn, mqttServer } = startMockServer();
186
+ await connect5(aConn, { clientId: "overlappingClient" });
187
+
188
+ await subscribe5(aConn, [
189
+ { topicFilter: wildtopics[6], qos: 2 },
190
+ { topicFilter: wildtopics[0], qos: 1 },
191
+ ]);
192
+
193
+ const publisher = addMockClient(mqttServer);
194
+ await connect5(publisher, { clientId: "publishingClient" });
195
+ await publish5(publisher, topics[3], 2, {
196
+ payload: "overlapping topic filters",
197
+ });
198
+
199
+ const { value: msg } = await aConn.next();
200
+ assert.strictEqual(msg.type, PacketType.publish);
201
+ await disconnect5(aConn);
202
+ });
203
+
204
+ test("Keepalive Timeout Triggering Will Message", async () => {
205
+ const { mqttConn: aConn, mqttServer } = startMockServer();
206
+ // set server keepalive small to speed up test
207
+ mqttServer.configuration.context.serverKeepAlive = 2;
208
+
209
+ await connect5(aConn, {
210
+ clientId: "keepaliveClient",
211
+ clean: true,
212
+ keepAlive: 1,
213
+ will: {
214
+ topic: topics[4],
215
+ payload: txtEncoder.encode("keepalive expiry"),
216
+ qos: 2,
217
+ retain: false,
218
+ },
219
+ });
220
+
221
+ const bConn = addMockClient(mqttServer);
222
+ await connect5(bConn, { clientId: "watcherClient" });
223
+ await subscribe5(bConn, [{ topicFilter: topics[4], qos: 2 }]);
224
+
225
+ // Wait for keepalive timeout on client A
226
+ await delay(2000);
227
+
228
+ const { value: willPublish } = await bConn.next();
229
+ assert.strictEqual(willPublish.type, PacketType.publish);
230
+ assert.strictEqual(willPublish.topic, topics[4]);
231
+
232
+ await disconnect5(bConn);
233
+ });
234
+
235
+ test("Redelivery on Reconnect", async () => {
236
+ const { mqttConn: bConn, mqttServer } = startMockServer();
237
+ const connProps: ConnectProperties = { sessionExpiryInterval: 99999 };
238
+
239
+ await connect5(bConn, {
240
+ clientId: "redeliverClient",
241
+ clean: false,
242
+ properties: connProps,
243
+ });
244
+ await subscribe5(bConn, [{ topicFilter: wildtopics[6], qos: 2 }]);
245
+
246
+ const publisher = addMockClient(mqttServer);
247
+ await connect5(publisher, { clientId: "publisher" });
248
+ await publish5(publisher, topics[1], 1, {
249
+ payload: "unacked qos 1",
250
+ id: 100,
251
+ });
252
+ await publish5(publisher, topics[3], 2, {
253
+ payload: "unacked qos 2",
254
+ id: 101,
255
+ });
256
+ await disconnect5(publisher);
257
+ bConn.close();
258
+
259
+ // Reconnect and verify redelivery
260
+ const bReconnect = addMockClient(mqttServer);
261
+ await connect5(bReconnect, {
262
+ clientId: "redeliverClient",
263
+ clean: false,
264
+ properties: connProps,
265
+ });
266
+
267
+ const msg1 = await bReconnect.next();
268
+ const msg2 = await bReconnect.next();
269
+ assert.strictEqual(msg1.value.type, PacketType.publish);
270
+ assert.strictEqual(msg2.value.type, PacketType.publish);
271
+
272
+ await disconnect5(bReconnect);
273
+ });
274
+
275
+ test("Subscribe Failure (Reason Code 0x80)", async () => {
276
+ const { mqttConn } = startMockServer();
277
+ await connect5(mqttConn, { clientId: "subFailClient" });
278
+
279
+ const suback = await subscribe5(mqttConn, [{
280
+ topicFilter: nosubscribeTopics[0],
281
+ qos: 2,
282
+ }]);
283
+ assert.strictEqual(suback.type, PacketType.suback);
284
+
285
+ await disconnect5(mqttConn);
286
+ });
287
+
288
+ test("Dollar ($) Topics Wildcard Isolation", async () => {
289
+ const { mqttConn, mqttServer } = startMockServer();
290
+
291
+ await connect5(mqttConn, { clientId: "dollarSubscriber" });
292
+ await subscribe5(mqttConn, [{ topicFilter: wildtopics[5], qos: 2 }]);
293
+
294
+ const pConn = addMockClient(mqttServer);
295
+ await connect5(pConn, { clientId: "dollarPublisher" });
296
+ await publish5(pConn, "$" + topics[1], 1, {
297
+ payload: "dollar topic payload",
298
+ });
299
+
300
+ await delay(50);
301
+ await disconnect5(mqttConn);
302
+ await disconnect5(pConn);
303
+ });
304
+
305
+ test("Unsubscribe Topics Flow", async () => {
306
+ const { mqttConn: bConn, mqttServer } = startMockServer();
307
+
308
+ await connect5(bConn, { clientId: "unsubClient" });
309
+ await subscribe5(bConn, [
310
+ { topicFilter: topics[0], qos: 2 },
311
+ { topicFilter: topics[1], qos: 2 },
312
+ { topicFilter: topics[2], qos: 2 },
313
+ ]);
314
+
315
+ await unsubscribe5(bConn, [topics[0]]);
316
+
317
+ const aConn = addMockClient(mqttServer);
318
+ await connect5(aConn, { clientId: "unsubPub" });
319
+ await publish5(aConn, topics[0], 1, { payload: "unsubscribed topic" });
320
+ await publish5(aConn, topics[1], 1, { payload: "active topic 1" });
321
+ await publish5(aConn, topics[2], 1, { payload: "active topic 2" });
322
+
323
+ const messages = await receiveMessages5(bConn);
324
+ assert.strictEqual(messages.length, 2);
325
+ await disconnect5(aConn);
326
+ });
327
+
328
+ test("Session Expiry Lifecycle and Reconnection", async () => {
329
+ const { mqttConn } = startMockServer();
330
+
331
+ // 1. Session Expiry = 0 (Immediate expiry)
332
+ await connect5(mqttConn, {
333
+ clientId: "expiryClient",
334
+ clean: true,
335
+ properties: { sessionExpiryInterval: 0 },
336
+ });
337
+ await subscribe5(mqttConn, [{ topicFilter: topics[0], qos: 2 }]);
338
+ await disconnect5(mqttConn);
339
+
340
+ // Reconnect clean=false -> session should not be present
341
+ const { mqttConn: conn2 } = startMockServer();
342
+ const connack2 = await connect5(conn2, {
343
+ clientId: "expiryClient",
344
+ clean: false,
345
+ properties: { sessionExpiryInterval: 0 },
346
+ });
347
+ assert.strictEqual(connack2.sessionPresent, false);
348
+ await disconnect5(conn2);
349
+ });
350
+
351
+ test("User Properties in Publish Packets", async () => {
352
+ const { mqttConn, mqttServer } = startMockServer();
353
+
354
+ await connect5(mqttConn, { clientId: "userPropSub" });
355
+ await subscribe5(mqttConn, [{ topicFilter: topics[0], qos: 2 }]);
356
+
357
+ const pConn = addMockClient(mqttServer);
358
+ await connect5(pConn, { clientId: "userPropPub" });
359
+
360
+ const userProps: PublishProperties = {
361
+ userProperty: [["a", "2"], ["c", "3"]],
362
+ };
363
+
364
+ await publish5(pConn, topics[0], 0, { properties: userProps });
365
+ await publish5(pConn, topics[0], 1, { properties: userProps, id: 1 });
366
+ await publish5(pConn, topics[0], 2, { properties: userProps, id: 2 });
367
+
368
+ const messages = await receiveMessages5(mqttConn);
369
+ assert.strictEqual(messages.length, 3);
370
+ await disconnect5(pConn);
371
+ });
372
+
373
+ test("Payload Format Indicator and Content Type", async () => {
374
+ const { mqttConn, mqttServer } = startMockServer();
375
+
376
+ await connect5(mqttConn, { clientId: "payloadFormatSub" });
377
+ await subscribe5(mqttConn, [{ topicFilter: topics[0], qos: 2 }]);
378
+
379
+ const pConn = addMockClient(mqttServer);
380
+ await connect5(pConn, { clientId: "payloadFormatPub" });
381
+
382
+ const props: PublishProperties = {
383
+ payloadFormatIndicator: true,
384
+ contentType: "application/json",
385
+ };
386
+
387
+ await publish5(pConn, topics[0], 1, {
388
+ payload: '{"key":"value"}',
389
+ properties: props,
390
+ id: 10,
391
+ });
392
+
393
+ const { value: pubMsg } = await mqttConn.next();
394
+ assert.strictEqual(pubMsg.type, PacketType.publish);
395
+ assert.strictEqual(pubMsg.properties?.payloadFormatIndicator, true);
396
+ assert.strictEqual(pubMsg.properties?.contentType, "application/json");
397
+
398
+ await disconnect5(mqttConn);
399
+ await disconnect5(pConn);
400
+ });
401
+
402
+ test("Publication Message Expiry Interval", async () => {
403
+ const { mqttConn: bConn, mqttServer } = startMockServer();
404
+
405
+ await connect5(bConn, {
406
+ clientId: "pubExpirySub",
407
+ clean: true,
408
+ properties: { sessionExpiryInterval: 99999 },
409
+ });
410
+ await subscribe5(bConn, [{ topicFilter: topics[0], qos: 2 }]);
411
+ await disconnect5(bConn, { properties: { sessionExpiryInterval: 99999 } });
412
+
413
+ const aConn = addMockClient(mqttServer);
414
+ await connect5(aConn, { clientId: "pubExpiryPub" });
415
+
416
+ await publish5(aConn, topics[0], 1, {
417
+ payload: "expired message",
418
+ properties: { messageExpiryInterval: 1 },
419
+ id: 1,
420
+ });
421
+ await publish5(aConn, topics[0], 1, {
422
+ payload: "valid message",
423
+ properties: { messageExpiryInterval: 60 },
424
+ id: 2,
425
+ });
426
+
427
+ await delay(1500); // Allow first message to expire
428
+
429
+ const bReconnect = addMockClient(mqttServer);
430
+ await connect5(bReconnect, { clientId: "pubExpirySub", clean: false });
431
+
432
+ const { value: recMsg } = await bReconnect.next();
433
+ assert.strictEqual(recMsg.type, PacketType.publish);
434
+ assert.deepEqual(recMsg.payload, txtEncoder.encode("valid message"));
435
+
436
+ await disconnect5(aConn);
437
+ await disconnect5(bReconnect);
438
+ });
439
+
440
+ test("Subscribe Options (noLocal, retainAsPublished, retainHandling)", async () => {
441
+ const { mqttConn: aConn, mqttServer } = startMockServer();
442
+
443
+ // --- 1. Test noLocal ---
444
+ await connect5(aConn, { clientId: "clientA" });
445
+ await subscribe5(aConn, [{ topicFilter: topics[0], qos: 2, noLocal: true }]);
446
+
447
+ const bConn = addMockClient(mqttServer);
448
+ await connect5(bConn, { clientId: "clientB" });
449
+ await subscribe5(bConn, [{ topicFilter: topics[0], qos: 2, noLocal: true }]);
450
+
451
+ // Client A publishes; should not receive its own message due to noLocal, but Client B should
452
+ await publish5(aConn, topics[0], 1, { payload: "noLocal test", id: 1 });
453
+
454
+ const { value: bMsg } = await bConn.next();
455
+ assert.strictEqual(bMsg.type, PacketType.publish);
456
+ assert.deepEqual(bMsg.payload, txtEncoder.encode("noLocal test"));
457
+
458
+ await disconnect5(aConn);
459
+ await disconnect5(bConn);
460
+
461
+ // --- 2. Test retainAsPublished ---
462
+ const { mqttConn: connRetain, mqttServer: mqttServer2 } = startMockServer();
463
+ await connect5(connRetain, { clientId: "retainAsPublishedClient" });
464
+ await subscribe5(connRetain, [{
465
+ topicFilter: topics[0],
466
+ qos: 2,
467
+ retainAsPublished: true,
468
+ }]);
469
+
470
+ const retainPublish = addMockClient(mqttServer2);
471
+ await connect5(retainPublish);
472
+ await publish5(retainPublish, topics[0], 1, {
473
+ payload: "retain false",
474
+ retain: false,
475
+ id: 2,
476
+ });
477
+ await publish5(retainPublish, topics[0], 1, {
478
+ payload: "retain true",
479
+ retain: true,
480
+ id: 3,
481
+ });
482
+
483
+ const { value: msg1 } = await connRetain.next();
484
+ const { value: msg2 } = await connRetain.next();
485
+
486
+ assert.strictEqual(msg1.retain, false);
487
+ assert.strictEqual(msg2.retain, true);
488
+
489
+ await disconnect5(connRetain);
490
+ await disconnect5(retainPublish);
491
+
492
+ // --- 3. Test retainHandling ---
493
+ // Clean start & prepare some retained messages via Client A
494
+ const { mqttConn: publisherConn, mqttServer: retainServer } =
495
+ startMockServer();
496
+ await connect5(publisherConn, { clientId: "retainPublisher" });
497
+ await publish5(publisherConn, topics[1], 0, {
498
+ payload: "qos 0",
499
+ retain: true,
500
+ });
501
+ await publish5(publisherConn, topics[2], 1, {
502
+ payload: "qos 1",
503
+ retain: true,
504
+ id: 4,
505
+ });
506
+ await publish5(publisherConn, topics[3], 2, {
507
+ payload: "qos 2",
508
+ retain: true,
509
+ id: 5,
510
+ });
511
+ await delay(50);
512
+
513
+ // retainHandling = 1 (send retained messages only on NEW subscription)
514
+ const subscriberConn = addMockClient(retainServer);
515
+ await connect5(subscriberConn, { clientId: "retainHandlerClient" });
516
+
517
+ // 1st subscription -> messages should arrive
518
+ await subscribe5(subscriberConn, [{
519
+ topicFilter: wildtopics[5],
520
+ qos: 2,
521
+ retainHandling: 1,
522
+ }]);
523
+ const r1 = await subscriberConn.next();
524
+ const r2 = await subscriberConn.next();
525
+ const r3 = await subscriberConn.next();
526
+ assert.strictEqual(r1.value.type, PacketType.publish);
527
+ assert.strictEqual(r2.value.type, PacketType.publish);
528
+ assert.strictEqual(r3.value.type, PacketType.publish);
529
+
530
+ // 2nd subscription to the same filter -> retainHandling=1 ensures they are NOT re-sent
531
+ await subscribe5(subscriberConn, [{
532
+ topicFilter: wildtopics[5],
533
+ qos: 2,
534
+ retainHandling: 1,
535
+ }]);
536
+ await delay(100);
537
+
538
+ // retainHandling = 2 (NEVER send retained messages on subscribe)
539
+ await subscribe5(subscriberConn, [{
540
+ topicFilter: wildtopics[5],
541
+ qos: 2,
542
+ retainHandling: 2,
543
+ }]);
544
+ await delay(100);
545
+
546
+ await disconnect5(publisherConn);
547
+ await disconnect5(subscriberConn);
548
+ });
549
+
550
+ test("Assigned Client Identifier", async () => {
551
+ const { mqttConn } = startMockServer();
552
+
553
+ // Send a CONNECT packet with an empty clientId
554
+ const connack = await connect5(mqttConn, { clientId: "" });
555
+
556
+ assert.strictEqual(connack.type, PacketType.connack);
557
+ // The broker must return an AssignedClientIdentifier in properties
558
+ assert.ok(connack.properties?.assignedClientIdentifier);
559
+ assert.notStrictEqual(connack.properties.assignedClientIdentifier, "");
560
+
561
+ await disconnect5(mqttConn);
562
+ });
563
+
564
+ test("Subscribe Identifiers", async () => {
565
+ const { mqttConn: aConn, mqttServer } = startMockServer();
566
+
567
+ await connect5(aConn, { clientId: "subIdClientA" });
568
+ await subscribe5(
569
+ aConn,
570
+ [{ topicFilter: topics[0], qos: 2 }],
571
+ { subscriptionIdentifier: 456789 },
572
+ );
573
+
574
+ const bConn = addMockClient(mqttServer);
575
+ await connect5(bConn, { clientId: "subIdClientB" });
576
+ await subscribe5(
577
+ bConn,
578
+ [{ topicFilter: topics[0], qos: 2 }],
579
+ { subscriptionIdentifier: 2 },
580
+ );
581
+ await subscribe5(
582
+ bConn,
583
+ [{ topicFilter: topics[0] + "/#", qos: 2 }],
584
+ { subscriptionIdentifier: 3 },
585
+ );
586
+
587
+ const publisher = addMockClient(mqttServer);
588
+ await connect5(publisher);
589
+ await publish5(publisher, topics[0], 1, {
590
+ payload: "sub identifier test",
591
+ id: 1,
592
+ });
593
+ await disconnect5(publisher);
594
+
595
+ const { value: msgA } = await aConn.next();
596
+ assert.strictEqual(msgA.type, PacketType.publish);
597
+ assert.deepStrictEqual(msgA.properties?.subscriptionIdentifiers, [456789]);
598
+
599
+ const { value: msgB } = await bConn.next();
600
+ assert.strictEqual(msgB.type, PacketType.publish);
601
+ // For multiple matching subscription IDs, expect them as an array/set
602
+ const subIds = msgB.properties?.subscriptionIdentifiers;
603
+ assert.deepStrictEqual(new Set(subIds), new Set([2, 3]));
604
+
605
+ await disconnect5(aConn);
606
+ await disconnect5(bConn);
607
+ });
608
+
609
+ test("Request Response Pattern", async () => {
610
+ const { mqttConn: aConn, mqttServer } = startMockServer();
611
+
612
+ await connect5(aConn, { clientId: "requester" });
613
+ const bConn = addMockClient(mqttServer);
614
+ await connect5(bConn, { clientId: "responder" });
615
+
616
+ await subscribe5(aConn, [{ topicFilter: topics[1], qos: 2 }]);
617
+ await subscribe5(bConn, [{ topicFilter: topics[0], qos: 2 }]);
618
+
619
+ const reqProps: PublishProperties = {
620
+ responseTopic: topics[1],
621
+ correlationData: txtEncoder.encode("334"),
622
+ };
623
+
624
+ // Requester sends a request
625
+ await publish5(aConn, topics[0], 1, {
626
+ payload: "request",
627
+ properties: reqProps,
628
+ id: 1,
629
+ });
630
+
631
+ // Responder receives the request
632
+ const { value: reqMsg } = await bConn.next();
633
+ assert.strictEqual(reqMsg.type, PacketType.publish);
634
+ assert.strictEqual(reqMsg.properties?.responseTopic, topics[1]);
635
+
636
+ // Responder sends a response back to responseTopic using correlationData
637
+ await publish5(bConn, reqMsg.properties.responseTopic, 1, {
638
+ payload: "response",
639
+ properties: { correlationData: reqMsg.properties.correlationData },
640
+ id: 2,
641
+ });
642
+
643
+ // Requester receives the response
644
+ const { value: respMsg } = await aConn.next();
645
+ assert.strictEqual(respMsg.type, PacketType.publish);
646
+ assert.deepEqual(respMsg.payload, txtEncoder.encode("response"));
647
+
648
+ await disconnect5(aConn);
649
+ await disconnect5(bConn);
650
+ });
651
+
652
+ test("Client Topic Alias", async () => {
653
+ const { mqttConn } = startMockServer();
654
+
655
+ // Test 1: Topic Alias 0 is invalid and must trigger a disconnect
656
+ await connect5(mqttConn);
657
+ await publish5(mqttConn, topics[0], 1, {
658
+ id: 1,
659
+ payload: "invalid alias 0",
660
+ properties: { topicAlias: 0 },
661
+ checkAcks: false,
662
+ });
663
+
664
+ const { value: disc1 } = await mqttConn.next();
665
+ assert.strictEqual(disc1.type, PacketType.disconnect);
666
+
667
+ // Test 2: Valid Topic Alias usage
668
+ const { mqttConn: publisher, mqttServer } = startMockServer();
669
+ const connack = await connect5(publisher, {
670
+ clientId: "publisher",
671
+ });
672
+
673
+ if ((connack.properties?.topicAliasMaximum ?? 0) > 0) {
674
+ const subscriber = addMockClient(mqttServer);
675
+ await connect5(subscriber, { clientId: "topicAliasClient" });
676
+ await subscribe5(subscriber, [{ topicFilter: topics[0], qos: 2 }]);
677
+
678
+ // First message sets up the alias mapping
679
+ await publish5(publisher, topics[0], 1, {
680
+ payload: "alias mapping",
681
+ properties: { topicAlias: 1 },
682
+ id: 2,
683
+ });
684
+
685
+ // Subsequent message uses an empty topic string with the existing alias
686
+ await publish5(publisher, "", 1, {
687
+ payload: "using alias",
688
+ properties: { topicAlias: 1 },
689
+ id: 3,
690
+ });
691
+ const results = await receiveMessages5(subscriber);
692
+ assert.strictEqual(results.length, 2);
693
+ assert.strictEqual(results[0].type, PacketType.publish);
694
+ assert.strictEqual(results[1].type, PacketType.publish);
695
+ }
696
+
697
+ await disconnect5(publisher);
698
+ });
699
+
700
+ test("Server Topic Alias", async () => {
701
+ const { mqttConn: subscriber, mqttServer } = startMockServer();
702
+ const publisher = addMockClient(mqttServer);
703
+
704
+ // Client indicates support for server topic aliases (max 1)
705
+ await connect5(subscriber, {
706
+ clientId: "serverTopicAliasClient",
707
+ properties: { topicAliasMaximum: 1 },
708
+ });
709
+ await subscribe5(subscriber, [{ topicFilter: topics[0], qos: 2 }]);
710
+
711
+ await connect5(publisher, {
712
+ clientId: "publisher",
713
+ });
714
+ for (let qos = 0; qos < 3; qos++) {
715
+ await publish5(publisher, topics[0], qos as QoS, {
716
+ payload: `msg qos ${qos}`,
717
+ id: qos || undefined,
718
+ });
719
+ }
720
+
721
+ // First received message establishes the alias on the client
722
+ const { value: msg1 } = await subscriber.next();
723
+ assert.strictEqual(msg1.type, PacketType.publish);
724
+ assert.ok(msg1.properties?.topicAlias);
725
+ assert.strictEqual(msg1.topic, topics[0]);
726
+
727
+ // Subsequent messages use the alias and may contain an empty topic string
728
+ const { value: msg2 } = await subscriber.next();
729
+ assert.strictEqual(msg2.type, PacketType.publish);
730
+ assert.strictEqual(msg2.properties?.topicAlias, msg1.properties.topicAlias);
731
+
732
+ await disconnect5(publisher);
733
+ await disconnect5(subscriber);
734
+ });
735
+
736
+ test("Maximum Packet Size Handling", async () => {
737
+ const { mqttConn: subscriber, mqttServer } = startMockServer();
738
+ const publisher = addMockClient(mqttServer);
739
+ const maxPacketSize = 64;
740
+
741
+ await connect5(subscriber, {
742
+ clientId: "maxPacketClient",
743
+ properties: { maximumPacketSize: maxPacketSize },
744
+ });
745
+ await subscribe5(subscriber, [{ topicFilter: topics[0], qos: 2 }]);
746
+
747
+ await connect5(publisher, {
748
+ clientId: "publisher",
749
+ });
750
+ // Messages smaller than maximum packet size should be processed normally
751
+ const smallPayload = "a".repeat(Math.floor(maxPacketSize / 2));
752
+ await publish5(publisher, topics[0], 0, { payload: smallPayload });
753
+
754
+ const { value: smallMsg } = await subscriber.next();
755
+ assert.strictEqual(smallMsg.type, PacketType.publish);
756
+
757
+ // Messages exceeding MaximumPacketSize must not be delivered
758
+ const hugePayload = "a".repeat(maxPacketSize * 2);
759
+ await publish5(publisher, topics[0], 1, { payload: hugePayload, id: 10 });
760
+
761
+ // run ping to ensure no other packet was delivered
762
+ await ping(subscriber);
763
+ await disconnect5(subscriber);
764
+ await disconnect5(publisher);
765
+ });
766
+
767
+ test("Server Keep Alive Enforcement", async () => {
768
+ const { mqttConn } = startMockServer({
769
+ configuration: { context: { serverKeepAlive: 60 } },
770
+ });
771
+
772
+ // Request a keepAlive of 120 seconds
773
+ const connack = await connect5(mqttConn, {
774
+ clientId: "keepAliveClient",
775
+ keepAlive: 120,
776
+ });
777
+
778
+ // Verify the server enforces a ServerKeepAlive (e.g., 60 seconds)
779
+ assert.ok(connack.properties?.serverKeepAlive !== undefined);
780
+ assert.strictEqual(connack.properties.serverKeepAlive, 60);
781
+
782
+ await disconnect5(mqttConn);
783
+ });
784
+
785
+ test("Flow Control - Client Receive Maximum", async () => {
786
+ const { mqttConn: subscriber, mqttServer } = startMockServer();
787
+ const publisher = addMockClient(mqttServer);
788
+ const clientReceiveMaximum = 2;
789
+
790
+ await connect5(subscriber, {
791
+ clientId: "flowControlClient1",
792
+ properties: { receiveMaximum: clientReceiveMaximum },
793
+ });
794
+ await subscribe5(subscriber, [{ topicFilter: topics[0], qos: 2 }]);
795
+
796
+ await connect5(publisher, {
797
+ clientId: "publisher",
798
+ });
799
+ // Send 1 more than the allowed maximum number of unacknowledged messages
800
+ for (let i = 1; i <= clientReceiveMaximum + 1; i++) {
801
+ await publish5(publisher, topics[0], 1, {
802
+ payload: `flow msg ${i}`,
803
+ id: i,
804
+ });
805
+ }
806
+
807
+ // Receive the initial allowed messages
808
+ const { value: msg1 } = await subscriber.next();
809
+ const { value: msg2 } = await subscriber.next();
810
+ assert.strictEqual(msg1.type, PacketType.publish);
811
+ assert.strictEqual(msg2.type, PacketType.publish);
812
+ // ensure that there are no more messages
813
+ await ping(subscriber);
814
+
815
+ // Send PUBACK to free up a slot
816
+ await subscriber.send({
817
+ type: PacketType.puback,
818
+ protocolLevel: 5,
819
+ id: msg1.id,
820
+ });
821
+
822
+ // Now the 3rd message should be received
823
+ const { value: msg3 } = await subscriber.next();
824
+ assert.strictEqual(msg3.type, PacketType.publish);
825
+
826
+ await disconnect5(subscriber);
827
+ await disconnect5(publisher);
828
+ });
829
+
830
+ test("Flow Control - Exceeding Server Receive Maximum", async () => {
831
+ const { mqttConn } = startMockServer();
832
+
833
+ const connack = await connect5(mqttConn, { clientId: "flowControlClient2" });
834
+ const serverReceiveMax = connack.properties?.receiveMaximum ?? 65535;
835
+
836
+ // If the server enforces a low limit, exceed it to test disconnect reason code 0x93
837
+ if (serverReceiveMax < 10) {
838
+ for (let i = 1; i <= serverReceiveMax + 1; i++) {
839
+ await publish5(mqttConn, topics[0], 2, {
840
+ payload: `exceed msg ${i}`,
841
+ id: i,
842
+ });
843
+ }
844
+
845
+ const { value: disc } = await mqttConn.next();
846
+ assert.strictEqual(disc.type, PacketType.disconnect);
847
+ // Reason Code 147 (0x93) = Receive Maximum exceeded
848
+ assert.strictEqual(disc.reasonCode, 0x93);
849
+ } else {
850
+ await disconnect5(mqttConn);
851
+ }
852
+ });
853
+
854
+ test("Will Delay Interval and Session Expiry Interaction", async () => {
855
+ const { mqttConn: aConn, mqttServer } = startMockServer();
856
+
857
+ // Test case: WillDelayInterval is set
858
+ await connect5(aConn, {
859
+ clientId: "willDelayClient",
860
+ clean: true,
861
+ keepAlive: 0,
862
+ properties: { sessionExpiryInterval: 5 },
863
+ will: {
864
+ topic: topics[0],
865
+ payload: txtEncoder.encode("delayed will message"),
866
+ qos: 2,
867
+ retain: false,
868
+ properties: { willDelayInterval: 1 },
869
+ },
870
+ });
871
+
872
+ const bConn = addMockClient(mqttServer);
873
+ await connect5(bConn, { clientId: "watcherClient" });
874
+ await subscribe5(bConn, [{ topicFilter: topics[0], qos: 2 }]);
875
+
876
+ // Force an unclean disconnection of Client A
877
+ aConn.close();
878
+
879
+ // The will message should not arrive immediately, but only after the willDelayInterval (1s)
880
+ await delay(1200);
881
+
882
+ const { value: willPub } = await bConn.next();
883
+ assert.strictEqual(willPub.type, PacketType.publish);
884
+ assert.strictEqual(willPub.topic, topics[0]);
885
+
886
+ await disconnect5(bConn);
887
+ });