@seriousme/opifex 1.9.4 → 1.10.1

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 (304) 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 +126 -117
  5. package/client/client.ts +35 -15
  6. package/client/context.ts +42 -22
  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/dev_utils/dummyConn.ts +17 -2
  16. package/dist/bin/conformanceServer.js +3 -2
  17. package/dist/bin/conformanceServer.js.map +1 -1
  18. package/dist/bin/demoServer.js +3 -2
  19. package/dist/bin/demoServer.js.map +1 -1
  20. package/dist/bin/mqtt.d.ts +29 -0
  21. package/dist/bin/mqtt.d.ts.map +1 -1
  22. package/dist/bin/mqtt.js +101 -96
  23. package/dist/bin/mqtt.js.map +1 -1
  24. package/dist/client/client.d.ts +7 -4
  25. package/dist/client/client.d.ts.map +1 -1
  26. package/dist/client/client.js +17 -9
  27. package/dist/client/client.js.map +1 -1
  28. package/dist/client/context.d.ts +3 -1
  29. package/dist/client/context.d.ts.map +1 -1
  30. package/dist/client/context.js +27 -13
  31. package/dist/client/context.js.map +1 -1
  32. package/dist/client/deps.d.ts +3 -2
  33. package/dist/client/deps.d.ts.map +1 -1
  34. package/dist/client/deps.js +2 -1
  35. package/dist/client/deps.js.map +1 -1
  36. package/dist/client/handlers/handleConnack.d.ts +1 -1
  37. package/dist/client/handlers/handleConnack.d.ts.map +1 -1
  38. package/dist/client/handlers/handleConnack.js +14 -5
  39. package/dist/client/handlers/handleConnack.js.map +1 -1
  40. package/dist/client/handlers/handlePublish.d.ts +1 -1
  41. package/dist/client/handlers/handlePublish.d.ts.map +1 -1
  42. package/dist/client/handlers/handlePublish.js +2 -0
  43. package/dist/client/handlers/handlePublish.js.map +1 -1
  44. package/dist/client/handlers/handlePubrec.d.ts +1 -1
  45. package/dist/client/handlers/handlePubrec.d.ts.map +1 -1
  46. package/dist/client/handlers/handlePubrec.js +1 -0
  47. package/dist/client/handlers/handlePubrec.js.map +1 -1
  48. package/dist/client/handlers/handlePubrel.d.ts +1 -1
  49. package/dist/client/handlers/handlePubrel.d.ts.map +1 -1
  50. package/dist/client/handlers/handlePubrel.js +1 -0
  51. package/dist/client/handlers/handlePubrel.js.map +1 -1
  52. package/dist/client/handlers/handleSuback.d.ts.map +1 -1
  53. package/dist/client/handlers/handleSuback.js +3 -1
  54. package/dist/client/handlers/handleSuback.js.map +1 -1
  55. package/dist/client/mod.d.ts +3 -1
  56. package/dist/client/mod.d.ts.map +1 -1
  57. package/dist/client/mod.js +2 -1
  58. package/dist/client/mod.js.map +1 -1
  59. package/dist/client/store/memoryStore.d.ts +1 -1
  60. package/dist/client/store/memoryStore.d.ts.map +1 -1
  61. package/dist/client/store/memoryStore.js.map +1 -1
  62. package/dist/mqttConn/mqttConn.d.ts +13 -8
  63. package/dist/mqttConn/mqttConn.d.ts.map +1 -1
  64. package/dist/mqttConn/mqttConn.js +27 -12
  65. package/dist/mqttConn/mqttConn.js.map +1 -1
  66. package/dist/mqttPacket/PacketType.d.ts +1 -0
  67. package/dist/mqttPacket/PacketType.d.ts.map +1 -1
  68. package/dist/mqttPacket/PacketType.js +1 -0
  69. package/dist/mqttPacket/PacketType.js.map +1 -1
  70. package/dist/mqttPacket/Properties.d.ts +157 -0
  71. package/dist/mqttPacket/Properties.d.ts.map +1 -0
  72. package/dist/mqttPacket/Properties.js +177 -0
  73. package/dist/mqttPacket/Properties.js.map +1 -0
  74. package/dist/mqttPacket/ReasonCode.d.ts +74 -0
  75. package/dist/mqttPacket/ReasonCode.d.ts.map +1 -0
  76. package/dist/mqttPacket/ReasonCode.js +230 -0
  77. package/dist/mqttPacket/ReasonCode.js.map +1 -0
  78. package/dist/mqttPacket/RetainHandling.d.ts +12 -0
  79. package/dist/mqttPacket/RetainHandling.d.ts.map +1 -0
  80. package/dist/mqttPacket/RetainHandling.js +12 -0
  81. package/dist/mqttPacket/RetainHandling.js.map +1 -0
  82. package/dist/mqttPacket/auth.d.ts +21 -0
  83. package/dist/mqttPacket/auth.d.ts.map +1 -0
  84. package/dist/mqttPacket/auth.js +34 -0
  85. package/dist/mqttPacket/auth.js.map +1 -0
  86. package/dist/mqttPacket/connack.d.ts +15 -7
  87. package/dist/mqttPacket/connack.d.ts.map +1 -1
  88. package/dist/mqttPacket/connack.js +43 -15
  89. package/dist/mqttPacket/connack.js.map +1 -1
  90. package/dist/mqttPacket/connect.d.ts +27 -8
  91. package/dist/mqttPacket/connect.d.ts.map +1 -1
  92. package/dist/mqttPacket/connect.js +106 -30
  93. package/dist/mqttPacket/connect.js.map +1 -1
  94. package/dist/mqttPacket/decoder.d.ts +42 -3
  95. package/dist/mqttPacket/decoder.d.ts.map +1 -1
  96. package/dist/mqttPacket/decoder.js +135 -4
  97. package/dist/mqttPacket/decoder.js.map +1 -1
  98. package/dist/mqttPacket/disconnect.d.ts +13 -7
  99. package/dist/mqttPacket/disconnect.d.ts.map +1 -1
  100. package/dist/mqttPacket/disconnect.js +45 -6
  101. package/dist/mqttPacket/disconnect.js.map +1 -1
  102. package/dist/mqttPacket/encoder.d.ts +57 -8
  103. package/dist/mqttPacket/encoder.d.ts.map +1 -1
  104. package/dist/mqttPacket/encoder.js +185 -13
  105. package/dist/mqttPacket/encoder.js.map +1 -1
  106. package/dist/mqttPacket/length.d.ts.map +1 -1
  107. package/dist/mqttPacket/length.js +3 -2
  108. package/dist/mqttPacket/length.js.map +1 -1
  109. package/dist/mqttPacket/mod.d.ts +56 -91
  110. package/dist/mqttPacket/mod.d.ts.map +1 -1
  111. package/dist/mqttPacket/mod.js +22 -29
  112. package/dist/mqttPacket/mod.js.map +1 -1
  113. package/dist/mqttPacket/pingreq.d.ts +4 -6
  114. package/dist/mqttPacket/pingreq.d.ts.map +1 -1
  115. package/dist/mqttPacket/pingreq.js +5 -4
  116. package/dist/mqttPacket/pingreq.js.map +1 -1
  117. package/dist/mqttPacket/pingres.d.ts +4 -6
  118. package/dist/mqttPacket/pingres.d.ts.map +1 -1
  119. package/dist/mqttPacket/pingres.js +7 -5
  120. package/dist/mqttPacket/pingres.js.map +1 -1
  121. package/dist/mqttPacket/protocolLevels.d.ts +11 -0
  122. package/dist/mqttPacket/protocolLevels.d.ts.map +1 -0
  123. package/dist/mqttPacket/protocolLevels.js +11 -0
  124. package/dist/mqttPacket/protocolLevels.js.map +1 -0
  125. package/dist/mqttPacket/pubblishAcks.d.ts +35 -0
  126. package/dist/mqttPacket/pubblishAcks.d.ts.map +1 -0
  127. package/dist/mqttPacket/pubblishAcks.js +56 -0
  128. package/dist/mqttPacket/pubblishAcks.js.map +1 -0
  129. package/dist/mqttPacket/publish.d.ts +19 -8
  130. package/dist/mqttPacket/publish.d.ts.map +1 -1
  131. package/dist/mqttPacket/publish.js +26 -7
  132. package/dist/mqttPacket/publish.js.map +1 -1
  133. package/dist/mqttPacket/suback.d.ts +14 -7
  134. package/dist/mqttPacket/suback.d.ts.map +1 -1
  135. package/dist/mqttPacket/suback.js +41 -20
  136. package/dist/mqttPacket/suback.js.map +1 -1
  137. package/dist/mqttPacket/subscribe.d.ts +24 -9
  138. package/dist/mqttPacket/subscribe.d.ts.map +1 -1
  139. package/dist/mqttPacket/subscribe.js +71 -15
  140. package/dist/mqttPacket/subscribe.js.map +1 -1
  141. package/dist/mqttPacket/types.d.ts +33 -0
  142. package/dist/mqttPacket/types.d.ts.map +1 -1
  143. package/dist/mqttPacket/unsuback.d.ts +14 -7
  144. package/dist/mqttPacket/unsuback.d.ts.map +1 -1
  145. package/dist/mqttPacket/unsuback.js +29 -6
  146. package/dist/mqttPacket/unsuback.js.map +1 -1
  147. package/dist/mqttPacket/unsubscribe.d.ts +14 -7
  148. package/dist/mqttPacket/unsubscribe.d.ts.map +1 -1
  149. package/dist/mqttPacket/unsubscribe.js +24 -8
  150. package/dist/mqttPacket/unsubscribe.js.map +1 -1
  151. package/dist/node/wrapNodeSocket.d.ts.map +1 -1
  152. package/dist/node/wrapNodeSocket.js.map +1 -1
  153. package/dist/persistence/deps.d.ts +1 -1
  154. package/dist/persistence/deps.d.ts.map +1 -1
  155. package/dist/persistence/deps.js +1 -1
  156. package/dist/persistence/deps.js.map +1 -1
  157. package/dist/server/context.d.ts +3 -1
  158. package/dist/server/context.d.ts.map +1 -1
  159. package/dist/server/context.js +8 -2
  160. package/dist/server/context.js.map +1 -1
  161. package/dist/server/deps.d.ts +2 -2
  162. package/dist/server/deps.d.ts.map +1 -1
  163. package/dist/server/deps.js +1 -1
  164. package/dist/server/deps.js.map +1 -1
  165. package/dist/server/handlers/handleConnect.d.ts +1 -1
  166. package/dist/server/handlers/handleConnect.d.ts.map +1 -1
  167. package/dist/server/handlers/handleConnect.js +9 -1
  168. package/dist/server/handlers/handleConnect.js.map +1 -1
  169. package/dist/server/handlers/handlePacket.d.ts +1 -1
  170. package/dist/server/handlers/handlePacket.d.ts.map +1 -1
  171. package/dist/server/handlers/handlePacket.js +1 -1
  172. package/dist/server/handlers/handlePacket.js.map +1 -1
  173. package/dist/server/handlers/handlePingreq.d.ts.map +1 -1
  174. package/dist/server/handlers/handlePingreq.js +1 -0
  175. package/dist/server/handlers/handlePingreq.js.map +1 -1
  176. package/dist/server/handlers/handlePublish.d.ts +2 -2
  177. package/dist/server/handlers/handlePublish.d.ts.map +1 -1
  178. package/dist/server/handlers/handlePublish.js +2 -0
  179. package/dist/server/handlers/handlePublish.js.map +1 -1
  180. package/dist/server/handlers/handlePubrec.d.ts +1 -1
  181. package/dist/server/handlers/handlePubrec.d.ts.map +1 -1
  182. package/dist/server/handlers/handlePubrec.js +1 -0
  183. package/dist/server/handlers/handlePubrec.js.map +1 -1
  184. package/dist/server/handlers/handlePubrel.d.ts +1 -1
  185. package/dist/server/handlers/handlePubrel.d.ts.map +1 -1
  186. package/dist/server/handlers/handlePubrel.js +1 -0
  187. package/dist/server/handlers/handlePubrel.js.map +1 -1
  188. package/dist/server/handlers/handleSubscribe.d.ts +1 -1
  189. package/dist/server/handlers/handleSubscribe.d.ts.map +1 -1
  190. package/dist/server/handlers/handleSubscribe.js +2 -1
  191. package/dist/server/handlers/handleSubscribe.js.map +1 -1
  192. package/dist/server/handlers/handleUnsubscribe.d.ts +1 -1
  193. package/dist/server/handlers/handleUnsubscribe.d.ts.map +1 -1
  194. package/dist/server/handlers/handleUnsubscribe.js +1 -0
  195. package/dist/server/handlers/handleUnsubscribe.js.map +1 -1
  196. package/dist/server/server.d.ts +2 -2
  197. package/dist/server/server.d.ts.map +1 -1
  198. package/dist/server/server.js +5 -3
  199. package/dist/server/server.js.map +1 -1
  200. package/dist/socket/socket.d.ts.map +1 -1
  201. package/dist/socket/socket.js +6 -1
  202. package/dist/socket/socket.js.map +1 -1
  203. package/dist/utils/assert.d.ts +0 -3
  204. package/dist/utils/assert.d.ts.map +1 -1
  205. package/dist/utils/assert.js +0 -7
  206. package/dist/utils/assert.js.map +1 -1
  207. package/dist/utils/mod.d.ts +0 -3
  208. package/dist/utils/mod.d.ts.map +1 -1
  209. package/dist/utils/mod.js +0 -2
  210. package/dist/utils/mod.js.map +1 -1
  211. package/mqttConn/mqttConn.test.ts +27 -12
  212. package/mqttConn/mqttConn.ts +45 -14
  213. package/mqttPacket/PacketType.ts +1 -0
  214. package/mqttPacket/Properties.ts +276 -0
  215. package/mqttPacket/ReasonCode.test.ts +22 -0
  216. package/mqttPacket/ReasonCode.ts +256 -0
  217. package/mqttPacket/RetainHandling.ts +11 -0
  218. package/mqttPacket/auth.test.ts +112 -0
  219. package/mqttPacket/auth.ts +72 -0
  220. package/mqttPacket/connack.test.ts +84 -64
  221. package/mqttPacket/connack.ts +84 -20
  222. package/mqttPacket/connect.test.ts +497 -18
  223. package/mqttPacket/connect.ts +167 -36
  224. package/mqttPacket/decoder.test.ts +33 -16
  225. package/mqttPacket/decoder.ts +173 -5
  226. package/mqttPacket/disconnect.test.ts +97 -18
  227. package/mqttPacket/disconnect.ts +82 -10
  228. package/mqttPacket/encoder.test.ts +32 -8
  229. package/mqttPacket/encoder.ts +236 -11
  230. package/mqttPacket/length.ts +3 -2
  231. package/mqttPacket/mod.ts +75 -39
  232. package/mqttPacket/pingreq.test.ts +52 -4
  233. package/mqttPacket/pingreq.ts +20 -7
  234. package/mqttPacket/pingres.test.ts +52 -4
  235. package/mqttPacket/pingres.ts +22 -8
  236. package/mqttPacket/properties.test.ts +193 -0
  237. package/mqttPacket/protocolLevels.ts +13 -0
  238. package/mqttPacket/pubblishAcks.ts +117 -0
  239. package/mqttPacket/publish.test.ts +212 -133
  240. package/mqttPacket/publish.ts +69 -14
  241. package/mqttPacket/publishAcks.test.ts +128 -0
  242. package/mqttPacket/suback.test.ts +71 -27
  243. package/mqttPacket/suback.ts +78 -26
  244. package/mqttPacket/subscribe.test.ts +132 -43
  245. package/mqttPacket/subscribe.ts +125 -22
  246. package/mqttPacket/types.ts +40 -0
  247. package/mqttPacket/unsuback.test.ts +80 -30
  248. package/mqttPacket/unsuback.ts +65 -10
  249. package/mqttPacket/unsubscribe.test.ts +59 -34
  250. package/mqttPacket/unsubscribe.ts +61 -14
  251. package/node/wrapNodeSocket.ts +2 -1
  252. package/package.json +2 -2
  253. package/persistence/deps.ts +1 -1
  254. package/persistence/memory/memoryPersistence.test.ts +5 -1
  255. package/server/context.ts +23 -10
  256. package/server/deps.ts +2 -0
  257. package/server/handlers/handleConnect.ts +12 -9
  258. package/server/handlers/handlePacket.ts +10 -11
  259. package/server/handlers/handlePingreq.ts +1 -0
  260. package/server/handlers/handlePublish.ts +6 -2
  261. package/server/handlers/handlePubrec.ts +3 -1
  262. package/server/handlers/handlePubrel.ts +3 -1
  263. package/server/handlers/handleSubscribe.ts +3 -6
  264. package/server/handlers/handleUnsubscribe.ts +3 -1
  265. package/server/server.ts +8 -12
  266. package/server/test/handleConnect.test.ts +2 -1
  267. package/server/test/test-handlers.ts +2 -1
  268. package/socket/socket.ts +5 -1
  269. package/utils/assert.ts +0 -18
  270. package/utils/mod.ts +0 -3
  271. package/dist/mqttPacket/puback.d.ts +0 -16
  272. package/dist/mqttPacket/puback.d.ts.map +0 -1
  273. package/dist/mqttPacket/puback.js +0 -21
  274. package/dist/mqttPacket/puback.js.map +0 -1
  275. package/dist/mqttPacket/pubcomp.d.ts +0 -17
  276. package/dist/mqttPacket/pubcomp.d.ts.map +0 -1
  277. package/dist/mqttPacket/pubcomp.js +0 -21
  278. package/dist/mqttPacket/pubcomp.js.map +0 -1
  279. package/dist/mqttPacket/pubrec.d.ts +0 -17
  280. package/dist/mqttPacket/pubrec.d.ts.map +0 -1
  281. package/dist/mqttPacket/pubrec.js +0 -21
  282. package/dist/mqttPacket/pubrec.js.map +0 -1
  283. package/dist/mqttPacket/pubrel.d.ts +0 -17
  284. package/dist/mqttPacket/pubrel.d.ts.map +0 -1
  285. package/dist/mqttPacket/pubrel.js +0 -21
  286. package/dist/mqttPacket/pubrel.js.map +0 -1
  287. package/dist/utils/args.d.ts +0 -28
  288. package/dist/utils/args.d.ts.map +0 -1
  289. package/dist/utils/args.js +0 -76
  290. package/dist/utils/args.js.map +0 -1
  291. package/dist/utils/platform.d.ts +0 -5
  292. package/dist/utils/platform.d.ts.map +0 -1
  293. package/dist/utils/platform.js +0 -8
  294. package/dist/utils/platform.js.map +0 -1
  295. package/mqttPacket/puback.test.ts +0 -55
  296. package/mqttPacket/puback.ts +0 -34
  297. package/mqttPacket/pubcomp.test.ts +0 -55
  298. package/mqttPacket/pubcomp.ts +0 -35
  299. package/mqttPacket/pubrec.test.ts +0 -55
  300. package/mqttPacket/pubrec.ts +0 -35
  301. package/mqttPacket/pubrel.test.ts +0 -55
  302. package/mqttPacket/pubrel.ts +0 -35
  303. package/utils/args.ts +0 -103
  304. package/utils/platform.ts +0 -8
