kafka-ts 0.0.3-beta → 0.0.4

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 (176) hide show
  1. package/README.md +72 -8
  2. package/dist/api/api-versions.d.ts +9 -0
  3. package/{src/api/api-versions.ts → dist/api/api-versions.js} +8 -5
  4. package/dist/api/create-topics.d.ts +38 -0
  5. package/dist/api/create-topics.js +53 -0
  6. package/dist/api/delete-topics.d.ts +18 -0
  7. package/dist/api/delete-topics.js +33 -0
  8. package/dist/api/fetch.d.ts +84 -0
  9. package/dist/api/fetch.js +142 -0
  10. package/dist/api/find-coordinator.d.ts +21 -0
  11. package/{src/api/find-coordinator.ts → dist/api/find-coordinator.js} +14 -14
  12. package/dist/api/heartbeat.d.ts +11 -0
  13. package/dist/api/heartbeat.js +27 -0
  14. package/dist/api/index.d.ts +576 -0
  15. package/{src/api/index.ts → dist/api/index.js} +42 -41
  16. package/dist/api/init-producer-id.d.ts +13 -0
  17. package/dist/api/init-producer-id.js +29 -0
  18. package/dist/api/join-group.d.ts +34 -0
  19. package/dist/api/join-group.js +51 -0
  20. package/dist/api/leave-group.d.ts +19 -0
  21. package/dist/api/leave-group.js +39 -0
  22. package/dist/api/list-offsets.d.ts +29 -0
  23. package/dist/api/list-offsets.js +48 -0
  24. package/dist/api/metadata.d.ts +40 -0
  25. package/{src/api/metadata.ts → dist/api/metadata.js} +18 -26
  26. package/dist/api/offset-commit.d.ts +28 -0
  27. package/dist/api/offset-commit.js +48 -0
  28. package/dist/api/offset-fetch.d.ts +31 -0
  29. package/dist/api/offset-fetch.js +55 -0
  30. package/dist/api/produce.d.ts +54 -0
  31. package/{src/api/produce.ts → dist/api/produce.js} +55 -102
  32. package/dist/api/sasl-authenticate.d.ts +11 -0
  33. package/dist/api/sasl-authenticate.js +23 -0
  34. package/dist/api/sasl-handshake.d.ts +6 -0
  35. package/dist/api/sasl-handshake.js +19 -0
  36. package/dist/api/sync-group.d.ts +24 -0
  37. package/dist/api/sync-group.js +36 -0
  38. package/dist/auth/index.d.ts +2 -0
  39. package/dist/auth/index.js +8 -0
  40. package/dist/auth/plain.d.ts +5 -0
  41. package/dist/auth/plain.js +12 -0
  42. package/dist/auth/scram.d.ts +9 -0
  43. package/dist/auth/scram.js +40 -0
  44. package/dist/broker.d.ts +30 -0
  45. package/dist/broker.js +55 -0
  46. package/dist/client.d.ts +22 -0
  47. package/dist/client.js +36 -0
  48. package/dist/cluster.d.ts +27 -0
  49. package/dist/cluster.js +70 -0
  50. package/dist/cluster.test.d.ts +1 -0
  51. package/{src/cluster.test.ts → dist/cluster.test.js} +87 -113
  52. package/dist/codecs/gzip.d.ts +2 -0
  53. package/dist/codecs/gzip.js +8 -0
  54. package/dist/codecs/index.d.ts +2 -0
  55. package/dist/codecs/index.js +17 -0
  56. package/dist/codecs/none.d.ts +2 -0
  57. package/dist/codecs/none.js +7 -0
  58. package/dist/codecs/types.d.ts +5 -0
  59. package/dist/codecs/types.js +2 -0
  60. package/dist/connection.d.ts +26 -0
  61. package/dist/connection.js +175 -0
  62. package/dist/consumer/consumer-group.d.ts +41 -0
  63. package/dist/consumer/consumer-group.js +215 -0
  64. package/dist/consumer/consumer-metadata.d.ts +7 -0
  65. package/dist/consumer/consumer-metadata.js +14 -0
  66. package/dist/consumer/consumer.d.ts +44 -0
  67. package/dist/consumer/consumer.js +225 -0
  68. package/dist/consumer/fetch-manager.d.ts +33 -0
  69. package/dist/consumer/fetch-manager.js +140 -0
  70. package/dist/consumer/fetcher.d.ts +25 -0
  71. package/dist/consumer/fetcher.js +64 -0
  72. package/dist/consumer/offset-manager.d.ts +22 -0
  73. package/dist/consumer/offset-manager.js +66 -0
  74. package/dist/consumer/processor.d.ts +19 -0
  75. package/dist/consumer/processor.js +59 -0
  76. package/dist/distributors/assignments-to-replicas.d.ts +16 -0
  77. package/{src/distributors/assignments-to-replicas.ts → dist/distributors/assignments-to-replicas.js} +15 -41
  78. package/dist/distributors/assignments-to-replicas.test.d.ts +1 -0
  79. package/dist/distributors/assignments-to-replicas.test.js +40 -0
  80. package/dist/distributors/messages-to-topic-partition-leaders.d.ts +17 -0
  81. package/dist/distributors/messages-to-topic-partition-leaders.js +15 -0
  82. package/dist/distributors/messages-to-topic-partition-leaders.test.d.ts +1 -0
  83. package/dist/distributors/messages-to-topic-partition-leaders.test.js +30 -0
  84. package/dist/distributors/partitioner.d.ts +7 -0
  85. package/dist/distributors/partitioner.js +23 -0
  86. package/dist/index.d.ts +9 -0
  87. package/dist/index.js +26 -0
  88. package/dist/metadata.d.ts +24 -0
  89. package/dist/metadata.js +106 -0
  90. package/dist/producer/producer.d.ts +24 -0
  91. package/dist/producer/producer.js +131 -0
  92. package/{src/types.ts → dist/types.d.ts} +4 -4
  93. package/dist/types.js +2 -0
  94. package/{src/utils/api.ts → dist/utils/api.d.ts} +2 -4
  95. package/dist/utils/api.js +5 -0
  96. package/dist/utils/crypto.d.ts +8 -0
  97. package/dist/utils/crypto.js +18 -0
  98. package/dist/utils/decoder.d.ts +30 -0
  99. package/{src/utils/decoder.ts → dist/utils/decoder.js} +41 -57
  100. package/dist/utils/delay.d.ts +1 -0
  101. package/dist/utils/delay.js +5 -0
  102. package/dist/utils/encoder.d.ts +28 -0
  103. package/{src/utils/encoder.ts → dist/utils/encoder.js} +50 -66
  104. package/dist/utils/error.d.ts +11 -0
  105. package/dist/utils/error.js +27 -0
  106. package/dist/utils/logger.d.ts +9 -0
  107. package/dist/utils/logger.js +32 -0
  108. package/dist/utils/memo.d.ts +1 -0
  109. package/{src/utils/memo.ts → dist/utils/memo.js} +7 -3
  110. package/dist/utils/murmur2.d.ts +3 -0
  111. package/dist/utils/murmur2.js +40 -0
  112. package/dist/utils/retrier.d.ts +10 -0
  113. package/dist/utils/retrier.js +22 -0
  114. package/dist/utils/tracer.d.ts +5 -0
  115. package/dist/utils/tracer.js +39 -0
  116. package/package.json +11 -2
  117. package/.github/workflows/release.yml +0 -17
  118. package/.prettierrc +0 -8
  119. package/certs/ca.crt +0 -29
  120. package/certs/ca.key +0 -52
  121. package/certs/ca.srl +0 -1
  122. package/certs/kafka.crt +0 -29
  123. package/certs/kafka.csr +0 -26
  124. package/certs/kafka.key +0 -52
  125. package/certs/kafka.keystore.jks +0 -0
  126. package/certs/kafka.truststore.jks +0 -0
  127. package/docker-compose.yml +0 -104
  128. package/examples/package-lock.json +0 -31
  129. package/examples/package.json +0 -14
  130. package/examples/src/client.ts +0 -9
  131. package/examples/src/consumer.ts +0 -18
  132. package/examples/src/create-topic.ts +0 -44
  133. package/examples/src/producer.ts +0 -24
  134. package/examples/src/replicator.ts +0 -25
  135. package/examples/src/utils/delay.ts +0 -1
  136. package/examples/src/utils/json.ts +0 -1
  137. package/examples/tsconfig.json +0 -7
  138. package/log4j.properties +0 -95
  139. package/scripts/generate-certs.sh +0 -24
  140. package/src/__snapshots__/request-handler.test.ts.snap +0 -978
  141. package/src/api/create-topics.ts +0 -78
  142. package/src/api/delete-topics.ts +0 -42
  143. package/src/api/fetch.ts +0 -143
  144. package/src/api/heartbeat.ts +0 -33
  145. package/src/api/init-producer-id.ts +0 -35
  146. package/src/api/join-group.ts +0 -67
  147. package/src/api/leave-group.ts +0 -48
  148. package/src/api/list-offsets.ts +0 -65
  149. package/src/api/offset-commit.ts +0 -67
  150. package/src/api/offset-fetch.ts +0 -74
  151. package/src/api/sasl-authenticate.ts +0 -21
  152. package/src/api/sasl-handshake.ts +0 -16
  153. package/src/api/sync-group.ts +0 -54
  154. package/src/broker.ts +0 -74
  155. package/src/client.ts +0 -47
  156. package/src/cluster.ts +0 -87
  157. package/src/connection.ts +0 -143
  158. package/src/consumer/consumer-group.ts +0 -209
  159. package/src/consumer/consumer-metadata.ts +0 -14
  160. package/src/consumer/consumer.ts +0 -231
  161. package/src/consumer/fetch-manager.ts +0 -179
  162. package/src/consumer/fetcher.ts +0 -57
  163. package/src/consumer/offset-manager.ts +0 -93
  164. package/src/consumer/processor.ts +0 -47
  165. package/src/distributors/assignments-to-replicas.test.ts +0 -43
  166. package/src/distributors/messages-to-topic-partition-leaders.test.ts +0 -32
  167. package/src/distributors/messages-to-topic-partition-leaders.ts +0 -19
  168. package/src/index.ts +0 -4
  169. package/src/metadata.ts +0 -122
  170. package/src/producer/producer.ts +0 -132
  171. package/src/utils/debug.ts +0 -9
  172. package/src/utils/delay.ts +0 -1
  173. package/src/utils/error.ts +0 -21
  174. package/src/utils/retrier.ts +0 -39
  175. package/src/utils/tracer.ts +0 -31
  176. package/tsconfig.json +0 -17
