@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
@@ -0,0 +1,99 @@
1
+ import assert from "node:assert/strict";
2
+ import { test } from "node:test";
3
+ import { handlePuback } from "./handlePuback.ts";
4
+ import { PacketType, ReasonCode, ReasonCodeByNumber } from "../deps.ts";
5
+ import type { PubackPacket } from "../deps.ts";
6
+
7
+ function createMockContext() {
8
+ const receivedIds: number[] = [];
9
+ return {
10
+ protocolLevel: 4 as const,
11
+ store: {
12
+ pendingOutgoing: new Map<number, unknown>(),
13
+ pendingIncoming: new Map(),
14
+ pendingAckOutgoing: new Map(),
15
+ },
16
+ receivePuback: (id: number) => {
17
+ receivedIds.push(id);
18
+ return true;
19
+ },
20
+ receivedIds,
21
+ };
22
+ }
23
+
24
+ test("handlePuback removes packet from pending and notifies context", () => {
25
+ const ctx = createMockContext();
26
+ ctx.store.pendingOutgoing.set(1, { type: PacketType.publish });
27
+
28
+ const packet = {
29
+ type: PacketType.puback,
30
+ protocolLevel: 4 as const,
31
+ id: 1,
32
+ } as PubackPacket;
33
+
34
+ handlePuback(ctx as never, packet);
35
+
36
+ assert.deepStrictEqual(
37
+ ctx.store.pendingOutgoing.has(1),
38
+ false,
39
+ "Should remove from pending",
40
+ );
41
+ assert.deepStrictEqual(
42
+ ctx.receivedIds,
43
+ [1],
44
+ "Should notify context of puback",
45
+ );
46
+ });
47
+
48
+ test("handlePuback handles non-existent packet ID gracefully", () => {
49
+ const ctx = createMockContext();
50
+
51
+ const packet = {
52
+ type: PacketType.puback,
53
+ protocolLevel: 4 as const,
54
+ id: 999,
55
+ } as PubackPacket;
56
+
57
+ // Should not throw
58
+ handlePuback(ctx as never, packet);
59
+
60
+ assert.deepStrictEqual(
61
+ ctx.receivedIds,
62
+ [999],
63
+ "Should still notify context",
64
+ );
65
+ });
66
+
67
+ test("handlePuback processes multiple PUBACKs correctly", () => {
68
+ const ctx = createMockContext();
69
+ ctx.store.pendingOutgoing.set(1, { type: PacketType.publish });
70
+ ctx.store.pendingOutgoing.set(2, { type: PacketType.publish });
71
+ ctx.store.pendingOutgoing.set(3, { type: PacketType.publish });
72
+
73
+ handlePuback(ctx as never, {
74
+ type: PacketType.puback,
75
+ protocolLevel: 4,
76
+ id: 2,
77
+ } as PubackPacket);
78
+
79
+ assert.deepStrictEqual(ctx.store.pendingOutgoing.has(1), true);
80
+ assert.deepStrictEqual(ctx.store.pendingOutgoing.has(2), false);
81
+ assert.deepStrictEqual(ctx.store.pendingOutgoing.has(3), true);
82
+ assert.deepStrictEqual(ctx.receivedIds, [2]);
83
+ });
84
+
85
+ test("handlePuback processes V5 publish rejection", () => {
86
+ const ctx = createMockContext();
87
+ const reasonCode = ReasonCode.notAuthorized;
88
+ ctx.store.pendingOutgoing.set(2, {
89
+ type: PacketType.publish,
90
+ topic: "Test Puback",
91
+ });
92
+ assert.throws(() =>
93
+ handlePuback(ctx as never, {
94
+ type: PacketType.puback,
95
+ protocolLevel: 5,
96
+ id: 2,
97
+ reasonCode,
98
+ } as PubackPacket), Error(ReasonCodeByNumber[reasonCode]));
99
+ });
@@ -1,5 +1,6 @@
1
1
  import type { Context } from "../context.ts";
2
2
  import type { PubackPacket } from "../deps.ts";