@@ -1,4 +1,13 @@
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";
@@ -7,72 +16,166 @@ import { booleanFlag, Decoder, DecoderError } from "./decoder.ts";
7
16
  /**
8
17
  * SubscribePacket is sent from client to server to subscribe to topics
9
18
  */
10
- export type SubscribePacket = {
19
+ export type SubscribePacketV4 = {
11
20
  type: TPacketType;
21
+ protocolLevel: ProtocolLevelNoV5;
12
22
  id: PacketId;
13
- subscriptions: Subscription[];
23
+ subscriptions: Array<SubscriptionV4>;
14
24
  };
15
25
 
26
+ export type SubscribePacketV5 = {
27
+ type: TPacketType;
28
+ protocolLevel: 5;
29
+ id: PacketId;
30
+ properties?: SubscribeProperties;
31
+ subscriptions: Array<SubscriptionV5>;
32
+ };
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 = {
39
+ topicFilter: TopicFilter;
40
+ qos: QoS;
41
+ };
42
+
43
+ export type SubscriptionV5 = {
20
44
  topicFilter: TopicFilter;
21
45
  qos: QoS;
46
+ noLocal?: boolean;
47
+ retainAsPublished?: boolean;
48
+ retainHandling?: TRetainHandling;
22
49
  };
23
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
  };