@@ -1,58 +1,51 @@
1
- import { randomBytes } from 'crypto';
2
- import { readFileSync } from 'fs';
3
- import { afterAll, beforeAll, describe, expect, it } from 'vitest';
4
- import { API } from './api';
5
- import { KEY_TYPE } from './api/find-coordinator';
6
- import { createKafkaClient } from './client';
7
- import { Cluster } from './cluster';
8
- import { KafkaTSApiError } from './utils/error';
9
-
10
- export const kafka = createKafkaClient({
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const crypto_1 = require("crypto");
4
+ const fs_1 = require("fs");
5
+ const vitest_1 = require("vitest");
6
+ const api_1 = require("./api");
7
+ const find_coordinator_1 = require("./api/find-coordinator");
8
+ const auth_1 = require("./auth");
9
+ const client_1 = require("./client");
10
+ const kafka = (0, client_1.createKafkaClient)({
11
11
  clientId: 'kafka-ts',
12
12
  bootstrapServers: [{ host: 'localhost', port: 9092 }],
13
- sasl: { mechanism: 'PLAIN', username: 'admin', password: 'admin' },
14
- ssl: { ca: readFileSync('./certs/ca.crt').toString() },
13
+ sasl: (0, auth_1.saslPlain)({ username: 'admin', password: 'admin' }),
14
+ ssl: { ca: (0, fs_1.readFileSync)('./certs/ca.crt').toString() },
15
15
  });
16
-
17
- describe.sequential('Request handler', () => {
18
- const groupId = randomBytes(16).toString('hex');
19
-
20
- let cluster: Cluster;
21
-
22
- beforeAll(async () => {
23
- cluster = await kafka.createCluster().connect();
24
-
25
- const metadataResult = await cluster.sendRequest(API.METADATA, {
16
+ vitest_1.describe.sequential('Low-level API', () => {
17
+ const groupId = (0, crypto_1.randomBytes)(16).toString('hex');
18
+ let cluster;
19
+ (0, vitest_1.beforeAll)(async () => {
20
+ cluster = await kafka.createCluster();
21
+ await cluster.connect();
22
+ const metadataResult = await cluster.sendRequest(api_1.API.METADATA, {
26
23
  topics: null,
27
24
  allowTopicAutoCreation: false,
28
25
  includeTopicAuthorizedOperations: false,
29
26
  });
30
27
  if (metadataResult.topics.some((topic) => topic.name === 'kafka-ts-test-topic')) {
31
- await cluster.sendRequest(API.DELETE_TOPICS, {
28
+ await cluster.sendRequest(api_1.API.DELETE_TOPICS, {
32
29
  topics: [{ name: 'kafka-ts-test-topic', topicId: null }],
33
30
  timeoutMs: 10000,
34
31
  });
35
32
  }
36
33
  });
37
-
38
- afterAll(async () => {
34
+ (0, vitest_1.afterAll)(async () => {
39
35
  await cluster.disconnect();
40
36
  });
41
-
42
- it('should request api versions', async () => {
43
- const result = await cluster.sendRequest(API.API_VERSIONS, {});
44
- expect(result).toMatchSnapshot();
37
+ (0, vitest_1.it)('should request api versions', async () => {
38
+ const result = await cluster.sendRequest(api_1.API.API_VERSIONS, {});
39
+ (0, vitest_1.expect)(result).toMatchSnapshot();
45
40
  });
46
-
47
- let topicId: string = 'd6718d178e1b47c886441ad2d19faea5';
48
-
49
- it('should create topics', async () => {
50
- const result = await cluster.sendRequest(API.CREATE_TOPICS, {
41
+ let topicId = 'd6718d178e1b47c886441ad2d19faea5';
42
+ (0, vitest_1.it)('should create topics', async () => {
43
+ const result = await cluster.sendRequest(api_1.API.CREATE_TOPICS, {
51
44
  topics: [
52
45
  {
53
46
  name: 'kafka-ts-test-topic',
54
- numPartitions: 1,
55
- replicationFactor: 1,
47
+ numPartitions: 10,
48
+ replicationFactor: 3,
56
49
  assignments: [],
57
50
  configs: [],
58
51
  },
@@ -64,13 +57,11 @@ describe.sequential('Request handler', () => {
64
57
  result.topics.forEach((topic) => {
65
58
  topic.topicId = 'Any<UUID>';
66
59
  });
67
- expect(result).toMatchSnapshot();
68
-
60
+ (0, vitest_1.expect)(result).toMatchSnapshot();
69
61
  await new Promise((resolve) => setTimeout(resolve, 1000));
70
62
  });
71
-
72
- it('should request metadata for all topics', async () => {
73
- const result = await cluster.sendRequest(API.METADATA, {
63
+ (0, vitest_1.it)('should request metadata for all topics', async () => {
64
+ const result = await cluster.sendRequest(api_1.API.METADATA, {
74
65
  topics: null,
75
66
  allowTopicAutoCreation: false,
76
67
  includeTopicAuthorizedOperations: false,
@@ -85,17 +76,17 @@ describe.sequential('Request handler', () => {
85
76
  partition.replicaNodes = [0];
86
77
  });
87
78
  });
88
- expect(result).toMatchSnapshot();
79
+ (0, vitest_1.expect)(result).toMatchSnapshot();
89
80
  });
90
-
81
+ let partitionIndex = 0;
91
82
  let leaderId = 0;
92
-
93
- it('should request metadata for a topic', async () => {
94
- const result = await cluster.sendRequest(API.METADATA, {
83
+ (0, vitest_1.it)('should request metadata for a topic', async () => {
84
+ const result = await cluster.sendRequest(api_1.API.METADATA, {
95
85
  topics: [{ id: topicId, name: 'kafka-ts-test-topic' }],
96
86
  allowTopicAutoCreation: false,
97
87
  includeTopicAuthorizedOperations: false,
98
88
  });
89
+ partitionIndex = result.topics[0].partitions[0].partitionIndex;
99
90
  leaderId = result.topics[0].partitions[0].leaderId;
100
91
  result.controllerId = 0;
101
92
  result.topics.forEach((topic) => {
@@ -106,25 +97,22 @@ describe.sequential('Request handler', () => {
106
97
  partition.replicaNodes = [0];
107
98
  });
108
99
  });
109
- expect(result).toMatchSnapshot();
100
+ (0, vitest_1.expect)(result).toMatchSnapshot();
110
101
  });
111
-
112
102
  let producerId = 9n;
113
-
114
- it('should init producer id', async () => {
115
- const result = await cluster.sendRequest(API.INIT_PRODUCER_ID, {
103
+ (0, vitest_1.it)('should init producer id', async () => {
104
+ const result = await cluster.sendRequest(api_1.API.INIT_PRODUCER_ID, {
116
105
  transactionalId: null,
117
106
  transactionTimeoutMs: 0,
118
107
  producerId,
119
108
  producerEpoch: 0,
120
109
  });
121
110
  result.producerId = 0n;
122
- expect(result).toMatchSnapshot();
111
+ (0, vitest_1.expect)(result).toMatchSnapshot();
123
112
  });
124
-
125
- it('should produce messages', async () => {
113
+ (0, vitest_1.it)('should produce messages', async () => {
126
114
  const now = Date.now();
127
- const result = await cluster.sendRequestToNode(leaderId)(API.PRODUCE, {
115
+ const result = await cluster.sendRequestToNode(leaderId)(api_1.API.PRODUCE, {
128
116
  transactionalId: null,
129
117
  timeoutMs: 10000,
130
118
  acks: 1,
@@ -133,7 +121,7 @@ describe.sequential('Request handler', () => {
133
121
  name: 'kafka-ts-test-topic',
134
122
  partitionData: [
135
123
  {
136
- index: 0,
124
+ index: partitionIndex,
137
125
  baseOffset: 0n,
138
126
  partitionLeaderEpoch: 0,
139
127
  attributes: 0,
@@ -148,12 +136,12 @@ describe.sequential('Request handler', () => {
148
136
  attributes: 0,
149
137
  offsetDelta: 0,
150
138
  timestampDelta: 0n,
151
- key: 'key',
152
- value: 'value',
139
+ key: Buffer.from('key'),
140
+ value: Buffer.from('value'),
153
141
  headers: [
154
142
  {
155
- key: 'header-key',
156
- value: 'header-value',
143
+ key: Buffer.from('header-key'),
144
+ value: Buffer.from('header-value'),
157
145
  },
158
146
  ],
159
147
  },
@@ -163,11 +151,10 @@ describe.sequential('Request handler', () => {
163
151
  },
164
152
  ],
165
153
  });
166
- expect(result).toMatchSnapshot();
154
+ (0, vitest_1.expect)(result).toMatchSnapshot();
167
155
  });
168
-
169
- it('should fetch messages', async () => {
170
- const result = await cluster.sendRequestToNode(leaderId)(API.FETCH, {
156
+ (0, vitest_1.it)('should fetch messages', async () => {
157
+ const result = await cluster.sendRequestToNode(leaderId)(api_1.API.FETCH, {
171
158
  maxWaitMs: 100,
172
159
  minBytes: 1,
173
160
  maxBytes: 10485760,
@@ -179,7 +166,7 @@ describe.sequential('Request handler', () => {
179
166
  topicId,
180
167
  partitions: [
181
168
  {
182
- partition: 0,
169
+ partition: partitionIndex,
183
170
  currentLeaderEpoch: -1,
184
171
  fetchOffset: 0n,
185
172
  lastFetchedEpoch: 0,
@@ -196,23 +183,20 @@ describe.sequential('Request handler', () => {
196
183
  response.topicId = 'Any<UUID>';
197
184
  response.partitions.forEach((partition) => {
198
185
  partition.records.forEach((record) => {
199
- expect(record.baseTimestamp).toBeGreaterThan(1721926744730n);
200
- expect(record.maxTimestamp).toBeGreaterThan(1721926744730n);
201
- expect(record.crc).toBeGreaterThan(0);
202
-
186
+ (0, vitest_1.expect)(record.baseTimestamp).toBeGreaterThan(1721926744730n);
187
+ (0, vitest_1.expect)(record.maxTimestamp).toBeGreaterThan(1721926744730n);
188
+ (0, vitest_1.expect)(record.crc).toBeGreaterThan(0);
203
189
  record.baseTimestamp = 0n;
204
190
  record.maxTimestamp = 0n;
205
191
  record.crc = 0;
206
192
  });
207
193
  });
208
194
  });
209
- expect(result).toMatchSnapshot();
195
+ (0, vitest_1.expect)(result).toMatchSnapshot();
210
196
  });
211
-
212
197
  let coordinatorId = -1;
213
-
214
- it('should find coordinator', async () => {
215
- const result = await cluster.sendRequest(API.FIND_COORDINATOR, { keyType: KEY_TYPE.GROUP, keys: [groupId] });
198
+ (0, vitest_1.it)('should find coordinator', async () => {
199
+ const result = await cluster.sendRequest(api_1.API.FIND_COORDINATOR, { keyType: find_coordinator_1.KEY_TYPE.GROUP, keys: [groupId] });
216
200
  result.coordinators.forEach((coordinator) => {
217
201
  coordinator.key = 'Any<String>';
218
202
  });
@@ -221,14 +205,12 @@ describe.sequential('Request handler', () => {
221
205
  coordinator.nodeId = 1;
222
206
  coordinator.port = 9093;
223
207
  });
224
- expect(result).toMatchSnapshot();
208
+ (0, vitest_1.expect)(result).toMatchSnapshot();
225
209
  });
226
-
227
210
  let memberId = '';
228
-
229
- it('should fail join group request with new memberId', async () => {
211
+ (0, vitest_1.it)('should fail join group request with new memberId', async () => {
230
212
  try {
231
- const result = await cluster.sendRequestToNode(coordinatorId)(API.JOIN_GROUP, {
213
+ const result = await cluster.sendRequestToNode(coordinatorId)(api_1.API.JOIN_GROUP, {
232
214
  groupId,
233
215
  sessionTimeoutMs: 30000,
234
216
  rebalanceTimeoutMs: 60000,
@@ -243,17 +225,17 @@ describe.sequential('Request handler', () => {
243
225
  ],
244
226
  reason: null,
245
227
  });
246
- expect(false, 'Should throw an error').toBe(true);
247
- } catch (error) {
248
- const { response } = error as KafkaTSApiError;
228
+ (0, vitest_1.expect)(false, 'Should throw an error').toBe(true);
229
+ }
230
+ catch (error) {
231
+ const { response } = error;
249
232
  memberId = response.memberId;
250
233
  response.memberId = 'Any<UUID>';
251
- expect(response).toMatchSnapshot();
234
+ (0, vitest_1.expect)(response).toMatchSnapshot();
252
235
  }
253
236
  });
254
-
255
- it('should join group', async () => {
256
- const result = await cluster.sendRequestToNode(coordinatorId)(API.JOIN_GROUP, {
237
+ (0, vitest_1.it)('should join group', async () => {
238
+ const result = await cluster.sendRequestToNode(coordinatorId)(api_1.API.JOIN_GROUP, {
257
239
  groupId,
258
240
  sessionTimeoutMs: 30000,
259
241
  rebalanceTimeoutMs: 60000,
@@ -273,11 +255,10 @@ describe.sequential('Request handler', () => {
273
255
  result.members.forEach((member) => {
274
256
  member.memberId = 'Any<UUID>';
275
257
  });
276
- expect(result).toMatchSnapshot();
258
+ (0, vitest_1.expect)(result).toMatchSnapshot();
277
259
  });
278
-
279
- it('should sync group', async () => {
280
- const result = await cluster.sendRequestToNode(coordinatorId)(API.SYNC_GROUP, {
260
+ (0, vitest_1.it)('should sync group', async () => {
261
+ const result = await cluster.sendRequestToNode(coordinatorId)(api_1.API.SYNC_GROUP, {
281
262
  groupId,
282
263
  generationId: 1,
283
264
  memberId,
@@ -291,11 +272,10 @@ describe.sequential('Request handler', () => {
291
272
  },
292
273
  ],
293
274
  });
294
- expect(result).toMatchSnapshot();
275
+ (0, vitest_1.expect)(result).toMatchSnapshot();
295
276
  });
296
-
297
- it('should commit offsets', async () => {
298
- const result = await cluster.sendRequestToNode(coordinatorId)(API.OFFSET_COMMIT, {
277
+ (0, vitest_1.it)('should commit offsets', async () => {
278
+ const result = await cluster.sendRequestToNode(coordinatorId)(api_1.API.OFFSET_COMMIT, {
299
279
  groupId,
300
280
  generationIdOrMemberEpoch: 1,
301
281
  memberId,
@@ -309,16 +289,13 @@ describe.sequential('Request handler', () => {
309
289
  },
310
290
  ],
311
291
  });
312
- expect(result).toMatchSnapshot();
292
+ (0, vitest_1.expect)(result).toMatchSnapshot();
313
293
  });
314
-
315
- it('should fetch offsets', async () => {
316
- const result = await cluster.sendRequestToNode(coordinatorId)(API.OFFSET_FETCH, {
294
+ (0, vitest_1.it)('should fetch offsets', async () => {
295
+ const result = await cluster.sendRequestToNode(coordinatorId)(api_1.API.OFFSET_FETCH, {
317
296
  groups: [
318
297
  {
319
298
  groupId,
320
- memberId,
321
- memberEpoch: 0,
322
299
  topics: [
323
300
  {
324
301
  name: 'kafka-ts-test-topic',
@@ -332,38 +309,35 @@ describe.sequential('Request handler', () => {
332
309
  result.groups.forEach((group) => {
333
310
  group.groupId = 'Any<String>';
334
311
  });
335
- expect(result).toMatchSnapshot();
312
+ (0, vitest_1.expect)(result).toMatchSnapshot();
336
313
  });
337
-
338
- it('should heartbeat', async () => {
339
- const result = await cluster.sendRequestToNode(coordinatorId)(API.HEARTBEAT, {
314
+ (0, vitest_1.it)('should heartbeat', async () => {
315
+ const result = await cluster.sendRequestToNode(coordinatorId)(api_1.API.HEARTBEAT, {
340
316
  groupId,
341
317
  generationId: 1,
342
318
  memberId,
343
319
  groupInstanceId: null,
344
320
  });
345
- expect(result).toMatchSnapshot();
321
+ (0, vitest_1.expect)(result).toMatchSnapshot();
346
322
  });
347
-
348
- it('should leave group', async () => {
349
- const result = await cluster.sendRequestToNode(coordinatorId)(API.LEAVE_GROUP, {
323
+ (0, vitest_1.it)('should leave group', async () => {
324
+ const result = await cluster.sendRequestToNode(coordinatorId)(api_1.API.LEAVE_GROUP, {
350
325
  groupId,
351
326
  members: [{ memberId, groupInstanceId: null, reason: null }],
352
327
  });
353
328
  result.members.forEach((member) => {
354
329
  member.memberId = 'Any<UUID>';
355
330
  });
356
- expect(result).toMatchSnapshot();
331
+ (0, vitest_1.expect)(result).toMatchSnapshot();
357
332
  });
358
-
359
- it('should delete topics', async () => {
360
- const result = await cluster.sendRequest(API.DELETE_TOPICS, {
333
+ (0, vitest_1.it)('should delete topics', async () => {
334
+ const result = await cluster.sendRequest(api_1.API.DELETE_TOPICS, {
361
335
  topics: [{ name: 'kafka-ts-test-topic', topicId: null }],
362
336
  timeoutMs: 10000,
363
337
  });
364
338
  result.responses.forEach((response) => {
365
339
  response.topicId = 'Any<UUID>';
366
340
  });
367
- expect(result).toMatchSnapshot();
341
+ (0, vitest_1.expect)(result).toMatchSnapshot();
368
342
  });
369
343
  });
@@ -0,0 +1,2 @@
1
+ import { Codec } from './types';
2
+ export declare const GZIP: Codec;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GZIP = void 0;
4
+ const zlib_1 = require("zlib");
5
+ exports.GZIP = {
6
+ compress: async (data) => new Promise((resolve, reject) => (0, zlib_1.gzip)(data, (err, result) => (err ? reject(err) : resolve(result)))),
7
+ decompress: async (data) => new Promise((resolve, reject) => (0, zlib_1.unzip)(data, (err, result) => (err ? reject(err) : resolve(result)))),
8
+ };
@@ -0,0 +1,2 @@
1
+ import { Codec } from './types';
2
+ export declare const findCodec: (type: number) => Codec;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findCodec = void 0;
4
+ const gzip_1 = require("./gzip");
5
+ const none_1 = require("./none");
6
+ const codecs = {
7
+ 0: none_1.NONE,
8
+ 1: gzip_1.GZIP,
9
+ };
10
+ const findCodec = (type) => {
11
+ const codec = codecs[type];
12
+ if (!codec) {
13
+ throw new Error(`Unsupported codec: ${type}`);
14
+ }
15
+ return codec;
16
+ };
17
+ exports.findCodec = findCodec;
@@ -0,0 +1,2 @@
1
+ import { Codec } from './types';
2
+ export declare const NONE: Codec;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NONE = void 0;
4
+ exports.NONE = {
5
+ compress: (data) => Promise.resolve(data),
6
+ decompress: (data) => Promise.resolve(data),
7
+ };
@@ -0,0 +1,5 @@
1
+ /// <reference types="node" />
2
+ export type Codec = {
3
+ compress: (data: Buffer) => Promise<Buffer>;
4
+ decompress: (data: Buffer) => Promise<Buffer>;
5
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,26 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ import { TcpSocketConnectOpts } from 'net';
4
+ import { TLSSocketOptions } from 'tls';
5
+ import { Api } from './utils/api';
6
+ type ConnectionOptions = {
7
+ clientId: string | null;
8
+ connection: TcpSocketConnectOpts;
9
+ ssl: TLSSocketOptions | null;
10
+ };
11
+ export declare class Connection {
12
+ private options;
13
+ private socket;
14
+ private queue;
15
+ private lastCorrelationId;
16
+ private chunks;
17
+ constructor(options: ConnectionOptions);
18
+ connect(): Promise<void>;
19
+ disconnect(): Promise<void>;
20
+ sendRequest<Request, Response>(api: Api<Request, Response>, body: Request): Promise<Response>;
21
+ private write;
22
+ private handleData;
23
+ private nextCorrelationId;
24
+ }
25
+ export type SendRequest = typeof Connection.prototype.sendRequest;
26
+ export {};
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
19
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
20
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
21
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
22
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
23
+ };
24
+ var __importStar = (this && this.__importStar) || function (mod) {
25
+ if (mod && mod.__esModule) return mod;
26
+ var result = {};
27
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
28
+ __setModuleDefault(result, mod);
29
+ return result;
30
+ };
31
+ var __metadata = (this && this.__metadata) || function (k, v) {
32
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
33
+ };
34
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.Connection = void 0;
39
+ const assert_1 = __importDefault(require("assert"));
40
+ const net_1 = __importStar(require("net"));
41
+ const tls_1 = __importDefault(require("tls"));
42
+ const api_1 = require("./api");
43
+ const decoder_1 = require("./utils/decoder");
44
+ const encoder_1 = require("./utils/encoder");
45
+ const error_1 = require("./utils/error");
46
+ const logger_1 = require("./utils/logger");
47
+ const tracer_1 = require("./utils/tracer");
48
+ const trace = (0, tracer_1.createTracer)('Connection');
49
+ class Connection {
50
+ options;
51
+ socket = new net_1.Socket();
52
+ queue = {};
53
+ lastCorrelationId = 0;
54
+ chunks = [];
55
+ constructor(options) {
56
+ this.options = options;
57
+ }
58
+ async connect() {
59
+ this.queue = {};
60
+ this.chunks = [];
61
+ await new Promise((resolve, reject) => {
62
+ const { ssl, connection } = this.options;
63
+ this.socket = ssl
64
+ ? tls_1.default.connect({
65
+ ...connection,
66
+ ...ssl,
67
+ ...(connection.host && !(0, net_1.isIP)(connection.host) && { servername: connection.host }),
68
+ }, resolve)
69
+ : net_1.default.connect(connection, resolve);
70
+ this.socket.once('error', reject);
71
+ });
72
+ this.socket.removeAllListeners('error');
73
+ this.socket.on('data', (data) => this.handleData(data));
74
+ this.socket.once('close', async () => {
75
+ Object.values(this.queue).forEach(({ reject }) => {
76
+ reject(new error_1.ConnectionError('Socket closed unexpectedly'));
77
+ });
78
+ this.queue = {};
79
+ });
80
+ }
81
+ disconnect() {
82
+ this.socket.removeAllListeners();
83
+ return new Promise((resolve) => {
84
+ if (this.socket.pending) {
85
+ return resolve();
86
+ }
87
+ this.socket.end(resolve);
88
+ });
89
+ }
90
+ async sendRequest(api, body) {
91
+ const correlationId = this.nextCorrelationId();
92
+ const apiName = (0, api_1.getApiName)(api);
93
+ const encoder = new encoder_1.Encoder()
94
+ .writeInt16(api.apiKey)
95
+ .writeInt16(api.apiVersion)
96
+ .writeInt32(correlationId)
97
+ .writeString(this.options.clientId);
98
+ const request = api.request(encoder, body);
99
+ const requestEncoder = new encoder_1.Encoder().writeInt32(request.getByteLength()).writeEncoder(request);
100
+ let timeout;
101
+ const { responseDecoder, responseSize } = await new Promise(async (resolve, reject) => {
102
+ timeout = setTimeout(() => {
103
+ delete this.queue[correlationId];
104
+ reject(new error_1.ConnectionError(`${apiName} timed out`));
105
+ }, 30_000);
106
+ try {
107
+ this.queue[correlationId] = { resolve, reject };
108
+ await this.write(requestEncoder.value());
109
+ }
110
+ catch (error) {
111
+ reject(error);
112
+ }
113
+ });
114
+ clearTimeout(timeout);
115
+ const response = await api.response(responseDecoder);
116
+ (0, assert_1.default)(responseDecoder.getOffset() - 4 === responseSize, `Buffer not correctly consumed: ${responseDecoder.getOffset() - 4} !== ${responseSize}`);
117
+ return response;
118
+ }
119
+ write(buffer) {
120
+ return new Promise((resolve, reject) => {
121
+ const { stack } = new Error('Write error');
122
+ this.socket.write(buffer, (error) => {
123
+ if (error) {
124
+ const err = new error_1.ConnectionError(error.message);
125
+ err.stack += `\n${stack}`;
126
+ return reject(err);
127
+ }
128
+ resolve();
129
+ });
130
+ });
131
+ }
132
+ handleData(buffer) {
133
+ this.chunks.push(buffer);
134
+ const decoder = new decoder_1.Decoder(Buffer.concat(this.chunks));
135
+ if (decoder.getBufferLength() < 4) {
136
+ return;
137
+ }
138
+ const size = decoder.readInt32();
139
+ if (size !== decoder.getBufferLength() - 4) {
140
+ return;
141
+ }
142
+ const correlationId = decoder.readInt32();
143
+ const context = this.queue[correlationId];
144
+ if (context) {
145
+ delete this.queue[correlationId];
146
+ context.resolve({ responseDecoder: decoder, responseSize: size });
147
+ }
148
+ else {
149
+ logger_1.log.debug('Could not find pending request for correlationId', { correlationId });
150
+ }
151
+ this.chunks = [];
152
+ }
153
+ nextCorrelationId() {
154
+ return this.lastCorrelationId++;
155
+ }
156
+ }
157
+ exports.Connection = Connection;
158
+ __decorate([
159
+ trace(),
160
+ __metadata("design:type", Function),
161
+ __metadata("design:paramtypes", []),
162
+ __metadata("design:returntype", Promise)
163
+ ], Connection.prototype, "connect", null);
164
+ __decorate([
165
+ trace(),
166
+ __metadata("design:type", Function),
167
+ __metadata("design:paramtypes", []),
168
+ __metadata("design:returntype", void 0)
169
+ ], Connection.prototype, "disconnect", null);
170
+ __decorate([
171
+ trace((api, body) => ({ message: (0, api_1.getApiName)(api), body })),
172
+ __metadata("design:type", Function),
173
+ __metadata("design:paramtypes", [Object, Request]),
174
+ __metadata("design:returntype", Promise)
175
+ ], Connection.prototype, "sendRequest", null);