@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
@@ -1,67 +1,186 @@
1
+ import { SessionState } from "../context.ts";
1
2
  import type { Context } from "../context.ts";
2
- import { PacketType } from "../deps.ts";
3
- import type { SubscribePacket, Subscription, Topic } from "../deps.ts";
3
+ import {
4
+ hasWildcards,
5
+ invalidmaxTopicLevels,
6
+ invalidTopicFilter,
7
+ joinTopicFilter,
8
+ logger,
9
+ PacketType,
10
+ parseTopicFilter,
11
+ ReasonCode,
12
+ } from "../deps.ts";
13
+ import type {
14
+ ClientSubscription,
15
+ ShareName,
16
+ SubscribePacket,
17
+ Topic,
18
+ TReasonCode,
19
+ } from "../deps.ts";
4
20
 
21
+ // V4 Subscription Failure
22
+ const V4SubscriptionFailure = 0x80;
5
23
  /**
6
- * @constant {number} SubscriptionFailure
7
- * @description Code indicating a failed subscription attempt
24
+ * Checks if a client is authorized to subscribe to a topic.
8
25
  */
9
- const SubscriptionFailure = 0x80;
26
+ async function authorizedToSubscribe(
27
+ ctx: Context,
28
+ topicFilter: Topic,
29
+ shareName: ShareName,
30
+ ): Promise<boolean> {
31
+ if (ctx.state === SessionState.authenticating) {
32
+ return false;
33
+ }
34
+ try {
35
+ if (ctx.handlers.isAuthorizedToSubscribe) {
36
+ return await ctx.handlers.isAuthorizedToSubscribe(
37
+ ctx,
38
+ topicFilter,
39
+ shareName,
40
+ );
41
+ }
42
+ } catch (err) {
43
+ let message = "unknown error";
44
+ if (err instanceof Error) {
45
+ message = err.message;
46
+ }
47
+ logger.error("isAuthorizedToSubscribe failed with error", message);
48
+ return false;
49
+ }
50
+ return true;
51
+ }
10
52
 
11
53
  /**
12
- * Checks if a client is authorized to subscribe to a topic
13
- * @param ctx - The connection context
14
- * @param topicFilter - The topic filter to check authorization for
15
- * @returns True if authorized, false otherwise
54
+ * Validates a single subscription topic filter against server configuration.
55
+ * Returns an error ReasonCode if invalid, or null if valid.
16
56
  */