@@ -1,6 +1,8 @@
1
1
  import type { BitMask } from "./BitMask.ts";
2
2
  import type { PacketType } from "./PacketType.ts";
3
+ import type { RetainHandling } from "./RetainHandling.ts";
3
4
  import type { AuthenticationResult } from "./AuthenticationResult.ts";
5
+ import type { ReasonCode } from "./ReasonCode.ts";
4
6
 
5
7
  /**
6
8
  * Type to limit bit mask to valid values
@@ -17,6 +19,20 @@ export type TPacketType = typeof PacketType[keyof typeof PacketType];
17
19
  export type TAuthenticationResult =
18
20
  typeof AuthenticationResult[keyof typeof AuthenticationResult];
19
21
 
22
+ /**
23
+ * Type to limit reason code to valid values
24
+ */
25
+ export type TReasonCode = typeof ReasonCode[keyof typeof ReasonCode];
26
+
27
+ /**
28
+ * Protocol version
29
+ * 3.1 = 3
30
+ * 3.1.1 = 4
31
+ * 5.0 = 5
32
+ */
33
+ export type ProtocolLevel = 3 | 4 | 5 | undefined;
34
+ export type ProtocolLevelNoV5 = Exclude<ProtocolLevel, 5>;
35
+
20
36
  /**
21
37
  * Quality of Service level
22
38
  */
