@seriousme/opifex 1.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 (120) hide show
  1. package/.github/workflows/closeStale.yml +15 -0
  2. package/.github/workflows/codeql-analysis.yml +71 -0
  3. package/.github/workflows/deno-ci.yml +16 -0
  4. package/.github/workflows/nodejs-ci.yml +23 -0
  5. package/.github/workflows/publish.yml +16 -0
  6. package/.vscode/extensions.json +10 -0
  7. package/.vscode/settings.json +12 -0
  8. package/LICENSE.txt +21 -0
  9. package/README.md +34 -0
  10. package/bin/conformanceServer.ts +70 -0
  11. package/bin/demoServer.ts +64 -0
  12. package/bin/mqtt.ts +211 -0
  13. package/client/client.ts +181 -0
  14. package/client/context.ts +197 -0
  15. package/client/deps.ts +36 -0
  16. package/client/handlers/handleConnack.ts +21 -0
  17. package/client/handlers/handlePacket.ts +70 -0
  18. package/client/handlers/handlePuback.ts +10 -0
  19. package/client/handlers/handlePubcomp.ts +13 -0
  20. package/client/handlers/handlePublish.ts +32 -0
  21. package/client/handlers/handlePubrec.ts +24 -0
  22. package/client/handlers/handlePubrel.ts +26 -0
  23. package/client/handlers/handleSuback.ts +14 -0
  24. package/client/handlers/handleUnsuback.ts +11 -0
  25. package/client/mod.ts +11 -0
  26. package/client/store/deps.ts +22 -0
  27. package/client/store/memoryStore.ts +56 -0
  28. package/client/store/store.ts +29 -0
  29. package/deno/README.md +64 -0
  30. package/deno/client.ts +48 -0
  31. package/deno/server.test.ts +14 -0
  32. package/deno/server.ts +31 -0
  33. package/deno/wrapDenoConn.ts +12 -0
  34. package/deno.json +8 -0
  35. package/deno.lock +47 -0
  36. package/dev_utils/dummyConn.ts +95 -0
  37. package/dev_utils/mod.ts +1 -0
  38. package/mqttConn/mqttConn.test.ts +110 -0
  39. package/mqttConn/mqttConn.ts +134 -0
  40. package/mqttPacket/AuthenticationResult.ts +16 -0
  41. package/mqttPacket/BitMask.ts +10 -0
  42. package/mqttPacket/PacketType.ts +21 -0
  43. package/mqttPacket/connack.test.ts +129 -0
  44. package/mqttPacket/connack.ts +37 -0
  45. package/mqttPacket/connect.test.ts +297 -0
  46. package/mqttPacket/connect.ts +159 -0
  47. package/mqttPacket/decoder.test.ts +123 -0
  48. package/mqttPacket/decoder.ts +109 -0
  49. package/mqttPacket/disconnect.test.ts +50 -0
  50. package/mqttPacket/disconnect.ts +21 -0
  51. package/mqttPacket/encoder.test.ts +39 -0
  52. package/mqttPacket/encoder.ts +72 -0
  53. package/mqttPacket/length.test.ts +75 -0
  54. package/mqttPacket/length.ts +57 -0
  55. package/mqttPacket/mod.ts +151 -0
  56. package/mqttPacket/pingreq.test.ts +50 -0
  57. package/mqttPacket/pingreq.ts +22 -0
  58. package/mqttPacket/pingres.test.ts +50 -0
  59. package/mqttPacket/pingres.ts +21 -0
  60. package/mqttPacket/puback.test.ts +55 -0
  61. package/mqttPacket/puback.ts +28 -0
  62. package/mqttPacket/pubcomp.test.ts +55 -0
  63. package/mqttPacket/pubcomp.ts +28 -0
  64. package/mqttPacket/publish.test.ts +198 -0
  65. package/mqttPacket/publish.ts +73 -0
  66. package/mqttPacket/pubrec.test.ts +55 -0
  67. package/mqttPacket/pubrec.ts +28 -0
  68. package/mqttPacket/pubrel.test.ts +55 -0
  69. package/mqttPacket/pubrel.ts +28 -0
  70. package/mqttPacket/suback.test.ts +49 -0
  71. package/mqttPacket/suback.ts +41 -0
  72. package/mqttPacket/subscribe.test.ts +233 -0
  73. package/mqttPacket/subscribe.ts +69 -0
  74. package/mqttPacket/types.ts +27 -0
  75. package/mqttPacket/unsuback.test.ts +55 -0
  76. package/mqttPacket/unsuback.ts +28 -0
  77. package/mqttPacket/unsubscribe.test.ts +136 -0
  78. package/mqttPacket/unsubscribe.ts +48 -0
  79. package/mqttPacket/validators.ts +20 -0
  80. package/node/README.md +46 -0
  81. package/node/client.ts +58 -0
  82. package/node/server.test.ts +14 -0
  83. package/node/server.ts +34 -0
  84. package/node/wrapNodeSocket.ts +54 -0
  85. package/package.json +35 -0
  86. package/persistence/deps.ts +12 -0
  87. package/persistence/memory/memoryPersistence.test.ts +151 -0
  88. package/persistence/memory/memoryPersistence.ts +156 -0
  89. package/persistence/persistence.ts +24 -0
  90. package/persistence/store.ts +14 -0
  91. package/server/context.ts +157 -0
  92. package/server/deps.ts +37 -0
  93. package/server/handlers/handleConnect.ts +73 -0
  94. package/server/handlers/handleDisconnect.ts +6 -0
  95. package/server/handlers/handlePacket.ts +78 -0
  96. package/server/handlers/handlePingreq.ts +8 -0
  97. package/server/handlers/handlePuback.ts +12 -0
  98. package/server/handlers/handlePubcomp.ts +12 -0
  99. package/server/handlers/handlePublish.ts +47 -0
  100. package/server/handlers/handlePubrec.ts +20 -0
  101. package/server/handlers/handlePubrel.ts +24 -0
  102. package/server/handlers/handleSubscribe.ts +47 -0
  103. package/server/handlers/handleUnsubscribe.ts +17 -0
  104. package/server/mod.ts +16 -0
  105. package/server/server.ts +74 -0
  106. package/server/test/handleConnect.test.ts +126 -0
  107. package/server/test/test-handlers.ts +52 -0
  108. package/socket/socket.ts +59 -0
  109. package/timer/timer.test.ts +48 -0
  110. package/timer/timer.ts +45 -0
  111. package/trie/trie.test.ts +147 -0
  112. package/trie/trie.ts +106 -0
  113. package/utils/args.ts +86 -0
  114. package/utils/assert.ts +31 -0
  115. package/utils/asyncQueue.ts +63 -0
  116. package/utils/deferred.ts +12 -0
  117. package/utils/logger.ts +35 -0
  118. package/utils/mod.ts +7 -0
  119. package/utils/nextTick.ts +3 -0
  120. package/utils/platform.ts +4 -0
