@seriousme/opifex 1.9.4 → 1.11.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 (331) hide show
  1. package/README.md +37 -26
  2. package/bin/conformanceServer.ts +3 -2
  3. package/bin/demoServer.ts +3 -2
  4. package/bin/mqtt.ts +127 -118
  5. package/client/client.ts +61 -21
  6. package/client/context.ts +71 -30
  7. package/client/deps.ts +5 -0
  8. package/client/handlers/handleConnack.ts +17 -5
  9. package/client/handlers/handlePublish.ts +4 -1
  10. package/client/handlers/handlePubrec.ts +3 -1
  11. package/client/handlers/handlePubrel.ts +3 -1
  12. package/client/handlers/handleSuback.ts +3 -1
  13. package/client/mod.ts +8 -1
  14. package/client/store/memoryStore.ts +2 -1
  15. package/deno/tcpClient.ts +1 -1
  16. package/dev_utils/dummyConn.ts +17 -2
  17. package/dist/bin/conformanceServer.js +3 -2
  18. package/dist/bin/conformanceServer.js.map +1 -1
  19. package/dist/bin/demoServer.js +3 -2
  20. package/dist/bin/demoServer.js.map +1 -1
  21. package/dist/bin/mqtt.d.ts +29 -0
  22. package/dist/bin/mqtt.d.ts.map +1 -1
  23. package/dist/bin/mqtt.js +102 -97
  24. package/dist/bin/mqtt.js.map +1 -1
  25. package/dist/client/client.d.ts +16 -5
  26. package/dist/client/client.d.ts.map +1 -1
  27. package/dist/client/client.js +36 -15
  28. package/dist/client/client.js.map +1 -1
  29. package/dist/client/context.d.ts +8 -3
  30. package/dist/client/context.d.ts.map +1 -1
  31. package/dist/client/context.js +51 -21
  32. package/dist/client/context.js.map +1 -1
  33. package/dist/client/deps.d.ts +3 -2
  34. package/dist/client/deps.d.ts.map +1 -1
  35. package/dist/client/deps.js +2 -1
  36. package/dist/client/deps.js.map +1 -1
  37. package/dist/client/handlers/handleConnack.d.ts +1 -1
  38. package/dist/client/handlers/handleConnack.d.ts.map +1 -1
  39. package/dist/client/handlers/handleConnack.js +14 -5
  40. package/dist/client/handlers/handleConnack.js.map +1 -1
  41. package/dist/client/handlers/handlePublish.d.ts +1 -1
  42. package/dist/client/handlers/handlePublish.d.ts.map +1 -1
  43. package/dist/client/handlers/handlePublish.js +2 -0
  44. package/dist/client/handlers/handlePublish.js.map +1 -1
  45. package/dist/client/handlers/handlePubrec.d.ts +1 -1
  46. package/dist/client/handlers/handlePubrec.d.ts.map +1 -1
  47. package/dist/client/handlers/handlePubrec.js +1 -0
  48. package/dist/client/handlers/handlePubrec.js.map +1 -1
  49. package/dist/client/handlers/handlePubrel.d.ts +1 -1
  50. package/dist/client/handlers/handlePubrel.d.ts.map +1 -1
  51. package/dist/client/handlers/handlePubrel.js +1 -0
  52. package/dist/client/handlers/handlePubrel.js.map +1 -1
  53. package/dist/client/handlers/handleSuback.d.ts.map +1 -1
  54. package/dist/client/handlers/handleSuback.js +3 -1
  55. package/dist/client/handlers/handleSuback.js.map +1 -1
  56. package/dist/client/mod.d.ts +3 -1
  57. package/dist/client/mod.d.ts.map +1 -1
  58. package/dist/client/mod.js +2 -1
  59. package/dist/client/mod.js.map +1 -1
  60. package/dist/client/store/memoryStore.d.ts +1 -1
  61. package/dist/client/store/memoryStore.d.ts.map +1 -1
  62. package/dist/client/store/memoryStore.js.map +1 -1
  63. package/dist/mqttConn/mqttConn.d.ts +13 -8
  64. package/dist/mqttConn/mqttConn.d.ts.map +1 -1
  65. package/dist/mqttConn/mqttConn.js +27 -12
  66. package/dist/mqttConn/mqttConn.js.map +1 -1
  67. package/dist/mqttPacket/PacketType.d.ts +1 -0
  68. package/dist/mqttPacket/PacketType.d.ts.map +1 -1
  69. package/dist/mqttPacket/PacketType.js +1 -0
  70. package/dist/mqttPacket/PacketType.js.map +1 -1
  71. package/dist/mqttPacket/Properties.d.ts +157 -0
  72. package/dist/mqttPacket/Properties.d.ts.map +1 -0
  73. package/dist/mqttPacket/Properties.js +177 -0
  74. package/dist/mqttPacket/Properties.js.map +1 -0
  75. package/dist/mqttPacket/ReasonCode.d.ts +74 -0
  76. package/dist/mqttPacket/ReasonCode.d.ts.map +1 -0
  77. package/dist/mqttPacket/ReasonCode.js +230 -0
  78. package/dist/mqttPacket/ReasonCode.js.map +1 -0
  79. package/dist/mqttPacket/RetainHandling.d.ts +12 -0
  80. package/dist/mqttPacket/RetainHandling.d.ts.map +1 -0
  81. package/dist/mqttPacket/RetainHandling.js +12 -0
  82. package/dist/mqttPacket/RetainHandling.js.map +1 -0
  83. package/dist/mqttPacket/auth.d.ts +21 -0
  84. package/dist/mqttPacket/auth.d.ts.map +1 -0
  85. package/dist/mqttPacket/auth.js +34 -0
  86. package/dist/mqttPacket/auth.js.map +1 -0
  87. package/dist/mqttPacket/connack.d.ts +19 -11
  88. package/dist/mqttPacket/connack.d.ts.map +1 -1
  89. package/dist/mqttPacket/connack.js +43 -15
  90. package/dist/mqttPacket/connack.js.map +1 -1
  91. package/dist/mqttPacket/connect.d.ts +30 -11
  92. package/dist/mqttPacket/connect.d.ts.map +1 -1
  93. package/dist/mqttPacket/connect.js +106 -30
  94. package/dist/mqttPacket/connect.js.map +1 -1
  95. package/dist/mqttPacket/decoder.d.ts +42 -3
  96. package/dist/mqttPacket/decoder.d.ts.map +1 -1
  97. package/dist/mqttPacket/decoder.js +135 -4
  98. package/dist/mqttPacket/decoder.js.map +1 -1
  99. package/dist/mqttPacket/disconnect.d.ts +15 -9
  100. package/dist/mqttPacket/disconnect.d.ts.map +1 -1
  101. package/dist/mqttPacket/disconnect.js +45 -6
  102. package/dist/mqttPacket/disconnect.js.map +1 -1
  103. package/dist/mqttPacket/encoder.d.ts +57 -8
  104. package/dist/mqttPacket/encoder.d.ts.map +1 -1
  105. package/dist/mqttPacket/encoder.js +185 -13
  106. package/dist/mqttPacket/encoder.js.map +1 -1
  107. package/dist/mqttPacket/length.d.ts.map +1 -1
  108. package/dist/mqttPacket/length.js +3 -2
  109. package/dist/mqttPacket/length.js.map +1 -1
  110. package/dist/mqttPacket/mod.d.ts +57 -91
  111. package/dist/mqttPacket/mod.d.ts.map +1 -1
  112. package/dist/mqttPacket/mod.js +23 -29
  113. package/dist/mqttPacket/mod.js.map +1 -1
  114. package/dist/mqttPacket/pingreq.d.ts +4 -6
  115. package/dist/mqttPacket/pingreq.d.ts.map +1 -1
  116. package/dist/mqttPacket/pingreq.js +5 -4
  117. package/dist/mqttPacket/pingreq.js.map +1 -1
  118. package/dist/mqttPacket/pingres.d.ts +4 -6
  119. package/dist/mqttPacket/pingres.d.ts.map +1 -1
  120. package/dist/mqttPacket/pingres.js +7 -5
  121. package/dist/mqttPacket/pingres.js.map +1 -1
  122. package/dist/mqttPacket/protocolLevels.d.ts +12 -0
  123. package/dist/mqttPacket/protocolLevels.d.ts.map +1 -0
  124. package/dist/mqttPacket/protocolLevels.js +11 -0
  125. package/dist/mqttPacket/protocolLevels.js.map +1 -0
  126. package/dist/mqttPacket/pubblishAcks.d.ts +42 -0
  127. package/dist/mqttPacket/pubblishAcks.d.ts.map +1 -0
  128. package/dist/mqttPacket/pubblishAcks.js +56 -0
  129. package/dist/mqttPacket/pubblishAcks.js.map +1 -0
  130. package/dist/mqttPacket/publish.d.ts +19 -8
  131. package/dist/mqttPacket/publish.d.ts.map +1 -1
  132. package/dist/mqttPacket/publish.js +26 -7
  133. package/dist/mqttPacket/publish.js.map +1 -1
  134. package/dist/mqttPacket/suback.d.ts +18 -11
  135. package/dist/mqttPacket/suback.d.ts.map +1 -1
  136. package/dist/mqttPacket/suback.js +41 -20
  137. package/dist/mqttPacket/suback.js.map +1 -1
  138. package/dist/mqttPacket/subscribe.d.ts +27 -12
  139. package/dist/mqttPacket/subscribe.d.ts.map +1 -1
  140. package/dist/mqttPacket/subscribe.js +71 -15
  141. package/dist/mqttPacket/subscribe.js.map +1 -1
  142. package/dist/mqttPacket/types.d.ts +36 -0
  143. package/dist/mqttPacket/types.d.ts.map +1 -1
  144. package/dist/mqttPacket/unsuback.d.ts +17 -10
  145. package/dist/mqttPacket/unsuback.d.ts.map +1 -1
  146. package/dist/mqttPacket/unsuback.js +29 -6
  147. package/dist/mqttPacket/unsuback.js.map +1 -1
  148. package/dist/mqttPacket/unsubscribe.d.ts +17 -10
  149. package/dist/mqttPacket/unsubscribe.d.ts.map +1 -1
  150. package/dist/mqttPacket/unsubscribe.js +24 -8
  151. package/dist/mqttPacket/unsubscribe.js.map +1 -1
  152. package/dist/mqttPacket/validators.d.ts +15 -0
  153. package/dist/mqttPacket/validators.d.ts.map +1 -1
  154. package/dist/mqttPacket/validators.js +15 -0
  155. package/dist/mqttPacket/validators.js.map +1 -1
  156. package/dist/node/tcpClient.js +1 -1
  157. package/dist/node/tcpClient.js.map +1 -1
  158. package/dist/node/wrapNodeSocket.d.ts.map +1 -1
  159. package/dist/node/wrapNodeSocket.js.map +1 -1
  160. package/dist/persistence/deps.d.ts +1 -1
  161. package/dist/persistence/deps.d.ts.map +1 -1
  162. package/dist/persistence/deps.js +1 -1
  163. package/dist/persistence/deps.js.map +1 -1
  164. package/dist/persistence/memory/memoryPersistence.js +1 -1
  165. package/dist/persistence/memory/memoryPersistence.js.map +1 -1
  166. package/dist/server/context.d.ts +3 -1
  167. package/dist/server/context.d.ts.map +1 -1
  168. package/dist/server/context.js +8 -2
  169. package/dist/server/context.js.map +1 -1
  170. package/dist/server/deps.d.ts +2 -2
  171. package/dist/server/deps.d.ts.map +1 -1
  172. package/dist/server/deps.js +1 -1
  173. package/dist/server/deps.js.map +1 -1
  174. package/dist/server/handlers/handleConnect.d.ts +1 -1
  175. package/dist/server/handlers/handleConnect.d.ts.map +1 -1
  176. package/dist/server/handlers/handleConnect.js +9 -1
  177. package/dist/server/handlers/handleConnect.js.map +1 -1
  178. package/dist/server/handlers/handlePacket.d.ts +1 -1
  179. package/dist/server/handlers/handlePacket.d.ts.map +1 -1
  180. package/dist/server/handlers/handlePacket.js +1 -1
  181. package/dist/server/handlers/handlePacket.js.map +1 -1
  182. package/dist/server/handlers/handlePingreq.d.ts.map +1 -1
  183. package/dist/server/handlers/handlePingreq.js +1 -0
  184. package/dist/server/handlers/handlePingreq.js.map +1 -1
  185. package/dist/server/handlers/handlePublish.d.ts +2 -2
  186. package/dist/server/handlers/handlePublish.d.ts.map +1 -1
  187. package/dist/server/handlers/handlePublish.js +2 -0
  188. package/dist/server/handlers/handlePublish.js.map +1 -1
  189. package/dist/server/handlers/handlePubrec.d.ts +1 -1
  190. package/dist/server/handlers/handlePubrec.d.ts.map +1 -1
  191. package/dist/server/handlers/handlePubrec.js +1 -0
  192. package/dist/server/handlers/handlePubrec.js.map +1 -1
  193. package/dist/server/handlers/handlePubrel.d.ts +1 -1
  194. package/dist/server/handlers/handlePubrel.d.ts.map +1 -1
  195. package/dist/server/handlers/handlePubrel.js +1 -0
  196. package/dist/server/handlers/handlePubrel.js.map +1 -1
  197. package/dist/server/handlers/handleSubscribe.d.ts +1 -1
  198. package/dist/server/handlers/handleSubscribe.d.ts.map +1 -1
  199. package/dist/server/handlers/handleSubscribe.js +2 -1
  200. package/dist/server/handlers/handleSubscribe.js.map +1 -1
  201. package/dist/server/handlers/handleUnsubscribe.d.ts +1 -1
  202. package/dist/server/handlers/handleUnsubscribe.d.ts.map +1 -1
  203. package/dist/server/handlers/handleUnsubscribe.js +1 -0
  204. package/dist/server/handlers/handleUnsubscribe.js.map +1 -1
  205. package/dist/server/server.d.ts +2 -2
  206. package/dist/server/server.d.ts.map +1 -1
  207. package/dist/server/server.js +5 -3
  208. package/dist/server/server.js.map +1 -1
  209. package/dist/socket/socket.d.ts.map +1 -1
  210. package/dist/socket/socket.js +6 -1
  211. package/dist/socket/socket.js.map +1 -1
  212. package/dist/utils/assert.d.ts +0 -3
  213. package/dist/utils/assert.d.ts.map +1 -1
  214. package/dist/utils/assert.js +0 -7
  215. package/dist/utils/assert.js.map +1 -1
  216. package/dist/utils/asyncQueue.d.ts +1 -3
  217. package/dist/utils/asyncQueue.d.ts.map +1 -1
  218. package/dist/utils/asyncQueue.js +16 -21
  219. package/dist/utils/asyncQueue.js.map +1 -1
  220. package/dist/utils/logger.d.ts +5 -15
  221. package/dist/utils/logger.d.ts.map +1 -1
  222. package/dist/utils/logger.js +7 -8
  223. package/dist/utils/logger.js.map +1 -1
  224. package/dist/utils/mod.d.ts +0 -3
  225. package/dist/utils/mod.d.ts.map +1 -1
  226. package/dist/utils/mod.js +0 -2
  227. package/dist/utils/mod.js.map +1 -1
  228. package/dist/utils/utils.d.ts +2 -0
  229. package/dist/utils/utils.d.ts.map +1 -0
  230. package/dist/utils/utils.js +6 -0
  231. package/dist/utils/utils.js.map +1 -0
  232. package/mqttConn/mqttConn.test.ts +27 -12
  233. package/mqttConn/mqttConn.ts +45 -14
  234. package/mqttPacket/PacketType.ts +1 -0
  235. package/mqttPacket/Properties.ts +276 -0
  236. package/mqttPacket/ReasonCode.test.ts +22 -0
  237. package/mqttPacket/ReasonCode.ts +256 -0
  238. package/mqttPacket/RetainHandling.ts +11 -0
  239. package/mqttPacket/auth.test.ts +112 -0
  240. package/mqttPacket/auth.ts +71 -0
  241. package/mqttPacket/connack.test.ts +84 -64
  242. package/mqttPacket/connack.ts +88 -24
  243. package/mqttPacket/connect.test.ts +497 -18
  244. package/mqttPacket/connect.ts +170 -39
  245. package/mqttPacket/decoder.test.ts +33 -16
  246. package/mqttPacket/decoder.ts +173 -5
  247. package/mqttPacket/disconnect.test.ts +97 -18
  248. package/mqttPacket/disconnect.ts +84 -12
  249. package/mqttPacket/encoder.test.ts +32 -8
  250. package/mqttPacket/encoder.ts +236 -11
  251. package/mqttPacket/length.ts +3 -2
  252. package/mqttPacket/mod.ts +76 -39
  253. package/mqttPacket/pingreq.test.ts +52 -4
  254. package/mqttPacket/pingreq.ts +20 -7
  255. package/mqttPacket/pingres.test.ts +52 -4
  256. package/mqttPacket/pingres.ts +22 -8
  257. package/mqttPacket/properties.test.ts +193 -0
  258. package/mqttPacket/protocolLevels.ts +13 -0
  259. package/mqttPacket/pubblishAcks.ts +123 -0
  260. package/mqttPacket/publish.test.ts +212 -133
  261. package/mqttPacket/publish.ts +69 -14
  262. package/mqttPacket/publishAcks.test.ts +128 -0
  263. package/mqttPacket/suback.test.ts +71 -27
  264. package/mqttPacket/suback.ts +82 -30
  265. package/mqttPacket/subscribe.test.ts +132 -43
  266. package/mqttPacket/subscribe.ts +128 -25
  267. package/mqttPacket/types.ts +43 -0
  268. package/mqttPacket/unsuback.test.ts +80 -30
  269. package/mqttPacket/unsuback.ts +68 -13
  270. package/mqttPacket/unsubscribe.test.ts +59 -34
  271. package/mqttPacket/unsubscribe.ts +64 -17
  272. package/mqttPacket/validators.ts +15 -0
  273. package/node/tcpClient.ts +1 -1
  274. package/node/wrapNodeSocket.ts +2 -1
  275. package/package.json +2 -2
  276. package/persistence/deps.ts +1 -1
  277. package/persistence/memory/memoryPersistence.test.ts +5 -1
  278. package/persistence/memory/memoryPersistence.ts +1 -1
  279. package/server/context.ts +23 -10
  280. package/server/deps.ts +2 -0
  281. package/server/handlers/handleConnect.ts +12 -9
  282. package/server/handlers/handlePacket.ts +10 -11
  283. package/server/handlers/handlePingreq.ts +1 -0
  284. package/server/handlers/handlePublish.ts +6 -2
  285. package/server/handlers/handlePubrec.ts +3 -1
  286. package/server/handlers/handlePubrel.ts +3 -1
  287. package/server/handlers/handleSubscribe.ts +3 -6
  288. package/server/handlers/handleUnsubscribe.ts +3 -1
  289. package/server/server.ts +8 -12
  290. package/server/test/handleConnect.test.ts +2 -1
  291. package/server/test/test-handlers.ts +2 -1
  292. package/socket/socket.ts +5 -1
  293. package/utils/assert.ts +0 -18
  294. package/utils/asyncQueue.ts +17 -21
  295. package/utils/logger.ts +12 -11
  296. package/utils/mod.ts +0 -3
  297. package/utils/utils.ts +6 -0
  298. package/dist/mqttPacket/puback.d.ts +0 -16
  299. package/dist/mqttPacket/puback.d.ts.map +0 -1
  300. package/dist/mqttPacket/puback.js +0 -21
  301. package/dist/mqttPacket/puback.js.map +0 -1
  302. package/dist/mqttPacket/pubcomp.d.ts +0 -17
  303. package/dist/mqttPacket/pubcomp.d.ts.map +0 -1
  304. package/dist/mqttPacket/pubcomp.js +0 -21
  305. package/dist/mqttPacket/pubcomp.js.map +0 -1
  306. package/dist/mqttPacket/pubrec.d.ts +0 -17
  307. package/dist/mqttPacket/pubrec.d.ts.map +0 -1
  308. package/dist/mqttPacket/pubrec.js +0 -21
  309. package/dist/mqttPacket/pubrec.js.map +0 -1
  310. package/dist/mqttPacket/pubrel.d.ts +0 -17
  311. package/dist/mqttPacket/pubrel.d.ts.map +0 -1
  312. package/dist/mqttPacket/pubrel.js +0 -21
  313. package/dist/mqttPacket/pubrel.js.map +0 -1
  314. package/dist/utils/args.d.ts +0 -28
  315. package/dist/utils/args.d.ts.map +0 -1
  316. package/dist/utils/args.js +0 -76
  317. package/dist/utils/args.js.map +0 -1
  318. package/dist/utils/platform.d.ts +0 -5
  319. package/dist/utils/platform.d.ts.map +0 -1
  320. package/dist/utils/platform.js +0 -8
  321. package/dist/utils/platform.js.map +0 -1
  322. package/mqttPacket/puback.test.ts +0 -55
  323. package/mqttPacket/puback.ts +0 -34
  324. package/mqttPacket/pubcomp.test.ts +0 -55
  325. package/mqttPacket/pubcomp.ts +0 -35
  326. package/mqttPacket/pubrec.test.ts +0 -55
  327. package/mqttPacket/pubrec.ts +0 -35
  328. package/mqttPacket/pubrel.test.ts +0 -55
  329. package/mqttPacket/pubrel.ts +0 -35
  330. package/utils/args.ts +0 -103
  331. package/utils/platform.ts +0 -8