3
+ import { ReasonCodeByNumber } from "../deps.ts";
3
4
 
4
5
  /**
5
6
  * Handles PUBACK packet processing for QoS level 1 PUBLISH responses
@@ -12,5 +13,10 @@ import type { PubackPacket } from "../deps.ts";
12
13
  export function handlePuback(ctx: Context, packet: PubackPacket): void {
13
14
  const id = packet.id;
14
15
  ctx.store.pendingOutgoing.delete(id);
16
+
17
+ if (packet.protocolLevel === 5 && ((packet.reasonCode ?? 0) !== 0)) {
18
+ ctx.store.pendingOutgoing.delete(id);
19
+ throw new Error(ReasonCodeByNumber[packet.reasonCode!]);
20
+ }
15
21
  ctx.receivePuback(id);
16
22
  }
@@ -0,0 +1,112 @@
1
+ import assert from "node:assert/strict";
2
+ import { test } from "node:test";
3
+ import { handlePubcomp } from "./handlePubcomp.ts";
4
+ import { PacketType, ReasonCode, ReasonCodeByNumber } from "../deps.ts";
5
+ import type { PubcompPacket } from "../deps.ts";
6
+
7
+ function createMockContext() {
8
+ const receivedIds: number[] = [];
9
+ return {
10
+ protocolLevel: 4 as const,
11
+ store: {
12
+ pendingOutgoing: new Map(),
13
+ pendingIncoming: new Map(),
14
+ pendingAckOutgoing: new Map<number, unknown>(),
15
+ },
16
+ receivePubcomp: (id: number) => {
17
+ receivedIds.push(id);
18
+ return true;
19
+ },
20
+ receivedIds,
21
+ };
22
+ }
23
+
24
+ test("handlePubcomp removes from pendingAckOutgoing and notifies", () => {
25
+ const ctx = createMockContext();
26
+ ctx.store.pendingAckOutgoing.set(1, { type: PacketType.pubrel, id: 1 });
27
+
28
+ const packet = {
29
+ type: PacketType.pubcomp,
30
+ protocolLevel: 4 as const,
31
+ id: 1,
32
+ } as PubcompPacket;
33
+
34
+ handlePubcomp(ctx as never, packet);
35
+
36
+ assert.deepStrictEqual(
37
+ ctx.store.pendingAckOutgoing.has(1),
38
+ false,
39
+ "Should remove from pendingAckOutgoing",
40
+ );
41
+ assert.deepStrictEqual(
42
+ ctx.receivedIds,
43
+ [1],
44
+ "Should notify context of pubcomp",
45
+ );
46
+ });
47
+
48
+ test("handlePubcomp ignores unknown packet ID", () => {
49
+ const ctx = createMockContext();
50
+
51
+ const packet = {
52
+ type: PacketType.pubcomp,
53
+ protocolLevel: 4 as const,
54
+ id: 999,
55
+ } as PubcompPacket;
56
+
57
+ handlePubcomp(ctx as never, packet);
58
+
59
+ // Should not notify for unknown ID (based on implementation)
60
+ assert.deepStrictEqual(
61
+ ctx.receivedIds.length,
62
+ 0,
63
+ "Should not notify for unknown ID",
64
+ );
65
+ });
66
+
67
+ test("handlePubcomp completes QoS 2 outgoing flow", () => {
68
+ const ctx = createMockContext();
69
+
70
+ // Simulate QoS 2 state after PUBREC was received
71
+ ctx.store.pendingAckOutgoing.set(5, { type: PacketType.pubrel, id: 5 });
72
+
73
+ handlePubcomp(ctx as never, {
74
+ type: PacketType.pubcomp,
75
+ protocolLevel: 4,
76
+ id: 5,
77
+ } as PubcompPacket);
78
+
79
+ assert.deepStrictEqual(ctx.store.pendingAckOutgoing.size, 0);
80
+ assert.deepStrictEqual(ctx.receivedIds, [5]);
81
+ });
82
+
83
+ test("handlePubcomp processes multiple PUBCOMPs correctly", () => {
84
+ const ctx = createMockContext();
85
+ ctx.store.pendingAckOutgoing.set(1, { type: PacketType.pubrel, id: 1 });
86
+ ctx.store.pendingAckOutgoing.set(2, { type: PacketType.pubrel, id: 2 });
87
+ ctx.store.pendingAckOutgoing.set(3, { type: PacketType.pubrel, id: 3 });
88
+
89
+ handlePubcomp(ctx as never, {
90
+ type: PacketType.pubcomp,
91
+ protocolLevel: 4,
92
+ id: 2,
93
+ } as PubcompPacket);
94
+
95
+ assert.deepStrictEqual(ctx.store.pendingAckOutgoing.has(1), true);
96
+ assert.deepStrictEqual(ctx.store.pendingAckOutgoing.has(2), false);
97
+ assert.deepStrictEqual(ctx.store.pendingAckOutgoing.has(3), true);
98
+ assert.deepStrictEqual(ctx.receivedIds, [2]);
99
+ });
100
+
101
+ test("handlePubComp processes V5 rejection", () => {
102
+ const ctx = createMockContext();
103
+ ctx.store.pendingAckOutgoing.set(3, { type: PacketType.pubrel, id: 3 });
104
+ const reasonCode = ReasonCode.notAuthorized;
105
+ assert.throws(() =>
106
+ handlePubcomp(ctx as never, {
107
+ type: PacketType.pubcomp,
108
+ protocolLevel: 5,
109
+ id: 3,
110
+ reasonCode,
111
+ } as PubcompPacket), Error(ReasonCodeByNumber[reasonCode]));
112
+ });
@@ -1,5 +1,6 @@
1
1
  import type { Context } from "../context.ts";
2
2
  import type { PubcompPacket } from "../deps.ts";
3
+ import { ReasonCodeByNumber } from "../deps.ts";
3
4
 
4
5
  /**
5
6
  * Handles PUBCOMP packets which are the response to PUBREL packets in QoS 2 flow
@@ -12,6 +13,10 @@ import type { PubcompPacket } from "../deps.ts";
12
13
  */
