kafka-ts 0.0.1-beta → 0.0.1-beta.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.
- package/.github/workflows/release.yml +17 -0
- package/.prettierrc +3 -2
- package/LICENSE +1 -1
- package/README.md +56 -35
- package/docker-compose.yml +108 -102
- package/examples/package-lock.json +28 -27
- package/examples/package.json +12 -12
- package/examples/src/client.ts +6 -6
- package/examples/src/consumer.ts +9 -8
- package/examples/src/create-topic.ts +22 -16
- package/examples/src/producer.ts +7 -7
- package/examples/src/replicator.ts +4 -4
- package/examples/src/utils/delay.ts +1 -0
- package/examples/src/utils/json.ts +1 -1
- package/examples/tsconfig.json +2 -2
- package/package.json +22 -15
- package/scripts/create-scram-user.sh +5 -0
- package/scripts/generate-certs.sh +1 -0
- package/scripts/kafka-local.properties +33 -0
- package/src/__snapshots__/request-handler.test.ts.snap +9 -718
- package/src/api/api-versions.ts +2 -2
- package/src/api/create-topics.ts +2 -2
- package/src/api/delete-topics.ts +2 -2
- package/src/api/fetch.ts +3 -3
- package/src/api/find-coordinator.ts +2 -2
- package/src/api/heartbeat.ts +2 -2
- package/src/api/index.ts +18 -18
- package/src/api/init-producer-id.ts +2 -2
- package/src/api/join-group.ts +3 -3
- package/src/api/leave-group.ts +2 -2
- package/src/api/list-offsets.ts +3 -3
- package/src/api/metadata.ts +3 -3
- package/src/api/offset-commit.ts +2 -2
- package/src/api/offset-fetch.ts +2 -2
- package/src/api/produce.ts +3 -3
- package/src/api/sasl-authenticate.ts +2 -2
- package/src/api/sasl-handshake.ts +2 -2
- package/src/api/sync-group.ts +2 -2
- package/src/auth/index.ts +2 -0
- package/src/auth/plain.ts +10 -0
- package/src/auth/scram.ts +52 -0
- package/src/broker.ts +12 -14
- package/src/client.ts +7 -7
- package/src/{request-handler.test.ts → cluster.test.ts} +73 -69
- package/src/cluster.ts +8 -8
- package/src/connection.ts +17 -15
- package/src/consumer/consumer-group.ts +14 -14
- package/src/consumer/consumer-metadata.ts +2 -2
- package/src/consumer/consumer.ts +84 -82
- package/src/consumer/fetch-manager.ts +179 -0
- package/src/consumer/fetcher.ts +57 -0
- package/src/consumer/offset-manager.ts +6 -6
- package/src/consumer/processor.ts +47 -0
- package/src/distributors/assignments-to-replicas.test.ts +7 -7
- package/src/distributors/assignments-to-replicas.ts +1 -1
- package/src/distributors/messages-to-topic-partition-leaders.test.ts +6 -6
- package/src/index.ts +6 -3
- package/src/metadata.ts +4 -4
- package/src/producer/producer.ts +8 -8
- package/src/types.ts +2 -0
- package/src/utils/api.ts +4 -4
- package/src/utils/crypto.ts +15 -0
- package/src/utils/debug.ts +2 -2
- package/src/utils/decoder.ts +4 -4
- package/src/utils/encoder.ts +6 -6
- package/src/utils/error.ts +3 -3
- package/src/utils/retrier.ts +1 -1
- package/src/utils/tracer.ts +7 -4
- package/tsconfig.json +16 -16
- package/dist/api/api-versions.d.ts +0 -9
- package/dist/api/api-versions.js +0 -24
- package/dist/api/create-topics.d.ts +0 -38
- package/dist/api/create-topics.js +0 -53
- package/dist/api/delete-topics.d.ts +0 -18
- package/dist/api/delete-topics.js +0 -33
- package/dist/api/fetch.d.ts +0 -77
- package/dist/api/fetch.js +0 -106
- package/dist/api/find-coordinator.d.ts +0 -21
- package/dist/api/find-coordinator.js +0 -39
- package/dist/api/heartbeat.d.ts +0 -11
- package/dist/api/heartbeat.js +0 -27
- package/dist/api/index.d.ts +0 -573
- package/dist/api/index.js +0 -164
- package/dist/api/init-producer-id.d.ts +0 -13
- package/dist/api/init-producer-id.js +0 -29
- package/dist/api/join-group.d.ts +0 -34
- package/dist/api/join-group.js +0 -51
- package/dist/api/leave-group.d.ts +0 -19
- package/dist/api/leave-group.js +0 -39
- package/dist/api/list-offsets.d.ts +0 -29
- package/dist/api/list-offsets.js +0 -48
- package/dist/api/metadata.d.ts +0 -40
- package/dist/api/metadata.js +0 -58
- package/dist/api/offset-commit.d.ts +0 -28
- package/dist/api/offset-commit.js +0 -48
- package/dist/api/offset-fetch.d.ts +0 -33
- package/dist/api/offset-fetch.js +0 -57
- package/dist/api/produce.d.ts +0 -53
- package/dist/api/produce.js +0 -129
- package/dist/api/sasl-authenticate.d.ts +0 -11
- package/dist/api/sasl-authenticate.js +0 -23
- package/dist/api/sasl-handshake.d.ts +0 -6
- package/dist/api/sasl-handshake.js +0 -19
- package/dist/api/sync-group.d.ts +0 -24
- package/dist/api/sync-group.js +0 -36
- package/dist/broker.d.ts +0 -29
- package/dist/broker.js +0 -60
- package/dist/client.d.ts +0 -23
- package/dist/client.js +0 -36
- package/dist/cluster.d.ts +0 -24
- package/dist/cluster.js +0 -72
- package/dist/connection.d.ts +0 -25
- package/dist/connection.js +0 -155
- package/dist/consumer/consumer-group.d.ts +0 -36
- package/dist/consumer/consumer-group.js +0 -182
- package/dist/consumer/consumer-metadata.d.ts +0 -7
- package/dist/consumer/consumer-metadata.js +0 -14
- package/dist/consumer/consumer.d.ts +0 -37
- package/dist/consumer/consumer.js +0 -178
- package/dist/consumer/metadata.d.ts +0 -24
- package/dist/consumer/metadata.js +0 -64
- package/dist/consumer/offset-manager.d.ts +0 -22
- package/dist/consumer/offset-manager.js +0 -56
- package/dist/distributors/assignments-to-replicas.d.ts +0 -17
- package/dist/distributors/assignments-to-replicas.js +0 -60
- package/dist/distributors/assignments-to-replicas.test.d.ts +0 -1
- package/dist/distributors/assignments-to-replicas.test.js +0 -40
- package/dist/distributors/messages-to-topic-partition-leaders.d.ts +0 -17
- package/dist/distributors/messages-to-topic-partition-leaders.js +0 -15
- package/dist/distributors/messages-to-topic-partition-leaders.test.d.ts +0 -1
- package/dist/distributors/messages-to-topic-partition-leaders.test.js +0 -30
- package/dist/examples/src/replicator.js +0 -34
- package/dist/examples/src/utils/json.js +0 -5
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -19
- package/dist/metadata.d.ts +0 -24
- package/dist/metadata.js +0 -89
- package/dist/producer/producer.d.ts +0 -19
- package/dist/producer/producer.js +0 -111
- package/dist/request-handler.d.ts +0 -16
- package/dist/request-handler.js +0 -67
- package/dist/request-handler.test.d.ts +0 -1
- package/dist/request-handler.test.js +0 -340
- package/dist/src/api/api-versions.js +0 -18
- package/dist/src/api/create-topics.js +0 -46
- package/dist/src/api/delete-topics.js +0 -26
- package/dist/src/api/fetch.js +0 -95
- package/dist/src/api/find-coordinator.js +0 -34
- package/dist/src/api/heartbeat.js +0 -22
- package/dist/src/api/index.js +0 -38
- package/dist/src/api/init-producer-id.js +0 -24
- package/dist/src/api/join-group.js +0 -48
- package/dist/src/api/leave-group.js +0 -30
- package/dist/src/api/list-offsets.js +0 -39
- package/dist/src/api/metadata.js +0 -47
- package/dist/src/api/offset-commit.js +0 -39
- package/dist/src/api/offset-fetch.js +0 -44
- package/dist/src/api/produce.js +0 -119
- package/dist/src/api/sync-group.js +0 -31
- package/dist/src/broker.js +0 -35
- package/dist/src/connection.js +0 -21
- package/dist/src/consumer/consumer-group.js +0 -131
- package/dist/src/consumer/consumer.js +0 -103
- package/dist/src/consumer/metadata.js +0 -52
- package/dist/src/consumer/offset-manager.js +0 -23
- package/dist/src/index.js +0 -19
- package/dist/src/producer/producer.js +0 -84
- package/dist/src/request-handler.js +0 -57
- package/dist/src/request-handler.test.js +0 -321
- package/dist/src/types.js +0 -2
- package/dist/src/utils/api.js +0 -5
- package/dist/src/utils/decoder.js +0 -161
- package/dist/src/utils/encoder.js +0 -137
- package/dist/src/utils/error.js +0 -10
- package/dist/types.d.ts +0 -9
- package/dist/types.js +0 -2
- package/dist/utils/api.d.ts +0 -9
- package/dist/utils/api.js +0 -5
- package/dist/utils/debug.d.ts +0 -2
- package/dist/utils/debug.js +0 -11
- package/dist/utils/decoder.d.ts +0 -29
- package/dist/utils/decoder.js +0 -147
- package/dist/utils/delay.d.ts +0 -1
- package/dist/utils/delay.js +0 -5
- package/dist/utils/encoder.d.ts +0 -28
- package/dist/utils/encoder.js +0 -122
- package/dist/utils/error.d.ts +0 -11
- package/dist/utils/error.js +0 -27
- package/dist/utils/memo.d.ts +0 -1
- package/dist/utils/memo.js +0 -16
- package/dist/utils/retrier.d.ts +0 -10
- package/dist/utils/retrier.js +0 -22
- package/dist/utils/tracer.d.ts +0 -1
- package/dist/utils/tracer.js +0 -26
- package/examples/node_modules/.package-lock.json +0 -22
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import { randomBytes } from
|
|
2
|
-
import { readFileSync } from
|
|
3
|
-
import { afterAll, beforeAll, describe, expect, it } from
|
|
4
|
-
import { API } from
|
|
5
|
-
import { KEY_TYPE } from
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
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 { saslPlain } from './auth';
|
|
7
|
+
import { createKafkaClient } from './client';
|
|
8
|
+
import { Cluster } from './cluster';
|
|
9
|
+
import { KafkaTSApiError } from './utils/error';
|
|
9
10
|
|
|
10
11
|
export const kafka = createKafkaClient({
|
|
11
|
-
clientId:
|
|
12
|
-
bootstrapServers: [{ host:
|
|
13
|
-
sasl: {
|
|
14
|
-
ssl: { ca: readFileSync(
|
|
12
|
+
clientId: 'kafka-ts',
|
|
13
|
+
bootstrapServers: [{ host: 'localhost', port: 9092 }],
|
|
14
|
+
sasl: saslPlain({ username: 'admin', password: 'admin' }),
|
|
15
|
+
ssl: { ca: readFileSync('./certs/ca.crt').toString() },
|
|
15
16
|
});
|
|
16
17
|
|
|
17
|
-
describe.sequential(
|
|
18
|
-
const groupId = randomBytes(16).toString(
|
|
18
|
+
describe.sequential('Request handler', () => {
|
|
19
|
+
const groupId = randomBytes(16).toString('hex');
|
|
19
20
|
|
|
20
21
|
let cluster: Cluster;
|
|
21
22
|
|
|
@@ -27,9 +28,9 @@ describe.sequential("Request handler", () => {
|
|
|
27
28
|
allowTopicAutoCreation: false,
|
|
28
29
|
includeTopicAuthorizedOperations: false,
|
|
29
30
|
});
|
|
30
|
-
if (metadataResult.topics.some((topic) => topic.name ===
|
|
31
|
+
if (metadataResult.topics.some((topic) => topic.name === 'kafka-ts-test-topic')) {
|
|
31
32
|
await cluster.sendRequest(API.DELETE_TOPICS, {
|
|
32
|
-
topics: [{ name:
|
|
33
|
+
topics: [{ name: 'kafka-ts-test-topic', topicId: null }],
|
|
33
34
|
timeoutMs: 10000,
|
|
34
35
|
});
|
|
35
36
|
}
|
|
@@ -39,18 +40,18 @@ describe.sequential("Request handler", () => {
|
|
|
39
40
|
await cluster.disconnect();
|
|
40
41
|
});
|
|
41
42
|
|
|
42
|
-
it(
|
|
43
|
+
it('should request api versions', async () => {
|
|
43
44
|
const result = await cluster.sendRequest(API.API_VERSIONS, {});
|
|
44
45
|
expect(result).toMatchSnapshot();
|
|
45
46
|
});
|
|
46
47
|
|
|
47
|
-
let topicId: string =
|
|
48
|
+
let topicId: string = 'd6718d178e1b47c886441ad2d19faea5';
|
|
48
49
|
|
|
49
|
-
it(
|
|
50
|
+
it('should create topics', async () => {
|
|
50
51
|
const result = await cluster.sendRequest(API.CREATE_TOPICS, {
|
|
51
52
|
topics: [
|
|
52
53
|
{
|
|
53
|
-
name:
|
|
54
|
+
name: 'kafka-ts-test-topic',
|
|
54
55
|
numPartitions: 1,
|
|
55
56
|
replicationFactor: 1,
|
|
56
57
|
assignments: [],
|
|
@@ -62,22 +63,23 @@ describe.sequential("Request handler", () => {
|
|
|
62
63
|
});
|
|
63
64
|
topicId = result.topics[0].topicId;
|
|
64
65
|
result.topics.forEach((topic) => {
|
|
65
|
-
topic.topicId =
|
|
66
|
+
topic.topicId = 'Any<UUID>';
|
|
66
67
|
});
|
|
67
68
|
expect(result).toMatchSnapshot();
|
|
68
69
|
|
|
69
70
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
70
71
|
});
|
|
71
72
|
|
|
72
|
-
it(
|
|
73
|
+
it('should request metadata for all topics', async () => {
|
|
73
74
|
const result = await cluster.sendRequest(API.METADATA, {
|
|
74
75
|
topics: null,
|
|
75
76
|
allowTopicAutoCreation: false,
|
|
76
77
|
includeTopicAuthorizedOperations: false,
|
|
77
78
|
});
|
|
78
79
|
result.controllerId = 0;
|
|
80
|
+
result.topics = result.topics.filter((topic) => topic.name !== '__consumer_offsets');
|
|
79
81
|
result.topics.forEach((topic) => {
|
|
80
|
-
topic.topicId =
|
|
82
|
+
topic.topicId = 'Any<UUID>';
|
|
81
83
|
topic.partitions.forEach((partition) => {
|
|
82
84
|
partition.leaderId = 0;
|
|
83
85
|
partition.isrNodes = [0];
|
|
@@ -89,16 +91,16 @@ describe.sequential("Request handler", () => {
|
|
|
89
91
|
|
|
90
92
|
let leaderId = 0;
|
|
91
93
|
|
|
92
|
-
it(
|
|
94
|
+
it('should request metadata for a topic', async () => {
|
|
93
95
|
const result = await cluster.sendRequest(API.METADATA, {
|
|
94
|
-
topics: [{ id: topicId, name:
|
|
96
|
+
topics: [{ id: topicId, name: 'kafka-ts-test-topic' }],
|
|
95
97
|
allowTopicAutoCreation: false,
|
|
96
98
|
includeTopicAuthorizedOperations: false,
|
|
97
99
|
});
|
|
98
100
|
leaderId = result.topics[0].partitions[0].leaderId;
|
|
99
101
|
result.controllerId = 0;
|
|
100
102
|
result.topics.forEach((topic) => {
|
|
101
|
-
topic.topicId =
|
|
103
|
+
topic.topicId = 'Any<UUID>';
|
|
102
104
|
topic.partitions.forEach((partition) => {
|
|
103
105
|
partition.leaderId = 0;
|
|
104
106
|
partition.isrNodes = [0];
|
|
@@ -108,18 +110,20 @@ describe.sequential("Request handler", () => {
|
|
|
108
110
|
expect(result).toMatchSnapshot();
|
|
109
111
|
});
|
|
110
112
|
|
|
111
|
-
|
|
113
|
+
let producerId = 9n;
|
|
114
|
+
|
|
115
|
+
it('should init producer id', async () => {
|
|
112
116
|
const result = await cluster.sendRequest(API.INIT_PRODUCER_ID, {
|
|
113
117
|
transactionalId: null,
|
|
114
118
|
transactionTimeoutMs: 0,
|
|
115
|
-
producerId
|
|
119
|
+
producerId,
|
|
116
120
|
producerEpoch: 0,
|
|
117
121
|
});
|
|
118
122
|
result.producerId = 0n;
|
|
119
123
|
expect(result).toMatchSnapshot();
|
|
120
124
|
});
|
|
121
125
|
|
|
122
|
-
it(
|
|
126
|
+
it('should produce messages', async () => {
|
|
123
127
|
const now = Date.now();
|
|
124
128
|
const result = await cluster.sendRequestToNode(leaderId)(API.PRODUCE, {
|
|
125
129
|
transactionalId: null,
|
|
@@ -127,7 +131,7 @@ describe.sequential("Request handler", () => {
|
|
|
127
131
|
acks: 1,
|
|
128
132
|
topicData: [
|
|
129
133
|
{
|
|
130
|
-
name:
|
|
134
|
+
name: 'kafka-ts-test-topic',
|
|
131
135
|
partitionData: [
|
|
132
136
|
{
|
|
133
137
|
index: 0,
|
|
@@ -139,18 +143,18 @@ describe.sequential("Request handler", () => {
|
|
|
139
143
|
lastOffsetDelta: 0,
|
|
140
144
|
maxTimestamp: BigInt(now),
|
|
141
145
|
producerEpoch: 0,
|
|
142
|
-
producerId
|
|
146
|
+
producerId,
|
|
143
147
|
records: [
|
|
144
148
|
{
|
|
145
149
|
attributes: 0,
|
|
146
150
|
offsetDelta: 0,
|
|
147
151
|
timestampDelta: 0n,
|
|
148
|
-
key:
|
|
149
|
-
value:
|
|
152
|
+
key: 'key',
|
|
153
|
+
value: 'value',
|
|
150
154
|
headers: [
|
|
151
155
|
{
|
|
152
|
-
key:
|
|
153
|
-
value:
|
|
156
|
+
key: 'header-key',
|
|
157
|
+
value: 'header-value',
|
|
154
158
|
},
|
|
155
159
|
],
|
|
156
160
|
},
|
|
@@ -163,7 +167,7 @@ describe.sequential("Request handler", () => {
|
|
|
163
167
|
expect(result).toMatchSnapshot();
|
|
164
168
|
});
|
|
165
169
|
|
|
166
|
-
it(
|
|
170
|
+
it('should fetch messages', async () => {
|
|
167
171
|
const result = await cluster.sendRequestToNode(leaderId)(API.FETCH, {
|
|
168
172
|
maxWaitMs: 100,
|
|
169
173
|
minBytes: 1,
|
|
@@ -187,10 +191,10 @@ describe.sequential("Request handler", () => {
|
|
|
187
191
|
},
|
|
188
192
|
],
|
|
189
193
|
forgottenTopicsData: [],
|
|
190
|
-
rackId:
|
|
194
|
+
rackId: '',
|
|
191
195
|
});
|
|
192
196
|
result.responses.forEach((response) => {
|
|
193
|
-
response.topicId =
|
|
197
|
+
response.topicId = 'Any<UUID>';
|
|
194
198
|
response.partitions.forEach((partition) => {
|
|
195
199
|
partition.records.forEach((record) => {
|
|
196
200
|
expect(record.baseTimestamp).toBeGreaterThan(1721926744730n);
|
|
@@ -208,10 +212,10 @@ describe.sequential("Request handler", () => {
|
|
|
208
212
|
|
|
209
213
|
let coordinatorId = -1;
|
|
210
214
|
|
|
211
|
-
it(
|
|
215
|
+
it('should find coordinator', async () => {
|
|
212
216
|
const result = await cluster.sendRequest(API.FIND_COORDINATOR, { keyType: KEY_TYPE.GROUP, keys: [groupId] });
|
|
213
217
|
result.coordinators.forEach((coordinator) => {
|
|
214
|
-
coordinator.key =
|
|
218
|
+
coordinator.key = 'Any<String>';
|
|
215
219
|
});
|
|
216
220
|
coordinatorId = result.coordinators[0].nodeId;
|
|
217
221
|
result.coordinators.forEach((coordinator) => {
|
|
@@ -221,9 +225,9 @@ describe.sequential("Request handler", () => {
|
|
|
221
225
|
expect(result).toMatchSnapshot();
|
|
222
226
|
});
|
|
223
227
|
|
|
224
|
-
let memberId =
|
|
228
|
+
let memberId = '';
|
|
225
229
|
|
|
226
|
-
it(
|
|
230
|
+
it('should fail join group request with new memberId', async () => {
|
|
227
231
|
try {
|
|
228
232
|
const result = await cluster.sendRequestToNode(coordinatorId)(API.JOIN_GROUP, {
|
|
229
233
|
groupId,
|
|
@@ -231,67 +235,67 @@ describe.sequential("Request handler", () => {
|
|
|
231
235
|
rebalanceTimeoutMs: 60000,
|
|
232
236
|
memberId,
|
|
233
237
|
groupInstanceId: null,
|
|
234
|
-
protocolType:
|
|
238
|
+
protocolType: 'consumer',
|
|
235
239
|
protocols: [
|
|
236
240
|
{
|
|
237
|
-
name:
|
|
238
|
-
metadata: { version: 0, topics: [
|
|
241
|
+
name: 'RoundRobinAssigner',
|
|
242
|
+
metadata: { version: 0, topics: ['kafka-ts-test-topic'] },
|
|
239
243
|
},
|
|
240
244
|
],
|
|
241
245
|
reason: null,
|
|
242
246
|
});
|
|
243
|
-
expect(false,
|
|
247
|
+
expect(false, 'Should throw an error').toBe(true);
|
|
244
248
|
} catch (error) {
|
|
245
249
|
const { response } = error as KafkaTSApiError;
|
|
246
250
|
memberId = response.memberId;
|
|
247
|
-
response.memberId =
|
|
251
|
+
response.memberId = 'Any<UUID>';
|
|
248
252
|
expect(response).toMatchSnapshot();
|
|
249
253
|
}
|
|
250
254
|
});
|
|
251
255
|
|
|
252
|
-
it(
|
|
256
|
+
it('should join group', async () => {
|
|
253
257
|
const result = await cluster.sendRequestToNode(coordinatorId)(API.JOIN_GROUP, {
|
|
254
258
|
groupId,
|
|
255
259
|
sessionTimeoutMs: 30000,
|
|
256
260
|
rebalanceTimeoutMs: 60000,
|
|
257
261
|
memberId,
|
|
258
262
|
groupInstanceId: null,
|
|
259
|
-
protocolType:
|
|
263
|
+
protocolType: 'consumer',
|
|
260
264
|
protocols: [
|
|
261
265
|
{
|
|
262
|
-
name:
|
|
263
|
-
metadata: { version: 0, topics: [
|
|
266
|
+
name: 'RoundRobinAssigner',
|
|
267
|
+
metadata: { version: 0, topics: ['kafka-ts-test-topic'] },
|
|
264
268
|
},
|
|
265
269
|
],
|
|
266
270
|
reason: null,
|
|
267
271
|
});
|
|
268
|
-
result.memberId =
|
|
269
|
-
result.leader =
|
|
272
|
+
result.memberId = 'Any<UUID>';
|
|
273
|
+
result.leader = 'Any<UUID>';
|
|
270
274
|
result.members.forEach((member) => {
|
|
271
|
-
member.memberId =
|
|
275
|
+
member.memberId = 'Any<UUID>';
|
|
272
276
|
});
|
|
273
277
|
expect(result).toMatchSnapshot();
|
|
274
278
|
});
|
|
275
279
|
|
|
276
|
-
it(
|
|
280
|
+
it('should sync group', async () => {
|
|
277
281
|
const result = await cluster.sendRequestToNode(coordinatorId)(API.SYNC_GROUP, {
|
|
278
282
|
groupId,
|
|
279
283
|
generationId: 1,
|
|
280
284
|
memberId,
|
|
281
285
|
groupInstanceId: null,
|
|
282
|
-
protocolType:
|
|
283
|
-
protocolName:
|
|
286
|
+
protocolType: 'consumer',
|
|
287
|
+
protocolName: 'RoundRobinAssigner',
|
|
284
288
|
assignments: [
|
|
285
289
|
{
|
|
286
290
|
memberId,
|
|
287
|
-
assignment: {
|
|
291
|
+
assignment: { 'kafka-test-topic': [0] },
|
|
288
292
|
},
|
|
289
293
|
],
|
|
290
294
|
});
|
|
291
295
|
expect(result).toMatchSnapshot();
|
|
292
296
|
});
|
|
293
297
|
|
|
294
|
-
it(
|
|
298
|
+
it('should commit offsets', async () => {
|
|
295
299
|
const result = await cluster.sendRequestToNode(coordinatorId)(API.OFFSET_COMMIT, {
|
|
296
300
|
groupId,
|
|
297
301
|
generationIdOrMemberEpoch: 1,
|
|
@@ -299,7 +303,7 @@ describe.sequential("Request handler", () => {
|
|
|
299
303
|
groupInstanceId: null,
|
|
300
304
|
topics: [
|
|
301
305
|
{
|
|
302
|
-
name:
|
|
306
|
+
name: 'kafka-ts-test-topic',
|
|
303
307
|
partitions: [
|
|
304
308
|
{ partitionIndex: 0, committedOffset: 1n, committedLeaderEpoch: 0, committedMetadata: null },
|
|
305
309
|
],
|
|
@@ -309,7 +313,7 @@ describe.sequential("Request handler", () => {
|
|
|
309
313
|
expect(result).toMatchSnapshot();
|
|
310
314
|
});
|
|
311
315
|
|
|
312
|
-
it(
|
|
316
|
+
it('should fetch offsets', async () => {
|
|
313
317
|
const result = await cluster.sendRequestToNode(coordinatorId)(API.OFFSET_FETCH, {
|
|
314
318
|
groups: [
|
|
315
319
|
{
|
|
@@ -318,7 +322,7 @@ describe.sequential("Request handler", () => {
|
|
|
318
322
|
memberEpoch: 0,
|
|
319
323
|
topics: [
|
|
320
324
|
{
|
|
321
|
-
name:
|
|
325
|
+
name: 'kafka-ts-test-topic',
|
|
322
326
|
partitionIndexes: [0],
|
|
323
327
|
},
|
|
324
328
|
],
|
|
@@ -327,12 +331,12 @@ describe.sequential("Request handler", () => {
|
|
|
327
331
|
requireStable: false,
|
|
328
332
|
});
|
|
329
333
|
result.groups.forEach((group) => {
|
|
330
|
-
group.groupId =
|
|
334
|
+
group.groupId = 'Any<String>';
|
|
331
335
|
});
|
|
332
336
|
expect(result).toMatchSnapshot();
|
|
333
337
|
});
|
|
334
338
|
|
|
335
|
-
it(
|
|
339
|
+
it('should heartbeat', async () => {
|
|
336
340
|
const result = await cluster.sendRequestToNode(coordinatorId)(API.HEARTBEAT, {
|
|
337
341
|
groupId,
|
|
338
342
|
generationId: 1,
|
|
@@ -342,24 +346,24 @@ describe.sequential("Request handler", () => {
|
|
|
342
346
|
expect(result).toMatchSnapshot();
|
|
343
347
|
});
|
|
344
348
|
|
|
345
|
-
it(
|
|
349
|
+
it('should leave group', async () => {
|
|
346
350
|
const result = await cluster.sendRequestToNode(coordinatorId)(API.LEAVE_GROUP, {
|
|
347
351
|
groupId,
|
|
348
352
|
members: [{ memberId, groupInstanceId: null, reason: null }],
|
|
349
353
|
});
|
|
350
354
|
result.members.forEach((member) => {
|
|
351
|
-
member.memberId =
|
|
355
|
+
member.memberId = 'Any<UUID>';
|
|
352
356
|
});
|
|
353
357
|
expect(result).toMatchSnapshot();
|
|
354
358
|
});
|
|
355
359
|
|
|
356
|
-
it(
|
|
360
|
+
it('should delete topics', async () => {
|
|
357
361
|
const result = await cluster.sendRequest(API.DELETE_TOPICS, {
|
|
358
|
-
topics: [{ name:
|
|
362
|
+
topics: [{ name: 'kafka-ts-test-topic', topicId: null }],
|
|
359
363
|
timeoutMs: 10000,
|
|
360
364
|
});
|
|
361
365
|
result.responses.forEach((response) => {
|
|
362
|
-
response.topicId =
|
|
366
|
+
response.topicId = 'Any<UUID>';
|
|
363
367
|
});
|
|
364
368
|
expect(result).toMatchSnapshot();
|
|
365
369
|
});
|
package/src/cluster.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { TcpSocketConnectOpts } from
|
|
2
|
-
import { TLSSocketOptions } from
|
|
3
|
-
import { API } from
|
|
4
|
-
import { Broker,
|
|
5
|
-
import { SendRequest } from
|
|
6
|
-
import { ConnectionError, KafkaTSError } from
|
|
1
|
+
import { TcpSocketConnectOpts } from 'net';
|
|
2
|
+
import { TLSSocketOptions } from 'tls';
|
|
3
|
+
import { API } from './api';
|
|
4
|
+
import { Broker, SASLProvider } from './broker';
|
|
5
|
+
import { SendRequest } from './connection';
|
|
6
|
+
import { ConnectionError, KafkaTSError } from './utils/error';
|
|
7
7
|
|
|
8
8
|
type ClusterOptions = {
|
|
9
9
|
clientId: string | null;
|
|
10
10
|
bootstrapServers: TcpSocketConnectOpts[];
|
|
11
|
-
sasl:
|
|
11
|
+
sasl: SASLProvider | null;
|
|
12
12
|
ssl: TLSSocketOptions | null;
|
|
13
13
|
};
|
|
14
14
|
|
|
@@ -82,6 +82,6 @@ export class Cluster {
|
|
|
82
82
|
console.warn(`Failed to connect to seed broker ${options.host}:${options.port}`, error);
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
-
throw new KafkaTSError(
|
|
85
|
+
throw new KafkaTSError('No seed brokers found');
|
|
86
86
|
}
|
|
87
87
|
}
|
package/src/connection.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import assert from
|
|
2
|
-
import net, { isIP, Socket, TcpSocketConnectOpts } from
|
|
3
|
-
import tls, { TLSSocketOptions } from
|
|
4
|
-
import { getApiName } from
|
|
5
|
-
import { Api } from
|
|
6
|
-
import { Decoder } from
|
|
7
|
-
import { Encoder } from
|
|
8
|
-
import { ConnectionError } from
|
|
9
|
-
import {
|
|
1
|
+
import assert from 'assert';
|
|
2
|
+
import net, { isIP, Socket, TcpSocketConnectOpts } from 'net';
|
|
3
|
+
import tls, { TLSSocketOptions } from 'tls';
|
|
4
|
+
import { getApiName } from './api';
|
|
5
|
+
import { Api } from './utils/api';
|
|
6
|
+
import { Decoder } from './utils/decoder';
|
|
7
|
+
import { Encoder } from './utils/encoder';
|
|
8
|
+
import { ConnectionError } from './utils/error';
|
|
9
|
+
import { createTracer } from './utils/tracer';
|
|
10
|
+
|
|
11
|
+
const trace = createTracer('Connection');
|
|
10
12
|
|
|
11
13
|
export type ConnectionOptions = {
|
|
12
14
|
clientId: string | null;
|
|
@@ -44,14 +46,14 @@ export class Connection {
|
|
|
44
46
|
resolve,
|
|
45
47
|
)
|
|
46
48
|
: net.connect(connection, resolve);
|
|
47
|
-
this.socket.once(
|
|
49
|
+
this.socket.once('error', reject);
|
|
48
50
|
});
|
|
49
|
-
this.socket.removeAllListeners(
|
|
51
|
+
this.socket.removeAllListeners('error');
|
|
50
52
|
|
|
51
|
-
this.socket.on(
|
|
52
|
-
this.socket.once(
|
|
53
|
+
this.socket.on('data', (data) => this.handleData(data));
|
|
54
|
+
this.socket.once('close', async () => {
|
|
53
55
|
Object.values(this.queue).forEach(({ reject }) => {
|
|
54
|
-
reject(new ConnectionError(
|
|
56
|
+
reject(new ConnectionError('Socket closed unexpectedly'));
|
|
55
57
|
});
|
|
56
58
|
this.queue = {};
|
|
57
59
|
});
|
|
@@ -100,7 +102,7 @@ export class Connection {
|
|
|
100
102
|
|
|
101
103
|
private write(buffer: Buffer) {
|
|
102
104
|
return new Promise<void>((resolve, reject) => {
|
|
103
|
-
const { stack } = new Error(
|
|
105
|
+
const { stack } = new Error('Write error');
|
|
104
106
|
this.socket.write(buffer, (error) => {
|
|
105
107
|
if (error) {
|
|
106
108
|
const err = new ConnectionError(error.message);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { API, API_ERROR } from
|
|
2
|
-
import { KEY_TYPE } from
|
|
3
|
-
import { Assignment, MemberAssignment } from
|
|
4
|
-
import { Cluster } from
|
|
5
|
-
import { KafkaTSApiError, KafkaTSError } from
|
|
6
|
-
import { ConsumerMetadata } from
|
|
7
|
-
import { OffsetManager } from
|
|
1
|
+
import { API, API_ERROR } from '../api';
|
|
2
|
+
import { KEY_TYPE } from '../api/find-coordinator';
|
|
3
|
+
import { Assignment, MemberAssignment } from '../api/sync-group';
|
|
4
|
+
import { Cluster } from '../cluster';
|
|
5
|
+
import { KafkaTSApiError, KafkaTSError } from '../utils/error';
|
|
6
|
+
import { ConsumerMetadata } from './consumer-metadata';
|
|
7
|
+
import { OffsetManager } from './offset-manager';
|
|
8
8
|
|
|
9
9
|
type ConsumerGroupOptions = {
|
|
10
10
|
cluster: Cluster;
|
|
@@ -19,9 +19,9 @@ type ConsumerGroupOptions = {
|
|
|
19
19
|
|
|
20
20
|
export class ConsumerGroup {
|
|
21
21
|
private coordinatorId = -1;
|
|
22
|
-
private memberId =
|
|
22
|
+
private memberId = '';
|
|
23
23
|
private generationId = -1;
|
|
24
|
-
private leaderId =
|
|
24
|
+
private leaderId = '';
|
|
25
25
|
private memberIds: string[] = [];
|
|
26
26
|
private heartbeatInterval: NodeJS.Timeout | null = null;
|
|
27
27
|
private heartbeatError: KafkaTSError | null = null;
|
|
@@ -76,8 +76,8 @@ export class ConsumerGroup {
|
|
|
76
76
|
memberId: this.memberId,
|
|
77
77
|
sessionTimeoutMs,
|
|
78
78
|
rebalanceTimeoutMs,
|
|
79
|
-
protocolType:
|
|
80
|
-
protocols: [{ name:
|
|
79
|
+
protocolType: 'consumer',
|
|
80
|
+
protocols: [{ name: 'RoundRobinAssigner', metadata: { version: 0, topics } }],
|
|
81
81
|
reason: null,
|
|
82
82
|
});
|
|
83
83
|
this.memberId = response.memberId;
|
|
@@ -118,11 +118,11 @@ export class ConsumerGroup {
|
|
|
118
118
|
groupInstanceId,
|
|
119
119
|
memberId: this.memberId,
|
|
120
120
|
generationId: this.generationId,
|
|
121
|
-
protocolType:
|
|
122
|
-
protocolName:
|
|
121
|
+
protocolType: 'consumer',
|
|
122
|
+
protocolName: 'RoundRobinAssigner',
|
|
123
123
|
assignments,
|
|
124
124
|
});
|
|
125
|
-
metadata.setAssignment(JSON.parse(response.assignments ||
|
|
125
|
+
metadata.setAssignment(JSON.parse(response.assignments || '{}') as Assignment);
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
private async offsetFetch() {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Assignment } from
|
|
2
|
-
import { Metadata } from
|
|
1
|
+
import { Assignment } from '../api/sync-group';
|
|
2
|
+
import { Metadata } from '../metadata';
|
|
3
3
|
|
|
4
4
|
export class ConsumerMetadata extends Metadata {
|
|
5
5
|
private assignment: Assignment = {};
|