@@ -1,16 +1,30 @@
1
- import { PacketType } from "./PacketType.ts";
2
1
  import assert from "node:assert/strict";
3
2
  import { test } from "node:test";
3
+ import { decode, encode, MQTTLevel, PacketType, ReasonCode } from "./mod.ts";
4
+ import type { CodecOpts } from "./mod.ts";
4
5
 
5
- import { decode, encode } from "./mod.ts";
6
+ const codecOptsV4: CodecOpts = {
7
+ protocolLevel: MQTTLevel.v4,
8
+ maxIncomingPacketSize: 0xffff,
9
+ maxOutgoingPacketSize: 0xffff,
10
+ };
6
11
 
7
- test("encode Suback", () => {
12
+ const codecOptsV5: CodecOpts = {
13
+ protocolLevel: MQTTLevel.v5,
14
+ maxIncomingPacketSize: 0xffff,
15
+ maxOutgoingPacketSize: 0xffff,
16
+ };
17
+
18
+ test("encode/decode Suback v4", () => {
19
+ const packet = {
20
+ type: PacketType.suback,
21
+ protocolLevel: MQTTLevel.v4,
22
+ id: 1,
23
+ returnCodes: [0, 1],
24
+ };
25
+ const encoded = encode(packet, codecOptsV4);
8
26
  assert.deepStrictEqual(
9
- encode({
10
- type: PacketType.suback,
11
- id: 1,
12
- returnCodes: [0, 1],
13
- }),
27
+ encoded,
14
28
  Uint8Array.from([
15
29
  // fixedHeader
16
30
  0x90, // packetType + flags
@@ -23,27 +37,57 @@ test("encode Suback", () => {
23
37
  1,
24
38
  ]),
25
39
  );
40
+ const decoded = decode(encoded, codecOptsV4);
41
+ assert.deepStrictEqual(decoded, packet);
26
42
  });
27
43
 
28
- test("decode Suback", () => {
29
- assert.deepStrictEqual(
30
- decode(
31
- Uint8Array.from([
32
- // fixedHeader
33
- 0x90, // packetType + flags
34
- 4, // remainingLength
35
- // variableHeader
36
- 0, // id MSB
37
- 1, // id LSB
38
- // payload
39
- 0,
40
- 1,
41
- ]),
42
- ),
43
- {
44
- type: PacketType.suback,
45
- id: 1,
46
- returnCodes: [0, 1],
44
+ test("encode/decode Suback v5", () => {
45
+ const packet = {
46
+ type: PacketType.suback,
47
+ protocolLevel: MQTTLevel.v5,
48
+ id: 1,
49
+ reasonCodes: [ReasonCode.grantedQos0, ReasonCode.grantedQos1],
50
+ properties: {
51
+ reasonString: "reason",
52
+ userProperty: [["test", "test"]],
47
53
  },
54
+ };
55
+ const encoded = encode(packet, codecOptsV5);
56
+ assert.deepStrictEqual(
57
+ encoded,
58
+ Uint8Array.from([
59
+ // fixedHeader
60
+ 144, // packetType + flags
61
+ 27, // remaining length
62
+ 0, // id MSB
63
+ 1, // id LSB
64
+ 22, // propertysize
65
+ 31, // reason string
66
+ 0, // string length MSB
67
+ 6, // string length LSB
68
+ 114, // r
69
+ 101, // e
70
+ 97, // a
71
+ 115, // s
72
+ 111, // o
73
+ 110, // n
74
+ 38, // user property
75
+ 0, // string length MSB
76
+ 4, // string length LSB
77
+ 116, // t
78
+ 101, // e
79
+ 115, // s
80
+ 116, // t
81
+ 0, // string length MSB
82
+ 4, // string length LSB
83
+ 116, // t
84
+ 101, // e
85
+ 115, // s
86
+ 116, // t
87
+ 0, // return code
88
+ 1, // return code
89
+ ]),
48
90
  );
91
+ const decoded = decode(encoded, codecOptsV5);
92
+ assert.deepStrictEqual(decoded, packet);
49
93
  });
@@ -1,48 +1,100 @@
1
- import type { PacketId, ReturnCodes, TPacketType } from "./types.ts";
1
+ import type {
2
+ CodecOpts,
3
+ PacketId,
4
+ ProtocolLevelNoV5,
5
+ ReturnCodes,
6
+ TPacketType,
7
+ TReasonCode,
8
+ } from "./types.ts";
9
+ import type { SubackProperties } from "./Properties.ts";
2
10
  import { PacketType } from "./PacketType.ts";
3
11
  import { Encoder } from "./encoder.ts";
4
- import { Decoder } from "./decoder.ts";
12
+ import { Decoder, DecoderError } from "./decoder.ts";
13
+ const validReturnCodes = [0x00, 0x01, 0x02, 0x80];
5
14
 
6
- /**
7
- * SubackPacket is sent by the server to the client to confirm receipt and
8
- * processing of a SubscribePacket.
9
- */
10
- export type SubackPacket = {
15
+ export type SubackPacketV4 = {
11
16
  type: TPacketType;
17
+ protocolLevel: ProtocolLevelNoV5;
12
18
  id: PacketId;
13
19
  returnCodes: ReturnCodes;
14
20
  };
15
21
 
22
+ export type SubackPacketV5 = {
23
+ type: TPacketType;
24
+ protocolLevel: 5;
25
+ id: PacketId;
26
+ properties: SubackProperties;
27
+ reasonCodes: Array<TReasonCode>;
28
+ };
29
+
30
+ /**
31
+ * SubackPacket is sent by the server to the client to confirm receipt and
32
+ * processing of a SubscribePacket.
33
+ */
34
+ export type SubackPacket = SubackPacketV4 | SubackPacketV5;
35
+
16
36
  export const suback: {
17
- encode(packet: SubackPacket): { flags: number; bytes: number[] };
18
- decode(buffer: Uint8Array): SubackPacket;
37
+ encode(packet: SubackPacket, _codecOpts: CodecOpts): Uint8Array;
38
+ decode(
39
+ buffer: Uint8Array,
40
+ flags: number,
41
+ codecOpts: CodecOpts,
42
+ packetType: TPacketType,
43
+ ): SubackPacket;
19
44
  } = {
20
- encode(packet: SubackPacket): { flags: number; bytes: number[] } {
45
+ encode(packet: SubackPacket, codecOpts: CodecOpts): Uint8Array {
21
46
  const flags = 0;
22
- const encoder = new Encoder();
47
+ const encoder = new Encoder(packet.type);
23
48
  encoder.setInt16(packet.id);
24
- encoder.setRemainder(packet.returnCodes);
25
-
26
- return {
27
- flags,
28
- bytes: encoder.done(),
29
- };
49
+ if (packet.protocolLevel !== 5) {
50
+ for (const code of packet.returnCodes) {
51
+ if (!validReturnCodes.includes(code)) {
52
+ throw new Error("Invalid return code");
53
+ }
54
+ }
55
+ encoder.setRemainder(packet.returnCodes);
56
+ return encoder.done(flags);
57
+ }
58
+ encoder.setProperties(
59
+ packet.properties || {},
60
+ packet.type,
61
+ codecOpts.maxOutgoingPacketSize,
62
+ );
63
+ for (const code of packet.reasonCodes) {
64
+ encoder.setReasonCode(code);
65
+ }
66
+ return encoder.done(flags);
30
67
  },
31
68
 
32
- decode(buffer: Uint8Array): SubackPacket {
33
- const decoder = new Decoder(buffer);
34
- const id = decoder.getInt16();
35
- const payload = decoder.getRemainder();
36
- const returnCodes = [];
69
+ decode(
70
+ buffer: Uint8Array,
71
+ _flags: number,
72
+ codecOpts: CodecOpts,
73
+ packetType: TPacketType,
74
+ ): SubackPacket {
75
+ const packet = {} as SubackPacket;
76
+ const decoder = new Decoder(packetType, buffer);
77
+ packet.type = PacketType.suback;
78
+ packet.id = decoder.getInt16();
79
+ packet.protocolLevel = codecOpts.protocolLevel;
37
80
 
38
- for (const code of payload) {
39
- returnCodes.push(code);
81
+ if (packet.protocolLevel !== 5) {
82
+ const payload = decoder.getRemainder();
83
+ packet.returnCodes = [];
84
+ for (const code of payload) {
85
+ if (!validReturnCodes.includes(code)) {
86
+ throw new DecoderError("Invalid return code");
87
+ }
88
+ packet.returnCodes.push(code);
89
+ }
90
+ return packet;
40
91
  }
41
-
42
- return {
43
- type: PacketType.suback,
44
- id,
45
- returnCodes,
46
- };
92
+ packet.properties = decoder.getProperties(PacketType.suback);
93
+ packet.reasonCodes = [];
94
+ while (!decoder.atEnd()) {
95
+ const code = decoder.getReasonCode();
96
+ packet.reasonCodes.push(code);
97
+ }
98
+ return packet;
47
99
  },
48
100
  };
@@ -2,18 +2,34 @@ import { PacketType } from "./PacketType.ts";
2
2
  import assert from "node:assert/strict";
3
3
  import { test } from "node:test";
4
4
 
5
- import { decode, encode } from "./mod.ts";
5
+ import { decode, encode, MQTTLevel, RetainHandling } from "./mod.ts";
6
+ import type { CodecOpts } from "./mod.ts";
6
7
 
7
- test("encode Subscribe", () => {
8
+ const codecOptsV4: CodecOpts = {
9
+ protocolLevel: MQTTLevel.v4,
10
+ maxIncomingPacketSize: 0xffff,
11
+ maxOutgoingPacketSize: 0xffff,
12
+ };
13
+
14
+ const codecOptsV5: CodecOpts = {
15
+ protocolLevel: MQTTLevel.v5,
16
+ maxIncomingPacketSize: 0xffff,
17
+ maxOutgoingPacketSize: 0xffff,
18
+ };
19
+
20
+ test("encode/decode Subscribe v4", () => {
21
+ const packet = {
22
+ type: PacketType.subscribe,
23
+ protocolLevel: MQTTLevel.v4,
24
+ id: 1,
25
+ subscriptions: [
26
+ { topicFilter: "a/b", qos: 0 },
27
+ { topicFilter: "c/d", qos: 1 },
28
+ ],
29
+ };
30
+ const encoded = encode(packet, codecOptsV4);
8
31
  assert.deepStrictEqual(
9
- encode({
10
- type: PacketType.subscribe,
11
- id: 1,
12
- subscriptions: [
13
- { topicFilter: "a/b", qos: 0 },
14
- { topicFilter: "c/d", qos: 1 },
15
- ],
16
- }),
32
+ encoded,
17
33
  Uint8Array.from([
18
34
  // fixedHeader
19
35
  0x82, // packetType + flags
@@ -36,45 +52,75 @@ test("encode Subscribe", () => {
36
52
  1, // qos
37
53
  ]),
38
54
  );
55
+ const decoded = decode(encoded, codecOptsV4);
56
+ assert.deepStrictEqual(decoded, packet);
39
57
  });
40
58
 
41
- test("decode Subscribe", () => {
42
- assert.deepStrictEqual(
43
- decode(
44
- Uint8Array.from([
45
- // fixedHeader
46
- 0x82, // packetType + flags
47
- 14, // remainingLength
48
- // variableHeader
49
- 0, // id MSB
50
- 1, // id LSB
51
- // payload
52
- 0, // topic filter length MSB
53
- 3, // topic filter length LSB
54
- 97, // 'a'
55
- 47, // '/'
56
- 98, // 'b'
57
- 0, // qos
58
- 0, // topic filter length MSB
59
- 3, // topic filter length LSB
60
- 99, // 'c'
61
- 47, // '/'
62
- 100, // 'd'
63
- 1, // qos
64
- ]),
65
- ),
66
- {
67
- type: PacketType.subscribe,
68
- id: 1,
69
- subscriptions: [
70
- { topicFilter: "a/b", qos: 0 },
71
- { topicFilter: "c/d", qos: 1 },
72
- ],
59
+ test("encode/decode Subscribe v5", () => {
60
+ const packet = {
61
+ type: PacketType.subscribe,
62
+ protocolLevel: MQTTLevel.v5,
63
+ id: 1,
64
+ subscriptions: [
65
+ { topicFilter: "a/b", qos: 0 },
66
+ {
67
+ topicFilter: "c/d",
68
+ qos: 2,
69
+ noLocal: true,
70
+ retainAsPublished: true,
71
+ retainHandling: RetainHandling.noRetain,
72
+ },
73
+ ],
74
+ properties: {
75
+ subscriptionIdentifier: 123,
73
76
  },
77
+ };
78
+ const encoded = encode(packet, codecOptsV5);
79
+ assert.deepStrictEqual(
80
+ encoded,
81
+ Uint8Array.from([
82
+ // fixedHeader
83
+ 0x82, // packetType + flags
84
+ 17, // remainingLength
85
+ // variableHeader
86
+ 0, // id MSB
87
+ 1, // id LSB
88
+ 2, // propertyLength
89
+ 11, // subscription identifier
90
+ 123, // 123
91
+ // payload
92
+ 0, // topic filter length MSB
93
+ 3, // topic filter length LSB
94
+ 97, // 'a'
95
+ 47, // '/'
96
+ 98, // 'b'
97
+ 0, // options
98
+ 0, // topic filter length MSB
99
+ 3, // topic filter length LSB
100
+ 99, // 'c'
101
+ 47, // '/'
102
+ 100, // 'd'
103
+ 46, // options 0b101110
104
+ ]),
74
105
  );
106
+ const decoded = decode(encoded, codecOptsV5);
107
+ // add the defaults for comparison
108
+ const packetWithDefaults = {
109
+ ...packet,
110
+ subscriptions: [
111
+ {
112
+ ...packet.subscriptions[0],
113
+ noLocal: false,
114
+ retainAsPublished: false,
115
+ retainHandling: RetainHandling.sendRetained,
116
+ },
117
+ { ...packet.subscriptions[1] },
118
+ ],
119
+ };
120
+ assert.deepStrictEqual(decoded, packetWithDefaults);
75
121
  });
76
122
 
77
- test("decode Subscribe missing bit 1 flag", () => {
123
+ test("decode Subscribe v4 missing bit 1 flag", () => {
78
124
  assert.throws(
79
125
  () =>
80
126
  decode(
@@ -99,6 +145,7 @@ test("decode Subscribe missing bit 1 flag", () => {
99
145
  100, // 'd'
100
146
  1, // qos
101
147
  ]),
148
+ codecOptsV4,
102
149
  ),
103
150
  Error,
104
151
  "Invalid header",
@@ -129,6 +176,7 @@ test("decode Subscribe packet too short", () => {
129
176
  47, // '/'
130
177
  1, // qos
131
178
  ]),
179
+ codecOptsV4,
132
180
  ),
133
181
  Error,
134
182
  "Invalid qos",
@@ -154,6 +202,7 @@ test("decode Subscribe packet too short", () => {
154
202
  3, // topic filter length LSB
155
203
  99, // 'c'
156
204
  ]),
205
+ codecOptsV4,
157
206
  ),
158
207
  Error,
159
208
  "too short",
@@ -169,6 +218,7 @@ test("decode Subscribe packet too short", () => {
169
218
  0, // id MSB
170
219
  1, // id LSB
171
220
  ]),
221
+ codecOptsV4,
172
222
  ),
173
223
  Error,
174
224
  "too short",
@@ -199,6 +249,7 @@ test("decode Subscribe packet invalid packet id with QoS > 0", () => {
199
249
  47, // '/'
200
250
  1, // qos
201
251
  ]),
252
+ codecOptsV4,
202
253
  ),
203
254
  Error,
204
255
  "Invalid packet identifier",
@@ -226,8 +277,46 @@ test("decode Subscribe packet invalid packet id with QoS > 0", () => {
226
277
  47, // '/'
227
278
  2, // qos
228
279
  ]),
280
+ codecOptsV4,
229
281
  ),
230
282
  Error,
231
283
  "Invalid packet identifier",
232
284
  );
233
285
  });
286
+
287
+ test("decode Subscribe v5 with invalid subscription options", () => {
288
+ for (
289
+ const item of [
290
+ [0b10000000, /Invalid subscription options/], // bit 7 must be 0
291
+ [0b1000000, /Invalid subscription options/], // bit 6 must be 0
292
+ [0b110000, /Invalid retain handling/], // retain handling can't be 3
293
+ [0b100011, /Invalid qos/], // qos can't be 3
294
+ ]
295
+ ) {
296
+ const [options, err] = item as [number, RegExp];
297
+ assert.throws(
298
+ () =>
299
+ decode(
300
+ Uint8Array.from([
301
+ // fixedHeader
302
+ 0x82, // packetType + flags
303
+ 9, // remainingLength
304
+ // variableHeader
305
+ 0, // id MSB
306
+ 1, // id LSB
307
+ 0, // propertyLength
308
+ // payload
309
+ 0, // topic filter length MSB
310
+ 3, // topic filter length LSB
311
+ 97, // 'a'
312
+ 47, // '/'
313
+ 98, // 'b'
314
+ options, // options
315
+ ]),
316
+ codecOptsV5,
317
+ ),
318
+ err,
319
+ "Invalid subscription options",
320
+ );
321
+ }
322
+ });
@@ -1,78 +1,181 @@
1
- import type { PacketId, QoS, TopicFilter, TPacketType } from "./types.ts";
1
+ import type {
2
+ CodecOpts,
3
+ PacketId,
4
+ ProtocolLevelNoV5,
5
+ QoS,
6
+ TopicFilter,
7
+ TPacketType,
8
+ TRetainHandling,
9
+ } from "./types.ts";
10
+ import type { SubscribeProperties } from "./Properties.ts";
2
11
  import { PacketType } from "./PacketType.ts";
3
12
  import { BitMask } from "./BitMask.ts";
4
13
  import { Encoder } from "./encoder.ts";
5
14
  import { booleanFlag, Decoder, DecoderError } from "./decoder.ts";
6
15
 
7
- /**
8
- * SubscribePacket is sent from client to server to subscribe to topics
9
- */
10
- export type SubscribePacket = {
16
+ export type SubscribePacketV4 = {
11
17
  type: TPacketType;
18
+ protocolLevel: ProtocolLevelNoV5;
12
19
  id: PacketId;
13
- subscriptions: Subscription[];
20
+ subscriptions: Array<SubscriptionV4>;
21
+ };
22
+
23
+ export type SubscribePacketV5 = {
24
+ type: TPacketType;
25
+ protocolLevel: 5;
26
+ id: PacketId;
27
+ properties?: SubscribeProperties;
28
+ subscriptions: Array<SubscriptionV5>;
14
29
  };
15
30
 
31
+ /**
32
+ * SubscribePacket is sent from client to server to subscribe to topics
33
+ */
34
+ export type SubscribePacket = SubscribePacketV4 | SubscribePacketV5;
16
35
  /**
17
36
  * The topic to subscribe to and the associated QoS
18
37
  */
19
- export type Subscription = {
38
+ export type SubscriptionV4 = {
20
39
  topicFilter: TopicFilter;
21
40
  qos: QoS;
22
41
  };
23
42
 
43
+ export type SubscriptionV5 = {
44
+ topicFilter: TopicFilter;
45
+ qos: QoS;
46
+ noLocal?: boolean;
47
+ retainAsPublished?: boolean;
48
+ retainHandling?: TRetainHandling;
49
+ };
50
+
51
+ export type Subscription = SubscriptionV4 | SubscriptionV5;
52
+
24
53
  export const subscribe: {
25
- encode(packet: SubscribePacket): { flags: number; bytes: number[] };
26
- decode(buffer: Uint8Array, flags: number): SubscribePacket;
54
+ encode(packet: SubscribePacket, codecOpts: CodecOpts): Uint8Array;
55
+ decode(
56
+ buffer: Uint8Array,
57
+ flags: number,
58
+ codecOpts: CodecOpts,
59
+ packetType: TPacketType,
60
+ ): SubscribePacket;
27
61
  } = {
28
- encode(packet: SubscribePacket): { flags: number; bytes: number[] } {
62
+ encode(packet: SubscribePacket, codecOpts: CodecOpts): Uint8Array {
29
63
  // Bits 3,2,1 and 0 of the fixed header of the SUBSCRIBE Control Packet are reserved and
30
64
  // MUST be set to 0,0,1 and 0 respectively. The Server MUST treat any other value as
31
65
  // malformed and close the Network Connection [MQTT-3.8.1-1].
32
66
  const flags = 0b0010;
33
67
 
34
- const encoder = new Encoder();
68
+ const encoder = new Encoder(packet.type);
35
69
  encoder.setInt16(packet.id);
70
+ if (packet.protocolLevel === 5) {
71
+ encoder.setProperties(
72
+ packet.properties || {},
73
+ packet.type,
74
+ codecOpts.maxOutgoingPacketSize,
75
+ );
76
+ }
36
77
  for (const sub of packet.subscriptions) {
37
- encoder.setTopic(sub.topicFilter);
38
- encoder.setByte(sub.qos);
78
+ encoder.setTopicFilter(sub.topicFilter);
79
+ if (packet.protocolLevel === 5) {
80
+ const {
81
+ qos,
82
+ noLocal = false,
83
+ retainAsPublished = false,
84
+ retainHandling = 0,
85
+ } = sub as SubscriptionV5;
86
+ const option = (qos & 1 ? BitMask.bit0 : 0) +
87
+ (qos & 2 ? BitMask.bit1 : 0) +
88
+ (noLocal ? BitMask.bit2 : 0) +
89
+ (retainAsPublished ? BitMask.bit3 : 0) +
90
+ ((retainHandling as number) & 1 ? BitMask.bit4 : 0) +
91
+ ((retainHandling as number) & 2 ? BitMask.bit5 : 0);
92
+ encoder.setByte(option);
93
+ } else {
94
+ encoder.setByte(sub.qos);
95
+ }
39
96
  }
40
- return { flags, bytes: encoder.done() };
97
+ return encoder.done(flags);
41
98
  },
42
99
 
43
- decode(buffer: Uint8Array, flags: number): SubscribePacket {
100
+ decode(
101
+ buffer: Uint8Array,
102
+ flags: number,
103
+ codecOpts: CodecOpts,
104
+ packetType: TPacketType,
105
+ ): SubscribePacket {
44
106
  // Bits 3,2,1 and 0 of the fixed header of the SUBSCRIBE Control Packet are reserved and
45
107
  // MUST be set to 0,0,1 and 0 respectively. The Server MUST treat any other value as
46
108
  // malformed and close the Network Connection [MQTT-3.8.1-1].
47
- if (!booleanFlag(flags, BitMask.bit1)) {
109
+ if (flags !== 0b0010) {
48
110
  throw new DecoderError("Invalid header");
49
111
  }
50
-
51
- const decoder = new Decoder(buffer);
112
+ const decoder = new Decoder(packetType, buffer);
52
113
  const id = decoder.getInt16();
114
+ let properties = {};
115
+ if (codecOpts.protocolLevel === 5) {
116
+ properties = decoder.getProperties(PacketType.subscribe);
117
+ }
53
118
 
54
119
  const subscriptions: Subscription[] = [];
55
- // The payload of a SUBSCRIBE packet MUST contain at least one Topic Filter / QoS pair.
120
+ // The payload of a SUBSCRIBE packet MUST contain at least one Topic Filter / Option pair.
56
121
  // A SUBSCRIBE packet with no payload is a protocol violation [MQTT-3.8.3-3].
57
122
  do {
58
123
  const topicFilter = decoder.getTopicFilter();
59
- const qos = decoder.getByte();
124
+ const option = decoder.getByte();
125
+ const qos = option & 0b11;
60
126
  if (qos !== 0 && qos !== 1 && qos !== 2) {
61
127
  throw new DecoderError("Invalid qos");
62
128
  }
63
129
  if (qos > 0 && id === 0) {
64
130
  throw new DecoderError("Invalid packet identifier");
65
131
  }
66
- subscriptions.push({
67
- topicFilter: topicFilter,
68
- qos,
69
- });
132
+ if (codecOpts.protocolLevel !== 5) {
133
+ if (option !== qos) {
134
+ throw new DecoderError("Invalid qos");
135
+ }
136
+ subscriptions.push({
137
+ topicFilter: topicFilter,
138
+ qos,
139
+ } as SubscriptionV4);
140
+ } else {
141
+ // Bits 6 and 7 of the Subscription Options byte are reserved for future use.
142
+ // The Server MUST treat a SUBSCRIBE packet as malformed if any of
143
+ // Reserved bits in the Payload are non-zero [MQTT-3.8.3-5].
144
+ if (option > 0b111111) {
145
+ throw new DecoderError("Invalid subscription options");
146
+ }
147
+ const noLocal = booleanFlag(option, BitMask.bit2);
148
+ const retainAsPublished = booleanFlag(option, BitMask.bit3);
149
+ const retainHandling = (option & 0b110000) >> 4;
150
+ if (
151
+ retainHandling !== 0 && retainHandling !== 1 && retainHandling !== 2
152
+ ) {
153
+ throw new DecoderError("Invalid retain handling");
154
+ }
155
+ subscriptions.push({
156
+ topicFilter: topicFilter,
157
+ qos,
158
+ noLocal,
159
+ retainAsPublished,
160
+ retainHandling,
161
+ } as SubscriptionV5);
162
+ }
70
163
  } while (!decoder.atEnd());
71
164
  decoder.done();
165
+ if (codecOpts.protocolLevel !== 5) {
166
+ return {
167
+ type: PacketType.subscribe,
168
+ protocolLevel: codecOpts.protocolLevel,
169
+ id,
170
+ subscriptions: subscriptions as Array<SubscriptionV4>,
171
+ };
172
+ }
72
173
  return {
73
174
  type: PacketType.subscribe,
175
+ protocolLevel: 5,
74
176
  id,
75
- subscriptions,
177
+ properties,
178
+ subscriptions: subscriptions as Array<SubscriptionV5>,
76
179
  };
77
180
  },
78
181
  };