@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,50 @@
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 Pingreq", () => {
8
+ assert.deepStrictEqual(
9
+ encode({
10
+ type: PacketType.pingreq,
11
+ }),
12
+ Uint8Array.from([
13
+ // fixedHeader
14
+ 192, // packetType + flags
15
+ 0, // remainingLength
16
+ ]),
17
+ );
18
+ });
19
+
20
+ test("decode Pingreq", () => {
21
+ assert.deepStrictEqual(
22
+ decode(
23
+ Uint8Array.from([
24
+ // fixedHeader
25
+ 192, // packetType + flags
26
+ 0, // remainingLength
27
+ ]),
28
+ ),
29
+ {
30
+ type: PacketType.pingreq,
31
+ },
32
+ );
33
+ });
34
+
35
+ test("decode invalid Pingreq", () => {
36
+ assert.throws(
37
+ () =>
38
+ decode(
39
+ Uint8Array.from([
40
+ // fixedHeader
41
+ 192, // packetType + flags
42
+ 2, // remainingLength
43
+ 0,
44
+ 0,
45
+ ]),
46
+ ),
47
+ Error,
48
+ "too long",
49
+ );
50
+ });
@@ -0,0 +1,22 @@
1
+ import { PacketType } from "./PacketType.ts";
2
+ import { hasEmptyFlags, isEmptyBuf } from "./decoder.ts";
3
+ import type { TPacketType } from "./types.ts";
4
+
5
+ export type PingreqPacket = {
6
+ type: TPacketType;
7
+ };
8
+
9
+ export default {
10
+ encode(_packet: PingreqPacket) {
11
+ const flags = 0;
12
+ return { flags, bytes: [] };
13
+ },
14
+
15
+ decode(buffer: Uint8Array, flags: number): PingreqPacket {
16
+ hasEmptyFlags(flags);
17
+ isEmptyBuf(buffer);
18
+ return {
19
+ type: PacketType.pingreq,
20
+ };
21
+ },
22
+ };
@@ -0,0 +1,50 @@
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 Pingres", () => {
8
+ assert.deepStrictEqual(
9
+ encode({
10
+ type: PacketType.pingres,
11
+ }),
12
+ Uint8Array.from([
13
+ // fixedHeader
14
+ 208, // packetType + flags
15
+ 0, // remainingLength
16
+ ]),
17
+ );
18
+ });
19
+
20
+ test("decode Pingres", () => {
21
+ assert.deepStrictEqual(
22
+ decode(
23
+ Uint8Array.from([
24
+ // fixedHeader
25
+ 208, // packetType + flags
26
+ 0, // remainingLength
27
+ ]),
28
+ ),
29
+ {
30
+ type: PacketType.pingres,
31
+ },
32
+ );
33
+ });
34
+
35
+ test("decode invalid Pingres", () => {
36
+ assert.throws(
37
+ () =>
38
+ decode(
39
+ Uint8Array.from([
40
+ // fixedHeader
41
+ 208, // packetType + flags
42
+ 2, // remainingLength
43
+ 0,
44
+ 0,
45
+ ]),
46
+ ),
47
+ Error,
48
+ "too long",
49
+ );
50
+ });
@@ -0,0 +1,21 @@
1
+ import { PacketType } from "./PacketType.ts";
2
+ import { isEmptyBuf } from "./decoder.ts";
3
+ import type { TPacketType } from "./types.ts";
4
+
5
+ export type PingresPacket = {
6
+ type: TPacketType;
7
+ };
8
+
9
+ export default {
10
+ encode(_packet: PingresPacket) {
11
+ const flags = 0;
12
+ return { flags, bytes: [] };
13
+ },
14
+
15
+ decode(buffer: Uint8Array): PingresPacket {
16
+ isEmptyBuf(buffer);
17
+ return {
18
+ type: PacketType.pingres,
19
+ };
20
+ },
21
+ };
@@ -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.puback,
11
+ id: 1337,
12
+ }),
13
+ Uint8Array.from([
14
+ // fixedHeader
15
+ 0x40, // 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
+ 0x40, // packetType + flags
30
+ 2, // remainingLength
31
+ // variableHeader
32
+ 5, // id MSB
33
+ 57, // id LSB
34
+ ]),
35
+ ),
36
+ {
37
+ type: PacketType.puback,
38
+ id: 1337,
39
+ },
40
+ );
41
+ });
42
+
43
+ test("decodeShortPubackPackets", () => {
44
+ assert.throws(
45
+ () => decode(Uint8Array.from([0x40])),
46
+ Error,
47
+ "decoding failed",
48
+ );
49
+ assert.throws(() => decode(Uint8Array.from([0x40, 2])), Error, "too short");
50
+ assert.throws(
51
+ () => decode(Uint8Array.from([0x40, 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 PubackPacket = {
7
+ type: TPacketType;
8
+ id: PacketId;
9
+ };
10
+
11
+ export default {
12
+ encode(packet: PubackPacket) {
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): PubackPacket {
20
+ const decoder = new Decoder(buffer);
21
+ const id = decoder.getInt16();
22
+ decoder.done();
23
+ return {
24
+ type: PacketType.puback,
25
+ id,
26
+ };
27
+ },
28
+ };
@@ -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 Pubcomp", () => {
8
+ assert.deepStrictEqual(
9
+ encode({
10
+ type: PacketType.pubcomp,
11
+ id: 1337,
12
+ }),
13
+ Uint8Array.from([
14
+ // fixedHeader
15
+ 0x70, // packetType + flags
16
+ 2, // remainingLength
17
+ // variableHeader
18
+ 5, // id MSB
19
+ 57, // id LSB
20
+ ]),
21
+ );
22
+ });
23
+
24
+ test("decode Pubcomp ", () => {
25
+ assert.deepStrictEqual(
26
+ decode(
27
+ Uint8Array.from([
28
+ // fixedHeader
29
+ 0x70, // packetType + flags
30
+ 2, // remainingLength
31
+ // variableHeader
32
+ 5, // id MSB
33
+ 57, // id LSB
34
+ ]),
35
+ ),
36
+ {
37
+ type: PacketType.pubcomp,
38
+ id: 1337,
39
+ },
40
+ );
41
+ });
42
+
43
+ test("decodeShortPubcompPackets", () => {
44
+ assert.throws(
45
+ () => decode(Uint8Array.from([0x70])),
46
+ Error,
47
+ "decoding failed",
48
+ );
49
+ assert.throws(() => decode(Uint8Array.from([0x70, 2])), Error, "too short");
50
+ assert.throws(
51
+ () => decode(Uint8Array.from([0x70, 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 PubcompPacket = {
7
+ type: TPacketType;
8
+ id: PacketId;
9
+ };
10
+
11
+ export default {
12
+ encode(packet: PubcompPacket) {
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): PubcompPacket {
20
+ const decoder = new Decoder(buffer);
21
+ const id = decoder.getInt16();
22
+ decoder.done();
23
+ return {
24
+ type: PacketType.pubcomp,
25
+ id,
26
+ };
27
+ },
28
+ };
@@ -0,0 +1,198 @@
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
+ // const utf8Decoder = new TextDecoder();
8
+ const utf8Encoder = new TextEncoder();
9
+ const payload = utf8Encoder.encode("payload");
10
+
11
+ test("encode Publish", () => {
12
+ assert.deepStrictEqual(
13
+ encode({
14
+ type: PacketType.publish,
15
+ topic: "a/b",
16
+ payload,
17
+ }),
18
+ Uint8Array.from([
19
+ // fixedHeader
20
+ 48, // packetType + flags
21
+ 12, // remainingLength
22
+ // variableHeader
23
+ 0, // topicLength MSB
24
+ 3, // topicLength LSB
25
+ 97, // 'a'
26
+ 47, // '/'
27
+ 98, // 'b'
28
+ // payload
29
+ 112, // 'p'
30
+ 97, // 'a'
31
+ 121, // 'y'
32
+ 108, // 'l'
33
+ 111, // 'o'
34
+ 97, // 'a'
35
+ 100, // 'd'
36
+ ]),
37
+ );
38
+ });
39
+
40
+ test("decode Publish", () => {
41
+ assert.deepStrictEqual(
42
+ decode(
43
+ Uint8Array.from([
44
+ // fixedHeader
45
+ 48, // packetType + flags
46
+ 12, // remainingLength
47
+ // variableHeader
48
+ 0, // topicLength MSB
49
+ 3, // topicLength LSB
50
+ 97, // 'a'
51
+ 47, // '/'
52
+ 98, // 'b'
53
+ // payload
54
+ 112, // 'p'
55
+ 97, // 'a'
56
+ 121, // 'y'
57
+ 108, // 'l'
58
+ 111, // 'o'
59
+ 97, // 'a'
60
+ 100, // 'd'
61
+ ]),
62
+ ),
63
+ {
64
+ type: PacketType.publish,
65
+ dup: false,
66
+ qos: 0,
67
+ retain: false,
68
+ id: 0,
69
+ topic: "a/b",
70
+ payload: Uint8Array.from([
71
+ 112, // 'p'
72
+ 97, // 'a'
73
+ 121, // 'y'
74
+ 108, // 'l'
75
+ 111, // 'o'
76
+ 97, // 'a'
77
+ 100, // 'd'
78
+ ]),
79
+ },
80
+ );
81
+ });
82
+
83
+ test("decode Publish with extra bytes", () => {
84
+ assert.deepStrictEqual(
85
+ decode(
86
+ Uint8Array.from([
87
+ // fixedHeader
88
+ 48, // packetType + flags
89
+ 12, // remainingLength
90
+ // variableHeader
91
+ 0, // topicLength MSB
92
+ 3, // topicLength LSB
93
+ 97, // 'a'
94
+ 47, // '/'
95
+ 98, // 'b'
96
+ // payload
97
+ 112, // 'p'
98
+ 97, // 'a'
99
+ 121, // 'y'
100
+ 108, // 'l'
101
+ 111, // 'o'
102
+ 97, // 'a'
103
+ 100, // 'd'
104
+ 101, // 'e'
105
+ 116, // 't'
106
+ 99, // 'c'
107
+ ]),
108
+ ),
109
+ {
110
+ type: PacketType.publish,
111
+ dup: false,
112
+ qos: 0,
113
+ retain: false,
114
+ id: 0,
115
+ topic: "a/b",
116
+ payload: Uint8Array.from([
117
+ 112, // 'p'
118
+ 97, // 'a'
119
+ 121, // 'y'
120
+ 108, // 'l'
121
+ 111, // 'o'
122
+ 97, // 'a'
123
+ 100, // 'd'
124
+ ]),
125
+ },
126
+ );
127
+ });
128
+
129
+ test("decode Publish no payload", () => {
130
+ assert.deepStrictEqual(
131
+ decode(
132
+ Uint8Array.from([
133
+ // fixedHeader
134
+ 48, // packetType + flags
135
+ 5, // remainingLength
136
+ // variableHeader
137
+ 0, // topicLength MSB
138
+ 3, // topicLength LSB
139
+ 97, // 'a'
140
+ 47, // '/'
141
+ 98, // 'b'
142
+ // payload
143
+ ]),
144
+ ),
145
+ {
146
+ type: PacketType.publish,
147
+ dup: false,
148
+ qos: 0,
149
+ retain: false,
150
+ id: 0,
151
+ topic: "a/b",
152
+ payload: Uint8Array.from([]),
153
+ },
154
+ );
155
+ });
156
+
157
+ test("Invalid qos", () => {
158
+ assert.throws(
159
+ () =>
160
+ decode(
161
+ Uint8Array.from([
162
+ // fixedHeader
163
+ 0x36, // packetType + flags
164
+ 5, // remainingLength
165
+ // variableHeader
166
+ 0, // topicLength MSB
167
+ 3, // topicLength LSB
168
+ 97, // 'a'
169
+ 47, // '/'
170
+ 98, // 'b'
171
+ // payload
172
+ ]),
173
+ ),
174
+ Error,
175
+ "Invalid qos",
176
+ );
177
+ });
178
+ test("Invalid qos for duplicate", () => {
179
+ assert.throws(
180
+ () =>
181
+ decode(
182
+ Uint8Array.from([
183
+ // fixedHeader
184
+ 0x38, // packetType + flags
185
+ 5, // remainingLength
186
+ // variableHeader
187
+ 0, // topicLength MSB
188
+ 3, // topicLength LSB
189
+ 97, // 'a'
190
+ 47, // '/'
191
+ 98, // 'b'
192
+ // payload
193
+ ]),
194
+ ),
195
+ Error,
196
+ "Invalid qos for possible duplicate",
197
+ );
198
+ });
@@ -0,0 +1,73 @@
1
+ import type { Payload, QoS, Topic, TPacketType } from "./types.ts";
2
+ import { PacketType } from "./PacketType.ts";
3
+ import { BitMask } from "./BitMask.ts";
4
+ import { Encoder, EncoderError } from "./encoder.ts";
5
+ import { booleanFlag, Decoder, DecoderError } from "./decoder.ts";
6
+
7
+ export type PublishPacket = {
8
+ type: TPacketType;
9
+ topic: Topic;
10
+ payload: Payload;
11
+ dup?: boolean;
12
+ retain?: boolean;
13
+ qos?: QoS;
14
+ id?: number;
15
+ };
16
+
17
+ export default {
18
+ encode(packet: PublishPacket) {
19
+ const qos = packet.qos || 0;
20
+
21
+ const flags = (packet.dup ? BitMask.bit3 : 0) +
22
+ (qos & 2 ? BitMask.bit2 : 0) +
23
+ (qos & 1 ? BitMask.bit1 : 0) +
24
+ (packet.retain ? BitMask.bit0 : 0);
25
+
26
+ const encoder = new Encoder();
27
+ encoder.setTopic(packet.topic);
28
+
29
+ if (qos === 1 || qos === 2) {
30
+ if (typeof packet.id !== "number" || packet.id < 1) {
31
+ throw new EncoderError("when qos is 1 or 2, packet must have id");
32
+ }
33
+ encoder.setInt16(packet.id);
34
+ }
35
+ encoder.setRemainder(packet.payload);
36
+ return { flags, bytes: encoder.done() };
37
+ },
38
+
39
+ decode(buffer: Uint8Array, flags: number): PublishPacket {
40
+ const dup = booleanFlag(flags, BitMask.bit3);
41
+ const qos = (flags & 6) >> 1;
42
+ const retain = booleanFlag(flags, BitMask.bit0);
43
+
44
+ if (qos !== 0 && qos !== 1 && qos !== 2) {
45
+ throw new DecoderError("Invalid qos");
46
+ }
47
+
48
+ if (dup && qos === 0) {
49
+ throw new DecoderError("Invalid qos for possible duplicate");
50
+ }
51
+
52
+ const decoder = new Decoder(buffer);
53
+ const topic = decoder.getTopic();
54
+
55
+ let id = 0;
56
+ if (qos > 0) {
57
+ id = decoder.getInt16();
58
+ }
59
+ const payload = decoder.getRemainder();
60
+
61
+ // no decoder.done() required because of getRemainder
62
+
63
+ return {
64
+ type: PacketType.publish,
65
+ topic,
66
+ payload,
67
+ dup,
68
+ retain,
69
+ qos,
70
+ id,
71
+ };
72
+ },
73
+ };
@@ -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 Pubrec", () => {
8
+ assert.deepStrictEqual(
9
+ encode({
10
+ type: PacketType.pubrec,
11
+ id: 1337,
12
+ }),
13
+ Uint8Array.from([
14
+ // fixedHeader
15
+ 0x50, // packetType + flags
16
+ 2, // remainingLength
17
+ // variableHeader
18
+ 5, // id MSB
19
+ 57, // id LSB
20
+ ]),
21
+ );
22
+ });
23
+
24
+ test("decode Pubrec ", () => {
25
+ assert.deepStrictEqual(
26
+ decode(
27
+ Uint8Array.from([
28
+ // fixedHeader
29
+ 0x50, // packetType + flags
30
+ 2, // remainingLength
31
+ // variableHeader
32
+ 5, // id MSB
33
+ 57, // id LSB
34
+ ]),
35
+ ),
36
+ {
37
+ type: PacketType.pubrec,
38
+ id: 1337,
39
+ },
40
+ );
41
+ });
42
+
43
+ test("decodeShortPubrecPackets", () => {
44
+ assert.throws(
45
+ () => decode(Uint8Array.from([0x50])),
46
+ Error,
47
+ "decoding failed",
48
+ );
49
+ assert.throws(() => decode(Uint8Array.from([0x50, 2])), Error, "too short");
50
+ assert.throws(
51
+ () => decode(Uint8Array.from([0x50, 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 PubrecPacket = {
7
+ type: TPacketType;
8
+ id: PacketId;
9
+ };
10
+
11
+ export default {
12
+ encode(packet: PubrecPacket) {
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): PubrecPacket {
20
+ const decoder = new Decoder(buffer);
21
+ const id = decoder.getInt16();
22
+ decoder.done();
23
+ return {
24
+ type: PacketType.pubrec,
25
+ id,
26
+ };
27
+ },
28
+ };