@seriousme/opifex 1.11.3 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (542) hide show
  1. package/README.md +99 -40
  2. package/bin/conformanceServer.ts +45 -13
  3. package/bin/demoServer.ts +38 -13
  4. package/bin/mqtt.ts +2 -2
  5. package/client/ConnectionState.ts +3 -1
  6. package/client/client.ts +88 -47
  7. package/client/context.ts +79 -27
  8. package/client/deps.ts +10 -3
  9. package/client/handlers/handleAuth.test.ts +193 -0
  10. package/client/handlers/handleAuth.ts +89 -0
  11. package/client/handlers/handleConnack.test.ts +173 -0
  12. package/client/handlers/handleConnack.ts +18 -8
  13. package/client/handlers/handleDisconnect.test.ts +22 -0
  14. package/client/handlers/handleDisconnect.ts +17 -0
  15. package/client/handlers/handlePacket.test.ts +242 -0
  16. package/client/handlers/handlePacket.ts +19 -5
  17. package/client/handlers/handlePuback.test.ts +99 -0
  18. package/client/handlers/handlePuback.ts +6 -0
  19. package/client/handlers/handlePubcomp.test.ts +112 -0
  20. package/client/handlers/handlePubcomp.ts +5 -0
  21. package/client/handlers/handlePublish.test.ts +188 -0
  22. package/client/handlers/handlePubrec.test.ts +119 -0
  23. package/client/handlers/handlePubrec.ts +5 -1
  24. package/client/handlers/handlePubrel.test.ts +136 -0
  25. package/client/handlers/handleSuback.test.ts +122 -0
  26. package/client/handlers/handleSuback.ts +3 -0
  27. package/client/handlers/handleUnsuback.test.ts +101 -0
  28. package/client/mod.ts +13 -2
  29. package/client/store/memoryStore.ts +12 -11
  30. package/client/store/store.ts +4 -2
  31. package/deno/README.md +1 -2
  32. package/deno/tcpClient.test.ts +75 -0
  33. package/deno/tcpClient.ts +36 -18
  34. package/deno/tcpServer.test.ts +22 -21
  35. package/deno/tcpServer.ts +26 -4
  36. package/deno/tlsServer.test.ts +97 -0
  37. package/deno/tlsServer.ts +58 -0
  38. package/deno/wsServer.test.ts +93 -0
  39. package/deno/wsServer.ts +96 -0
  40. package/dev_utils/generateCert.ts +95 -0
  41. package/dev_utils/mockConn.ts +36 -0
  42. package/dev_utils/mockServer.ts +28 -0
  43. package/dev_utils/mod.ts +30 -3
  44. package/dev_utils/packetHelpers.ts +404 -0
  45. package/dev_utils/test-handlers.ts +98 -0
  46. package/dev_utils/timers.ts +14 -0
  47. package/dev_utils/webStreamPair.test.ts +171 -0
  48. package/dev_utils/webStreamPair.ts +143 -0
  49. package/dist/bin/conformanceServer.js +17 -12
  50. package/dist/bin/conformanceServer.js.map +1 -1
  51. package/dist/bin/demoServer.js +16 -12
  52. package/dist/bin/demoServer.js.map +1 -1
  53. package/dist/bin/mqtt.js +2 -2
  54. package/dist/bin/mqtt.js.map +1 -1
  55. package/dist/client/ConnectionState.d.ts +3 -1
  56. package/dist/client/ConnectionState.d.ts.map +1 -1
  57. package/dist/client/ConnectionState.js +2 -0
  58. package/dist/client/ConnectionState.js.map +1 -1
  59. package/dist/client/client.d.ts +47 -21
  60. package/dist/client/client.d.ts.map +1 -1
  61. package/dist/client/client.js +57 -20
  62. package/dist/client/client.js.map +1 -1
  63. package/dist/client/context.d.ts +15 -7
  64. package/dist/client/context.d.ts.map +1 -1
  65. package/dist/client/context.js +44 -12
  66. package/dist/client/context.js.map +1 -1
  67. package/dist/client/deps.d.ts +4 -3
  68. package/dist/client/deps.d.ts.map +1 -1
  69. package/dist/client/deps.js +1 -1
  70. package/dist/client/deps.js.map +1 -1
  71. package/dist/client/handlers/handleAuth.d.ts +9 -0
  72. package/dist/client/handlers/handleAuth.d.ts.map +1 -0
  73. package/dist/client/handlers/handleAuth.js +66 -0
  74. package/dist/client/handlers/handleAuth.js.map +1 -0
  75. package/dist/client/handlers/handleConnack.d.ts +2 -2
  76. package/dist/client/handlers/handleConnack.d.ts.map +1 -1
  77. package/dist/client/handlers/handleConnack.js +16 -6
  78. package/dist/client/handlers/handleConnack.js.map +1 -1
  79. package/dist/client/handlers/handleDisconnect.d.ts +11 -0
  80. package/dist/client/handlers/handleDisconnect.d.ts.map +1 -0
  81. package/dist/client/handlers/handleDisconnect.js +15 -0
  82. package/dist/client/handlers/handleDisconnect.js.map +1 -0
  83. package/dist/client/handlers/handlePacket.d.ts.map +1 -1
  84. package/dist/client/handlers/handlePacket.js +14 -3
  85. package/dist/client/handlers/handlePacket.js.map +1 -1
  86. package/dist/client/handlers/handlePuback.d.ts.map +1 -1
  87. package/dist/client/handlers/handlePuback.js +5 -0
  88. package/dist/client/handlers/handlePuback.js.map +1 -1
  89. package/dist/client/handlers/handlePubcomp.d.ts.map +1 -1
  90. package/dist/client/handlers/handlePubcomp.js +5 -0
  91. package/dist/client/handlers/handlePubcomp.js.map +1 -1
  92. package/dist/client/handlers/handlePubrec.d.ts.map +1 -1
  93. package/dist/client/handlers/handlePubrec.js +5 -1
  94. package/dist/client/handlers/handlePubrec.js.map +1 -1
  95. package/dist/client/handlers/handleSuback.d.ts +1 -0
  96. package/dist/client/handlers/handleSuback.d.ts.map +1 -1
  97. package/dist/client/handlers/handleSuback.js +3 -0
  98. package/dist/client/handlers/handleSuback.js.map +1 -1
  99. package/dist/client/mod.d.ts +3 -2
  100. package/dist/client/mod.d.ts.map +1 -1
  101. package/dist/client/mod.js +1 -1
  102. package/dist/client/mod.js.map +1 -1
  103. package/dist/client/store/memoryStore.d.ts +3 -3
  104. package/dist/client/store/memoryStore.d.ts.map +1 -1
  105. package/dist/client/store/memoryStore.js +3 -3
  106. package/dist/client/store/memoryStore.js.map +1 -1
  107. package/dist/client/store/store.d.ts +3 -2
  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 +24 -31
  128. package/dist/mqttConn/mqttConn.d.ts.map +1 -1
  129. package/dist/mqttConn/mqttConn.js +57 -36
  130. package/dist/mqttConn/mqttConn.js.map +1 -1
  131. package/dist/mqttPacket/AuthenticationResult.d.ts +4 -0
  132. package/dist/mqttPacket/AuthenticationResult.d.ts.map +1 -1
  133. package/dist/mqttPacket/AuthenticationResult.js.map +1 -1
  134. package/dist/mqttPacket/BitMask.d.ts.map +1 -1
  135. package/dist/mqttPacket/PacketType.d.ts +4 -0
  136. package/dist/mqttPacket/PacketType.d.ts.map +1 -1
  137. package/dist/mqttPacket/Properties.d.ts +4 -4
  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 +4 -5
  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 +4 -0
  145. package/dist/mqttPacket/RetainHandling.d.ts.map +1 -1
  146. package/dist/mqttPacket/auth.d.ts +7 -8
  147. package/dist/mqttPacket/auth.d.ts.map +1 -1
  148. package/dist/mqttPacket/auth.js +31 -30
  149. package/dist/mqttPacket/auth.js.map +1 -1
  150. package/dist/mqttPacket/codec.d.ts +48 -0
  151. package/dist/mqttPacket/codec.d.ts.map +1 -0
  152. package/dist/mqttPacket/codec.js +93 -0
  153. package/dist/mqttPacket/codec.js.map +1 -0
  154. package/dist/mqttPacket/connack.d.ts +11 -10
  155. package/dist/mqttPacket/connack.d.ts.map +1 -1
  156. package/dist/mqttPacket/connack.js +43 -45
  157. package/dist/mqttPacket/connack.js.map +1 -1
  158. package/dist/mqttPacket/connect.d.ts +7 -7
  159. package/dist/mqttPacket/connect.d.ts.map +1 -1
  160. package/dist/mqttPacket/connect.js +156 -157
  161. package/dist/mqttPacket/connect.js.map +1 -1
  162. package/dist/mqttPacket/decoder.d.ts +6 -16
  163. package/dist/mqttPacket/decoder.d.ts.map +1 -1
  164. package/dist/mqttPacket/decoder.js +7 -28
  165. package/dist/mqttPacket/decoder.js.map +1 -1
  166. package/dist/mqttPacket/disconnect.d.ts +9 -8
  167. package/dist/mqttPacket/disconnect.d.ts.map +1 -1
  168. package/dist/mqttPacket/disconnect.js +41 -43
  169. package/dist/mqttPacket/disconnect.js.map +1 -1
  170. package/dist/mqttPacket/encoder.d.ts +7 -19
  171. package/dist/mqttPacket/encoder.d.ts.map +1 -1
  172. package/dist/mqttPacket/encoder.js +5 -28
  173. package/dist/mqttPacket/encoder.js.map +1 -1
  174. package/dist/mqttPacket/mod.d.ts +21 -103
  175. package/dist/mqttPacket/mod.d.ts.map +1 -1
  176. package/dist/mqttPacket/mod.js +5 -94
  177. package/dist/mqttPacket/mod.js.map +1 -1
  178. package/dist/mqttPacket/pingreq.d.ts +6 -6
  179. package/dist/mqttPacket/pingreq.d.ts.map +1 -1
  180. package/dist/mqttPacket/pingreq.js +11 -13
  181. package/dist/mqttPacket/pingreq.js.map +1 -1
  182. package/dist/mqttPacket/pingres.d.ts +6 -6
  183. package/dist/mqttPacket/pingres.d.ts.map +1 -1
  184. package/dist/mqttPacket/pingres.js +11 -13
  185. package/dist/mqttPacket/pingres.js.map +1 -1
  186. package/dist/mqttPacket/protocolLevels.d.ts +11 -6
  187. package/dist/mqttPacket/protocolLevels.d.ts.map +1 -1
  188. package/dist/mqttPacket/protocolLevels.js +5 -1
  189. package/dist/mqttPacket/protocolLevels.js.map +1 -1
  190. package/dist/mqttPacket/pubblishAcks.d.ts +9 -10
  191. package/dist/mqttPacket/pubblishAcks.d.ts.map +1 -1
  192. package/dist/mqttPacket/pubblishAcks.js +43 -45
  193. package/dist/mqttPacket/pubblishAcks.js.map +1 -1
  194. package/dist/mqttPacket/publish.d.ts +8 -7
  195. package/dist/mqttPacket/publish.d.ts.map +1 -1
  196. package/dist/mqttPacket/publish.js +53 -55
  197. package/dist/mqttPacket/publish.js.map +1 -1
  198. package/dist/mqttPacket/suback.d.ts +9 -8
  199. package/dist/mqttPacket/suback.d.ts.map +1 -1
  200. package/dist/mqttPacket/suback.js +38 -40
  201. package/dist/mqttPacket/suback.js.map +1 -1
  202. package/dist/mqttPacket/subscribe.d.ts +41 -10
  203. package/dist/mqttPacket/subscribe.d.ts.map +1 -1
  204. package/dist/mqttPacket/subscribe.js +90 -89
  205. package/dist/mqttPacket/subscribe.js.map +1 -1
  206. package/dist/mqttPacket/types.d.ts +2 -29
  207. package/dist/mqttPacket/types.d.ts.map +1 -1
  208. package/dist/mqttPacket/unsuback.d.ts +9 -8
  209. package/dist/mqttPacket/unsuback.d.ts.map +1 -1
  210. package/dist/mqttPacket/unsuback.js +32 -34
  211. package/dist/mqttPacket/unsuback.js.map +1 -1
  212. package/dist/mqttPacket/unsubscribe.d.ts +26 -8
  213. package/dist/mqttPacket/unsubscribe.d.ts.map +1 -1
  214. package/dist/mqttPacket/unsubscribe.js +45 -44
  215. package/dist/mqttPacket/unsubscribe.js.map +1 -1
  216. package/dist/mqttPacket/validators.d.ts +4 -16
  217. package/dist/mqttPacket/validators.d.ts.map +1 -1
  218. package/dist/mqttPacket/validators.js +5 -26
  219. package/dist/mqttPacket/validators.js.map +1 -1
  220. package/dist/node/tcpClient.d.ts +22 -2
  221. package/dist/node/tcpClient.d.ts.map +1 -1
  222. package/dist/node/tcpClient.js +29 -10
  223. package/dist/node/tcpClient.js.map +1 -1
  224. package/dist/node/tcpServer.d.ts +18 -0
  225. package/dist/node/tcpServer.d.ts.map +1 -1
  226. package/dist/node/tcpServer.js +21 -2
  227. package/dist/node/tcpServer.js.map +1 -1
  228. package/dist/node/tlsServer.d.ts +37 -0
  229. package/dist/node/tlsServer.d.ts.map +1 -0
  230. package/dist/node/tlsServer.js +73 -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 +45 -70
  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 +199 -25
  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 +9 -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 +32 -9
  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 +15 -9
  340. package/dist/socket/socket.d.ts.map +1 -1
  341. package/dist/socket/socket.js +66 -18
  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 +61 -41
  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 +42 -5
  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 +14 -0
  396. package/dist/web/wsClient.d.ts.map +1 -0
  397. package/dist/web/wsClient.js +33 -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 +76 -60
  409. package/mqttPacket/AuthenticationResult.ts +6 -0
  410. package/mqttPacket/PacketType.ts +5 -0
  411. package/mqttPacket/Properties.ts +8 -5
  412. package/mqttPacket/ReasonCode.ts +8 -9
  413. package/mqttPacket/RetainHandling.ts +5 -0
  414. package/mqttPacket/auth.test.ts +1 -1
  415. package/mqttPacket/auth.ts +44 -51
  416. package/mqttPacket/codec.ts +147 -0
  417. package/mqttPacket/connack.ts +63 -73
  418. package/mqttPacket/connect.test.ts +2 -2
  419. package/mqttPacket/connect.ts +178 -192
  420. package/mqttPacket/decoder.test.ts +0 -39
  421. package/mqttPacket/decoder.ts +17 -46
  422. package/mqttPacket/disconnect.ts +60 -71
  423. package/mqttPacket/encoder.test.ts +2 -2
  424. package/mqttPacket/encoder.ts +13 -46
  425. package/mqttPacket/mod.ts +48 -204
  426. package/mqttPacket/pingreq.ts +22 -28
  427. package/mqttPacket/pingres.ts +22 -28
  428. package/mqttPacket/protocolLevels.ts +12 -7
  429. package/mqttPacket/pubblishAcks.ts +61 -75
  430. package/mqttPacket/publish.ts +70 -84
  431. package/mqttPacket/publishAcks.test.ts +3 -3
  432. package/mqttPacket/suback.ts +53 -68
  433. package/mqttPacket/subscribe.ts +146 -128
  434. package/mqttPacket/types.ts +2 -35
  435. package/mqttPacket/unsuback.ts +50 -61
  436. package/mqttPacket/unsubscribe.ts +77 -72
  437. package/mqttPacket/validators.ts +5 -31
  438. package/node/socket-node-stream.test.ts +322 -0
  439. package/node/socket-node-stream.ts +174 -0
  440. package/node/tcpClient.test.ts +70 -0
  441. package/node/tcpClient.ts +33 -17
  442. package/node/tcpServer.test.ts +24 -20
  443. package/node/tcpServer.ts +29 -6
  444. package/node/tlsServer.test.ts +94 -0
  445. package/node/tlsServer.ts +97 -0
  446. package/node/wrapNodeSocket.ts +7 -30
  447. package/package.json +72 -44
  448. package/persistence/basicPersistence.ts +495 -0
  449. package/persistence/deps.ts +11 -1
  450. package/persistence/memory/memoryPersistence.ts +12 -153
  451. package/persistence/memory/memoryStorage.ts +232 -0
  452. package/persistence/mod.ts +5 -10
  453. package/persistence/persistence.test.ts +24 -0
  454. package/persistence/persistence.testing.ts +1324 -0
  455. package/persistence/persistence.ts +112 -68
  456. package/persistence/sqlite/sqliteDatabase.ts +294 -0
  457. package/persistence/sqlite/sqlitePersistence.test.ts +48 -0
  458. package/persistence/sqlite/sqlitePersistence.ts +36 -0
  459. package/persistence/sqlite/sqliteStorage.ts +324 -0
  460. package/persistence/storage.ts +84 -0
  461. package/server/config.ts +65 -0
  462. package/server/context.ts +660 -76
  463. package/server/deps.ts +24 -5
  464. package/server/handlers/completeConnect.ts +93 -0
  465. package/server/handlers/duplicate.test.ts +196 -0
  466. package/server/handlers/handleAuth.test.ts +225 -0
  467. package/server/handlers/handleAuth.ts +88 -0
  468. package/server/handlers/handleConnect.test.ts +589 -0
  469. package/server/handlers/handleConnect.ts +201 -86
  470. package/server/handlers/handleConnect.version.test.ts +108 -0
  471. package/server/handlers/handleDisconnect.test.ts +56 -0
  472. package/server/handlers/handleDisconnect.ts +3 -3
  473. package/server/handlers/handlePacket.test.ts +24 -0
  474. package/server/handlers/handlePacket.ts +30 -8
  475. package/server/handlers/handlePingreq.test.ts +29 -0
  476. package/server/handlers/handlePuback.test.ts +28 -0
  477. package/server/handlers/handlePuback.ts +5 -8
  478. package/server/handlers/handlePubcomp.test.ts +28 -0
  479. package/server/handlers/handlePubcomp.ts +5 -4
  480. package/server/handlers/handlePublish.test.ts +471 -0
  481. package/server/handlers/handlePublish.ts +188 -35
  482. package/server/handlers/handlePubrec.test.ts +28 -0
  483. package/server/handlers/handlePubrec.ts +2 -3
  484. package/server/handlers/handlePubrel.test.ts +74 -0
  485. package/server/handlers/handlePubrel.ts +12 -2
  486. package/server/handlers/handleSubscribe.test.ts +971 -0
  487. package/server/handlers/handleSubscribe.ts +157 -39
  488. package/server/handlers/handleUnsubscribe.test.ts +79 -0
  489. package/server/handlers/handleUnsubscribe.ts +28 -4
  490. package/server/handlers/keepalive.test.ts +132 -0
  491. package/server/handlers/session.persistence.test.ts +194 -0
  492. package/server/handlers/will.delivery.test.ts +221 -0
  493. package/server/mod.ts +5 -4
  494. package/server/preconnect.test.ts +151 -0
  495. package/server/server.ts +117 -19
  496. package/socket/socket.test.ts +91 -0
  497. package/socket/socket.ts +85 -34
  498. package/timer/timer.test.ts +4 -7
  499. package/timer/timer.ts +36 -0
  500. package/tools/benchmarks/receiver.ts +51 -0
  501. package/tools/benchmarks/sender.ts +48 -0
  502. package/tools/benchmarks/utils.ts +31 -0
  503. package/tools/mqtt-compat/README.md +130 -0
  504. package/tools/mqtt-compat/broker.ts +52 -0
  505. package/tools/mqtt-compat/paho-mqtt4.test.ts +379 -0
  506. package/tools/mqtt-compat/paho-mqtt5.tests.ts +887 -0
  507. package/trie/trie.test.ts +9 -1
  508. package/trie/trie.ts +70 -45
  509. package/utils/bufferedAsyncIterable.test.ts +92 -0
  510. package/utils/deferred.test.ts +36 -0
  511. package/utils/deferred.ts +0 -1
  512. package/utils/getOrInsertPolyFill.ts +12 -0
  513. package/utils/logger.test.ts +189 -0
  514. package/utils/logger.ts +64 -9
  515. package/utils/mod.ts +15 -1
  516. package/utils/outboundTopicAliasManager.ts +100 -0
  517. package/utils/queue.test.ts +61 -0
  518. package/utils/topicFilter.test.ts +63 -0
  519. package/utils/topicFilter.ts +61 -0
  520. package/utils/utils.ts +3 -0
  521. package/utils/validators.ts +67 -0
  522. package/web/webSocketStream.ts +97 -0
  523. package/web/wrapWebSocket.ts +52 -0
  524. package/web/wsClient.test.ts +26 -0
  525. package/web/wsClient.ts +37 -0
  526. package/benchmarks/receiver.ts +0 -35
  527. package/benchmarks/sender.ts +0 -32
  528. package/benchmarks/utils.ts +0 -9
  529. package/dev_utils/dummyConn.ts +0 -110
  530. package/dev_utils/socketPair.ts +0 -85
  531. package/dist/persistence/store.d.ts +0 -14
  532. package/dist/persistence/store.d.ts.map +0 -1
  533. package/dist/persistence/store.js +0 -2
  534. package/dist/persistence/store.js.map +0 -1
  535. package/dist/utils/BufferedAsyncIterable.d.ts.map +0 -1
  536. package/dist/utils/BufferedAsyncIterable.js.map +0 -1
  537. package/examples/tcpServer.test.ts +0 -148
  538. package/persistence/memory/memoryPersistence.test.ts +0 -156
  539. package/persistence/store.ts +0 -16
  540. package/server/test/handleConnect.test.ts +0 -122
  541. package/server/test/test-handlers.ts +0 -53
  542. /package/utils/{BufferedAsyncIterable.ts → bufferedAsyncIterable.ts} +0 -0