17
- function authorizedToSubscribe(ctx: Context, topicFilter: Topic) {
18
- if (ctx.handlers.isAuthorizedToSubscribe) {
19
- return ctx.handlers.isAuthorizedToSubscribe(ctx, topicFilter);
57
+ function validateSubscription(
58
+ isProtocolV5: boolean,
59
+ sub: ClientSubscription,
60
+ cfg: Context["config"]["context"],
61
+ ): TReasonCode | null {
62
+ if (
63
+ cfg.wildcardSubscriptionAvailable === false && hasWildcards(sub.topicFilter)
64
+ ) {
65
+ return ReasonCode.wildcardSubscriptionsNotSupported;
20
66
  }
21
- return true;
67
+
68
+ if (sub.shareName !== "") {
69
+ if (cfg.sharedSubscriptionAvailable === false || !isProtocolV5) {
70
+ return ReasonCode.sharedSubscriptionsNotSupported;
71
+ }
72
+ // noLocal is not allowed on shared subscriptions
73
+ if (sub.noLocal) {
74
+ return ReasonCode.topicFilterInvalid;
75
+ }
76
+ }
77
+
78
+ if (
79
+ sub.topicFilter.length === 0 ||
80
+ invalidTopicFilter(sub.topicFilter) ||
81
+ invalidmaxTopicLevels(sub.topicFilter, cfg.maxTopicLevels)
82
+ ) {
83
+ return ReasonCode.topicFilterInvalid;
84
+ }
85
+
86
+ return null;
22
87
  }
23
88
 
24
89
  /**
25
- * @function handleSubscribe
26
- * @description Processes an MQTT SUBSCRIBE packet
27
- * @param {Context} ctx - The connection context
28
- * @param {SubscribePacket} packet - The SUBSCRIBE packet received from the client
29
- * @returns {Promise<void>}
30
- * @throws {Error} If subscription processing fails
90
+ * Processes an MQTT SUBSCRIBE packet.
31
91
  * @remarks The order of return codes in the SUBACK Packet MUST match the order of Topic Filters in the SUBSCRIBE Packet [MQTT-3.9.3-1]
32
92
  */
33
93
  export async function handleSubscribe(
34
94
  ctx: Context,
35
95
  packet: SubscribePacket,
36
96
  ): Promise<void> {
37
- /*
38
- * The order of return codes in the SUBACK Packet MUST match the order of
39
- * Topic Filters in the SUBSCRIBE Packet [MQTT-3.9.3-1].
40
- */
41
- const validSubscriptions: Subscription[] = [];
42
- const returnCodes = packet.subscriptions.map((sub) => {
43
- if (ctx.store) {
44
- if (!authorizedToSubscribe(ctx, sub.topicFilter)) {
45
- return SubscriptionFailure;
97
+ const cfg = ctx.config.context;
98
+ const isProtocolV5 = packet.protocolLevel === 5;
99
+
100
+ const subscriptionIdentifier = isProtocolV5
101
+ ? packet.properties?.subscriptionIdentifier
102
+ : undefined;
103
+
104
+ // Pre-fetch existing subscriptions to evaluate Retain Handling logic (retainHandling === 1)
105
+ const existingTopicFilters = new Set();
106
+ for await (const sub of ctx.persistence.listSubscriptions(ctx.clientId!)) {
107
+ existingTopicFilters.add(joinTopicFilter(sub.topicFilter, sub.shareName));
108
+ }
109
+
110
+ const retainedSubscriptions: ClientSubscription[] = [];
111
+ const results: TReasonCode[] = [];
112
+
113
+ for (const sub of packet.subscriptions) {
114
+ const clientSub = sub as ClientSubscription;
115
+ // split topicFilter into topicFilter and shareName
116
+ const { topicFilter, shareName } = parseTopicFilter(
117
+ sub.topicFilter,
118
+ );
119
+ clientSub.topicFilter = topicFilter;
120
+ clientSub.shareName = shareName;
121
+ // TopicFilter Validation
122
+ const validationError = validateSubscription(isProtocolV5, clientSub, cfg);
123
+ if (validationError !== null) {
124
+ if (!isProtocolV5) {
125
+ await ctx.close(false);
126
+ return;
46
127
  }
47
- ctx.persistence.subscribe(ctx.store, sub.topicFilter, sub.qos);
48
- validSubscriptions.push(sub);
49
- return sub.qos;
128
+ results.push(validationError);
129
+ continue;
50
130
  }
51
- return SubscriptionFailure;
52
- });
53
131
 
132
+ // Authorization Check
133
+ if (
134
+ !await authorizedToSubscribe(
135
+ ctx,
136
+ clientSub.topicFilter,
137
+ clientSub.shareName,
138
+ )
139
+ ) {
140
+ results.push(
141
+ isProtocolV5 ? ReasonCode.notAuthorized : V4SubscriptionFailure,
142
+ );
143
+ continue;
144
+ }
145
+
146
+ // Register Subscription
147
+ const filterKey = sub.topicFilter;
148
+ const isNewSubscription = !existingTopicFilters.has(filterKey);
149
+
150
+ if (subscriptionIdentifier) {
151
+ clientSub.subscriptionIdentifier = subscriptionIdentifier;
152
+ }
153
+ await ctx.persistence.subscribe(
154
+ ctx.clientId!,
155
+ clientSub,
156
+ );
157
+
158
+ existingTopicFilters.add(filterKey);
159
+
160
+ // Collect Subscriptions Requiring Retained Messages
161
+ if (
162
+ clientSub.retainHandling !== 2 &&
163
+ (clientSub.retainHandling !== 1 || isNewSubscription)
164
+ ) {
165
+ retainedSubscriptions.push(clientSub);
166
+ }
167
+
168
+ // Success code (Granted QoS)
169
+ results.push(sub.qos as TReasonCode);
170
+ }
171
+
172
+ // Send SUBACK response
54
173
  await ctx.send({
55
174
  type: PacketType.suback,
56
175
  protocolLevel: ctx.protocolLevel,
57
176
  id: packet.id,
58
- returnCodes: returnCodes,
177
+ ...(isProtocolV5
178
+ ? { reasonCodes: results }
179
+ : { returnCodes: results as number[] }),
59
180
  });
60
181
 
61
- /*
62
- * send any retained messages that match these subscriptions
63
- */
64
- if (ctx.store) {
65
- ctx.persistence.handleRetained(ctx.store.clientId);
182
+ // Dispatch matching retained messages
183
+ if (retainedSubscriptions.length > 0) {
184
+ await ctx.persistence.handleRetained(ctx.clientId!, retainedSubscriptions);
66
185
  }
67
186
  }
@@ -0,0 +1,79 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import {
4
+ connect,
5
+ connect5,
6
+ disconnect,
7
+ disconnect5,
8
+ startMockServer,
9
+ subscribe,
10
+ subscribe5,
11
+ unsubscribe,
12
+ unsubscribe5,
13
+ } from "../../dev_utils/mod.ts";
14
+ import { ReasonCode } from "../deps.ts";
15
+
16
+ test("UNSUBSCRIBE returns UNSUBACK", async () => {
17
+ const { mqttConn } = startMockServer();
18
+
19
+ // Connect first
20
+ await connect(mqttConn);
21
+
22
+ // Subscribe first
23
+ await subscribe(mqttConn, [{ topicFilter: "test/topic", qos: 0 }]);
24
+
25
+ // Unsubscribe
26
+ await unsubscribe(mqttConn, ["test/topic"], { id: 2 });
27
+ await disconnect(mqttConn);
28
+ });
29
+
30
+ test("UNSUBSCRIBE from multiple topics returns UNSUBACK", async () => {
31
+ const { mqttConn } = startMockServer();
32
+
33
+ await connect(mqttConn);
34
+
35
+ // Subscribe to multiple topics
36
+ await subscribe(mqttConn, [
37
+ { topicFilter: "topic/one", qos: 0 },
38
+ { topicFilter: "topic/two", qos: 0 },
39
+ ]);
40
+
41
+ // Unsubscribe from both
42
+ await unsubscribe(mqttConn, ["topic/one", "topic/two"], { id: 3 });
43
+ await disconnect(mqttConn);
44
+ });
45
+
46
+ test("UNSUBSCRIBE from non-existent subscription still returns UNSUBACK", async () => {
47
+ const { mqttConn } = startMockServer();
48
+
49
+ await connect(mqttConn);
50
+
51
+ // Unsubscribe without subscribing first,should still get a SUBACK
52
+ await unsubscribe(mqttConn, ["nonexistent/topic"], { id: 3 });
53
+ await disconnect(mqttConn);
54
+ });
55
+
56
+ test("V5 UNSUBSCRIBE from multiple subscriptions gives correct reasonCodes", async () => {
57
+ const { mqttConn } = startMockServer();
58
+
59
+ await connect5(mqttConn);
60
+ // Subscribe to multiple topics
61
+ await subscribe5(mqttConn, [
62
+ { topicFilter: "topic/one", qos: 0 },
63
+ { topicFilter: "topic/two", qos: 0 },
64
+ ]);
65
+
66
+ const unsuback = await unsubscribe5(mqttConn, [
67
+ "topic/one",
68
+ "topic/two",
69
+ "nonexistent/topic",
70
+ ], { id: 3 });
71
+ assert.equal(unsuback.protocolLevel, 5, "V5 packet");
72
+ assert.deepStrictEqual(unsuback.reasonCodes, [
73
+ ReasonCode.success,
74
+ ReasonCode.success,
75
+ ReasonCode.noSubscriptionExisted,
76
+ ]);
77
+
78
+ await disconnect5(mqttConn);
79
+ });
@@ -1,5 +1,11 @@
1
- import { PacketType } from "../deps.ts";
2
- import type { UnsubscribePacket } from "../deps.ts";
1
+ import {
2
+ joinTopicFilter,
3
+ PacketType,
4
+ parseTopicFilter,
5
+ ReasonCode,
6
+ } from "../deps.ts";
7
+ import type { TReasonCode, UnsubscribePacket } from "../deps.ts";
8
+ import { SessionState } from "../context.ts";
3
9
  import type { Context } from "../context.ts";
4
10
 
5
11
  /**
@@ -12,14 +18,32 @@ export async function handleUnsubscribe(
12
18
  ctx: Context,
13
19
  packet: UnsubscribePacket,
14
20
  ): Promise<void> {
15
- for (const topic of packet.topicFilters) {
16
- if (ctx.store) {
17
- ctx.persistence.unsubscribe(ctx.store, topic);
21
+ // this is v5 only, no unsubscriptions while reauthenticating
22
+ const isAuthenticating = ctx.state === SessionState.authenticating;
23
+
24
+ const subscriptions = new Set();
25
+ for await (const sub of ctx.persistence.listSubscriptions(ctx.clientId!)) {
26
+ subscriptions.add(joinTopicFilter(sub.topicFilter, sub.shareName));
27
+ }
28
+
29
+ const reasonCodes: TReasonCode[] = [];
30
+
31
+ for (const packetTopicFilter of packet.topicFilters) {
32
+ // split topicFilter into topicFilter and shareName
33
+ const { topicFilter, shareName } = parseTopicFilter(
34
+ packetTopicFilter,
35
+ );
36
+ if (subscriptions.has(packetTopicFilter) && !isAuthenticating) {
37
+ reasonCodes.push(ReasonCode.success);
38
+ await ctx.persistence.unsubscribe(ctx.clientId!, topicFilter, shareName);
39
+ } else {
40
+ reasonCodes.push(ReasonCode.noSubscriptionExisted);
18
41
  }
19
42
  }
20
43
  await ctx.send({
21
44
  type: PacketType.unsuback,
22
45
  id: packet.id,
23
46
  protocolLevel: ctx.protocolLevel,
47
+ reasonCodes,
24
48
  });
25
49
  }
@@ -0,0 +1,132 @@
1
+ import assert from "node:assert/strict";
2
+ import { test } from "node:test";
3
+ import type { AnyPacket } from "../deps.ts";
4
+ import { MQTTLevel, PacketType } from "../deps.ts";
5
+ import {
6
+ connect,
7
+ delay,
8
+ disconnect,
9
+ ping,
10
+ startMockServer,
11
+ } from "../../dev_utils/mod.ts";
12
+
13
+ const txtEncoder = new TextEncoder();
14
+
15
+ const publishPacket: AnyPacket = {
16
+ type: PacketType.publish,
17
+ protocolLevel: MQTTLevel.v4,
18
+ topic: "test/topic",
19
+ payload: txtEncoder.encode("test payload"),
20
+ qos: 0,
21
+ retain: false,
22
+ dup: false,
23
+ id: 0,
24
+ };
25
+
26
+ test("MQTT-3.1.2.10: connection stays alive with PINGREQ", {
27
+ concurrency: false,
28
+ }, async () => {
29
+ const { mqttConn } = startMockServer();
30
+ const keepAlive = 1; // 1 second -> 1500ms timeout
31
+
32
+ // Connect with keepAlive
33
+ await connect(mqttConn, { clientId: "keepaliveTest1", keepAlive });
34
+
35
+ // Wait for 750ms (half the timeout period)
36
+ await delay(750);
37
+
38
+ // Send PINGREQ to reset timer
39
+ await ping(mqttConn);
40
+
41
+ // Wait another 750ms (total 1500ms from start, but timer was reset at 750ms)
42
+ await delay(750);
43
+
44
+ // Connection should still be alive
45
+ assert.deepStrictEqual(
46
+ mqttConn.isClosed,
47
+ false,
48
+ "Connection should stay alive after PINGREQ resets timer",
49
+ );
50
+
51
+ // Cleanup
52
+ await disconnect(mqttConn);
53
+ });
54
+
55
+ test("MQTT-3.1.2.10: connection closes after 1.5x keepAlive timeout", {
56
+ concurrency: false,
57
+ }, async () => {
58
+ const { mqttConn } = startMockServer();
59
+ const keepAlive = 1; // 1 second -> 1500ms timeout
60
+
61
+ // Connect with keepAlive
62
+ await connect(mqttConn, { clientId: "keepaliveTest2", keepAlive });
63
+
64
+ // Wait for timeout to expire (1500ms + buffer)
65
+ await delay(1600);
66
+
67
+ // flush state
68
+ await mqttConn.next();
69
+
70
+ // Connection should be closed
71
+ assert.deepStrictEqual(
72
+ mqttConn.isClosed,
73
+ true,
74
+ "Connection should close after keepAlive timeout expires",
75
+ );
76
+ });
77
+
78
+ test(
79
+ "MQTT-3.1.2.10: any packet resets keepAlive timer",
80
+ { concurrency: false },
81
+ async () => {
82
+ const { mqttConn } = startMockServer();
83
+ const keepAlive = 1; // 1 second -> 1500ms timeout
84
+
85
+ // Connect with keepAlive
86
+ await connect(mqttConn, { clientId: "keepaliveTest3", keepAlive });
87
+
88
+ // Wait for 750ms (half timeout)
89
+ await delay(750);
90
+
91
+ // Send PUBLISH packet (not PINGREQ) to reset timer
92
+ mqttConn.send(publishPacket);
93
+
94
+ // Wait another 750ms (total 1500ms from start, but timer was reset at 750ms)
95
+ await delay(750);
96
+
97
+ // Connection should still be alive
98
+ assert.deepStrictEqual(
99
+ mqttConn.isClosed,
100
+ false,
101
+ "Connection should stay alive - any packet should reset timer",
102
+ );
103
+
104
+ // Cleanup
105
+ await disconnect(mqttConn);
106
+ },
107
+ );
108
+
109
+ test(
110
+ "MQTT-3.1.2.10: keepAlive=0 disables timeout",
111
+ { concurrency: false },
112
+ async () => {
113
+ const { mqttConn } = startMockServer();
114
+ const keepAlive = 0; // 0 means no timeout
115
+
116
+ // Connect with keepAlive=0
117
+ await connect(mqttConn, { clientId: "keepaliveTest4", keepAlive });
118
+
119
+ // Wait longer than any reasonable timeout
120
+ await delay(2000);
121
+
122
+ // Connection should still be open
123
+ assert.deepStrictEqual(
124
+ mqttConn.isClosed,
125
+ false,
126
+ "Connection should remain open when keepAlive=0",
127
+ );
128
+
129
+ // Cleanup
130
+ await disconnect(mqttConn);
131
+ },
132
+ );
@@ -0,0 +1,194 @@
1
+ import assert from "node:assert/strict";
2
+ import { test } from "node:test";
3
+ import { PacketType } from "../deps.ts";
4
+ import {
5
+ addMockClient,
6
+ connect,
7
+ disconnect,
8
+ startMockServer,
9
+ subscribe,
10
+ } from "../../dev_utils/mod.ts";
11
+
12
+ test("sessionPresent is false for new client", async () => {
13
+ const { mqttConn } = startMockServer();
14
+
15
+ const connack = await connect(mqttConn, {
16
+ clientId: "new-client",
17
+ clean: false,
18
+ });
19
+
20
+ assert.deepStrictEqual(
21
+ connack.sessionPresent,
22
+ false,
23
+ "Expected sessionPresent=false for new client",
24
+ );
25
+
26
+ await disconnect(mqttConn);
27
+ });
28
+
29
+ test("sessionPresent is true when reconnecting with same clientId and clean=false", async () => {
30
+ const { mqttConn: mqttConn1, mqttServer } = startMockServer();
31
+
32
+ const clientId = "persist-client";
33
+ // First connection
34
+ const connack1 = await connect(mqttConn1, {
35
+ clientId,
36
+ clean: false,
37
+ });
38
+
39
+ if (connack1.type === PacketType.connack) {
40
+ assert.deepStrictEqual(
41
+ connack1.sessionPresent,
42
+ false,
43
+ "Expected sessionPresent=false for first connection",
44
+ );
45
+ }
46
+ await disconnect(mqttConn1);
47
+
48
+ // Second connection with same clientId and clean=false
49
+ const mqttConn2 = addMockClient(mqttServer);
50
+ const connack2 = await connect(mqttConn2, {
51
+ clientId,
52
+ clean: false,
53
+ });
54
+
55
+ assert.deepStrictEqual(
56
+ connack2.sessionPresent,
57
+ true,
58
+ "Expected sessionPresent=true for reconnection with clean=false",
59
+ );
60
+ await disconnect(mqttConn2);
61
+ });
62
+
63
+ test("subscriptions persist with clean=false", async () => {
64
+ function subsMap(subs: { topicFilter: string; qos: number }[]) {
65
+ const result = new Map();
66
+ for (const { topicFilter, qos } of subs) {
67
+ result.set(topicFilter, qos);
68
+ }
69
+ return result;
70
+ }
71
+ const { mqttConn: mqttConn1, mqttServer } = startMockServer();
72
+ const clientId = "subscription-persist-client";
73
+
74
+ // First connection
75
+ await connect(mqttConn1, {
76
+ clientId,
77
+ clean: false,
78
+ });
79
+
80
+ await subscribe(mqttConn1, [
81
+ { topicFilter: "sensors/temperature", qos: 1 },
82
+ { topicFilter: "sensors/humidity", qos: 2 },
83
+ ], { id: 1 });
84
+ await disconnect(mqttConn1);
85
+
86
+ // Verify subscriptions are stored
87
+ const client1Subs = await Array.fromAsync(
88
+ mqttServer.persistence.listSubscriptions(clientId),
89
+ );
90
+ assert.strictEqual(
91
+ client1Subs.length,
92
+ 2,
93
+ "Expected 2 subscriptions after first connection",
94
+ );
95
+ const client1subsMap = subsMap(client1Subs);
96
+ assert.strictEqual(
97
+ client1subsMap.get("sensors/temperature"),
98
+ 1,
99
+ "Expected sensors/temperature with QoS 1",
100
+ );
101
+ assert.strictEqual(
102
+ client1subsMap.get("sensors/humidity"),
103
+ 2,
104
+ "Expected sensors/humidity with QoS 2",
105
+ );
106
+
107
+ // Second connection with clean=false
108
+ const mqttConn2 = addMockClient(mqttServer);
109
+ const connack2 = await connect(mqttConn2, {
110
+ clientId,
111
+ clean: false,
112
+ });
113
+
114
+ if (connack2.type === PacketType.connack) {
115
+ assert.deepStrictEqual(
116
+ connack2.sessionPresent,
117
+ true,
118
+ "Expected sessionPresent=true on reconnection",
119
+ );
120
+ }
121
+
122
+ // Verify subscriptions are restored
123
+ const client2Subs = await Array.fromAsync(
124
+ mqttServer.persistence.listSubscriptions(clientId),
125
+ );
126
+ assert.strictEqual(
127
+ client1Subs.length,
128
+ 2,
129
+ "Expected 2 subscriptions after reconnection",
130
+ );
131
+ const client2subsMap = subsMap(client2Subs);
132
+ assert.strictEqual(
133
+ client2subsMap.get("sensors/temperature"),
134
+ 1,
135
+ "Expected sensors/temperature with QoS 1",
136
+ );
137
+ assert.strictEqual(
138
+ client2subsMap.get("sensors/humidity"),
139
+ 2,
140
+ "Expected sensors/humidity with QoS 2",
141
+ );
142
+
143
+ await disconnect(mqttConn2);
144
+ });
145
+
146
+ test("subscriptions cleared with clean=true", async () => {
147
+ const { mqttConn: mqttConn1, mqttServer } = startMockServer();
148
+ const clientId = "clean-client";
149
+
150
+ // First connection - subscribe to topics
151
+ await connect(mqttConn1, {
152
+ clientId,
153
+ clean: false,
154
+ });
155
+
156
+ await subscribe(mqttConn1, [{ topicFilter: "device/status", qos: 0 }], {
157
+ id: 1,
158
+ });
159
+ await disconnect(mqttConn1);
160
+
161
+ // Verify subscriptions are stored
162
+ const storedSubs = await Array.fromAsync(
163
+ mqttServer.persistence.listSubscriptions(clientId),
164
+ );
165
+ assert.strictEqual(
166
+ storedSubs.length,
167
+ 1,
168
+ "Expected 1 subscription after first connection",
169
+ );
170
+
171
+ // Second connection with clean=true
172
+ const mqttConn2 = addMockClient(mqttServer);
173
+ const connack2 = await connect(mqttConn2, {
174
+ clientId,
175
+ clean: true,
176
+ });
177
+
178
+ assert.deepStrictEqual(
179
+ connack2.sessionPresent,
180
+ false,
181
+ "Expected sessionPresent=false when clean=true",
182
+ );
183
+
184
+ const cleanedSubs = await Array.fromAsync(
185
+ mqttServer.persistence.listSubscriptions(clientId),
186
+ );
187
+ assert.strictEqual(
188
+ cleanedSubs.length,
189
+ 0,
190
+ "Expected subscriptions to be cleared with clean=true",
191
+ );
192
+
193
+ await disconnect(mqttConn2);
194
+ });