@@ -56,3 +72,27 @@ export type ReturnCodes = number[];
56
72
  * Client identifier that uniquely identifies a client
57
73
  */
58
74
  export type ClientId = string;
75
+
76
+ export type TRetainHandling =
77
+ typeof RetainHandling[keyof typeof RetainHandling];
78
+
79
+ /**
80
+ * UTF8 string pair (for v5)
81
+ */
82
+ export type UTF8StringPair = [string, string];
83
+
84
+ /**
85
+ * Options for the codec
86
+ */
87
+ export type CodecOpts = {
88
+ protocolLevel: ProtocolLevel;
89
+ maxIncomingPacketSize: number;
90
+ maxOutgoingPacketSize: number;
91
+ };
92
+
93
+ /**
94
+ * Typescript helper to create an inverted record type
95
+ */
96
+ export type InvertRecord<R extends Record<string, number>> = {
97
+ [K in keyof R as R[K]]: K;
98
+ };
@@ -1,15 +1,30 @@
1
- import { PacketType } from "./PacketType.ts";
2
1
  import assert from "node:assert/strict";
3
2
  import { test } from "node:test";
4
3
 
5
- import { decode, encode } from "./mod.ts";
4
+ import { decode, encode, MQTTLevel, PacketType, ReasonCode } from "./mod.ts";
5
+ import type { CodecOpts } from "./mod.ts";
6
6
 
