@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,119 +1,234 @@
1
- import type { Context } from "../context.ts";
2
- import { AuthenticationResult, logger, PacketType, Timer } from "../deps.ts";
1
+ import type {
2
+ AuthenticatedResult,
3
+ ConnectOptions,
4
+ Context,
5
+ } from "../context.ts";
6
+ import {
7
+ invalidmaxTopicLevels,
8
+ invalidTopic,
9
+ logger,
10
+ PacketType,
11
+ ReasonCode,
12
+ } from "../deps.ts";
13
+ import type { ConnectPacket, ExtPublishPacket } from "../deps.ts";
14
+ import { completeConnect } from "./completeConnect.ts";
3
15
 
4
- import type { ConnectPacket, TAuthenticationResult } from "../deps.ts";
16
+ /**
17
+ * Extracts options from MQTT v5 packet properties.
18
+ */
19
+ function extractConnectOptions(packet: ConnectPacket): ConnectOptions {
20
+ if (packet.protocolLevel !== 5) {
21
+ return {};
22
+ }
23
+
24
+ return {
25
+ sessionExpiryInterval: packet.properties?.sessionExpiryInterval,
26
+ willDelayInterval: packet.will?.properties?.willDelayInterval,
27
+ topicAliasMaximum: packet.properties?.topicAliasMaximum,
28
+ maximumOutgoingPacketSize: packet.properties?.maximumPacketSize,
29
+ receiveMaximum: packet.properties?.receiveMaximum,
30
+ };
31
+ }
5
32
 
6
33
  /**
7
- * Checks if the client is authenticated based on the provided credentials
8
- * @param ctx - The connection context
9
- * @param packet - The MQTT CONNECT packet
10
- * @returns Authentication result indicating if the client is authenticated
34
+ * Checks if client credentials are valid.
11
35
  */