@@ -0,0 +1,55 @@
1
+ import { PacketType } from "./PacketType.ts";
2
+ import assert from "node:assert/strict";
3
+ import { test } from "node:test";
4
+
5
+ import { decode, encode } from "./mod.ts";
6
+
7
+ test("encode Pubrel", () => {
8
+ assert.deepStrictEqual(
9
+ encode({
10
+ type: PacketType.pubrel,
11
+ id: 1337,
12
+ }),
13
+ Uint8Array.from([
14
+ // fixedHeader
15
+ 0x60, // packetType + flags
16
+ 2, // remainingLength
17
+ // variableHeader
18
+ 5, // id MSB
19
+ 57, // id LSB
20
+ ]),
21
+ );
22
+ });
23
+
24
+ test("decode Pubrel ", () => {
25
+ assert.deepStrictEqual(
26
+ decode(
27
+ Uint8Array.from([
28
+ // fixedHeader
29
+ 0x60, // packetType + flags
30
+ 2, // remainingLength
31
+ // variableHeader
32
+ 5, // id MSB
33
+ 57, // id LSB
34
+ ]),
35
+ ),
36
+ {
37
+ type: PacketType.pubrel,
38
+ id: 1337,
39
+ },
40
+ );
41
+ });
42
+
43
+ test("decodeShortPubrelPackets", () => {
44
+ assert.throws(
45
+ () => decode(Uint8Array.from([0x60])),
46
+ Error,
47
+ "decoding failed",
48
+ );
49
+ assert.throws(() => decode(Uint8Array.from([0x60, 2])), Error, "too short");
50
+ assert.throws(
51
+ () => decode(Uint8Array.from([0x60, 3, 0, 0, 0])),
52
+ Error,
53
+ "too long",
54
+ );
55
+ });
@@ -0,0 +1,28 @@
1
+ import type { PacketId, TPacketType } from "./types.ts";
2
+ import { PacketType } from "./PacketType.ts";
3
+ import { Decoder } from "./decoder.ts";
4
+ import { Encoder } from "./encoder.ts";
5
+
6
+ export type PubrelPacket = {
7
+ type: TPacketType;
8
+ id: PacketId;
9
+ };
10
+
11
+ export default {
12
+ encode(packet: PubrelPacket) {
13
+ const flags = 0;
14
+ const encoder = new Encoder();
15
+ encoder.setInt16(packet.id);
16
+ return { flags, bytes: encoder.done() };
17
+ },
18
+
19
+ decode(buffer: Uint8Array): PubrelPacket {
20
+ const decoder = new Decoder(buffer);
21
+ const id = decoder.getInt16();
22
+ decoder.done();
23
+ return {
24
+ type: PacketType.pubrel,
25
+ id,
26
+ };
27
+ },
28
+ };
@@ -0,0 +1,49 @@
1
+ import { PacketType } from "./PacketType.ts";
2
+ import assert from "node:assert/strict";
3
+ import { test } from "node:test";
4
+
5
+ import { decode, encode } from "./mod.ts";
6
+
7
+ test("encode Suback", () => {
8
+ assert.deepStrictEqual(
9
+ encode({
10
+ type: PacketType.suback,
11
+ id: 1,
12
+ returnCodes: [0, 1],
13
+ }),
14
+ Uint8Array.from([
15
+ // fixedHeader
16
+ 0x90, // packetType + flags
17
+ 4, // remainingLength
18
+ // variableHeader
19
+ 0, // id MSB
20
+ 1, // id LSB
21
+ // payload
22
+ 0,
23
+ 1,
24
+ ]),
25
+ );
26
+ });
27
+
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],
47
+ },
48
+ );
49
+ });
@@ -0,0 +1,41 @@
1
+ import type { PacketId, ReturnCodes, TPacketType } from "./types.ts";
2
+ import { PacketType } from "./PacketType.ts";
3
+ import { Encoder } from "./encoder.ts";
4
+ import { Decoder } from "./decoder.ts";
5
+
6
+ export type SubackPacket = {
7
+ type: TPacketType;
8
+ id: PacketId;
9
+ returnCodes: ReturnCodes;
10
+ };
11
+
12
+ export default {
13
+ encode(packet: SubackPacket) {
14
+ const flags = 0;
15
+ const encoder = new Encoder();
16
+ encoder.setInt16(packet.id);
17
+ encoder.setRemainder(packet.returnCodes);
18
+
19
+ return {
20
+ flags,
21
+ bytes: encoder.done(),
22
+ };
23
+ },
24
+
25
+ decode(buffer: Uint8Array): SubackPacket {
26
+ const decoder = new Decoder(buffer);
27
+ const id = decoder.getInt16();
28
+ const payload = decoder.getRemainder();
29
+ const returnCodes = [];
30
+
31
+ for (const code of payload) {
32
+ returnCodes.push(code);
33
+ }
34
+
35
+ return {
36
+ type: PacketType.suback,
37
+ id,
38
+ returnCodes,
39
+ };
40
+ },
41
+ };
@@ -0,0 +1,233 @@
1
+ import { PacketType } from "./PacketType.ts";
2
+ import assert from "node:assert/strict";
3
+ import { test } from "node:test";
4
+
5
+ import { decode, encode } from "./mod.ts";
6
+
7
+ test("encode Subscribe", () => {
8
+ 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
+ }),
17
+ Uint8Array.from([
18
+ // fixedHeader
19
+ 0x82, // packetType + flags
20
+ 14, // remainingLength
21
+ // variableHeader
22
+ 0, // id MSB
23
+ 1, // id LSB
24
+ // payload
25
+ 0, // topic filter length MSB
26
+ 3, // topic filter length LSB
27
+ 97, // 'a'
28
+ 47, // '/'
29
+ 98, // 'b'
30
+ 0, // qos
31
+ 0, // topic filter length MSB
32
+ 3, // topic filter length LSB
33
+ 99, // 'c'
34
+ 47, // '/'
35
+ 100, // 'd'
36
+ 1, // qos
37
+ ]),
38
+ );
39
+ });
40
+
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
+ ],
73
+ },
74
+ );
75
+ });
76
+
77
+ test("decode Subscribe missing bit 1 flag", () => {
78
+ assert.throws(
79
+ () =>
80
+ decode(
81
+ Uint8Array.from([
82
+ // fixedHeader
83
+ 0x80, // packetType + flags
84
+ 14, // remainingLength
85
+ // variableHeader
86
+ 0, // id MSB
87
+ 1, // id LSB
88
+ // payload
89
+ 0, // topic filter length MSB
90
+ 3, // topic filter length LSB
91
+ 97, // 'a'
92
+ 47, // '/'
93
+ 98, // 'b'
94
+ 0, // qos
95
+ 0, // topic filter length MSB
96
+ 3, // topic filter length LSB
97
+ 99, // 'c'
98
+ 47, // '/'
99
+ 100, // 'd'
100
+ 1, // qos
101
+ ]),
102
+ ),
103
+ Error,
104
+ "Invalid header",
105
+ );
106
+ });
107
+
108
+ test("decode Subscribe packet too short", () => {
109
+ assert.throws(
110
+ () =>
111
+ decode(
112
+ Uint8Array.from([
113
+ // fixedHeader
114
+ 0x82, // packetType + flags
115
+ 14, // remainingLength
116
+ // variableHeader
117
+ 0, // id MSB
118
+ 1, // id LSB
119
+ // payload
120
+ 0, // topic filter length MSB
121
+ 3, // topic filter length LSB
122
+ 97, // 'a'
123
+ 47, // '/'
124
+ 98, // 'b'
125
+ 0, // qos
126
+ 0, // topic filter length MSB
127
+ 3, // topic filter length LSB
128
+ 99, // 'c'
129
+ 47, // '/'
130
+ 1, // qos
131
+ ]),
132
+ ),
133
+ Error,
134
+ "Invalid qos",
135
+ );
136
+ assert.throws(
137
+ () =>
138
+ decode(
139
+ Uint8Array.from([
140
+ // fixedHeader
141
+ 0x82, // packetType + flags
142
+ 14, // remainingLength
143
+ // variableHeader
144
+ 0, // id MSB
145
+ 1, // id LSB
146
+ // payload
147
+ 0, // topic filter length MSB
148
+ 3, // topic filter length LSB
149
+ 97, // 'a'
150
+ 47, // '/'
151
+ 98, // 'b'
152
+ 0, // qos
153
+ 0, // topic filter length MSB
154
+ 3, // topic filter length LSB
155
+ 99, // 'c'
156
+ ]),
157
+ ),
158
+ Error,
159
+ "too short",
160
+ );
161
+ assert.throws(
162
+ () =>
163
+ decode(
164
+ Uint8Array.from([
165
+ // fixedHeader
166
+ 0x82, // packetType + flags
167
+ 14, // remainingLength
168
+ // variableHeader
169
+ 0, // id MSB
170
+ 1, // id LSB
171
+ ]),
172
+ ),
173
+ Error,
174
+ "too short",
175
+ );
176
+ });
177
+
178
+ test("decode Subscribe packet invalid packet id with QoS > 0", () => {
179
+ assert.throws(
180
+ () =>
181
+ decode(
182
+ Uint8Array.from([
183
+ // fixedHeader
184
+ 0x82, // packetType + flags
185
+ 13, // remainingLength
186
+ // variableHeader
187
+ 0, // id MSB
188
+ 0, // id LSB
189
+ // payload
190
+ 0, // topic filter length MSB
191
+ 3, // topic filter length LSB
192
+ 97, // 'a'
193
+ 47, // '/'
194
+ 98, // 'b'
195
+ 0, // qos
196
+ 0, // topic filter length MSB
197
+ 2, // topic filter length LSB
198
+ 99, // 'c'
199
+ 47, // '/'
200
+ 1, // qos
201
+ ]),
202
+ ),
203
+ Error,
204
+ "Invalid packet identifier",
205
+ );
206
+ assert.throws(
207
+ () =>
208
+ decode(
209
+ Uint8Array.from([
210
+ // fixedHeader
211
+ 0x82, // packetType + flags
212
+ 13, // remainingLength
213
+ // variableHeader
214
+ 0, // id MSB
215
+ 0, // id LSB
216
+ // payload
217
+ 0, // topic filter length MSB
218
+ 3, // topic filter length LSB
219
+ 97, // 'a'
220
+ 47, // '/'
221
+ 98, // 'b'
222
+ 0, // qos
223
+ 0, // topic filter length MSB
224
+ 2, // topic filter length LSB
225
+ 99, // 'c'
226
+ 47, // '/'
227
+ 2, // qos
228
+ ]),
229
+ ),
230
+ Error,
231
+ "Invalid packet identifier",
232
+ );
233
+ });
@@ -0,0 +1,69 @@
1
+ import type { PacketId, QoS, TopicFilter, TPacketType } from "./types.ts";
2
+ import { PacketType } from "./PacketType.ts";
3
+ import { BitMask } from "./BitMask.ts";
4
+ import { Encoder } from "./encoder.ts";
5
+ import { booleanFlag, Decoder, DecoderError } from "./decoder.ts";
6
+
7
+ export type SubscribePacket = {
8
+ type: TPacketType;
9
+ id: PacketId;
10
+ subscriptions: Subscription[];
11
+ };
12
+
13
+ export type Subscription = {
14
+ topicFilter: TopicFilter;
15
+ qos: QoS;
16
+ };
17
+
18
+ export default {
19
+ encode(packet: SubscribePacket) {
20
+ // Bits 3,2,1 and 0 of the fixed header of the SUBSCRIBE Control Packet are reserved and
21
+ // MUST be set to 0,0,1 and 0 respectively. The Server MUST treat any other value as
22
+ // malformed and close the Network Connection [MQTT-3.8.1-1].
23
+ const flags = 0b0010;
24
+
25
+ const encoder = new Encoder();
26
+ encoder.setInt16(packet.id);
27
+ for (const sub of packet.subscriptions) {
28
+ encoder.setTopic(sub.topicFilter);
29
+ encoder.setByte(sub.qos);
30
+ }
31
+ return { flags, bytes: encoder.done() };
32
+ },
33
+
34
+ decode(buffer: Uint8Array, flags: number): SubscribePacket {
35
+ // Bits 3,2,1 and 0 of the fixed header of the SUBSCRIBE Control Packet are reserved and
36
+ // MUST be set to 0,0,1 and 0 respectively. The Server MUST treat any other value as
37
+ // malformed and close the Network Connection [MQTT-3.8.1-1].
38
+ if (!booleanFlag(flags, BitMask.bit1)) {
39
+ throw new DecoderError("Invalid header");
40
+ }
41
+
42
+ const decoder = new Decoder(buffer);
43
+ const id = decoder.getInt16();
44
+
45
+ const subscriptions: Subscription[] = [];
46
+ // The payload of a SUBSCRIBE packet MUST contain at least one Topic Filter / QoS pair.
47
+ // A SUBSCRIBE packet with no payload is a protocol violation [MQTT-3.8.3-3].
48
+ do {
49
+ const topicFilter = decoder.getTopicFilter();
50
+ const qos = decoder.getByte();
51
+ if (qos !== 0 && qos !== 1 && qos !== 2) {
52
+ throw new DecoderError("Invalid qos");
53
+ }
54
+ if (qos > 0 && id === 0) {
55
+ throw new DecoderError("Invalid packet identifier");
56
+ }
57
+ subscriptions.push({
58
+ topicFilter: topicFilter,
59
+ qos,
60
+ });
61
+ } while (!decoder.atEnd());
62
+ decoder.done();
63
+ return {
64
+ type: PacketType.subscribe,
65
+ id,
66
+ subscriptions,
67
+ };
68
+ },
69
+ };
@@ -0,0 +1,27 @@
1
+ import type { BitMask } from "./BitMask.ts";
2
+ import type { PacketType } from "./PacketType.ts";
3
+ import type { AuthenticationResult } from "./AuthenticationResult.ts";
4
+
5
+ export type TBitMask = typeof BitMask[keyof typeof BitMask];
6
+ export type TPacketType = typeof PacketType[keyof typeof PacketType];
7
+ export type TAuthenticationResult =
8
+ typeof AuthenticationResult[keyof typeof AuthenticationResult];
9
+
10
+ export type QoS = 0 | 1 | 2;
11
+
12
+ export type Payload = Uint8Array;
13
+
14
+ /**
15
+ * The MQTT topic to publish or subscribe to
16
+ */
17
+ export type Topic = string;
18
+
19
+ export type TopicFilter = string;
20
+
21
+ export type Dup = boolean;
22
+
23
+ export type PacketId = number;
24
+
25
+ export type ReturnCodes = number[];
26
+
27
+ export type ClientId = string;
@@ -0,0 +1,55 @@
1
+ import { PacketType } from "./PacketType.ts";
2
+ import assert from "node:assert/strict";
3
+ import { test } from "node:test";
4
+
5
+ import { decode, encode } from "./mod.ts";
6
+
7
+ test("encode Puback", () => {
8
+ assert.deepStrictEqual(
9
+ encode({
10
+ type: PacketType.unsuback,
11
+ id: 1337,
12
+ }),
13
+ Uint8Array.from([
14
+ // fixedHeader
15
+ 0xb0, // packetType + flags
16
+ 2, // remainingLength
17
+ // variableHeader
18
+ 5, // id MSB
19
+ 57, // id LSB
20
+ ]),
21
+ );
22
+ });
23
+
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,
39
+ },
40
+ );
41
+ });
42
+
43
+ test("decodeShortPubackPackets", () => {
44
+ assert.throws(
45
+ () => decode(Uint8Array.from([0xb0])),
46
+ Error,
47
+ "decoding failed",
48
+ );
49
+ assert.throws(() => decode(Uint8Array.from([0xb0, 2])), Error, "too short");
50
+ assert.throws(
51
+ () => decode(Uint8Array.from([0xb0, 3, 0, 0, 0])),
52
+ Error,
53
+ "too long",
54
+ );
55
+ });
@@ -0,0 +1,28 @@
1
+ import type { PacketId, TPacketType } from "./types.ts";
2
+ import { PacketType } from "./PacketType.ts";
3
+ import { Decoder } from "./decoder.ts";
4
+ import { Encoder } from "./encoder.ts";
5
+
6
+ export type UnsubackPacket = {
7
+ type: TPacketType;
8
+ id: PacketId;
9
+ };
10
+
11
+ export default {
12
+ encode(packet: UnsubackPacket) {
13
+ const flags = 0;
14
+ const encoder = new Encoder();
15
+ encoder.setInt16(packet.id);
16
+ return { flags, bytes: encoder.done() };
17
+ },
18
+
19
+ decode(buffer: Uint8Array): UnsubackPacket {
20
+ const decoder = new Decoder(buffer);
21
+ const id = decoder.getInt16();
22
+ decoder.done();
23
+ return {
24
+ type: PacketType.unsuback,
25
+ id,
26
+ };
27
+ },
28
+ };