7
- test("encode Puback", () => {
7
+ const codecOptsV4: CodecOpts = {
8
+ protocolLevel: MQTTLevel.v4,
9
+ maxIncomingPacketSize: 0xffff,
10
+ maxOutgoingPacketSize: 0xffff,
11
+ };
12
+
13
+ const codecOptsV5: CodecOpts = {
14
+ protocolLevel: MQTTLevel.v5,
15
+ maxIncomingPacketSize: 0xffff,
16
+ maxOutgoingPacketSize: 0xffff,
17
+ };
18
+
19
+ test("encode/decode Unsuback V4", () => {
20
+ const packet = {
21
+ type: PacketType.unsuback,
22
+ protocolLevel: MQTTLevel.v4,
23
+ id: 1337,
24
+ };
25
+ const encoded = encode(packet, codecOptsV4);
8
26
  assert.deepStrictEqual(
9
- encode({
10
- type: PacketType.unsuback,
11
- id: 1337,
12
- }),
27
+ encoded,
13
28
  Uint8Array.from([
14
29
  // fixedHeader
15
30
  0xb0, // packetType + flags
@@ -19,37 +34,72 @@ test("encode Puback", () => {
19
34
  57, // id LSB
20
35
  ]),
21
36
  );
37
+ const decoded = decode(encoded, codecOptsV4);
38
+ assert.deepStrictEqual(decoded, packet);
22
39
  });
23
40
 
24
- test("decode Puback ", () => {
25
- assert.deepStrictEqual(
26
- decode(
27
- Uint8Array.from([
28
- // fixedHeader
29
- 0xb0, // packetType + flags
30
- 2, // remainingLength
31
- // variableHeader
32
- 5, // id MSB
33
- 57, // id LSB
34
- ]),
35
- ),
36
- {
37
- type: PacketType.unsuback,
38
- id: 1337,
41
+ test("encode/decode Unsuback V5", () => {
42
+ const packet = {
43
+ type: PacketType.unsuback,
44
+ protocolLevel: MQTTLevel.v5,
45
+ id: 1337,
46
+ properties: {
47
+ reasonString: "reason",
39
48
  },
49
+ reasonCodes: [ReasonCode.success, ReasonCode.unspecifiedError],
50
+ };
51
+ const encoded = encode(packet, codecOptsV5);
52
+ assert.deepStrictEqual(
53
+ encoded,
54
+ Uint8Array.from([
55
+ // fixedHeader
56
+ 176, // packet type + flags
57
+ 14, // remaining length
58
+ 5, // id MSB
59
+ 57, // id LSB
60
+ 9, // property length
61
+ 31, // reasonString reason
62
+ 0, // string lenght MSB
63
+ 6, // string lengtg LSB
64
+ 114, // r
65
+ 101, // e
66
+ 97, // a
67
+ 115, // s
68
+ 111, // o
69
+ 110, // n
70
+ 0, // ReasonCode.success
71
+ 128, // ReasonCode.unspecifiedError
72
+ ]),
40
73
  );
74
+ const decoded = decode(encoded, codecOptsV5);
75
+ assert.deepStrictEqual(decoded, packet);
41
76
  });
42
77
 
43
- test("decodeShortPubackPackets", () => {
78
+ test("decode short unsuback packets", () => {
79
+ assert.throws(
80
+ () => decode(Uint8Array.from([0xb0]), codecOptsV4),
81
+ /Packet decoding failed/,
82
+ "single byte",
83
+ );
44
84
  assert.throws(
45
- () => decode(Uint8Array.from([0xb0])),
46
- Error,
47
- "decoding failed",
85
+ () => decode(Uint8Array.from([0xb0, 2]), codecOptsV4),
86
+ /too short/,
87
+ "incorrect length",
48
88
  );
49
- assert.throws(() => decode(Uint8Array.from([0xb0, 2])), Error, "too short");
50
89
  assert.throws(
51
- () => decode(Uint8Array.from([0xb0, 3, 0, 0, 0])),
52
- Error,
53
- "too long",
90
+ () => decode(Uint8Array.from([0xb0, 3, 0, 0, 0]), codecOptsV4),
91
+ /too long/,
92
+ "additional bytes",
93
+ );
94
+ });
95
+
96
+ test("decode invalid Unsuback V5, invalid reasonCode", () => {
97
+ assert.throws(
98
+ () =>
99
+ decode(
100
+ Uint8Array.from([224, 4, 1, 0, 0, ReasonCode.quotaExceeded]),
101
+ codecOptsV5,
102
+ ),
103
+ /Invalid reason code/,
54
104
  );
55
105
  });
@@ -1,34 +1,89 @@
1
- import type { PacketId, TPacketType } from "./types.ts";
1
+ import type {
2
+ CodecOpts,
3
+ PacketId,
4
+ ProtocolLevelNoV5,
5
+ TPacketType,
6
+ TReasonCode,
7
+ } from "./types.ts";
8
+ import type { UnsubackProperties } from "./Properties.ts";
2
9
  import { PacketType } from "./PacketType.ts";
3
- import { Decoder } from "./decoder.ts";
10
+ import { Decoder, hasEmptyFlags } from "./decoder.ts";
4
11
  import { Encoder } from "./encoder.ts";
5
12
 
6
13
  /**
7
14
  * UnsubackPacket is sent by the server to the client to confirm receipt
8
15
  * of an UnsubscribePacket.
9
16
  */
10
- export type UnsubackPacket = {
17
+ export type UnsubackPacketV4 = {
11
18
  type: TPacketType;
19
+ protocolLevel: ProtocolLevelNoV5;
12
20
  id: PacketId;
13
21
  };
14
22
 
23
+ export type UnsubackPacketV5 = {
24
+ type: TPacketType;
25
+ protocolLevel: 5;
26
+ id: PacketId;
27
+ properties: UnsubackProperties;
28
+ reasonCodes: Array<TReasonCode>;
29
+ };
30
+
31
+ export type UnsubackPacket = UnsubackPacketV4 | UnsubackPacketV5;
32
+
15
33
  export const unsuback: {
16
- encode(packet: UnsubackPacket): { flags: number; bytes: number[] };
17
- decode(buffer: Uint8Array): UnsubackPacket;
34
+ encode(packet: UnsubackPacket, codecOpts: CodecOpts): Uint8Array;
35
+ decode(
36
+ buffer: Uint8Array,
37
+ flags: number,
38
+ codecOpts: CodecOpts,
39
+ packetType: TPacketType,
40
+ ): UnsubackPacket;
18
41
  } = {
19
- encode(packet: UnsubackPacket): { flags: number; bytes: number[] } {
42
+ encode(packet: UnsubackPacket, codecOpts: CodecOpts): Uint8Array {
20
43
  const flags = 0;
21
- const encoder = new Encoder();
44
+ const encoder = new Encoder(packet.type);
22
45
  encoder.setInt16(packet.id);
23
- return { flags, bytes: encoder.done() };
46
+ if (packet.protocolLevel === 5) {
47
+ encoder.setProperties(
48
+ packet.properties || {},
49
+ PacketType.unsuback,
50
+ codecOpts.maxOutgoingPacketSize,
51
+ );
52
+ for (const reasonCode of packet.reasonCodes) {
53
+ encoder.setByte(reasonCode);
54
+ }
55
+ }
56
+ return encoder.done(flags);
24
57
  },
25
58
 
26
- decode(buffer: Uint8Array): UnsubackPacket {
27
- const decoder = new Decoder(buffer);
59
+ decode(
60
+ buffer: Uint8Array,
61
+ flags: number,
62
+ codecOpts: CodecOpts,
63
+ packetType: TPacketType,
64
+ ): UnsubackPacket {
65
+ hasEmptyFlags(flags);
66
+ const decoder = new Decoder(packetType, buffer);
28
67
  const id = decoder.getInt16();
68
+ if (codecOpts.protocolLevel === 5) {
69
+ const properties = decoder.getProperties(PacketType.unsuback);
70
+ const reasonCodes = [];
71
+ while (!decoder.atEnd()) {
72
+ const reasonCode = decoder.getReasonCode();
73
+ reasonCodes.push(reasonCode);
74
+ }
75
+ return {
76
+ type: PacketType.unsuback,
77
+ protocolLevel: 5,
78
+ id,
79
+ properties,
80
+ reasonCodes: reasonCodes as Array<TReasonCode>,
81
+ };
82
+ }
29
83
  decoder.done();
30
84
  return {
31
85
  type: PacketType.unsuback,
86
+ protocolLevel: codecOpts.protocolLevel,
32
87
  id,
33
88
  };
34
89
  },
@@ -1,16 +1,31 @@
1
1
  import { PacketType } from "./PacketType.ts";
2
2
  import assert from "node:assert/strict";
3
3
  import { test } from "node:test";
4
+ import { decode, encode, MQTTLevel } from "./mod.ts";
5
+ import type { CodecOpts } from "./mod.ts";
4
6
 
5
- import { decode, encode } from "./mod.ts";
7
+ const codecOptsV4: CodecOpts = {
8
+ protocolLevel: MQTTLevel.v4,
9
+ maxIncomingPacketSize: 0xffff,
10
+ maxOutgoingPacketSize: 0xffff,
11
+ };
6
12
 
7
- test("encode Unsubscribe", () => {
13
+ const codecOptsV5: CodecOpts = {
14
+ protocolLevel: MQTTLevel.v5,
15
+ maxIncomingPacketSize: 0xffff,
16
+ maxOutgoingPacketSize: 0xffff,
17
+ };
18
+
19
+ test("encode/decode Unsubscribe V4", () => {
20
+ const packet = {
21
+ type: PacketType.unsubscribe,
22
+ protocolLevel: MQTTLevel.v4,
23
+ id: 1,
24
+ topicFilters: ["a/b", "c/d"],
25
+ };
26
+ const encoded = encode(packet, codecOptsV4);
8
27
  assert.deepStrictEqual(
9
- encode({
10
- type: PacketType.unsubscribe,
11
- id: 1,
12
- topicFilters: ["a/b", "c/d"],
13
- }),
28
+ encoded,
14
29
  Uint8Array.from([
15
30
  // fixedHeader
16
31
  0xa2, // packetType + flags
@@ -31,37 +46,44 @@ test("encode Unsubscribe", () => {
31
46
  100, // 'd'
32
47
  ]),
33
48
  );
49
+ const decoded = decode(encoded, codecOptsV4);
50
+ assert.deepStrictEqual(decoded, packet);
34
51
  });
35
52
 
36
- test("decode Unsubscribe", () => {
53
+ test("encode/decode Unsubscribe V5", () => {
54
+ const packet = {
55
+ type: PacketType.unsubscribe,
56
+ protocolLevel: MQTTLevel.v5,
57
+ id: 1,
58
+ properties: {},
59
+ topicFilters: ["a/b", "c/d"],
60
+ };
61
+ const encoded = encode(packet, codecOptsV4);
37
62
  assert.deepStrictEqual(
38
- decode(
39
- Uint8Array.from([
40
- // fixedHeader
41
- 0xa2, // packetType + flags
42
- 12, // remainingLength
43
- // variableHeader
44
- 0, // id MSB
45
- 1, // id LSB
46
- // payload
47
- 0, // topic filter length MSB
48
- 3, // topic filter length LSB
49
- 97, // 'a'
50
- 47, // '/'
51
- 98, // 'b'
52
- 0, // topic filter length MSB
53
- 3, // topic filter length LSB
54
- 99, // 'c'
55
- 47, // '/'
56
- 100, // 'd'
57
- ]),
58
- ),
59
- {
60
- type: PacketType.unsubscribe,
61
- id: 1,
62
- topicFilters: ["a/b", "c/d"],
63
- },
63
+ encoded,
64
+ Uint8Array.from([
65
+ // fixedHeader
66
+ 0xa2, // packetType + flags
67
+ 13, // remainingLength
68
+ // variableHeader
69
+ 0, // id MSB
70
+ 1, // id LSB
71
+ 0, // property length
72
+ // payload
73
+ 0, // topic filter length MSB
74
+ 3, // topic filter length LSB
75
+ 97, // 'a'
76
+ 47, // '/'
77
+ 98, // 'b'
78
+ 0, // topic filter length MSB
79
+ 3, // topic filter length LSB
80
+ 99, // 'c'
81
+ 47, // '/'
82
+ 100, // 'd'
83
+ ]),
64
84
  );
85
+ const decoded = decode(encoded, codecOptsV5);
86
+ assert.deepStrictEqual(decoded, packet);
65
87
  });
66
88
 
67
89
  test("decode Unsubscribe missing bit 1 flag", () => {
@@ -87,6 +109,7 @@ test("decode Unsubscribe missing bit 1 flag", () => {
87
109
  47, // '/'
88
110
  100, // 'd'
89
111
  ]),
112
+ codecOptsV4,
90
113
  ),
91
114
  Error,
92
115
  "Invalid header",
@@ -114,6 +137,7 @@ test("decode unsubscribe packet too short", () => {
114
137
  3, // topic filter length LSB
115
138
  99, // 'c'
116
139
  ]),
140
+ codecOptsV4,
117
141
  ),
118
142
  Error,
119
143
  "too short",
@@ -129,6 +153,7 @@ test("decode unsubscribe packet too short", () => {
129
153
  0, // id MSB
130
154
  1, // id LSB
131
155
  ]),
156
+ codecOptsV4,
132
157
  ),
133
158
  Error,
134
159
  "too short",