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.
- package/README.md +72 -8
- package/dist/api/api-versions.d.ts +9 -0
- package/{src/api/api-versions.ts → dist/api/api-versions.js} +8 -5
- package/dist/api/create-topics.d.ts +38 -0
- package/dist/api/create-topics.js +53 -0
- package/dist/api/delete-topics.d.ts +18 -0
- package/dist/api/delete-topics.js +33 -0
- package/dist/api/fetch.d.ts +84 -0
- package/dist/api/fetch.js +142 -0
- package/dist/api/find-coordinator.d.ts +21 -0
- package/{src/api/find-coordinator.ts → dist/api/find-coordinator.js} +14 -14
- package/dist/api/heartbeat.d.ts +11 -0
- package/dist/api/heartbeat.js +27 -0
- package/dist/api/index.d.ts +576 -0
- package/{src/api/index.ts → dist/api/index.js} +42 -41
- package/dist/api/init-producer-id.d.ts +13 -0
- package/dist/api/init-producer-id.js +29 -0
- package/dist/api/join-group.d.ts +34 -0
- package/dist/api/join-group.js +51 -0
- package/dist/api/leave-group.d.ts +19 -0
- package/dist/api/leave-group.js +39 -0
- package/dist/api/list-offsets.d.ts +29 -0
- package/dist/api/list-offsets.js +48 -0
- package/dist/api/metadata.d.ts +40 -0
- package/{src/api/metadata.ts → dist/api/metadata.js} +18 -26
- package/dist/api/offset-commit.d.ts +28 -0
- package/dist/api/offset-commit.js +48 -0
- package/dist/api/offset-fetch.d.ts +31 -0
- package/dist/api/offset-fetch.js +55 -0
- package/dist/api/produce.d.ts +54 -0
- package/{src/api/produce.ts → dist/api/produce.js} +55 -102
- package/dist/api/sasl-authenticate.d.ts +11 -0
- package/dist/api/sasl-authenticate.js +23 -0
- package/dist/api/sasl-handshake.d.ts +6 -0
- package/dist/api/sasl-handshake.js +19 -0
- package/dist/api/sync-group.d.ts +24 -0
- package/dist/api/sync-group.js +36 -0
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.js +8 -0
- package/dist/auth/plain.d.ts +5 -0
- package/dist/auth/plain.js +12 -0
- package/dist/auth/scram.d.ts +9 -0
- package/dist/auth/scram.js +40 -0
- package/dist/broker.d.ts +30 -0
- package/dist/broker.js +55 -0
- package/dist/client.d.ts +22 -0
- package/dist/client.js +36 -0
- package/dist/cluster.d.ts +27 -0
- package/dist/cluster.js +70 -0
- package/dist/cluster.test.d.ts +1 -0
- package/{src/cluster.test.ts → dist/cluster.test.js} +87 -113
- package/dist/codecs/gzip.d.ts +2 -0
- package/dist/codecs/gzip.js +8 -0
- package/dist/codecs/index.d.ts +2 -0
- package/dist/codecs/index.js +17 -0
- package/dist/codecs/none.d.ts +2 -0
- package/dist/codecs/none.js +7 -0
- package/dist/codecs/types.d.ts +5 -0
- package/dist/codecs/types.js +2 -0
- package/dist/connection.d.ts +26 -0
- package/dist/connection.js +175 -0
- package/dist/consumer/consumer-group.d.ts +41 -0
- package/dist/consumer/consumer-group.js +215 -0
- package/dist/consumer/consumer-metadata.d.ts +7 -0
- package/dist/consumer/consumer-metadata.js +14 -0
- package/dist/consumer/consumer.d.ts +44 -0
- package/dist/consumer/consumer.js +225 -0
- package/dist/consumer/fetch-manager.d.ts +33 -0
- package/dist/consumer/fetch-manager.js +140 -0
- package/dist/consumer/fetcher.d.ts +25 -0
- package/dist/consumer/fetcher.js +64 -0
- package/dist/consumer/offset-manager.d.ts +22 -0
- package/dist/consumer/offset-manager.js +66 -0
- package/dist/consumer/processor.d.ts +19 -0
- package/dist/consumer/processor.js +59 -0
- package/dist/distributors/assignments-to-replicas.d.ts +16 -0
- package/{src/distributors/assignments-to-replicas.ts → dist/distributors/assignments-to-replicas.js} +15 -41
- package/dist/distributors/assignments-to-replicas.test.d.ts +1 -0
- package/dist/distributors/assignments-to-replicas.test.js +40 -0
- package/dist/distributors/messages-to-topic-partition-leaders.d.ts +17 -0
- package/dist/distributors/messages-to-topic-partition-leaders.js +15 -0
- package/dist/distributors/messages-to-topic-partition-leaders.test.d.ts +1 -0
- package/dist/distributors/messages-to-topic-partition-leaders.test.js +30 -0
- package/dist/distributors/partitioner.d.ts +7 -0
- package/dist/distributors/partitioner.js +23 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +26 -0
- package/dist/metadata.d.ts +24 -0
- package/dist/metadata.js +106 -0
- package/dist/producer/producer.d.ts +24 -0
- package/dist/producer/producer.js +131 -0
- package/{src/types.ts → dist/types.d.ts} +4 -4
- package/dist/types.js +2 -0
- package/{src/utils/api.ts → dist/utils/api.d.ts} +2 -4
- package/dist/utils/api.js +5 -0
- package/dist/utils/crypto.d.ts +8 -0
- package/dist/utils/crypto.js +18 -0
- package/dist/utils/decoder.d.ts +30 -0
- package/{src/utils/decoder.ts → dist/utils/decoder.js} +41 -57
- package/dist/utils/delay.d.ts +1 -0
- package/dist/utils/delay.js +5 -0
- package/dist/utils/encoder.d.ts +28 -0
- package/{src/utils/encoder.ts → dist/utils/encoder.js} +50 -66
- package/dist/utils/error.d.ts +11 -0
- package/dist/utils/error.js +27 -0
- package/dist/utils/logger.d.ts +9 -0
- package/dist/utils/logger.js +32 -0
- package/dist/utils/memo.d.ts +1 -0
- package/{src/utils/memo.ts → dist/utils/memo.js} +7 -3
- package/dist/utils/murmur2.d.ts +3 -0
- package/dist/utils/murmur2.js +40 -0
- package/dist/utils/retrier.d.ts +10 -0
- package/dist/utils/retrier.js +22 -0
- package/dist/utils/tracer.d.ts +5 -0
- package/dist/utils/tracer.js +39 -0
- package/package.json +11 -2
- package/.github/workflows/release.yml +0 -17
- package/.prettierrc +0 -8
- package/certs/ca.crt +0 -29
- package/certs/ca.key +0 -52
- package/certs/ca.srl +0 -1
- package/certs/kafka.crt +0 -29
- package/certs/kafka.csr +0 -26
- package/certs/kafka.key +0 -52
- package/certs/kafka.keystore.jks +0 -0
- package/certs/kafka.truststore.jks +0 -0
- package/docker-compose.yml +0 -104
- package/examples/package-lock.json +0 -31
- package/examples/package.json +0 -14
- package/examples/src/client.ts +0 -9
- package/examples/src/consumer.ts +0 -18
- package/examples/src/create-topic.ts +0 -44
- package/examples/src/producer.ts +0 -24
- package/examples/src/replicator.ts +0 -25
- package/examples/src/utils/delay.ts +0 -1
- package/examples/src/utils/json.ts +0 -1
- package/examples/tsconfig.json +0 -7
- package/log4j.properties +0 -95
- package/scripts/generate-certs.sh +0 -24
- package/src/__snapshots__/request-handler.test.ts.snap +0 -978
- package/src/api/create-topics.ts +0 -78
- package/src/api/delete-topics.ts +0 -42
- package/src/api/fetch.ts +0 -143
- package/src/api/heartbeat.ts +0 -33
- package/src/api/init-producer-id.ts +0 -35
- package/src/api/join-group.ts +0 -67
- package/src/api/leave-group.ts +0 -48
- package/src/api/list-offsets.ts +0 -65
- package/src/api/offset-commit.ts +0 -67
- package/src/api/offset-fetch.ts +0 -74
- package/src/api/sasl-authenticate.ts +0 -21
- package/src/api/sasl-handshake.ts +0 -16
- package/src/api/sync-group.ts +0 -54
- package/src/broker.ts +0 -74
- package/src/client.ts +0 -47
- package/src/cluster.ts +0 -87
- package/src/connection.ts +0 -143
- package/src/consumer/consumer-group.ts +0 -209
- package/src/consumer/consumer-metadata.ts +0 -14
- package/src/consumer/consumer.ts +0 -231
- package/src/consumer/fetch-manager.ts +0 -179
- package/src/consumer/fetcher.ts +0 -57
- package/src/consumer/offset-manager.ts +0 -93
- package/src/consumer/processor.ts +0 -47
- package/src/distributors/assignments-to-replicas.test.ts +0 -43
- package/src/distributors/messages-to-topic-partition-leaders.test.ts +0 -32
- package/src/distributors/messages-to-topic-partition-leaders.ts +0 -19
- package/src/index.ts +0 -4
- package/src/metadata.ts +0 -122
- package/src/producer/producer.ts +0 -132
- package/src/utils/debug.ts +0 -9
- package/src/utils/delay.ts +0 -1
- package/src/utils/error.ts +0 -21
- package/src/utils/retrier.ts +0 -39
- package/src/utils/tracer.ts +0 -31
- package/tsconfig.json +0 -17
package/dist/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.setTracer = void 0;
|
|
18
|
+
__exportStar(require("./api"), exports);
|
|
19
|
+
__exportStar(require("./auth"), exports);
|
|
20
|
+
__exportStar(require("./client"), exports);
|
|
21
|
+
__exportStar(require("./distributors/partitioner"), exports);
|
|
22
|
+
__exportStar(require("./types"), exports);
|
|
23
|
+
__exportStar(require("./utils/error"), exports);
|
|
24
|
+
__exportStar(require("./utils/logger"), exports);
|
|
25
|
+
var tracer_1 = require("./utils/tracer");
|
|
26
|
+
Object.defineProperty(exports, "setTracer", { enumerable: true, get: function () { return tracer_1.setTracer; } });
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Cluster } from './cluster';
|
|
2
|
+
type MetadataOptions = {
|
|
3
|
+
cluster: Cluster;
|
|
4
|
+
};
|
|
5
|
+
export declare class Metadata {
|
|
6
|
+
private options;
|
|
7
|
+
private topicPartitions;
|
|
8
|
+
private topicNameById;
|
|
9
|
+
private topicIdByName;
|
|
10
|
+
private leaderIdByTopicPartition;
|
|
11
|
+
private isrNodesByTopicPartition;
|
|
12
|
+
constructor(options: MetadataOptions);
|
|
13
|
+
getTopicPartitionLeaderIds(): Record<string, Record<number, number>>;
|
|
14
|
+
getTopicPartitionReplicaIds(): Record<string, Record<number, number[]>>;
|
|
15
|
+
getTopicPartitions(): Record<string, number[]>;
|
|
16
|
+
getTopicIdByName(name: string): string;
|
|
17
|
+
getTopicNameById(id: string): string;
|
|
18
|
+
fetchMetadataIfNecessary({ topics, allowTopicAutoCreation, }: {
|
|
19
|
+
topics: string[];
|
|
20
|
+
allowTopicAutoCreation: boolean;
|
|
21
|
+
}): Promise<void>;
|
|
22
|
+
private fetchMetadata;
|
|
23
|
+
}
|
|
24
|
+
export {};
|
package/dist/metadata.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.Metadata = void 0;
|
|
13
|
+
const api_1 = require("./api");
|
|
14
|
+
const delay_1 = require("./utils/delay");
|
|
15
|
+
const error_1 = require("./utils/error");
|
|
16
|
+
const tracer_1 = require("./utils/tracer");
|
|
17
|
+
const trace = (0, tracer_1.createTracer)('Metadata');
|
|
18
|
+
class Metadata {
|
|
19
|
+
options;
|
|
20
|
+
topicPartitions = {};
|
|
21
|
+
topicNameById = {};
|
|
22
|
+
topicIdByName = {};
|
|
23
|
+
leaderIdByTopicPartition = {};
|
|
24
|
+
isrNodesByTopicPartition = {};
|
|
25
|
+
constructor(options) {
|
|
26
|
+
this.options = options;
|
|
27
|
+
}
|
|
28
|
+
getTopicPartitionLeaderIds() {
|
|
29
|
+
return this.leaderIdByTopicPartition;
|
|
30
|
+
}
|
|
31
|
+
getTopicPartitionReplicaIds() {
|
|
32
|
+
return this.isrNodesByTopicPartition;
|
|
33
|
+
}
|
|
34
|
+
getTopicPartitions() {
|
|
35
|
+
return this.topicPartitions;
|
|
36
|
+
}
|
|
37
|
+
getTopicIdByName(name) {
|
|
38
|
+
return this.topicIdByName[name];
|
|
39
|
+
}
|
|
40
|
+
getTopicNameById(id) {
|
|
41
|
+
return this.topicNameById[id];
|
|
42
|
+
}
|
|
43
|
+
async fetchMetadataIfNecessary({ topics, allowTopicAutoCreation, }) {
|
|
44
|
+
const missingTopics = topics.filter((topic) => !this.topicPartitions[topic]);
|
|
45
|
+
if (!missingTopics.length) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
return await this.fetchMetadata({ topics: missingTopics, allowTopicAutoCreation });
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
if (error instanceof error_1.KafkaTSApiError &&
|
|
53
|
+
error.errorCode === api_1.API_ERROR.UNKNOWN_TOPIC_OR_PARTITION &&
|
|
54
|
+
allowTopicAutoCreation) {
|
|
55
|
+
// TODO: investigate if we can avoid the delay
|
|
56
|
+
await (0, delay_1.delay)(1000);
|
|
57
|
+
return await this.fetchMetadata({ topics: missingTopics, allowTopicAutoCreation });
|
|
58
|
+
}
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async fetchMetadata({ topics, allowTopicAutoCreation, }) {
|
|
63
|
+
const { cluster } = this.options;
|
|
64
|
+
const response = await cluster.sendRequest(api_1.API.METADATA, {
|
|
65
|
+
allowTopicAutoCreation,
|
|
66
|
+
includeTopicAuthorizedOperations: false,
|
|
67
|
+
topics: topics?.map((name) => ({ id: null, name })) ?? null,
|
|
68
|
+
});
|
|
69
|
+
this.topicPartitions = {
|
|
70
|
+
...this.topicPartitions,
|
|
71
|
+
...Object.fromEntries(response.topics.map((topic) => [
|
|
72
|
+
topic.name,
|
|
73
|
+
topic.partitions.map((partition) => partition.partitionIndex),
|
|
74
|
+
])),
|
|
75
|
+
};
|
|
76
|
+
this.topicNameById = {
|
|
77
|
+
...this.topicNameById,
|
|
78
|
+
...Object.fromEntries(response.topics.map((topic) => [topic.topicId, topic.name])),
|
|
79
|
+
};
|
|
80
|
+
this.topicIdByName = {
|
|
81
|
+
...this.topicIdByName,
|
|
82
|
+
...Object.fromEntries(response.topics.map((topic) => [topic.name, topic.topicId])),
|
|
83
|
+
};
|
|
84
|
+
this.leaderIdByTopicPartition = {
|
|
85
|
+
...this.leaderIdByTopicPartition,
|
|
86
|
+
...Object.fromEntries(response.topics.map((topic) => [
|
|
87
|
+
topic.name,
|
|
88
|
+
Object.fromEntries(topic.partitions.map((partition) => [partition.partitionIndex, partition.leaderId])),
|
|
89
|
+
])),
|
|
90
|
+
};
|
|
91
|
+
this.isrNodesByTopicPartition = {
|
|
92
|
+
...this.isrNodesByTopicPartition,
|
|
93
|
+
...Object.fromEntries(response.topics.map((topic) => [
|
|
94
|
+
topic.name,
|
|
95
|
+
Object.fromEntries(topic.partitions.map((partition) => [partition.partitionIndex, partition.isrNodes])),
|
|
96
|
+
])),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
exports.Metadata = Metadata;
|
|
101
|
+
__decorate([
|
|
102
|
+
trace(),
|
|
103
|
+
__metadata("design:type", Function),
|
|
104
|
+
__metadata("design:paramtypes", [Object]),
|
|
105
|
+
__metadata("design:returntype", Promise)
|
|
106
|
+
], Metadata.prototype, "fetchMetadataIfNecessary", null);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Cluster } from '../cluster';
|
|
2
|
+
import { Partitioner } from '../distributors/partitioner';
|
|
3
|
+
import { Message } from '../types';
|
|
4
|
+
export type ProducerOptions = {
|
|
5
|
+
allowTopicAutoCreation?: boolean;
|
|
6
|
+
partitioner?: Partitioner;
|
|
7
|
+
};
|
|
8
|
+
export declare class Producer {
|
|
9
|
+
private cluster;
|
|
10
|
+
private options;
|
|
11
|
+
private metadata;
|
|
12
|
+
private producerId;
|
|
13
|
+
private producerEpoch;
|
|
14
|
+
private sequences;
|
|
15
|
+
private partition;
|
|
16
|
+
constructor(cluster: Cluster, options: ProducerOptions);
|
|
17
|
+
send(messages: Message[], { acks }?: {
|
|
18
|
+
acks?: -1 | 1;
|
|
19
|
+
}): Promise<void>;
|
|
20
|
+
close(): Promise<void>;
|
|
21
|
+
private ensureConnected;
|
|
22
|
+
private initProducerId;
|
|
23
|
+
private nextSequence;
|
|
24
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.Producer = void 0;
|
|
13
|
+
const api_1 = require("../api");
|
|
14
|
+
const messages_to_topic_partition_leaders_1 = require("../distributors/messages-to-topic-partition-leaders");
|
|
15
|
+
const partitioner_1 = require("../distributors/partitioner");
|
|
16
|
+
const metadata_1 = require("../metadata");
|
|
17
|
+
const delay_1 = require("../utils/delay");
|
|
18
|
+
const memo_1 = require("../utils/memo");
|
|
19
|
+
const tracer_1 = require("../utils/tracer");
|
|
20
|
+
const trace = (0, tracer_1.createTracer)('Producer');
|
|
21
|
+
class Producer {
|
|
22
|
+
cluster;
|
|
23
|
+
options;
|
|
24
|
+
metadata;
|
|
25
|
+
producerId = 0n;
|
|
26
|
+
producerEpoch = 0;
|
|
27
|
+
sequences = {};
|
|
28
|
+
partition;
|
|
29
|
+
constructor(cluster, options) {
|
|
30
|
+
this.cluster = cluster;
|
|
31
|
+
this.options = {
|
|
32
|
+
...options,
|
|
33
|
+
allowTopicAutoCreation: options.allowTopicAutoCreation ?? false,
|
|
34
|
+
partitioner: options.partitioner ?? partitioner_1.defaultPartitioner,
|
|
35
|
+
};
|
|
36
|
+
this.metadata = new metadata_1.Metadata({ cluster });
|
|
37
|
+
this.partition = this.options.partitioner({ metadata: this.metadata });
|
|
38
|
+
}
|
|
39
|
+
async send(messages, { acks = -1 } = {}) {
|
|
40
|
+
await this.ensureConnected();
|
|
41
|
+
const { allowTopicAutoCreation } = this.options;
|
|
42
|
+
const defaultTimestamp = BigInt(Date.now());
|
|
43
|
+
const topics = Array.from(new Set(messages.map((message) => message.topic)));
|
|
44
|
+
await this.metadata.fetchMetadataIfNecessary({ topics, allowTopicAutoCreation });
|
|
45
|
+
const nodeTopicPartitionMessages = (0, messages_to_topic_partition_leaders_1.distributeMessagesToTopicPartitionLeaders)(messages.map((message) => ({ ...message, partition: this.partition(message) })), this.metadata.getTopicPartitionLeaderIds());
|
|
46
|
+
await Promise.all(Object.entries(nodeTopicPartitionMessages).map(([nodeId, topicPartitionMessages]) => this.cluster.sendRequestToNode(parseInt(nodeId))(api_1.API.PRODUCE, {
|
|
47
|
+
transactionalId: null,
|
|
48
|
+
acks,
|
|
49
|
+
timeoutMs: 5000,
|
|
50
|
+
topicData: Object.entries(topicPartitionMessages).map(([topic, partitionMessages]) => ({
|
|
51
|
+
name: topic,
|
|
52
|
+
partitionData: Object.entries(partitionMessages).map(([partition, messages]) => {
|
|
53
|
+
const partitionIndex = parseInt(partition);
|
|
54
|
+
let baseTimestamp;
|
|
55
|
+
let maxTimestamp;
|
|
56
|
+
messages.forEach(({ timestamp = defaultTimestamp }) => {
|
|
57
|
+
if (!baseTimestamp || timestamp < baseTimestamp) {
|
|
58
|
+
baseTimestamp = timestamp;
|
|
59
|
+
}
|
|
60
|
+
if (!maxTimestamp || timestamp > maxTimestamp) {
|
|
61
|
+
maxTimestamp = timestamp;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
const baseSequence = this.nextSequence(topic, partitionIndex, messages.length);
|
|
65
|
+
return {
|
|
66
|
+
index: partitionIndex,
|
|
67
|
+
baseOffset: 0n,
|
|
68
|
+
partitionLeaderEpoch: -1,
|
|
69
|
+
attributes: 0,
|
|
70
|
+
lastOffsetDelta: messages.length - 1,
|
|
71
|
+
baseTimestamp: baseTimestamp ?? 0n,
|
|
72
|
+
maxTimestamp: maxTimestamp ?? 0n,
|
|
73
|
+
producerId: this.producerId,
|
|
74
|
+
producerEpoch: 0,
|
|
75
|
+
baseSequence,
|
|
76
|
+
records: messages.map((message, index) => ({
|
|
77
|
+
attributes: 0,
|
|
78
|
+
timestampDelta: (message.timestamp ?? defaultTimestamp) - (baseTimestamp ?? 0n),
|
|
79
|
+
offsetDelta: index,
|
|
80
|
+
key: message.key ?? null,
|
|
81
|
+
value: message.value,
|
|
82
|
+
headers: Object.entries(message.headers ?? {}).map(([key, value]) => ({
|
|
83
|
+
key: Buffer.from(key),
|
|
84
|
+
value: Buffer.from(value),
|
|
85
|
+
})),
|
|
86
|
+
})),
|
|
87
|
+
};
|
|
88
|
+
}),
|
|
89
|
+
})),
|
|
90
|
+
})));
|
|
91
|
+
}
|
|
92
|
+
async close() {
|
|
93
|
+
await this.cluster.disconnect();
|
|
94
|
+
}
|
|
95
|
+
ensureConnected = (0, memo_1.memo)(async () => {
|
|
96
|
+
await this.cluster.connect();
|
|
97
|
+
await this.initProducerId();
|
|
98
|
+
});
|
|
99
|
+
async initProducerId() {
|
|
100
|
+
try {
|
|
101
|
+
const result = await this.cluster.sendRequest(api_1.API.INIT_PRODUCER_ID, {
|
|
102
|
+
transactionalId: null,
|
|
103
|
+
transactionTimeoutMs: 0,
|
|
104
|
+
producerId: this.producerId,
|
|
105
|
+
producerEpoch: this.producerEpoch,
|
|
106
|
+
});
|
|
107
|
+
this.producerId = result.producerId;
|
|
108
|
+
this.producerEpoch = result.producerEpoch;
|
|
109
|
+
this.sequences = {};
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
if (error.errorCode === api_1.API_ERROR.COORDINATOR_LOAD_IN_PROGRESS) {
|
|
113
|
+
await (0, delay_1.delay)(100);
|
|
114
|
+
return this.initProducerId();
|
|
115
|
+
}
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
nextSequence(topic, partition, messagesCount) {
|
|
120
|
+
this.sequences[topic] ??= {};
|
|
121
|
+
this.sequences[topic][partition] ??= 0;
|
|
122
|
+
return (this.sequences[topic][partition] += messagesCount || 1);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
exports.Producer = Producer;
|
|
126
|
+
__decorate([
|
|
127
|
+
trace(() => ({ root: true })),
|
|
128
|
+
__metadata("design:type", Function),
|
|
129
|
+
__metadata("design:paramtypes", [Array, Object]),
|
|
130
|
+
__metadata("design:returntype", Promise)
|
|
131
|
+
], Producer.prototype, "send", null);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
export type Message = {
|
|
2
3
|
topic: string;
|
|
3
|
-
partition
|
|
4
|
+
partition?: number;
|
|
4
5
|
offset?: bigint;
|
|
5
6
|
timestamp?: bigint;
|
|
6
|
-
key
|
|
7
|
-
value:
|
|
7
|
+
key?: Buffer | null;
|
|
8
|
+
value: Buffer | null;
|
|
8
9
|
headers?: Record<string, string>;
|
|
9
10
|
};
|
|
10
|
-
|
|
11
11
|
export type Batch = Required<Message>[];
|
package/dist/types.js
ADDED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { Decoder } from './decoder';
|
|
2
2
|
import { Encoder } from './encoder';
|
|
3
|
-
|
|
4
3
|
export type Api<Request, Response> = {
|
|
5
4
|
apiKey: number;
|
|
6
5
|
apiVersion: number;
|
|
7
6
|
request: (encoder: Encoder, body: Request) => Encoder;
|
|
8
|
-
response: (buffer: Decoder) => Response;
|
|
7
|
+
response: (buffer: Decoder) => Promise<Response> | Response;
|
|
9
8
|
};
|
|
10
|
-
|
|
11
|
-
export const createApi = <Request, Response>(api: Api<Request, Response>) => api;
|
|
9
|
+
export declare const createApi: <Request, Response>(api: Api<Request, Response>) => Api<Request, Response>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
export declare const generateNonce: () => string;
|
|
3
|
+
export declare const saltPassword: (password: string, salt: string, iterations: number, keyLength: number, digest: string) => Promise<Buffer>;
|
|
4
|
+
export declare const base64Encode: (input: Buffer | string) => string;
|
|
5
|
+
export declare const base64Decode: (input: string) => string;
|
|
6
|
+
export declare const hash: (data: Buffer, digest: string) => Buffer;
|
|
7
|
+
export declare const hmac: (key: Buffer, data: Buffer | string, digest: string) => Buffer;
|
|
8
|
+
export declare const xor: (a: Buffer, b: Buffer) => Buffer;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.xor = exports.hmac = exports.hash = exports.base64Decode = exports.base64Encode = exports.saltPassword = exports.generateNonce = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
const generateNonce = () => (0, crypto_1.randomBytes)(16).toString('base64').replace(/[\/=]/g, '');
|
|
6
|
+
exports.generateNonce = generateNonce;
|
|
7
|
+
const saltPassword = (password, salt, iterations, keyLength, digest) => new Promise((resolve, reject) => (0, crypto_1.pbkdf2)(password, salt, iterations, keyLength, digest, (err, key) => (err ? reject(err) : resolve(key))));
|
|
8
|
+
exports.saltPassword = saltPassword;
|
|
9
|
+
const base64Encode = (input) => Buffer.from(input).toString('base64');
|
|
10
|
+
exports.base64Encode = base64Encode;
|
|
11
|
+
const base64Decode = (input) => Buffer.from(input, 'base64').toString();
|
|
12
|
+
exports.base64Decode = base64Decode;
|
|
13
|
+
const hash = (data, digest) => (0, crypto_1.createHash)(digest).update(data).digest();
|
|
14
|
+
exports.hash = hash;
|
|
15
|
+
const hmac = (key, data, digest) => (0, crypto_1.createHmac)(digest, key).update(data).digest();
|
|
16
|
+
exports.hmac = hmac;
|
|
17
|
+
const xor = (a, b) => Buffer.from(a.map((byte, i) => byte ^ b[i]));
|
|
18
|
+
exports.xor = xor;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
export declare class Decoder {
|
|
3
|
+
private buffer;
|
|
4
|
+
private offset;
|
|
5
|
+
constructor(buffer: Buffer);
|
|
6
|
+
getOffset(): number;
|
|
7
|
+
getBufferLength(): number;
|
|
8
|
+
readInt8(): number;
|
|
9
|
+
readInt16(): number;
|
|
10
|
+
readInt32(): number;
|
|
11
|
+
readUInt32(): number;
|
|
12
|
+
readInt64(): bigint;
|
|
13
|
+
readUVarInt(): number;
|
|
14
|
+
readVarInt(): number;
|
|
15
|
+
readUVarLong(): bigint;
|
|
16
|
+
readVarLong(): bigint;
|
|
17
|
+
readString(): string | null;
|
|
18
|
+
readCompactString(): string | null;
|
|
19
|
+
readVarIntBuffer(): Buffer | null;
|
|
20
|
+
readUUID(): string;
|
|
21
|
+
readBoolean(): boolean;
|
|
22
|
+
readArray<T>(callback: (opts: Decoder) => T): T[];
|
|
23
|
+
readCompactArray<T>(callback: (opts: Decoder) => T): T[];
|
|
24
|
+
readVarIntArray<T>(callback: (opts: Decoder) => T): T[];
|
|
25
|
+
readRecords<T>(callback: (opts: Decoder) => T): T[];
|
|
26
|
+
read(length?: number): Buffer;
|
|
27
|
+
readBytes(): Buffer;
|
|
28
|
+
readCompactBytes(): Buffer | null;
|
|
29
|
+
readTagBuffer(): void;
|
|
30
|
+
}
|
|
@@ -1,47 +1,44 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Decoder = void 0;
|
|
4
|
+
class Decoder {
|
|
5
|
+
buffer;
|
|
6
|
+
offset = 0;
|
|
7
|
+
constructor(buffer) {
|
|
8
|
+
this.buffer = buffer;
|
|
9
|
+
}
|
|
10
|
+
getOffset() {
|
|
7
11
|
return this.offset;
|
|
8
12
|
}
|
|
9
|
-
|
|
10
|
-
public getBufferLength() {
|
|
13
|
+
getBufferLength() {
|
|
11
14
|
return this.buffer.length;
|
|
12
15
|
}
|
|
13
|
-
|
|
14
|
-
public readInt8() {
|
|
16
|
+
readInt8() {
|
|
15
17
|
const value = this.buffer.readInt8(this.offset);
|
|
16
18
|
this.offset += 1;
|
|
17
19
|
return value;
|
|
18
20
|
}
|
|
19
|
-
|
|
20
|
-
public readInt16() {
|
|
21
|
+
readInt16() {
|
|
21
22
|
const value = this.buffer.readInt16BE(this.offset);
|
|
22
23
|
this.offset += 2;
|
|
23
24
|
return value;
|
|
24
25
|
}
|
|
25
|
-
|
|
26
|
-
public readInt32() {
|
|
26
|
+
readInt32() {
|
|
27
27
|
const value = this.buffer.readInt32BE(this.offset);
|
|
28
28
|
this.offset += 4;
|
|
29
29
|
return value;
|
|
30
30
|
}
|
|
31
|
-
|
|
32
|
-
public readUInt32() {
|
|
31
|
+
readUInt32() {
|
|
33
32
|
const value = this.buffer.readUInt32BE(this.offset);
|
|
34
33
|
this.offset += 4;
|
|
35
34
|
return value;
|
|
36
35
|
}
|
|
37
|
-
|
|
38
|
-
public readInt64() {
|
|
36
|
+
readInt64() {
|
|
39
37
|
const value = this.buffer.readBigInt64BE(this.offset);
|
|
40
38
|
this.offset += 8;
|
|
41
39
|
return value;
|
|
42
40
|
}
|
|
43
|
-
|
|
44
|
-
public readUVarInt() {
|
|
41
|
+
readUVarInt() {
|
|
45
42
|
let result = 0;
|
|
46
43
|
let shift = 0;
|
|
47
44
|
let currentByte;
|
|
@@ -52,13 +49,11 @@ export class Decoder {
|
|
|
52
49
|
} while ((currentByte & 0x80) !== 0);
|
|
53
50
|
return result;
|
|
54
51
|
}
|
|
55
|
-
|
|
56
|
-
public readVarInt() {
|
|
52
|
+
readVarInt() {
|
|
57
53
|
const decodedValue = this.readUVarInt();
|
|
58
54
|
return (decodedValue >>> 1) ^ -(decodedValue & 1);
|
|
59
55
|
}
|
|
60
|
-
|
|
61
|
-
public readUVarLong() {
|
|
56
|
+
readUVarLong() {
|
|
62
57
|
let result = BigInt(0);
|
|
63
58
|
let shift = BigInt(0);
|
|
64
59
|
let currentByte;
|
|
@@ -69,72 +64,64 @@ export class Decoder {
|
|
|
69
64
|
} while ((currentByte & BigInt(0x80)) !== BigInt(0));
|
|
70
65
|
return result;
|
|
71
66
|
}
|
|
72
|
-
|
|
73
|
-
public readVarLong() {
|
|
67
|
+
readVarLong() {
|
|
74
68
|
const decodedValue = this.readUVarLong();
|
|
75
69
|
return (decodedValue >> BigInt(1)) ^ -(decodedValue & BigInt(1));
|
|
76
70
|
}
|
|
77
|
-
|
|
78
|
-
public readString() {
|
|
71
|
+
readString() {
|
|
79
72
|
const length = this.readInt16();
|
|
80
73
|
if (length < 0) {
|
|
81
74
|
return null;
|
|
82
75
|
}
|
|
83
|
-
|
|
84
76
|
const value = this.buffer.toString('utf-8', this.offset, this.offset + length);
|
|
85
77
|
this.offset += length;
|
|
86
78
|
return value;
|
|
87
79
|
}
|
|
88
|
-
|
|
89
|
-
public readCompactString() {
|
|
80
|
+
readCompactString() {
|
|
90
81
|
const length = this.readUVarInt() - 1;
|
|
91
82
|
if (length < 0) {
|
|
92
83
|
return null;
|
|
93
84
|
}
|
|
94
|
-
|
|
95
85
|
const value = this.buffer.toString('utf-8', this.offset, this.offset + length);
|
|
96
86
|
this.offset += length;
|
|
97
87
|
return value;
|
|
98
88
|
}
|
|
99
|
-
|
|
100
|
-
public readVarIntString() {
|
|
89
|
+
readVarIntBuffer() {
|
|
101
90
|
const length = this.readVarInt();
|
|
102
91
|
if (length < 0) {
|
|
103
92
|
return null;
|
|
104
93
|
}
|
|
105
|
-
|
|
106
|
-
const value = this.buffer.toString('utf-8', this.offset, this.offset + length);
|
|
94
|
+
const value = this.buffer.subarray(this.offset, this.offset + length);
|
|
107
95
|
this.offset += length;
|
|
108
96
|
return value;
|
|
109
97
|
}
|
|
110
|
-
|
|
111
|
-
public readUUID() {
|
|
98
|
+
readUUID() {
|
|
112
99
|
const value = this.buffer.toString('hex', this.offset, this.offset + 16);
|
|
113
100
|
this.offset += 16;
|
|
114
101
|
return value;
|
|
115
102
|
}
|
|
116
|
-
|
|
117
|
-
public readBoolean() {
|
|
103
|
+
readBoolean() {
|
|
118
104
|
const value = this.buffer.readInt8(this.offset) === 1;
|
|
119
105
|
this.offset += 1;
|
|
120
106
|
return value;
|
|
121
107
|
}
|
|
122
|
-
|
|
123
|
-
public readArray<T>(callback: (opts: Decoder) => T): T[] {
|
|
108
|
+
readArray(callback) {
|
|
124
109
|
const length = this.readInt32();
|
|
125
110
|
const results = Array.from({ length }).map(() => callback(this));
|
|
126
111
|
return results;
|
|
127
112
|
}
|
|
128
|
-
|
|
129
|
-
public readCompactArray<T>(callback: (opts: Decoder) => T): T[] {
|
|
113
|
+
readCompactArray(callback) {
|
|
130
114
|
const length = this.readUVarInt() - 1;
|
|
131
115
|
const results = Array.from({ length }).map(() => callback(this));
|
|
132
116
|
return results;
|
|
133
117
|
}
|
|
134
|
-
|
|
135
|
-
|
|
118
|
+
readVarIntArray(callback) {
|
|
119
|
+
const length = this.readVarInt();
|
|
120
|
+
const results = Array.from({ length }).map(() => callback(this));
|
|
121
|
+
return results;
|
|
122
|
+
}
|
|
123
|
+
readRecords(callback) {
|
|
136
124
|
const length = this.readInt32();
|
|
137
|
-
|
|
138
125
|
return Array.from({ length }).map(() => {
|
|
139
126
|
const size = this.readVarInt();
|
|
140
127
|
const child = new Decoder(this.buffer.subarray(this.offset, this.offset + size));
|
|
@@ -142,27 +129,24 @@ export class Decoder {
|
|
|
142
129
|
return callback(child);
|
|
143
130
|
});
|
|
144
131
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
this.offset += length;
|
|
132
|
+
read(length) {
|
|
133
|
+
const value = this.buffer.subarray(this.offset, length !== undefined ? this.offset + length : undefined);
|
|
134
|
+
this.offset += Buffer.byteLength(value);
|
|
149
135
|
return value;
|
|
150
136
|
}
|
|
151
|
-
|
|
152
|
-
public readBytes() {
|
|
137
|
+
readBytes() {
|
|
153
138
|
const length = this.readInt32();
|
|
154
139
|
return this.read(length);
|
|
155
140
|
}
|
|
156
|
-
|
|
157
|
-
public readCompactBytes() {
|
|
141
|
+
readCompactBytes() {
|
|
158
142
|
const length = this.readUVarInt() - 1;
|
|
159
143
|
if (length < 0) {
|
|
160
144
|
return null;
|
|
161
145
|
}
|
|
162
146
|
return this.read(length);
|
|
163
147
|
}
|
|
164
|
-
|
|
165
|
-
public readTagBuffer() {
|
|
148
|
+
readTagBuffer() {
|
|
166
149
|
this.readUVarInt();
|
|
167
150
|
}
|
|
168
151
|
}
|
|
152
|
+
exports.Decoder = Decoder;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const delay: (delayMs: number) => Promise<void>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
export declare class Encoder {
|
|
3
|
+
private chunks;
|
|
4
|
+
getChunks(): Buffer[];
|
|
5
|
+
getByteLength(): number;
|
|
6
|
+
write(...buffers: Buffer[]): this;
|
|
7
|
+
writeEncoder(encoder: Encoder): this;
|
|
8
|
+
writeInt8(value: number): this;
|
|
9
|
+
writeInt16(value: number): this;
|
|
10
|
+
writeInt32(value: number): this;
|
|
11
|
+
writeUInt32(value: number): this;
|
|
12
|
+
writeInt64(value: bigint): this;
|
|
13
|
+
writeUVarInt(value: number): this;
|
|
14
|
+
writeVarInt(value: number): this;
|
|
15
|
+
writeUVarLong(value: bigint): this;
|
|
16
|
+
writeVarLong(value: bigint): this;
|
|
17
|
+
writeString(value: string | null): this;
|
|
18
|
+
writeCompactString(value: string | null): this;
|
|
19
|
+
writeVarIntBuffer(buffer: Buffer | null): this;
|
|
20
|
+
writeUUID(value: string | null): this;
|
|
21
|
+
writeBoolean(value: boolean): this;
|
|
22
|
+
writeArray<T>(arr: T[], callback: (encoder: Encoder, item: T) => Encoder): this;
|
|
23
|
+
writeCompactArray<T>(arr: T[] | null, callback: (encoder: Encoder, item: T) => Encoder): this;
|
|
24
|
+
writeVarIntArray<T>(arr: T[], callback: (encoder: Encoder, item: T) => Encoder): this;
|
|
25
|
+
writeBytes(value: Buffer): this;
|
|
26
|
+
writeCompactBytes(value: Buffer): this;
|
|
27
|
+
value(): Buffer;
|
|
28
|
+
}
|