@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
package/socket/socket.ts CHANGED
@@ -1,21 +1,16 @@
1
- export type SockAddr = NetAddr | UnixAddr | VsockAddr;
2
- export interface NetAddr {
1
+ /** Net adresses */
2
+ export type NetAddr = {
3
3
  transport: "tcp" | "udp";
4
4
  hostname: string;
5
5
  port: number;
6
- }
7
-
8
- export interface UnixAddr {
9
- transport: "unix" | "unixpacket";
10
- path: string;
11
- }
12
-
13
- export interface VsockAddr {
14
- transport: "vsock";
15
- cid: number;
16
- port: number;
17
- }
18
-
6
+ };
7
+ /** Unix adresses */
8
+ export type UnixAddr = { transport: "unix" | "unixpacket"; path: string };
9
+ /** vSock adresses */
10
+ export type VsockAddr = { transport: "vsock"; cid: number; port: number };
11
+ /** Socket adresses */
12
+ export type SockAddr = NetAddr | UnixAddr | VsockAddr;
13
+ /** Socket connection descriptor. */
19
14
  export type SockConn = {
20
15
  readable: ReadableStream<Uint8Array>;
21
16
  writable: WritableStream<Uint8Array>;
@@ -25,49 +20,105 @@ export type SockConn = {
25
20
  };
26
21
 
27
22
  export class Conn {
28
- reader: ReadableStreamBYOBReader;
23
+ reader: ReadableStreamDefaultReader<Uint8Array>;
29
24
  writer: WritableStreamDefaultWriter<Uint8Array>;
30
25
  closed: boolean;
31
26
  remoteAddr: SockAddr | undefined;
32
27
  closer: () => void;
33
28
 
29
+ private leftover: Uint8Array = new Uint8Array(0);
30
+
34
31
  constructor(sockConn: SockConn) {
35
32
  this.closed = false;
36
- this.reader = sockConn.readable.getReader({ mode: "byob" });
33
+ this.reader = sockConn.readable.getReader();
37
34
  this.writer = sockConn.writable.getWriter();
38
- // this.writer.closed.then(() => this.closed = true);
39
35
  this.closer = sockConn.close.bind(sockConn);
36
+ this.reader.closed.catch(() => {});
37
+ this.writer.closed.catch(() => {});
40
38
  this.remoteAddr = sockConn.remoteAddr;
41
39
  }
42
40
 
43
- async read(buff: Uint8Array): Promise<number | null> {
44
- const buff2 = new Uint8Array(buff.length);
45
- const result = await this.reader.read(buff2);
46
- if (!result.done) {
47
- buff.set(result.value);
41
+ async read(length: number): Promise<Uint8Array | null> {
42
+ if (this.closed || length < 0) {
43
+ return null;
44
+ }
45
+
46
+ if (length === 0) {
47
+ return new Uint8Array(0);
48
+ }
49
+
50
+ const result = new Uint8Array(length);
51
+ let bytesAccumulated = 0;
52
+
53
+ // Do we have data from the previous read()
54
+ if (this.leftover.length > 0) {
55
+ const take = Math.min(this.leftover.length, length);
56
+ result.set(this.leftover.subarray(0, take), bytesAccumulated);
57
+ bytesAccumulated += take;
58
+ this.leftover = this.leftover.subarray(take);
59
+ }
60
+
61
+ // Keep readin until we have enough data
62
+ while (bytesAccumulated < length) {
63
+ const { value, done } = await this.reader.read();
64
+
65
+ if (value) {
66
+ const needed = length - bytesAccumulated;
67
+
68
+ if (value.length <= needed) {
69
+ // We need the whole chunk
70
+ result.set(value, bytesAccumulated);
71
+ bytesAccumulated += value.length;
72
+ } else {
73
+ // Chunk is bigger than what we need
74
+ result.set(value.subarray(0, needed), bytesAccumulated);
75
+ bytesAccumulated += needed;
76
+ // Save the rest for the next read() call
77
+ this.leftover = value.subarray(needed);
78
+ }
79
+ }
80
+ if (done) {
81
+ // if the stream closed and not enough data was returned, return null
82
+ return null;
83
+ }
48
84
  }
49
- return result.value?.byteLength || null;
85
+ return result;
50
86
  }
51
87
 
52
- write(data: Uint8Array): Promise<number> {
88
+ async write(data: Uint8Array): Promise<number> {
53
89
  if (this.closed) {
54
- return Promise.reject();
90
+ return Promise.reject(new Error("Connection closed"));
91
+ }
92
+ try {
93
+ await this.writer.write(data);
94
+ return data.length;
95
+ } catch (err) {
96
+ this.closed = true;
97
+ throw err;
55
98
  }
56
- this.writer.write(data);
57
- return new Promise((resolve) => resolve(data.length));
58
99
  }
59
100
 
60
101
  close() {
61
102
  if (!this.closed) {
62
- try {
63
- this.writer.close();
64
- } catch (_err) { /* swallow any errors on close */ }
65
103
  this.closed = true;
104
+
105
+ // deno-coverage-ignore-start
106
+ void this.writer.close().catch(() => {
107
+ // ignore duplicate/late close attempts; the stream may already be closed
108
+ });
109
+ // deno-coverage-ignore-stop
110
+
111
+ try {
112
+ void this.reader.cancel().catch(() => {
113
+ // ignore duplicate/late cancel attempts; the stream may already be closed
114
+ });
115
+ this.reader?.releaseLock();
116
+ // deno-coverage-ignore
117
+ } catch (_err) { /* swallow */ }
118
+
66
119
  try {
67
120
  this.closer();
68
- } catch (_err) {
69
- // swallow any errors on close
70
- }
121
+ } catch (_err) { /* swallow */ }
71
122
  }
72
123
  }
73
124
  }
@@ -1,12 +1,9 @@
1
1
  import { Timer } from "./timer.ts";
2
2
  import assert from "node:assert/strict";
3
3
  import { test } from "node:test";
4
+ import { delay } from "../dev_utils/mod.ts";
4
5
 
5
- function delay(ms: number) {
6
- return new Promise((resolve) => setTimeout(resolve, ms));
7
- }
8
-
9
- test("timer should ring", async () => {
6
+ test("timer should ring", { concurrency: false }, async () => {
10
7
  const wait = 50;
11
8
  const start = Date.now();
12
9
  let end = Date.now();
@@ -18,7 +15,7 @@ test("timer should ring", async () => {
18
15
  assert.deepStrictEqual(timeDiff < 10, true);
19
16
  });
20
17
 
21
- test("snooze should work", async () => {
18
+ test("snooze should work", { concurrency: false }, async () => {
22
19
  const wait = 50;
23
20
  const quarterWait = Math.floor(wait / 4);
24
21
  const halfWait = quarterWait * 2;
@@ -37,7 +34,7 @@ test("snooze should work", async () => {
37
34
  assert.deepStrictEqual(timeDiff < 15, true, `TimeDiff of ${timeDiff} < 15`);
38
35
  });
39
36
 
40
- test("clear should work", () => {
37
+ test("clear should work", { concurrency: false }, () => {
41
38
  const wait = 50;
42
39
  let end = 0;
43
40
  const timer = new Timer(() => {
package/timer/timer.ts CHANGED
@@ -1,11 +1,31 @@
1
+ /**
2
+ * A reusable timer class that executes a callback function after a specified delay.
3
+ * It handles potential drifts or early triggers by checking the actual remaining time
4
+ * before executing the action.
5
+ */
1
6
  export class Timer {
7
+ /** The delay duration in milliseconds before the timer expires. */
2
8
  readonly delay: number; // delay in microseconds
9
+
10
+ /** The callback function to perform when the timer expires. */
3
11
  // deno-lint-ignore ban-types
4
12
  private action: Function; // function to perform when timer expires
13
+
14
+ /** The internal timeout identifier reference, if a timer is active. */
5
15
  private timer?: ReturnType<typeof setTimeout>;
16
+
17
+ /** The timestamp (in milliseconds) indicating when the timer is scheduled to end. */
6
18
  private end = 0;
19
+
20
+ /** Indicates whether the timer is currently active and running. */
7
21
  private running = false;
8
22
 
23
+ /**
24
+ * Initializes a new instance of the Timer.
25
+ * @param {Function} action - The callback function to execute upon expiration.
26
+ * @param {number} delay - The delay duration in milliseconds.
27
+ * @param {boolean} [wait=false] - If true, the timer will not start automatically until reset() is called.
28
+ */
9
29
  // deno-lint-ignore ban-types
10
30
  constructor(action: Function, delay: number, wait = false) {
11
31
  this.delay = delay;
@@ -15,11 +35,20 @@ export class Timer {
15
35
  }
16
36
  }
17
37
 
38
+ /**
39
+ * Starts the internal setTimeout with the specified delay.
40
+ * @param {number} delay - The duration in milliseconds for the timeout.
41
+ */
18
42
  private startTimer(delay: number): void {
19
43
  this.running = true;
20
44
  this.timer = setTimeout(() => this.ring(), delay);
21
45
  }
22
46
 
47
+ /**
48
+ * Internal handler triggered when the timeout fires.
49
+ * Verifies if the target end time has genuinely passed, rescheduling if necessary,
50
+ * or executes the action.
51
+ */
23
52
  private ring(): void {
24
53
  const timeLeft = this.end - Date.now();
25
54
  // check if delay has passed, else execute action
@@ -31,6 +60,10 @@ export class Timer {
31
60
  this.action();
32
61
  }
33
62
 
63
+ /**
64
+ * Resets the timer, recalculating the end time and restarting the countdown.
65
+ * If the timer is already running, it updates the target end time.
66
+ */
34
67
  reset(): void {
35
68
  this.end = Date.now() + this.delay;
36
69
  if (!this.running) {
@@ -38,6 +71,9 @@ export class Timer {
38
71
  }
39
72
  }
40
73
 
74
+ /**
75
+ * Cancels the active timeout and stops the timer from running.
76
+ */
41
77
  clear(): void {
42
78
  clearTimeout(this.timer);
43
79
  this.running = false;
@@ -0,0 +1,51 @@
1
+ import { exit } from "node:process";
2
+ import { getArgs, importClientClass } from "./utils.ts";
3
+ import { logger } from "../../utils/mod.ts";
4
+ import type { LogLevel } from "../../utils/logger.ts";
5
+ import type { QoS } from "../../client/deps.ts";
6
+
7
+ export async function runReceiver(
8
+ level: LogLevel,
9
+ url: string,
10
+ topic: string,
11
+ qos: QoS,
12
+ ) {
13
+ logger.level(level);
14
+ const { TcpClient } = await importClientClass();
15
+ const client = new TcpClient();
16
+ client.onError = (err: Error) => {
17
+ console.log("client error", err);
18
+ exit(1);
19
+ };
20
+
21
+ await client.connect({
22
+ url: new URL(url),
23
+ });
24
+
25
+ await client.subscribe({ subscriptions: [{ topicFilter: topic, qos }] });
26
+
27
+ let counter = 0;
28
+ const interval = 5000;
29
+
30
+ function count() {
31
+ console.log("received/s", (counter / interval) * 1000);
32
+ counter = 0;
33
+ }
34
+
35
+ setInterval(count, interval);
36
+
37
+ // // Consume using a callback
38
+ // client.onPacket = async (packet) => {
39
+ // counter++;
40
+ // };
41
+
42
+ // Consume using an AsyncIterator
43
+ for await (const _ of client.messages()) {
44
+ counter++;
45
+ }
46
+ }
47
+
48
+ if (import.meta.main) {
49
+ const { level, url, topic, qos } = getArgs();
50
+ runReceiver(level, url, topic, qos);
51
+ }
@@ -0,0 +1,48 @@
1
+ import { exit } from "node:process";
2
+ import { runAsap } from "../../dev_utils/timers.ts";
3
+ import { getArgs, importClientClass } from "./utils.ts";
4
+ import { logger } from "../../utils/mod.ts";
5
+ import type { LogLevel } from "../../utils/logger.ts";
6
+ import type { QoS } from "../../client/deps.ts";
7
+
8
+ const { TcpClient } = await importClientClass();
9
+ const client = new TcpClient();
10
+ client.onError = (err: Error) => {
11
+ console.log("client error", err);
12
+ exit(1);
13
+ };
14
+
15
+ export async function runSender(
16
+ level: LogLevel,
17
+ url: string,
18
+ topic: string,
19
+ qos: QoS,
20
+ ) {
21
+ logger.level(level);
22
+ await client.connect({
23
+ url: new URL(url),
24
+ });
25
+
26
+ const payload = new TextEncoder().encode("payload");
27
+ let sent = 0;
28
+ const interval = 5000;
29
+
30
+ const loop = () => {
31
+ sent++;
32
+ client.publish({ topic, qos, payload })
33
+ .then(() => runAsap(loop));
34
+ };
35
+
36
+ function count() {
37
+ console.log("sent/s", (sent / interval) * 1000);
38
+ sent = 0;
39
+ }
40
+
41
+ setInterval(count, interval);
42
+ loop();
43
+ }
44
+
45
+ if (import.meta.main) {
46
+ const { level, url, topic, qos } = getArgs();
47
+ runSender(level, url, topic, qos);
48
+ }
@@ -0,0 +1,31 @@
1
+ import { parseArgs } from "node:util";
2
+ import { LogLevel } from "../../utils/mod.ts";
3
+ import type { QoS } from "../../client/mod.ts";
4
+
5
+ export async function importClientClass() {
6
+ // @ts-ignore: the Deno global variable is not defined in @types/node,
7
+ // therefore we need to ignore this error because this file
8
+ // is meant to be used in both environments.
9
+ const isDeno = typeof Deno !== "undefined";
10
+ return isDeno
11
+ ? (await import("../../deno/tcpClient.ts"))
12
+ : (await import("../../node/tcpClient.ts"));
13
+ }
14
+
15
+ export function getArgs() {
16
+ const benchMarkOpts = {
17
+ url: { type: "string", short: "u", default: "mqtt://localhost:1883" },
18
+ topic: { type: "string", short: "t", default: "benchmark" },
19
+ qos: { type: "string", short: "q", default: "0" },
20
+ logLevel: { type: "string", short: "l", default: "error" },
21
+ } as const;
22
+
23
+ const { values } = parseArgs({ options: benchMarkOpts });
24
+ const url = values.url as string;
25
+ const topic = values.topic as string;
26
+ const qos = Number(values.qos ?? 0) as QoS;
27
+ const logLevelKey = (values.logLevel ?? "error") as keyof typeof LogLevel;
28
+ const level = LogLevel[logLevelKey] ?? LogLevel.error;
29
+
30
+ return { url, topic, qos, level };
31
+ }
@@ -0,0 +1,130 @@
1
+ # MQTT compatibility tests
2
+
3
+ Measures Opifex's **actual** MQTT 5.0 and 3.1.1 protocol compatibility by
4
+ running the vendor-neutral [Eclipse Paho interoperability suite][paho] against a
5
+ broker booted from this repo, and reports an honest pass percentage. Wired into
6
+ CI by
7
+ [`.github/workflows/mqtt-compat.yml`](../../.github/workflows/mqtt-compat.yml),
8
+ which posts the result as a sticky PR comment and a job summary.
9
+
10
+ ## Files
11
+
12
+ | File | Purpose |
13
+ | --------------- | ------------------------------------------------------------------------------------------------------------------ |
14
+ | `broker.js` | Boots Opifex on a plain-TCP port (`MQTT_PORT`, default 1883) with the v5 capabilities the suite exercises enabled. |
15
+ | `run_compat.py` | Runs each Paho test in an isolated subprocess against the broker, emits `report.md` + `result.json`. Pure stdlib. |
16
+
17
+ ## Running locally
18
+
19
+ ```bash
20
+ # 1. Fetch the Paho suite, pinned to the same commit CI uses so local results
21
+ # match. The pin (PAHO_REF) lives in .github/workflows/mqtt-compat.yml.
22
+ git clone https://github.com/eclipse-paho/paho.mqtt.testing /tmp/paho
23
+ git -C /tmp/paho checkout "$(grep -oP 'PAHO_REF:\s*\K\S+' ../../.github/workflows/mqtt-compat.yml)"
24
+
25
+ # 2. Start the broker
26
+ node ./broker.ts &
27
+
28
+ # 3. Run the suites
29
+ python3 ./run_compat.py --paho /tmp/paho/interoperability --host localhost --port 1883 --out report.md --json result.json
30
+ ```
31
+
32
+ `--protocols v5,v3` selects the suites; `--timeout` bounds each test (default
33
+ 45s).
34
+
35
+ ### Individual test
36
+
37
+ Version 3.11:
38
+
39
+ ```bash
40
+ python3 /tmp/paho/interoperability/client_test.py Test.test_retained_messages
41
+ ```
42
+
43
+ Version 5:
44
+
45
+ ```bash
46
+ python3 /tmp/paho/interoperability/client_test5.py Test.test_retained_messages
47
+ ```
48
+
49
+ ## How the score is computed
50
+
51
+ Each Paho `Test` method runs in its **own subprocess** with a hard timeout. This
52
+ matters because the Paho clients do blocking waits with no internal timeout: a
53
+ case where the broker never sends an expected packet would otherwise hang the
54
+ whole run, and a hung test would corrupt the class-level shared clients later
55
+ tests reuse. A timed-out test is recorded as a bounded failure.
56
+
57
+ The percentage is the raw pass rate (`passed / evaluated`). Two categories are
58
+ handled specially:
59
+
60
+ - **Expected gaps** (`EXPECTED_GAPS` in `run_compat.py`) โ€” features Opifex
61
+ intentionally does not implement yet (e.g. shared subscriptions, which the
62
+ broker advertises as `sharedSubscriptionAvailable=false`). These still count
63
+ as failures; they are only annotated with the reason so the table is readable.
64
+ Because v5 is a work in progress, the harness also detects the reverse: when
65
+ an `EXPECTED_GAPS` test starts **passing** (the feature got implemented), the
66
+ report highlights it with a ๐ŸŽ‰ banner and the workflow emits a CI warning,
67
+ prompting you to remove the now-stale entry from `EXPECTED_GAPS`.
68
+ - **Harness-limited** (`HARNESS_LIMITED`) โ€” tests that cannot be evaluated under
69
+ per-test isolation against _any_ broker (currently only `test_flow_control2`,
70
+ which depends on the persistent client the suite sets up only in
71
+ single-process mode). These are **excluded** from the denominator. The
72
+ capability they probe is still measured elsewhere (`test_flow_control1` for
73
+ receive-maximum).
74
+
75
+ ### Adding or moving a test category
76
+
77
+ Both lists in `run_compat.py` are keyed
78
+ `protocol -> exact Paho method name ->
79
+ reason string`. Pick the dict by what the
80
+ failure _means_:
81
+
82
+ - A genuine Opifex gap that should drag the score down โ†’ **`EXPECTED_GAPS`**. It
83
+ still runs and counts as a failure; when Opifex later implements it the
84
+ harness flags the ๐ŸŽ‰ xpass so you remove the entry.
85
+ - A test the harness can't fairly evaluate against _any_ broker โ†’
86
+ **`HARNESS_LIMITED`**. It is skipped before the gap logic and excluded from
87
+ the denominator. A method must live in **exactly one** list (`HARNESS_LIMITED`
88
+ is checked first, so a duplicate `EXPECTED_GAPS` entry would be dead code).
89
+
90
+ ## Coverage scope โ€” read the percentage correctly
91
+
92
+ The percentage is **"% of the Paho functional suite that passes"**, not "%
93
+ MQTT-5.0-compliant". The Paho suite is a third-party **happy-path functional**
94
+ test: it exercises the user-facing v5 features well (session expiry, will + will
95
+ delay, message expiry, RH/RAP/NL, request/response, payload format, assigned
96
+ client id, server keep alive, inbound topic aliases, max-packet-size rejection,
97
+ PUBLISH user properties), but it touches only 5 reason codes and deliberately
98
+ omits large parts of the spec:
99
+
100
+ - **Error / negative paths** โ€” most of Opifex's reason codes
101
+ (`lib/constants.js`): `0x87` not-authorized acks, `0x8E` session takeover,
102
+ `0x82` protocol errors, `0x8C` bad auth method, `0x9E`, the CONNACK reject
103
+ codes, broker-initiated DISCONNECT with ReasonString, the oversized-frame read
104
+ latch, wildcard ResponseTopic rejection. These are covered by
105
+ **`test/mqtt5.js`**, which is the authoritative place Opifex's v5 error
106
+ semantics are pinned.
107
+ - **Whole spec chapters** โ€” AUTH / enhanced auth (ยง4.12), Server Reference
108
+ (`0x9C`/`0x9D`), CONNACK capability flags, ReasonString round-trips, and
109
+ UserProperty on non-PUBLISH packets. Some of these Opifex does not implement;
110
+ the test gap left by _both_ suites is tracked in
111
+ [#1096](https://github.com/moscajs/Opifex/issues/1096).
112
+
113
+ So treat this workflow as the **cross-implementation functional gauge** and
114
+ `test/mqtt5.js` as the **gap-filler** โ€” they are complementary, not redundant.
115
+
116
+ Some Paho failures are intentional Opifex design decisions rather than bugs (see
117
+ `EXPECTED_GAPS`), and at least one is a genuine spec bug found by this suite:
118
+ [#1095](https://github.com/moscajs/Opifex/issues/1095) (zero-length ClientId +
119
+ CleanSession=0 must be rejected on v3.1.1).
120
+
121
+ ## Harness validation
122
+
123
+ The harness was validated against the Paho project's own fully-compliant
124
+ reference broker (`startbroker.py`): it scores **100%** of evaluated v5 tests
125
+ (with `test_flow_control2` excluded as above). Every test Opifex fails, the
126
+ reference broker passes under the identical harness โ€” so a failure here reflects
127
+ a real difference between Opifex and a spec-compliant broker, not a harness
128
+ artifact.
129
+
130
+ [paho]: https://github.com/eclipse-paho/paho.mqtt.testing
@@ -0,0 +1,52 @@
1
+ // Standalone aedes broker used by the MQTT compatibility workflow.
2
+ //
3
+ // It boots the broker from *this branch* on a plain-TCP port so the Eclipse Paho
4
+ // interoperability suite (tools/mqtt-compat/run_compat.py) can drive it as an
5
+ // external broker. v5 capabilities the suite exercises are enabled here so the
6
+ // reported score reflects real broker ability, not a broker started with features
7
+ // switched off (e.g. inbound topic aliases are a no-op when topicAliasMaximum: 0).
8
+ //
9
+ // Usage: MQTT_PORT=1883 node tools/mqtt-compat/broker.js
10
+ import { TcpServer } from "../../node/tcpServer.ts";
11
+ import type { Context, ShareName, Topic } from "../../server/mod.ts";
12
+ import { logger } from "../../utils/mod.ts";
13
+ import { isAuthenticatedBroker as isAuthenticated } from "../../dev_utils/mod.ts";
14
+ import { SqlitePersistence } from "../../persistence/sqlite/sqlitePersistence.ts";
15
+
16
+ const port = Number(process.env.MQTT_PORT) || 1883;
17
+ const persistence = new SqlitePersistence();
18
+
19
+ // The Paho `test_subscribe_failure` (v3.1.1 and v5) subscribes to a topic that is
20
+ // "not allowed to be subscribed to" and asserts the broker answers with SUBACK
21
+ // reason code 0x80.
22
+
23
+ const NO_SUBSCRIBE_TOPIC = "test/nosubscribe";
24
+
25
+ function isAuthorizedToSubscribe(
26
+ ctx: Context,
27
+ topic: Topic,
28
+ _shareName: ShareName,
29
+ ): boolean {
30
+ logger.debug(
31
+ `Checking authorization of client '${ctx.clientId}' to subscribe to topic '${topic}'`,
32
+ );
33
+ return topic !== NO_SUBSCRIBE_TOPIC;
34
+ }
35
+
36
+ const tcpServer = new TcpServer({ port }, {
37
+ persistence,
38
+ handlers: {
39
+ isAuthenticated,
40
+ isAuthorizedToSubscribe,
41
+ },
42
+ });
43
+ tcpServer.start();
44
+ logger.info("Server started on port", tcpServer.port);
45
+
46
+ function shutdown() {
47
+ tcpServer.stop();
48
+ process.exit(0);
49
+ }
50
+
51
+ process.on("SIGTERM", shutdown);
52
+ process.on("SIGINT", shutdown);