13
14
  export function handlePubcomp(ctx: Context, packet: PubcompPacket): void {
14
15
  const id = packet.id;
16
+ if (packet.protocolLevel === 5 && ((packet.reasonCode ?? 0) !== 0)) {
17
+ ctx.store.pendingOutgoing.delete(id);
18
+ throw new Error(ReasonCodeByNumber[packet.reasonCode!]);
19
+ }
15
20
  if (ctx.store.pendingAckOutgoing.has(id)) {
16
21
  ctx.store.pendingAckOutgoing.delete(id);
17
22
  ctx.receivePubcomp(id);
@@ -0,0 +1,188 @@
1
+ import assert from "node:assert/strict";
2
+ import { test } from "node:test";
3
+ import { handlePublish } from "./handlePublish.ts";
4
+ import { PacketType } from "../deps.ts";
5
+ import type { PublishPacket } from "../deps.ts";
6
+
7
+ function createMockContext() {
8
+ const sentPackets: unknown[] = [];
9
+ const receivedPublishes: PublishPacket[] = [];
10
+ return {
11
+ protocolLevel: 4 as const,
12
+ store: {
13
+ pendingOutgoing: new Map(),
14
+ pendingIncoming: new Map<number, PublishPacket>(),
15
+ pendingAckOutgoing: new Map(),
16
+ },
17
+ send: (packet: unknown) => {
18
+ sentPackets.push(packet);
19
+ },
20
+ receivePublish: (packet: PublishPacket) => {
21
+ receivedPublishes.push(packet);
22
+ },
23
+ sentPackets,
24
+ receivedPublishes,
25
+ };
26
+ }
27
+
28
+ test("handlePublish QoS 0 delivers message without acknowledgment", async () => {
29
+ const ctx = createMockContext();
30
+ const packet = {
31
+ type: PacketType.publish,
32
+ protocolLevel: 4 as const,
33
+ topic: "test/topic",
34
+ payload: new Uint8Array([1, 2, 3]),
35
+ qos: 0 as const,
36
+ retain: false,
37
+ dup: false,
38
+ } as PublishPacket;
39
+
40
+ await handlePublish(ctx as never, packet);
41
+
42
+ assert.deepStrictEqual(
43
+ ctx.receivedPublishes.length,
44
+ 1,
45
+ "Should receive publish",
46
+ );
47
+ assert.deepStrictEqual(
48
+ ctx.sentPackets.length,
49
+ 0,
50
+ "QoS 0 should not send acknowledgment",
51
+ );
52
+ });
53
+
54
+ test("handlePublish QoS 1 delivers message and sends PUBACK", async () => {
55
+ const ctx = createMockContext();
56
+ const packet = {
57
+ type: PacketType.publish,
58
+ protocolLevel: 4 as const,
59
+ topic: "test/topic",
60
+ payload: new Uint8Array([1, 2, 3]),
61
+ qos: 1 as const,
62
+ retain: false,
63
+ dup: false,
64
+ id: 1,
65
+ } as PublishPacket;
66
+
67
+ await handlePublish(ctx as never, packet);
68
+
69
+ assert.deepStrictEqual(
70
+ ctx.receivedPublishes.length,
71
+ 1,
72
+ "Should receive publish",
73
+ );
74
+ assert.deepStrictEqual(
75
+ ctx.sentPackets.length,
76
+ 1,
77
+ "Should send PUBACK",
78
+ );
79
+ assert.deepStrictEqual(
80
+ (ctx.sentPackets[0] as { type: number }).type,
81
+ PacketType.puback,
82
+ "Should send PUBACK packet",
83
+ );
84
+ assert.deepStrictEqual(
85
+ (ctx.sentPackets[0] as { id: number }).id,
86
+ 1,
87
+ "PUBACK should have same packet ID",
88
+ );
89
+ });
90
+
91
+ test("handlePublish QoS 2 stores message and sends PUBREC", async () => {
92
+ const ctx = createMockContext();
93
+ const packet = {
94
+ type: PacketType.publish,
95
+ protocolLevel: 4 as const,
96
+ topic: "test/topic",
97
+ payload: new Uint8Array([1, 2, 3]),
98
+ qos: 2 as const,
99
+ retain: false,
100
+ dup: false,
101
+ id: 2,
102
+ } as PublishPacket;
103
+
104
+ await handlePublish(ctx as never, packet);
105
+
106
+ // QoS 2: should NOT deliver message yet (waits for PUBREL)
107
+ assert.deepStrictEqual(
108
+ ctx.receivedPublishes.length,
109
+ 0,
110
+ "QoS 2 should not deliver message until PUBREL",
111
+ );
112
+
113
+ // Should store the packet
114
+ assert.deepStrictEqual(
115
+ ctx.store.pendingIncoming.has(2),
116
+ true,
117
+ "Should store incoming packet",
118
+ );
119
+
120
+ // Should send PUBREC
121
+ assert.deepStrictEqual(
122
+ ctx.sentPackets.length,
123
+ 1,
124
+ "Should send PUBREC",
125
+ );
126
+ assert.deepStrictEqual(
127
+ (ctx.sentPackets[0] as { type: number }).type,
128
+ PacketType.pubrec,
129
+ "Should send PUBREC packet",
130
+ );
131
+ assert.deepStrictEqual(
132
+ (ctx.sentPackets[0] as { id: number }).id,
133
+ 2,
134
+ "PUBREC should have same packet ID",
135
+ );
136
+ });
137
+
138
+ test("handlePublish without packet ID for QoS 1 does nothing", async () => {
139
+ const ctx = createMockContext();
140
+ const packet = {
141
+ type: PacketType.publish,
142
+ protocolLevel: 4 as const,
143
+ topic: "test/topic",
144
+ payload: new Uint8Array([1, 2, 3]),
145
+ qos: 1 as const,
146
+ retain: false,
147
+ dup: false,
148
+ // No id
149
+ } as PublishPacket;
150
+
151
+ await handlePublish(ctx as never, packet);
152
+
153
+ // Without packet ID, QoS 1/2 handling is skipped
154
+ assert.deepStrictEqual(
155
+ ctx.receivedPublishes.length,
156
+ 0,
157
+ "Should not receive without packet ID",
158
+ );
159
+ assert.deepStrictEqual(
160
+ ctx.sentPackets.length,
161
+ 0,
162
+ "Should not send without packet ID",
163
+ );
164
+ });
165
+
166
+ test("handlePublish QoS 2 without store does nothing", async () => {
167
+ const ctx = createMockContext();
168
+ (ctx as unknown as { store: null }).store = null as never;
169
+ const packet = {
170
+ type: PacketType.publish,
171
+ protocolLevel: 4 as const,
172
+ topic: "test/topic",
173
+ payload: new Uint8Array([1, 2, 3]),
174
+ qos: 2 as const,
175
+ retain: false,
176
+ dup: false,
177
+ id: 3,
178
+ } as PublishPacket;
179
+
180
+ // Should not throw, just silently skip
181
+ await handlePublish(ctx as never, packet);
182
+
183
+ assert.deepStrictEqual(
184
+ ctx.sentPackets.length,
185
+ 0,
186
+ "Should not send without store",
187
+ );
188
+ });
@@ -0,0 +1,119 @@
1
+ import assert from "node:assert/strict";
2
+ import { test } from "node:test";
3
+ import { handlePubrec } from "./handlePubrec.ts";
4
+ import { PacketType, ReasonCode, ReasonCodeByNumber } from "../deps.ts";
5
+ import type { PubrecPacket } from "../deps.ts";
6
+
7
+ function createMockContext() {
8
+ const sentPackets: unknown[] = [];
9
+ return {
10
+ protocolLevel: 4 as const,
11
+ store: {
12
+ pendingOutgoing: new Map<number, unknown>(),
13
+ pendingIncoming: new Map(),
14
+ pendingAckOutgoing: new Map<number, unknown>(),
15
+ },
16
+ send: (packet: unknown) => {
17
+ sentPackets.push(packet);
18
+ },
19
+ sentPackets,
20
+ };
21
+ }
22
+
23
+ test("handlePubrec sends PUBREL for pending outgoing QoS 2", async () => {
24
+ const ctx = createMockContext();
25
+ ctx.store.pendingOutgoing.set(1, { type: PacketType.publish, id: 1 });
26
+
27
+ const packet = {
28
+ type: PacketType.pubrec,
29
+ protocolLevel: 4 as const,
30
+ id: 1,
31
+ } as PubrecPacket;
32
+
33
+ await handlePubrec(ctx as never, packet);
34
+
35
+ // Should send PUBREL
36
+ assert.deepStrictEqual(ctx.sentPackets.length, 1, "Should send PUBREL");
37
+ assert.deepStrictEqual(
38
+ (ctx.sentPackets[0] as { type: number }).type,
39
+ PacketType.pubrel,
40
+ "Should send PUBREL packet",
41
+ );
42
+ assert.deepStrictEqual(
43
+ (ctx.sentPackets[0] as { id: number }).id,
44
+ 1,
45
+ "PUBREL should have same packet ID",
46
+ );
47
+
48
+ // Should move from pendingOutgoing to pendingAckOutgoing
49
+ assert.deepStrictEqual(
50
+ ctx.store.pendingOutgoing.has(1),
51
+ false,
52
+ "Should remove from pendingOutgoing",
53
+ );
54
+ assert.deepStrictEqual(
55
+ ctx.store.pendingAckOutgoing.has(1),
56
+ true,
57
+ "Should add to pendingAckOutgoing",
58
+ );
59
+ });
60
+
61
+ test("handlePubrec ignores unknown packet ID", async () => {
62
+ const ctx = createMockContext();
63
+
64
+ const packet = {
65
+ type: PacketType.pubrec,
66
+ protocolLevel: 4 as const,
67
+ id: 999,
68
+ } as PubrecPacket;
69
+
70
+ await handlePubrec(ctx as never, packet);
71
+
72
+ assert.deepStrictEqual(
73
+ ctx.sentPackets.length,
74
+ 0,
75
+ "Should not send PUBREL for unknown ID",
76
+ );
77
+ assert.deepStrictEqual(
78
+ ctx.store.pendingAckOutgoing.has(999),
79
+ false,
80
+ "Should not add to pendingAckOutgoing",
81
+ );
82
+ });
83
+
84
+ test("handlePubrec stores PUBREL packet for retransmission", async () => {
85
+ const ctx = createMockContext();
86
+ ctx.store.pendingOutgoing.set(5, { type: PacketType.publish, id: 5 });
87
+
88
+ const packet = {
89
+ type: PacketType.pubrec,
90
+ protocolLevel: 4 as const,
91
+ id: 5,
92
+ } as PubrecPacket;
93
+
94
+ await handlePubrec(ctx as never, packet);
95
+
96
+ const storedPubrel = ctx.store.pendingAckOutgoing.get(5);
97
+ assert.ok(storedPubrel, "Should store PUBREL");
98
+ assert.deepStrictEqual(
99
+ (storedPubrel as { type: number }).type,
100
+ PacketType.pubrel,
101
+ "Stored packet should be PUBREL",
102
+ );
103
+ });
104
+
105
+ test("handlePuback processes V5 publish rejection", () => {
106
+ const ctx = createMockContext();
107
+ const reasonCode = ReasonCode.notAuthorized;
108
+ ctx.store.pendingOutgoing.set(2, {
109
+ type: PacketType.publish,
110
+ topic: "Test Pubrec",
111
+ });
112
+ assert.rejects(() =>
113
+ handlePubrec(ctx as never, {
114
+ type: PacketType.pubrec,
115
+ protocolLevel: 5,
116
+ id: 2,
117
+ reasonCode,
118
+ } as PubrecPacket), Error(ReasonCodeByNumber[reasonCode]));
119
+ });
@@ -1,5 +1,5 @@
1
1
  import type { Context } from "../context.ts";
2
- import { PacketType } from "../deps.ts";
2
+ import { PacketType, ReasonCodeByNumber } from "../deps.ts";
3
3
  import type { PubrecPacket, PubrelPacket } from "../deps.ts";
4
4
 
5
5
  /**
@@ -26,6 +26,10 @@ export async function handlePubrec(
26
26
  id,
27
27
  };
28
28
  if (ctx.store.pendingOutgoing.has(id)) {
29
+ if (packet.protocolLevel === 5 && ((packet.reasonCode ?? 0) !== 0)) {
30
+ ctx.store.pendingOutgoing.delete(id);
31
+ throw new Error(ReasonCodeByNumber[packet.reasonCode!]);
32
+ }
29
33
  ctx.store.pendingAckOutgoing.set(id, ack);
30
34
  ctx.store.pendingOutgoing.delete(id);
31
35
  await ctx.send(ack);
@@ -0,0 +1,136 @@
1
+ import assert from "node:assert/strict";
2
+ import { test } from "node:test";
3
+ import { handlePubrel } from "./handlePubrel.ts";
4
+ import { PacketType } from "../deps.ts";
5
+ import type { PublishPacket, PubrelPacket } from "../deps.ts";
6
+
7
+ function createMockContext() {
8
+ const sentPackets: unknown[] = [];
9
+ const receivedPublishes: PublishPacket[] = [];
10
+ return {
11
+ protocolLevel: 4 as const,
12
+ store: {
13
+ pendingOutgoing: new Map(),
14
+ pendingIncoming: new Map<number, PublishPacket>(),
15
+ pendingAckOutgoing: new Map(),
16
+ },
17
+ send: (packet: unknown) => {
18
+ sentPackets.push(packet);
19
+ },
20
+ receivePublish: (packet: PublishPacket) => {
21
+ receivedPublishes.push(packet);
22
+ },
23
+ sentPackets,
24
+ receivedPublishes,
25
+ };
26
+ }
27
+
28
+ test("handlePubrel delivers stored message and sends PUBCOMP", async () => {
29
+ const ctx = createMockContext();
30
+ const storedPublish = {
31
+ type: PacketType.publish,
32
+ protocolLevel: 4 as const,
33
+ topic: "test/topic",
34
+ payload: new Uint8Array([1, 2, 3]),
35
+ qos: 2 as const,
36
+ retain: false,
37
+ dup: false,
38
+ id: 1,
39
+ } as PublishPacket;
40
+ ctx.store.pendingIncoming.set(1, storedPublish);
41
+
42
+ const packet = {
43
+ type: PacketType.pubrel,
44
+ protocolLevel: 4 as const,
45
+ id: 1,
46
+ } as PubrelPacket;
47
+
48
+ await handlePubrel(ctx as never, packet);
49
+
50
+ // Should deliver the message
51
+ assert.deepStrictEqual(
52
+ ctx.receivedPublishes.length,
53
+ 1,
54
+ "Should deliver stored message",
55
+ );
56
+ assert.deepStrictEqual(
57
+ ctx.receivedPublishes[0].topic,
58
+ "test/topic",
59
+ "Should deliver correct message",
60
+ );
61
+
62
+ // Should send PUBCOMP
63
+ assert.deepStrictEqual(ctx.sentPackets.length, 1, "Should send PUBCOMP");
64
+ assert.deepStrictEqual(
65
+ (ctx.sentPackets[0] as { type: number }).type,
66
+ PacketType.pubcomp,
67
+ "Should send PUBCOMP packet",
68
+ );
69
+ assert.deepStrictEqual(
70
+ (ctx.sentPackets[0] as { id: number }).id,
71
+ 1,
72
+ "PUBCOMP should have same packet ID",
73
+ );
74
+
75
+ // Should remove from pending incoming
76
+ assert.deepStrictEqual(
77
+ ctx.store.pendingIncoming.has(1),
78
+ false,
79
+ "Should remove from pendingIncoming",
80
+ );
81
+ });
82
+
83
+ test("handlePubrel ignores unknown packet ID", async () => {
84
+ const ctx = createMockContext();
85
+
86
+ const packet = {
87
+ type: PacketType.pubrel,
88
+ protocolLevel: 4 as const,
89
+ id: 999,
90
+ } as PubrelPacket;
91
+
92
+ await handlePubrel(ctx as never, packet);
93
+
94
+ assert.deepStrictEqual(
95
+ ctx.receivedPublishes.length,
96
+ 0,
97
+ "Should not deliver for unknown ID",
98
+ );
99
+ assert.deepStrictEqual(
100
+ ctx.sentPackets.length,
101
+ 0,
102
+ "Should not send PUBCOMP for unknown ID",
103
+ );
104
+ });
105
+
106
+ test("handlePubrel completes QoS 2 flow correctly", async () => {
107
+ const ctx = createMockContext();
108
+
109
+ // Simulate full QoS 2 flow - message already stored from PUBLISH
110
+ const storedPublish = {
111
+ type: PacketType.publish,
112
+ protocolLevel: 4 as const,
113
+ topic: "sensors/temp",
114
+ payload: new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f]), // "Hello"
115
+ qos: 2 as const,
116
+ retain: false,
117
+ dup: false,
118
+ id: 42,
119
+ } as PublishPacket;
120
+ ctx.store.pendingIncoming.set(42, storedPublish);
121
+
122
+ await handlePubrel(ctx as never, {
123
+ type: PacketType.pubrel,
124
+ protocolLevel: 4,
125
+ id: 42,
126
+ } as PubrelPacket);
127
+
128
+ // Verify complete flow
129
+ assert.deepStrictEqual(ctx.receivedPublishes.length, 1);
130
+ assert.deepStrictEqual(ctx.receivedPublishes[0], storedPublish);
131
+ assert.deepStrictEqual(
132
+ (ctx.sentPackets[0] as { type: number }).type,
133
+ PacketType.pubcomp,
134
+ );
135
+ assert.deepStrictEqual(ctx.store.pendingIncoming.size, 0);
136
+ });