@@ -1,67 +1,185 @@
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
+ } from "../deps.ts";
4
19
 
20
+ // V4 Subscription Failure
21
+ const V4SubscriptionFailure = 0x80;
5
22
  /**
6
- * @constant {number} SubscriptionFailure
7
- * @description Code indicating a failed subscription attempt
23
+ * Checks if a client is authorized to subscribe to a topic.
8
24
  */
9
- const SubscriptionFailure = 0x80;
25
+ async function authorizedToSubscribe(
26
+ ctx: Context,
27
+ topicFilter: Topic,
28
+ shareName: ShareName,
29
+ ): Promise<boolean> {
30
+ if (ctx.state === SessionState.authenticating) {
31
+ return false;
32
+ }
33
+ try {
34
+ if (ctx.handlers.isAuthorizedToSubscribe) {
35
+ return await ctx.handlers.isAuthorizedToSubscribe(
36
+ ctx,
37
+ topicFilter,
38
+ shareName,
39
+ );
40
+ }
41
+ } catch (err) {
42
+ let message = "unknown error";
43
+ if (err instanceof Error) {
44
+ message = err.message;
45
+ }
46
+ logger.error("isAuthorizedToSubscribe failed with error", message);
47
+ return false;
48
+ }
49
+ return true;
50
+ }
10
51
 