12
- function isAuthenticated(
36
+ async function authenticateClient(
13
37
  ctx: Context,
38
+ clientId: string,
14
39
  packet: ConnectPacket,
15
- ): TAuthenticationResult {
40
+ ): Promise<AuthenticatedResult> {
41
+ const isProtocolV5 = packet.protocolLevel === 5;
42
+ const authMethod = isProtocolV5
43
+ ? packet.properties?.authenticationMethod
44
+ : undefined;
45
+
16
46
  if (ctx.handlers.isAuthenticated) {
17
- return ctx.handlers.isAuthenticated(
18
- ctx,
19
- packet.clientId || "",
20
- packet.username || "",
21
- packet.password || new Uint8Array(0),
22
- );
47
+ try {
48
+ const result = await ctx.handlers.isAuthenticated(
49
+ ctx,
50
+ clientId,
51
+ packet.username || "",
52
+ packet.password || new Uint8Array(0),
53
+ packet,
54
+ );
55
+ if (
56
+ isProtocolV5 && result.reasonCode === ReasonCode.success &&
57
+ authMethod !== undefined && ctx.handlers.processAuth
58
+ ) {
59
+ const authData = packet.properties?.authenticationData;
60
+ return await ctx.handlers.processAuth(
61
+ ctx,
62
+ clientId,
63
+ authMethod,
64
+ authData!,
65
+ );
66
+ }
67
+ return result;
68
+ } catch (err) {
69
+ let message = "unknown error";
70
+ if (err instanceof Error) {
71
+ message = err.message;
72
+ }
73
+ logger.error("Authentication failed with error", message);
74
+ return {
75
+ reasonCode: ReasonCode.unspecifiedError,
76
+ reasonString: "Authentication failed",
77
+ };
78
+ }
23
79
  }
24
- return AuthenticationResult.ok;
80
+ return { reasonCode: ReasonCode.success };
25
81
  }
26
82
 
27
83
  /**
28
- * Validates the CONNECT packet
29
- * @param ctx - The connection context
30
- * @param packet - The MQTT CONNECT packet to validate
31
- * @returns Authentication result indicating if the CONNECT packet is valid
84
+ * Validates the CONNECT packet structure and Will configuration.
32
85
  */
33
- function validateConnect(
86
+ async function validateConnectPacket(
34
87
  ctx: Context,
35
88
  packet: ConnectPacket,
36
- ): TAuthenticationResult {
37
- if (packet.protocolLevel !== 4) {
38
- return AuthenticationResult.unacceptableProtocol;
89
+ sessionExpiryInterval: number,
90
+ ): Promise<AuthenticatedResult | null> {
91
+ const cfg = ctx.config.context;
92
+
93
+ // Protocol version check
94
+ if (!cfg.protocols.includes(packet.protocolLevel)) {
95
+ return {
96
+ reasonCode: ReasonCode.unsupportedProtocolVersion,
97
+ reasonString: `Protocol version ${packet.protocolLevel} is not supported`,
98
+ };
39
99
  }
40
100
 
41
- return isAuthenticated(ctx, packet);
42
- }
101
+ // Will message validation
102
+ if (packet.will) {
103
+ const isProtocolV5 = packet.protocolLevel === 5;
104
+ const will = packet.will as ExtPublishPacket;
43
105
 
44
- /**
45
- * Processes the validated CONNECT packet
46
- * @param packet - The MQTT CONNECT packet
47
- * @param ctx - The connection context
48
- * @param clientId - The client ID
49
- */
50
- function processValidatedConnect(
51
- returnCode: TAuthenticationResult,
52
- packet: ConnectPacket,
53
- ctx: Context,
54
- clientId: string,
55
- ): boolean {
56
- if (returnCode === AuthenticationResult.ok) {
57
- if (packet.will) {
58
- ctx.will = {
59
- type: PacketType.publish,
60
- protocolLevel: ctx.protocolLevel,
61
- qos: packet.will.qos,
62
- retain: packet.will.retain,
63
- topic: packet.will.topic,
64
- payload: packet.will.payload,
106
+ if (
107
+ will.topic === "" || invalidTopic(will.topic) ||
108
+ invalidmaxTopicLevels(will.topic, cfg.maxTopicLevels)
109
+ ) {
110
+ return {
111
+ reasonCode: ReasonCode.topicNameInvalid,
112
+ reasonString: "Invalid will topic",
113
+ };
114
+ }
115
+
116
+ if (!cfg.retainAvailable && will.retain) {
117
+ return {
118
+ reasonCode: ReasonCode.retainNotSupported,
119
+ reasonString: "Publish will with retain=true is not supported",
65
120
  };
66
121
  }
67
122
 
68
- ctx.connect(clientId, packet.clean || false);
69
- ctx.protocolLevel = packet.protocolLevel;
70
- if (ctx.mqttConn) {
71
- logger.debug(`Setting protocolLevel to ${ctx.protocolLevel}`);
72
- ctx.mqttConn.codecOpts.protocolLevel = ctx.protocolLevel;
123
+ const checkAuthz = ctx.handlers.isAuthorizedToPublish;
124
+ if (checkAuthz && !await checkAuthz(ctx, will.topic)) {
125
+ return {
126
+ reasonCode: ReasonCode.notAuthorized,
127
+ reasonString: `Client not authorized to publish will to ${will.topic}`,
128
+ };
73
129
  }
74
130
 
75
- const keepAlive = packet.keepAlive || 0;
76
- if (keepAlive > 0) {
77
- logger.debug(`Setting keepalive to ${keepAlive * 1500} ms`);
78
- ctx.timer = new Timer(() => {
79
- ctx.close();
80
- }, Math.floor(keepAlive * 1500));
131
+ const qos = will.qos || 0;
132
+ if (qos > cfg.maximumQos) {
133
+ return {
134
+ reasonCode: ReasonCode.qosNotSupported,
135
+ reasonString: `Server does not support publish will with QoS ${qos}`,
136
+ };
81
137
  }
82
- // is this a new session?
83
- // either because its the first time for the client
84
- // or it specifically asked for a clean one
85
- const previousSession = ctx.store?.existingSession;
86
- // client now has a history
87
- if (!previousSession && ctx.store) {
88
- ctx.store.existingSession = true;
138
+
139
+ if (isProtocolV5) {
140
+ const requestedInterval = packet.will.properties?.willDelayInterval || 0;
141
+ if (requestedInterval > sessionExpiryInterval) {
142
+ return {
143
+ reasonCode: ReasonCode.payloadFormatInvalid,
144
+ reasonString:
145
+ "Will delay interval larger than allowed session expiry interval",
146
+ };
147
+ }
148
+ const expiryInterval = packet.will.properties?.messageExpiryInterval;
149
+ if (expiryInterval) {
150
+ will.expiresAtMs = Date.now() + expiryInterval * 1000;
151
+ }
152
+
153
+ const authMethod = packet.properties?.authenticationMethod;
154
+ const authData = packet.properties?.authenticationData;
155
+
156
+ if (
157
+ // both need to be either present or absent, one is not enough
158
+ (authMethod !== undefined) !== (authData !== undefined) ||
159
+ // authMethod without a handler won't work
160
+ (authMethod !== undefined || !ctx.handlers.processAuth)
161
+ ) {
162
+ return {
163
+ reasonCode: ReasonCode.badAuthenticationMethod,
164
+ reasonString:
165
+ "Bad authentication method or missing authentication data",
166
+ };
167
+ }
89
168
  }
90
- return previousSession || false;
91
169
  }
92
- return false;
170
+
171
+ return null;
93
172
  }
94
173
 
95
174
  /**
96
- * Handles the MQTT CONNECT packet
97
- * @param ctx - The connection context
98
- * @param packet - The MQTT CONNECT packet to handle
175
+ * Handles the MQTT CONNECT packet.
99
176
  */
100
- export function handleConnect(ctx: Context, packet: ConnectPacket): void {
101
- const clientId = packet.clientId || `Opifex-${crypto.randomUUID()}`;
102
- const returnCode = validateConnect(ctx, packet);
103
- const sessionPresent = processValidatedConnect(
104
- returnCode,
105
- packet,
177
+ export async function handleConnect(
178
+ ctx: Context,
179
+ packet: ConnectPacket,
180
+ ): Promise<void> {
181
+ const isProtocolV5 = packet.protocolLevel === 5;
182
+ const cfg = ctx.config.context;
183
+
184
+ // Assign Client ID if missing
185
+ let clientId = packet.clientId;
186
+ let assignedClientIdentifier = undefined;
187
+ if (!clientId) {
188
+ clientId = `Opifex-${crypto.randomUUID()}`;
189
+ assignedClientIdentifier = clientId;
190
+ }
191
+
192
+ // Extract connect options for v5
193
+ const connectOpts = extractConnectOptions(packet);
194
+ // Limit session Expiry Interval to server maximum
195
+ connectOpts.sessionExpiryInterval = Math.min(
196
+ connectOpts.sessionExpiryInterval || 0,
197
+ cfg.maxSessionExpiryInterval,
198
+ );
199
+ connectOpts.keepAlive = packet.keepAlive;
200
+ connectOpts.assignedClientIdentifier = assignedClientIdentifier;
201
+
202
+ // Validate Packet & Authenticate Client
203
+ const validationError = await validateConnectPacket(
106
204
  ctx,
107
- clientId,
205
+ packet,
206
+ connectOpts.sessionExpiryInterval,
108
207
  );
109
- ctx.send({
110
- type: PacketType.connack,
111
- protocolLevel: ctx.protocolLevel,
112
- sessionPresent,
113
- returnCode,
114
- });
115
- logger.debug("connect returnCode", returnCode);
116
- if (returnCode !== AuthenticationResult.ok) {
117
- ctx.close();
208
+ const authResult = validationError ??
209
+ await authenticateClient(ctx, clientId, packet);
210
+ const { reasonCode, reasonString, authData } = authResult;
211
+ const requireAuth = reasonCode === ReasonCode.continueAuthentication;
212
+
213
+ ctx.prepareConnect(packet, clientId, connectOpts);
214
+ if (isProtocolV5 && requireAuth) {
215
+ const authMethod = packet.properties?.authenticationMethod;
216
+ await ctx.send({
217
+ type: PacketType.auth,
218
+ protocolLevel: 5,
219
+ reasonCode,
220
+ properties: {
221
+ authenticationMethod: authMethod,
222
+ authenticationData: authData,
223
+ },
224
+ });
225
+ return;
118
226
  }
227
+
228
+ await completeConnect(
229
+ ctx,
230
+ packet.protocolLevel || 4,
231
+ reasonCode,
232
+ reasonString,
233
+ );
119
234
  }
@@ -0,0 +1,108 @@
1
+ import assert from "node:assert/strict";
2
+ import { test } from "node:test";
3
+ import type { AnyPacket, ProtocolLevel } from "../deps.ts";
4
+ import { AuthenticationResult, MQTTLevel, PacketType } from "../deps.ts";
5
+ import { startMockServer } from "../../dev_utils/mod.ts";
6
+
7
+ const txtEncoder = new TextEncoder();
8
+
9
+ const baseConnectPacket: AnyPacket = {
10
+ type: PacketType.connect,
11
+ protocolName: "MQTT",
12
+ protocolLevel: MQTTLevel.v4 as ProtocolLevel,
13
+ clientId: "testClient",
14
+ clean: true,
15
+ keepAlive: 0,
16
+ username: "IoTester_1",
17
+ password: txtEncoder.encode("strong_password"),
18
+ will: undefined,
19
+ };
20
+
21
+ const disconnectPacket: AnyPacket = {
22
+ type: PacketType.disconnect,
23
+ protocolLevel: MQTTLevel.v4,
24
+ };
25
+
26
+ test("rejects MQTT 3.1 (protocolLevel 3) with unacceptableProtocol", async () => {
27
+ const { mqttConn } = startMockServer();
28
+ const packet = structuredClone(baseConnectPacket);
29
+ packet.protocolLevel = MQTTLevel.v3;
30
+ mqttConn.send(packet);
31
+ const { value: connack } = await mqttConn.next();
32
+ assert.deepStrictEqual(
33
+ connack.type,
34
+ PacketType.connack,
35
+ "Expect Connack packet",
36
+ );
37
+ if (connack.type === PacketType.connack) {
38
+ assert.deepStrictEqual(
39
+ connack.returnCode,
40
+ AuthenticationResult.unacceptableProtocol,
41
+ "Expected unacceptableProtocol for MQTT 3.1",
42
+ );
43
+ }
44
+ await mqttConn.next();
45
+ assert.deepStrictEqual(
46
+ mqttConn.isClosed,
47
+ true,
48
+ "Expected connection to be closed after protocol rejection",
49
+ );
50
+ });
51
+
52
+ test("accepts MQTT 3.1.1 (protocolLevel 4) connection", async () => {
53
+ const { mqttConn } = startMockServer();
54
+ const packet = structuredClone(baseConnectPacket);
55
+ packet.protocolLevel = MQTTLevel.v4;
56
+ mqttConn.send(packet);
57
+ const { value: connack } = await mqttConn.next();
58
+ assert.deepStrictEqual(
59
+ connack.type,
60
+ PacketType.connack,
61
+ "Expect Connack packet",
62
+ );
63
+ if (connack.type === PacketType.connack) {
64
+ assert.deepStrictEqual(
65
+ connack.returnCode,
66
+ AuthenticationResult.ok,
67
+ "Expected OK for MQTT 3.1.1",
68
+ );
69
+ }
70
+ mqttConn.send(disconnectPacket);
71
+ await mqttConn.next();
72
+ assert.deepStrictEqual(
73
+ mqttConn.isClosed,
74
+ true,
75
+ "Expected connection to be closed cleanly",
76
+ );
77
+ });
78
+
79
+ test("accepts MQTT 5.0 (protocolLevel 5) connection", async () => {
80
+ const { mqttConn } = startMockServer();
81
+ const packet = structuredClone(baseConnectPacket);
82
+ packet.protocolLevel = MQTTLevel.v5;
83
+ mqttConn.codecOpts.protocolLevel = MQTTLevel.v5;
84
+ mqttConn.send(packet);
85
+ const { value: connack } = await mqttConn.next();
86
+ assert.deepStrictEqual(
87
+ connack.type,
88
+ PacketType.connack,
89
+ "Expect Connack packet",
90
+ );
91
+ if (connack.type === PacketType.connack) {
92
+ assert.deepStrictEqual(
93
+ connack.reasonCode,
94
+ AuthenticationResult.ok,
95
+ "Expected Ok for MQTT 5.0",
96
+ );
97
+ }
98
+
99
+ const disconnectV5 = structuredClone(disconnectPacket);
100
+ disconnectV5.protocolLevel = 5;
101
+ mqttConn.send(disconnectV5);
102
+ await mqttConn.next();
103
+ assert.deepStrictEqual(
104
+ mqttConn.isClosed,
105
+ true,
106
+ "Expected connection to be closed cleanly",
107
+ );
108
+ });
@@ -0,0 +1,56 @@
1
+ import assert from "node:assert/strict";
2
+ import { test } from "node:test";
3
+ import type { AnyPacket } from "../deps.ts";
4
+ import { PacketType } from "../deps.ts";
5
+ import {
6
+ addMockClient,
7
+ checkNoPacket,
8
+ connect,
9
+ disconnect,
10
+ startMockServer,
11
+ subscribe,
12
+ } from "../../dev_utils/mod.ts";
13
+
14
+ const txtEncoder = new TextEncoder();
15
+
16
+ test("DISCONNECT closes connection cleanly", async () => {
17
+ const { mqttConn } = startMockServer();
18
+
19
+ // Connect first
20
+ await connect(mqttConn);
21
+ // Send DISCONNECT
22
+ await disconnect(mqttConn);
23
+ });
24
+
25
+ test("DISCONNECT clears will message", async () => {
26
+ const connectWithWill: AnyPacket = {
27
+ type: PacketType.connect,
28
+ protocolName: "MQTT",
29
+ protocolLevel: 4,
30
+ clientId: "testClientWithWill",
31
+ clean: true,
32
+ keepAlive: 0,
33
+ username: "IoTester_1",
34
+ password: txtEncoder.encode("strong_password"),
35
+ will: {
36
+ topic: "will/topic",
37
+ payload: txtEncoder.encode("goodbye"),
38
+ qos: 0,
39
+ retain: false,
40
+ },
41
+ };
42
+
43
+ const { mqttConn: mqttConn1, mqttServer } = startMockServer();
44
+ // Connect subscriber to catch any will message
45
+ await connect(mqttConn1);
46
+ await subscribe(mqttConn1, [{ topicFilter: "will/topic", qos: 0 }]);
47
+
48
+ // Connect with will message
49
+ const mqttConn2 = addMockClient(mqttServer);
50
+ mqttConn2.send(connectWithWill);
51
+ const { value: connack2 } = await mqttConn2.next();
52
+ assert.deepStrictEqual(connack2.type, PacketType.connack, "Expected CONNACK");
53
+ await disconnect(mqttConn2);
54
+ // Clean disconnect should clear will (will should not be published)
55
+ await checkNoPacket(mqttConn1);
56
+ });
@@ -5,7 +5,7 @@ import type { Context } from "../context.ts";
5
5
  * @param {Context} ctx - The connection context object
6
6
  * @returns {void}
7
7
  */
8
- export function handleDisconnect(ctx: Context): void {
9
- ctx.will = undefined;
10
- ctx.close();
8
+ export async function handleDisconnect(ctx: Context): Promise<void> {
9
+ // close the context without sending the will
10
+ await ctx.close(false);
11
11
  }
@@ -0,0 +1,24 @@
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 { startMockServer } from "../../dev_utils/mod.ts";
6
+
7
+ test("rejects packets before CONNECT", async () => {
8
+ const { mqttConn } = startMockServer();
9
+
10
+ // Try to send PINGREQ before CONNECT
11
+ const pingreqPacket: AnyPacket = {
12
+ type: PacketType.pingreq,
13
+ protocolLevel: MQTTLevel.v4,
14
+ };
15
+ mqttConn.send(pingreqPacket);
16
+ await mqttConn.next();
17
+
18
+ // Connection should be closed due to protocol violation
19
+ assert.deepStrictEqual(
20
+ mqttConn.isClosed,
21
+ true,
22
+ "Connection should be closed for packets before CONNECT",
23
+ );
24
+ });
@@ -1,7 +1,9 @@
1
+ import { SessionState } from "../context.ts";
1
2
  import type { Context } from "../context.ts";
2
3
  import { PacketNameByType, PacketType } from "../deps.ts";
3
4
  import type {
4
5
  AnyPacket,
6
+ AuthPacket,
5
7
  PubackPacket,
6
8
  PubcompPacket,
7
9
  PublishPacket,
@@ -20,6 +22,7 @@ import { handlePubcomp } from "./handlePubcomp.ts";
20
22
  import { handleSubscribe } from "./handleSubscribe.ts";
21
23
  import { handleUnsubscribe } from "./handleUnsubscribe.ts";
22
24
  import { handleDisconnect } from "./handleDisconnect.ts";
25
+ import { handleAuth } from "./handleAuth.ts";
23
26
  import { logger } from "../deps.ts";
24
27
 
25
28
  /**
@@ -33,16 +36,32 @@ export async function handlePacket(
33
36
  ctx: Context,
34
37
  packet: AnyPacket,
35
38
  ): Promise<void> {
36
- logger.debug("handling", PacketNameByType[packet.type]);
37
- logger.debug(JSON.stringify(packet, null, 2));
38
- if (!ctx.connected) {
39
+ logger.debug("server/handlePacket", PacketNameByType[packet.type]);
40
+ logger.debug(
41
+ "server/handlePacket",
42
+ () => JSON.stringify(packet, null, 2),
43
+ );
44
+ if (ctx.state === SessionState.disconnected) {
39
45
  if (packet.type === PacketType.connect) {
40
- handleConnect(ctx, packet);
41
- } else {
42
- throw new Error(
43
- `Received ${PacketNameByType[packet.type]} packet before connect`,
44
- );
46
+ await handleConnect(ctx, packet);
47
+ ctx.timer?.reset();
48
+ return;
45
49
  }
50
+ throw new Error(
51
+ `Received ${PacketNameByType[packet.type]} packet before connect`,
52
+ );
53
+ }
54
+ if (ctx.state === SessionState.connecting) {
55
+ if (packet.type === PacketType.auth) {
56
+ await handleAuth(ctx, packet as AuthPacket);
57
+ ctx.timer?.reset();
58
+ return;
59
+ }
60
+ throw new Error(
61
+ `Received unexpected ${
62
+ PacketNameByType[packet.type]
63
+ } packet before connect completed`,
64
+ );
46
65
  } else {
47
66
  switch (packet.type) {
48
67
  case PacketType.pingreq:
@@ -72,6 +91,9 @@ export async function handlePacket(
72
91
  case PacketType.disconnect:
73
92
  handleDisconnect(ctx);
74
93
  break;
94
+ case PacketType.auth:
95
+ handleAuth(ctx, packet as AuthPacket);
96
+ break;
75
97
  default:
76
98
  throw new Error(
77
99
  `Received unexpected ${
@@ -0,0 +1,29 @@
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 { connect, disconnect, startMockServer } from "../../dev_utils/mod.ts";
6
+
7
+ const pingreqPacket: AnyPacket = {
8
+ type: PacketType.pingreq,
9
+ protocolLevel: MQTTLevel.v4,
10
+ };
11
+
12
+ test("PINGREQ returns PINGRES", async () => {
13
+ const { mqttConn } = startMockServer();
14
+
15
+ // Connect first
16
+ await connect(mqttConn);
17
+
18
+ // Send PINGREQ
19
+ mqttConn.send(pingreqPacket);
20
+ const { value: pingres } = await mqttConn.next();
21
+ assert.deepStrictEqual(
22
+ pingres.type,
23
+ PacketType.pingres,
24
+ "Expected PINGRES response to PINGREQ",
25
+ );
26
+
27
+ // Disconnect
28
+ await disconnect(mqttConn);
29
+ });
@@ -0,0 +1,28 @@
1
+ import { test } from "node:test";
2
+ import type { AnyPacket } from "../deps.ts";
3
+ import { MQTTLevel, PacketType } from "../deps.ts";
4
+ import {
5
+ connect,
6
+ disconnect,
7
+ ping,
8
+ startMockServer,
9
+ } from "../../dev_utils/mod.ts";
10
+
11
+ test("PUBACK is handled without error", async () => {
12
+ const { mqttConn } = startMockServer();
13
+
14
+ await connect(mqttConn);
15
+
16
+ // Send PUBACK (simulating acknowledgment for outgoing QoS 1 message)
17
+ const pubackPacket: AnyPacket = {
18
+ type: PacketType.puback,
19
+ protocolLevel: MQTTLevel.v4,
20
+ id: 9999,
21
+ };
22
+ mqttConn.send(pubackPacket);
23
+
24
+ // Verify server is still responsive
25
+ await ping(mqttConn);
26
+
27
+ await disconnect(mqttConn);
28
+ });
@@ -7,13 +7,10 @@ import type { PubackPacket } from "../deps.ts";
7
7
  * @param packet - The PUBACK packet received from the client
8
8
  * @description
9
9
  * PUBACK packets are sent in response to PUBLISH packets with QoS level 1.
10
- * This function removes the original PUBLISH packet from the pending outgoing messages store
11
- * once acknowledgment is received.
12
10
  */
13
- export function handlePuback(ctx: Context, packet: PubackPacket) {
14
- // qos 1 only
15
- const id = packet.id;
16
- if (ctx.store?.pendingOutgoing.has(id)) {
17
- ctx.store.pendingOutgoing.delete(id);
18
- }
11
+ export async function handlePuback(
12
+ ctx: Context,
13
+ packet: PubackPacket,
14
+ ): Promise<void> {
15
+ await ctx.processAck(packet.id);
19
16
  }