11
52
  /**
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
53
+ * Validates a single subscription topic filter against server configuration.
54
+ * Returns an error ReasonCode if invalid, or null if valid.
16
55
  */
17
- function authorizedToSubscribe(ctx: Context, topicFilter: Topic) {
18
- if (ctx.handlers.isAuthorizedToSubscribe) {
19
- return ctx.handlers.isAuthorizedToSubscribe(ctx, topicFilter);
56
+ function validateSubscription(
57
+ isProtocolV5: boolean,
58
+ sub: ClientSubscription,
59
+ cfg: Context["config"]["context"],
60
+ ): ReasonCode | null {
61
+ if (
62
+ cfg.wildcardSubscriptionAvailable === false && hasWildcards(sub.topicFilter)
63
+ ) {
64
+ return ReasonCode.wildcardSubscriptionsNotSupported;
20
65
  }
21
- return true;
66
+
67
+ if (sub.shareName !== "") {
68
+ if (cfg.sharedSubscriptionAvailable === false || !isProtocolV5) {
69
+ return ReasonCode.sharedSubscriptionsNotSupported;
70
+ }
71
+ // noLocal is not allowed on shared subscriptions
72
+ if (sub.noLocal) {
73
+ return ReasonCode.topicFilterInvalid;
74
+ }
75
+ }
76
+
77
+ if (
78
+ sub.topicFilter.length === 0 ||
79
+ invalidTopicFilter(sub.topicFilter) ||
80
+ invalidmaxTopicLevels(sub.topicFilter, cfg.maxTopicLevels)
81
+ ) {
82
+ return ReasonCode.topicFilterInvalid;
83
+ }
84
+
85
+ return null;
22
86
  }
23
87
 
24
88
  /**
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
89
+ * Processes an MQTT SUBSCRIBE packet.
31
90
  * @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
91
  */
33
92
  export async function handleSubscribe(
34
93
  ctx: Context,
35
94
  packet: SubscribePacket,
36
95
  ): 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;
96
+ const cfg = ctx.config.context;
97
+ const isProtocolV5 = packet.protocolLevel === 5;
98
+
99
+ const subscriptionIdentifier = isProtocolV5
100
+ ? packet.properties?.subscriptionIdentifier
101
+ : undefined;
102
+
103
+ // Pre-fetch existing subscriptions to evaluate Retain Handling logic (retainHandling === 1)
104
+ const existingTopicFilters = new Set();
105
+ for await (const sub of ctx.persistence.listSubscriptions(ctx.clientId!)) {
106
+ existingTopicFilters.add(joinTopicFilter(sub.topicFilter, sub.shareName));
107
+ }
108
+
109
+ const retainedSubscriptions: ClientSubscription[] = [];
110
+ const results: ReasonCode[] = [];
111
+
112
+ for (const sub of packet.subscriptions) {
113
+ const clientSub = sub as ClientSubscription;
114
+ // split topicFilter into topicFilter and shareName
115
+ const { topicFilter, shareName } = parseTopicFilter(
116
+ sub.topicFilter,
117
+ );
118
+ clientSub.topicFilter = topicFilter;
119
+ clientSub.shareName = shareName;
120
+ // TopicFilter Validation
121
+ const validationError = validateSubscription(isProtocolV5, clientSub, cfg);
122
+ if (validationError !== null) {
123
+ if (!isProtocolV5) {
124
+ await ctx.close(false);
125
+ return;
46
126
  }
47
- ctx.persistence.subscribe(ctx.store, sub.topicFilter, sub.qos);
48
- validSubscriptions.push(sub);
49
- return sub.qos;
127
+ results.push(validationError);
128
+ continue;
50
129
  }
51
- return SubscriptionFailure;
52
- });
53
130
 
131
+ // Authorization Check
132
+ if (
133
+ !await authorizedToSubscribe(
134
+ ctx,
135
+ clientSub.topicFilter,
136
+ clientSub.shareName,
137
+ )
138
+ ) {
139
+ results.push(
140
+ isProtocolV5 ? ReasonCode.notAuthorized : V4SubscriptionFailure,
141
+ );
142
+ continue;
143
+ }
144
+
145
+ // Register Subscription
146
+ const filterKey = sub.topicFilter;
147
+ const isNewSubscription = !existingTopicFilters.has(filterKey);
148
+
149
+ if (subscriptionIdentifier) {
150
+ clientSub.subscriptionIdentifier = subscriptionIdentifier;
151
+ }
152
+ await ctx.persistence.subscribe(
153
+ ctx.clientId!,
154
+ clientSub,
155
+ );
156
+
157
+ existingTopicFilters.add(filterKey);
158
+
159
+ // Collect Subscriptions Requiring Retained Messages
160
+ if (
161
+ clientSub.retainHandling !== 2 &&
162
+ (clientSub.retainHandling !== 1 || isNewSubscription)
163
+ ) {
164
+ retainedSubscriptions.push(clientSub);
165
+ }
166
+
167
+ // Success code (Granted QoS)
168
+ results.push(sub.qos as ReasonCode);
169
+ }
170
+
171
+ // Send SUBACK response
54
172
  await ctx.send({
55
173
  type: PacketType.suback,
56
174
  protocolLevel: ctx.protocolLevel,
57
175
  id: packet.id,
58
- returnCodes: returnCodes,
176
+ ...(isProtocolV5
177
+ ? { reasonCodes: results }
178
+ : { returnCodes: results as number[] }),
59
179
  });
60
180
 
61
- /*
62
- * send any retained messages that match these subscriptions
63
- */
64
- if (ctx.store) {
65
- ctx.persistence.handleRetained(ctx.store.clientId);
181
+ // Dispatch matching retained messages
182
+ if (retainedSubscriptions.length > 0) {
183
+ await ctx.persistence.handleRetained(ctx.clientId!, retainedSubscriptions);
66
184
  }
67
185
  }
@@ -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";
1
+ import {
2
+ joinTopicFilter,
3
+ PacketType,
4
+ parseTopicFilter,
5
+ ReasonCode,
6
+ } from "../deps.ts";
2
7
  import type { 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: ReasonCode[] = [];
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
+ });