@platformatic/kafka 2.11.0 → 2.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/apis/definitions.d.ts +1 -1
- package/dist/apis/producer/produce-v10.d.ts +1 -0
- package/dist/apis/producer/produce-v10.js +26 -1
- package/dist/apis/producer/produce-v11.d.ts +1 -0
- package/dist/apis/producer/produce-v11.js +26 -1
- package/dist/apis/producer/produce-v7.d.ts +1 -0
- package/dist/apis/producer/produce-v7.js +23 -1
- package/dist/apis/producer/produce-v8.d.ts +1 -0
- package/dist/apis/producer/produce-v8.js +23 -1
- package/dist/apis/producer/produce-v9.d.ts +1 -0
- package/dist/apis/producer/produce-v9.js +26 -1
- package/dist/apis/producer/utils.d.ts +11 -0
- package/dist/apis/producer/utils.js +31 -0
- package/dist/clients/admin/admin.js +10 -13
- package/dist/clients/base/base.d.ts +1 -1
- package/dist/clients/base/base.js +6 -6
- package/dist/clients/base/options.d.ts +4 -0
- package/dist/clients/base/options.js +2 -1
- package/dist/clients/base/types.d.ts +1 -0
- package/dist/clients/consumer/consumer-protocol.d.ts +32 -0
- package/dist/clients/consumer/consumer-protocol.js +114 -0
- package/dist/clients/consumer/consumer.d.ts +3 -2
- package/dist/clients/consumer/consumer.js +305 -93
- package/dist/clients/consumer/index.d.ts +2 -0
- package/dist/clients/consumer/index.js +2 -0
- package/dist/clients/consumer/messages-stream.d.ts +4 -2
- package/dist/clients/consumer/messages-stream.js +126 -16
- package/dist/clients/consumer/partitions-assigners.d.ts +3 -0
- package/dist/clients/consumer/partitions-assigners.js +259 -0
- package/dist/clients/consumer/types.d.ts +11 -0
- package/dist/clients/producer/producer.d.ts +1 -1
- package/dist/clients/producer/producer.js +1 -1
- package/dist/errors.js +12 -1
- package/dist/network/connection.d.ts +1 -1
- package/dist/network/connection.js +83 -40
- package/dist/protocol/compression.d.ts +6 -0
- package/dist/protocol/compression.js +14 -1
- package/dist/protocol/records.d.ts +1 -0
- package/dist/protocol/records.js +40 -17
- package/dist/registries/confluent-schema-registry.d.ts +2 -1
- package/dist/registries/confluent-schema-registry.js +2 -1
- package/dist/symbols.d.ts +1 -0
- package/dist/symbols.js +1 -0
- package/dist/typescript-4/dist/apis/definitions.d.ts +1 -1
- package/dist/typescript-4/dist/apis/producer/produce-v10.d.ts +1 -0
- package/dist/typescript-4/dist/apis/producer/produce-v11.d.ts +1 -0
- package/dist/typescript-4/dist/apis/producer/produce-v7.d.ts +1 -0
- package/dist/typescript-4/dist/apis/producer/produce-v8.d.ts +1 -0
- package/dist/typescript-4/dist/apis/producer/produce-v9.d.ts +1 -0
- package/dist/typescript-4/dist/apis/producer/utils.d.ts +11 -0
- package/dist/typescript-4/dist/clients/base/base.d.ts +1 -1
- package/dist/typescript-4/dist/clients/base/options.d.ts +4 -0
- package/dist/typescript-4/dist/clients/base/types.d.ts +1 -0
- package/dist/typescript-4/dist/clients/consumer/consumer-protocol.d.ts +32 -0
- package/dist/typescript-4/dist/clients/consumer/consumer.d.ts +3 -2
- package/dist/typescript-4/dist/clients/consumer/index.d.ts +2 -0
- package/dist/typescript-4/dist/clients/consumer/messages-stream.d.ts +4 -2
- package/dist/typescript-4/dist/clients/consumer/partitions-assigners.d.ts +4 -1
- package/dist/typescript-4/dist/clients/consumer/types.d.ts +11 -0
- package/dist/typescript-4/dist/clients/producer/producer.d.ts +1 -1
- package/dist/typescript-4/dist/network/connection.d.ts +1 -1
- package/dist/typescript-4/dist/protocol/compression.d.ts +7 -1
- package/dist/typescript-4/dist/protocol/records.d.ts +1 -0
- package/dist/typescript-4/dist/registries/confluent-schema-registry.d.ts +2 -1
- package/dist/typescript-4/dist/symbols.d.ts +1 -0
- package/dist/version.js +1 -1
- package/package.json +5 -2
|
@@ -45,6 +45,7 @@ export class Connection extends TypedEventEmitter {
|
|
|
45
45
|
#correlationId;
|
|
46
46
|
#nextMessage;
|
|
47
47
|
#afterDrainRequests;
|
|
48
|
+
#payloadQueue;
|
|
48
49
|
#requestsQueue;
|
|
49
50
|
#inflightRequests;
|
|
50
51
|
#responseBuffer;
|
|
@@ -74,6 +75,7 @@ export class Connection extends TypedEventEmitter {
|
|
|
74
75
|
this.#correlationId = 0;
|
|
75
76
|
this.#nextMessage = 0;
|
|
76
77
|
this.#afterDrainRequests = [];
|
|
78
|
+
this.#payloadQueue = fastq((op, cb) => op(cb), 1);
|
|
77
79
|
this.#requestsQueue = fastq((op, cb) => op(cb), this.#options.maxInflights ?? defaultOptions.maxInflights);
|
|
78
80
|
this.#inflightRequests = new Map();
|
|
79
81
|
this.#responseBuffer = new DynamicBuffer();
|
|
@@ -274,45 +276,80 @@ export class Connection extends TypedEventEmitter {
|
|
|
274
276
|
apiVersion,
|
|
275
277
|
correlationId
|
|
276
278
|
});
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
279
|
+
this.#payloadQueue.push(payloadQueueCallback => {
|
|
280
|
+
let payloadQueueCompleted = false;
|
|
281
|
+
const completePayloadQueue = () => {
|
|
282
|
+
if (!payloadQueueCompleted) {
|
|
283
|
+
payloadQueueCompleted = true;
|
|
284
|
+
payloadQueueCallback(null);
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
const onPayloadError = (error) => {
|
|
288
|
+
diagnostic.error = error;
|
|
289
|
+
connectionsApiChannel.error.publish(diagnostic);
|
|
290
|
+
try {
|
|
291
|
+
callback(error);
|
|
292
|
+
}
|
|
293
|
+
finally {
|
|
294
|
+
completePayloadQueue();
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
const onPayload = (payload) => {
|
|
298
|
+
try {
|
|
299
|
+
const writer = Writer.create();
|
|
300
|
+
writer
|
|
301
|
+
.appendInt16(apiKey)
|
|
302
|
+
.appendInt16(apiVersion)
|
|
303
|
+
.appendInt32(correlationId)
|
|
304
|
+
.appendString(this.#clientId, false);
|
|
305
|
+
if (hasRequestHeaderTaggedFields) {
|
|
306
|
+
writer.appendTaggedFields();
|
|
307
|
+
}
|
|
308
|
+
writer.appendFrom(payload).prependLength();
|
|
309
|
+
const request = {
|
|
310
|
+
correlationId,
|
|
311
|
+
apiKey,
|
|
312
|
+
apiVersion,
|
|
313
|
+
parser: responseParser,
|
|
314
|
+
payload: writer.buffer,
|
|
315
|
+
callback: null, // Will be set later
|
|
316
|
+
hasResponseHeaderTaggedFields,
|
|
317
|
+
noResponse: payload.context.noResponse ?? false,
|
|
318
|
+
diagnostic,
|
|
319
|
+
timeoutHandle: null,
|
|
320
|
+
timedOut: false
|
|
321
|
+
};
|
|
322
|
+
this.#requestsQueue.push(fastQueueCallback => {
|
|
323
|
+
request.callback = fastQueueCallback;
|
|
324
|
+
if (!request.noResponse) {
|
|
325
|
+
request.timeoutHandle = setTimeout(this.#onRequestTimeout.bind(this, request), this.#options.requestTimeout);
|
|
326
|
+
}
|
|
327
|
+
if (this.#socketMustBeDrained) {
|
|
328
|
+
this.#afterDrainRequests.push(request);
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
return this.#sendRequest(request);
|
|
332
|
+
}, this.#onResponse.bind(this, request, callback));
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
onPayloadError(error);
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
completePayloadQueue();
|
|
339
|
+
};
|
|
340
|
+
try {
|
|
341
|
+
const payload = createPayload();
|
|
342
|
+
if (typeof payload.then === 'function') {
|
|
343
|
+
Promise.resolve(payload).then(onPayload, onPayloadError);
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
onPayload(payload);
|
|
347
|
+
}
|
|
309
348
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
return false;
|
|
349
|
+
catch (error) {
|
|
350
|
+
onPayloadError(error);
|
|
313
351
|
}
|
|
314
|
-
|
|
315
|
-
}, this.#onResponse.bind(this, request, callback));
|
|
352
|
+
}, () => { });
|
|
316
353
|
}
|
|
317
354
|
reauthenticate() {
|
|
318
355
|
if (!this.#options.sasl) {
|
|
@@ -332,7 +369,11 @@ export class Connection extends TypedEventEmitter {
|
|
|
332
369
|
}
|
|
333
370
|
#onRequestTimeout(request) {
|
|
334
371
|
request.timedOut = true;
|
|
335
|
-
request.
|
|
372
|
+
this.#inflightRequests.delete(request.correlationId);
|
|
373
|
+
this.#afterDrainRequests = this.#afterDrainRequests.filter(r => r !== request);
|
|
374
|
+
this.#status = ConnectionStatuses.CLOSING;
|
|
375
|
+
request.callback(new TimeoutError('Request timed out', { canRetry: true }), null);
|
|
376
|
+
this.#socket?.destroy();
|
|
336
377
|
}
|
|
337
378
|
#authenticate(host, port, diagnosticContext) {
|
|
338
379
|
if (this.#status === ConnectionStatuses.CONNECTING) {
|
|
@@ -628,12 +669,14 @@ export class Connection extends TypedEventEmitter {
|
|
|
628
669
|
this.emit('close');
|
|
629
670
|
const error = new NetworkError('Connection closed');
|
|
630
671
|
for (const request of this.#afterDrainRequests) {
|
|
631
|
-
if (!request.noResponse) {
|
|
672
|
+
if (!request.noResponse && !request.timedOut) {
|
|
632
673
|
request.callback(error, undefined);
|
|
633
674
|
}
|
|
634
675
|
}
|
|
635
676
|
for (const inflight of this.#inflightRequests.values()) {
|
|
636
|
-
inflight.
|
|
677
|
+
if (!inflight.timedOut) {
|
|
678
|
+
inflight.callback(error, undefined);
|
|
679
|
+
}
|
|
637
680
|
}
|
|
638
681
|
}
|
|
639
682
|
#onError(error) {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { DynamicBuffer } from '@platformatic/dynamic-buffer';
|
|
2
2
|
export type SyncCompressionPhase = (data: Buffer | DynamicBuffer) => Buffer;
|
|
3
|
+
export type AsyncCompressionPhase = (data: Buffer | DynamicBuffer) => Promise<Buffer>;
|
|
3
4
|
export type CompressionOperation = (data: Buffer) => Buffer;
|
|
4
5
|
export interface CompressionAlgorithmSpecification {
|
|
6
|
+
compress?: AsyncCompressionPhase;
|
|
5
7
|
compressSync: SyncCompressionPhase;
|
|
6
8
|
decompressSync: SyncCompressionPhase;
|
|
7
9
|
bitmask: number;
|
|
@@ -17,6 +19,7 @@ export declare const CompressionAlgorithms: {
|
|
|
17
19
|
export declare const allowedCompressionsAlgorithms: CompressionAlgorithmValue[];
|
|
18
20
|
export type CompressionAlgorithm = keyof typeof CompressionAlgorithms;
|
|
19
21
|
export type CompressionAlgorithmValue = (typeof CompressionAlgorithms)[keyof typeof CompressionAlgorithms];
|
|
22
|
+
declare function gzipAsync(data: Buffer | DynamicBuffer): Promise<Buffer>;
|
|
20
23
|
export declare const compressionsAlgorithms: {
|
|
21
24
|
readonly none: {
|
|
22
25
|
readonly compressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
@@ -25,6 +28,7 @@ export declare const compressionsAlgorithms: {
|
|
|
25
28
|
readonly available: true;
|
|
26
29
|
};
|
|
27
30
|
readonly gzip: {
|
|
31
|
+
readonly compress: typeof gzipAsync;
|
|
28
32
|
readonly compressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
29
33
|
readonly decompressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
30
34
|
readonly bitmask: 1;
|
|
@@ -56,6 +60,7 @@ export declare const compressionsAlgorithmsByBitmask: {
|
|
|
56
60
|
readonly bitmask: 0;
|
|
57
61
|
readonly available: true;
|
|
58
62
|
} | {
|
|
63
|
+
readonly compress: typeof gzipAsync;
|
|
59
64
|
readonly compressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
60
65
|
readonly decompressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
61
66
|
readonly bitmask: 1;
|
|
@@ -77,3 +82,4 @@ export declare const compressionsAlgorithmsByBitmask: {
|
|
|
77
82
|
readonly available: boolean;
|
|
78
83
|
};
|
|
79
84
|
};
|
|
85
|
+
export {};
|
|
@@ -2,7 +2,7 @@ import { DynamicBuffer } from '@platformatic/dynamic-buffer';
|
|
|
2
2
|
import { lz4Compress, lz4Decompress, snappyCompress, snappyDecompress } from '@platformatic/wasm-utils';
|
|
3
3
|
import zlib from 'node:zlib';
|
|
4
4
|
import { UnsupportedCompressionError } from "../errors.js";
|
|
5
|
-
const { zstdCompressSync, zstdDecompressSync, gzipSync, gunzipSync } = zlib;
|
|
5
|
+
const { gzip, zstdCompressSync, zstdDecompressSync, gzipSync, gunzipSync } = zlib;
|
|
6
6
|
export const CompressionAlgorithms = {
|
|
7
7
|
NONE: 'none',
|
|
8
8
|
GZIP: 'gzip',
|
|
@@ -14,6 +14,18 @@ export const allowedCompressionsAlgorithms = Object.values(CompressionAlgorithms
|
|
|
14
14
|
function ensureBuffer(data) {
|
|
15
15
|
return DynamicBuffer.isDynamicBuffer(data) ? data.buffer : data;
|
|
16
16
|
}
|
|
17
|
+
function gzipAsync(data) {
|
|
18
|
+
const { promise, resolve, reject } = Promise.withResolvers();
|
|
19
|
+
gzip(ensureBuffer(data), (error, result) => {
|
|
20
|
+
if (error) {
|
|
21
|
+
reject(error);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
resolve(result);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
return promise;
|
|
28
|
+
}
|
|
17
29
|
const snappyCompressSync = snappyCompress;
|
|
18
30
|
const lz4CompressFrameSync = lz4Compress;
|
|
19
31
|
const lz4DecompressFrameSync = lz4Decompress;
|
|
@@ -53,6 +65,7 @@ export const compressionsAlgorithms = {
|
|
|
53
65
|
available: true
|
|
54
66
|
},
|
|
55
67
|
gzip: {
|
|
68
|
+
compress: gzipAsync,
|
|
56
69
|
compressSync(data) {
|
|
57
70
|
return gzipSync(ensureBuffer(data));
|
|
58
71
|
},
|
|
@@ -123,5 +123,6 @@ export declare const messageSchema: {
|
|
|
123
123
|
export declare function createRecord(message: MessageRecord, offsetDelta: number, firstTimestamp: bigint): Writer;
|
|
124
124
|
export declare function readRecord(reader: Reader): KafkaRecord;
|
|
125
125
|
export declare function createRecordsBatch(messages: MessageRecord[], options?: Partial<CreateRecordsBatchOptions>): Writer;
|
|
126
|
+
export declare function createRecordsBatchAsync(messages: MessageRecord[], options?: Partial<CreateRecordsBatchOptions>): Promise<Writer>;
|
|
126
127
|
export declare function readRecordsBatch(reader: Reader): RecordsBatch;
|
|
127
128
|
export declare function readRecordsBatches(reader: Reader): RecordsBatch[];
|
package/dist/protocol/records.js
CHANGED
|
@@ -58,11 +58,11 @@ export function readRecord(reader) {
|
|
|
58
58
|
headers: reader.readVarIntArray(r => [r.readVarIntBytes(), r.readVarIntBytes()])
|
|
59
59
|
};
|
|
60
60
|
}
|
|
61
|
-
|
|
61
|
+
function prepareRecordsBatch(messages, options) {
|
|
62
62
|
const now = BigInt(Date.now());
|
|
63
63
|
const firstTimestamp = messages[0].timestamp ?? now;
|
|
64
64
|
let maxTimestamp = firstTimestamp;
|
|
65
|
-
|
|
65
|
+
const buffer = new DynamicBuffer();
|
|
66
66
|
for (let i = 0; i < messages.length; i++) {
|
|
67
67
|
let ts = messages[i].timestamp ?? now;
|
|
68
68
|
/* c8 ignore next 3 - Hard to test */
|
|
@@ -81,32 +81,34 @@ export function createRecordsBatch(messages, options = {}) {
|
|
|
81
81
|
const firstMessage = messages[0];
|
|
82
82
|
firstSequence = options.sequences.getWithDefault(`${firstMessage.topic}:${firstMessage.partition}`, 0);
|
|
83
83
|
}
|
|
84
|
-
// Set the transaction
|
|
85
84
|
if (options.transactionalId) {
|
|
86
85
|
attributes |= IS_TRANSACTIONAL;
|
|
87
86
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
87
|
+
return { attributes, buffer, firstSequence, firstTimestamp, maxTimestamp };
|
|
88
|
+
}
|
|
89
|
+
function getCompressionAlgorithm(compression) {
|
|
90
|
+
if ((compression ?? 'none') === 'none') {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
const algorithm = compressionsAlgorithms[compression];
|
|
94
|
+
if (!algorithm) {
|
|
95
|
+
throw new UnsupportedCompressionError(`Unsupported compression algorithm ${compression}`);
|
|
97
96
|
}
|
|
97
|
+
return algorithm;
|
|
98
|
+
}
|
|
99
|
+
function finalizeRecordsBatch(messages, options, prepared) {
|
|
98
100
|
const writer = Writer.create()
|
|
99
101
|
// Phase 1: Prepare the message from Attributes (included) to the end
|
|
100
|
-
.appendInt16(attributes)
|
|
102
|
+
.appendInt16(prepared.attributes)
|
|
101
103
|
// LastOffsetDelta, FirstTimestamp and MaxTimestamp are extracted from the messages
|
|
102
104
|
.appendInt32(messages.length - 1)
|
|
103
|
-
.appendInt64(BigInt(firstTimestamp))
|
|
104
|
-
.appendInt64(BigInt(maxTimestamp))
|
|
105
|
+
.appendInt64(BigInt(prepared.firstTimestamp))
|
|
106
|
+
.appendInt64(BigInt(prepared.maxTimestamp))
|
|
105
107
|
.appendInt64(options.producerId ?? -1n)
|
|
106
108
|
.appendInt16(options.producerEpoch ?? 0)
|
|
107
|
-
.appendInt32(firstSequence)
|
|
109
|
+
.appendInt32(prepared.firstSequence)
|
|
108
110
|
.appendInt32(messages.length) // Number of records
|
|
109
|
-
.appendFrom(buffer);
|
|
111
|
+
.appendFrom(prepared.buffer);
|
|
110
112
|
// Phase 2: Prepend the PartitionLeaderEpoch, Magic and CRC, then the Length and firstOffset, in reverse order
|
|
111
113
|
return (writer
|
|
112
114
|
.appendUnsignedInt32(crc32c(writer.dynamicBuffer), false)
|
|
@@ -116,6 +118,27 @@ export function createRecordsBatch(messages, options = {}) {
|
|
|
116
118
|
// FirstOffset is 0
|
|
117
119
|
.appendInt64(0n, false));
|
|
118
120
|
}
|
|
121
|
+
export function createRecordsBatch(messages, options = {}) {
|
|
122
|
+
const prepared = prepareRecordsBatch(messages, options);
|
|
123
|
+
const algorithm = getCompressionAlgorithm(options.compression);
|
|
124
|
+
if (algorithm) {
|
|
125
|
+
prepared.attributes |= algorithm.bitmask;
|
|
126
|
+
prepared.buffer = new DynamicBuffer(algorithm.compressSync(prepared.buffer.buffer));
|
|
127
|
+
}
|
|
128
|
+
return finalizeRecordsBatch(messages, options, prepared);
|
|
129
|
+
}
|
|
130
|
+
export async function createRecordsBatchAsync(messages, options = {}) {
|
|
131
|
+
const prepared = prepareRecordsBatch(messages, options);
|
|
132
|
+
const algorithm = getCompressionAlgorithm(options.compression);
|
|
133
|
+
if (algorithm) {
|
|
134
|
+
prepared.attributes |= algorithm.bitmask;
|
|
135
|
+
const compressed = algorithm.compress
|
|
136
|
+
? await algorithm.compress(prepared.buffer.buffer)
|
|
137
|
+
: algorithm.compressSync(prepared.buffer.buffer);
|
|
138
|
+
prepared.buffer = new DynamicBuffer(compressed);
|
|
139
|
+
}
|
|
140
|
+
return finalizeRecordsBatch(messages, options, prepared);
|
|
141
|
+
}
|
|
119
142
|
// TODO: Early bail out if there are not enough bytes to read all the records as it might be truncated
|
|
120
143
|
export function readRecordsBatch(reader) {
|
|
121
144
|
const initialPosition = reader.position;
|
|
@@ -4,7 +4,8 @@ import { type ConnectionOptions as TLSConnectionOptions } from 'node:tls';
|
|
|
4
4
|
import { type Root } from 'protobufjs';
|
|
5
5
|
import { type Callback } from '../apis/definitions.ts';
|
|
6
6
|
import { type BeforeDeserializationHook, type BeforeHookPayloadType, type BeforeSerializationHook, type Deserializers, type Serializers } from '../clients/serde.ts';
|
|
7
|
-
import {
|
|
7
|
+
import { UserError } from '../errors.ts';
|
|
8
|
+
import { type CredentialProvider } from '../network/connection.ts';
|
|
8
9
|
import { type MessageToConsume, type MessageToProduce } from '../protocol/records.ts';
|
|
9
10
|
import { AbstractSchemaRegistry } from './abstract.ts';
|
|
10
11
|
type ConfluentSchemaRegistryMessageToProduce = MessageToProduce<unknown, unknown, unknown, unknown>;
|
|
@@ -6,7 +6,8 @@ import avro from 'avsc';
|
|
|
6
6
|
import { createRequire } from 'node:module';
|
|
7
7
|
import { setTimeout as sleep } from 'node:timers/promises';
|
|
8
8
|
import { jsonDeserializer, jsonSerializer, stringDeserializer, stringSerializer } from "../clients/serde.js";
|
|
9
|
-
import {
|
|
9
|
+
import { MultipleErrors, NetworkError, TimeoutError, UnsupportedFormatError, UserError } from "../errors.js";
|
|
10
|
+
import { EMPTY_BUFFER } from "../protocol/definitions.js";
|
|
10
11
|
import { getCredential } from "../protocol/sasl/utils.js";
|
|
11
12
|
import { AbstractSchemaRegistry } from "./abstract.js";
|
|
12
13
|
const require = createRequire(import.meta.url);
|
package/dist/symbols.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export declare const kInstance: unique symbol;
|
|
2
2
|
export declare const kRefreshOffsetsAndFetch: unique symbol;
|
|
3
3
|
export declare const kAutocommit: unique symbol;
|
|
4
|
+
export declare const kUpdateCommittedOffset: unique symbol;
|
|
4
5
|
export declare const kGetFetchNode: unique symbol;
|
|
5
6
|
export declare const kDeserializationError: unique symbol;
|
|
6
7
|
export declare const kTransaction: unique symbol;
|
package/dist/symbols.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
export const kInstance = Symbol('plt.kafka.base.instance');
|
|
3
3
|
export const kRefreshOffsetsAndFetch = Symbol('plt.kafka.messagesStream.refreshOffsetsAndFetch');
|
|
4
4
|
export const kAutocommit = Symbol('plt.kafka.messagesStream.autocommit');
|
|
5
|
+
export const kUpdateCommittedOffset = Symbol('plt.kafka.messagesStream.updateCommittedOffset');
|
|
5
6
|
export const kGetFetchNode = Symbol('plt.kafka.consumer.getFetchNode');
|
|
6
7
|
export const kDeserializationError = Symbol('plt.kafka.messagesStream.deserializationError');
|
|
7
8
|
export const kTransaction = Symbol('plt.kafka.producer.transactions');
|
|
@@ -4,7 +4,7 @@ import { type Reader } from "../protocol/reader";
|
|
|
4
4
|
import { type Writer } from "../protocol/writer";
|
|
5
5
|
export type Callback<ReturnType> = (error: Error | null, payload?: ReturnType) => void;
|
|
6
6
|
export type CallbackArguments<ReturnType> = [cb: Callback<ReturnType>];
|
|
7
|
-
export type RequestCreator = (...args: any[]) => Writer
|
|
7
|
+
export type RequestCreator = (...args: any[]) => Writer | Promise<Writer>;
|
|
8
8
|
export type ResponseParser<ReturnType> = (correlationId: number, apiKey: number, apiVersion: number, reader: Reader) => ReturnType | Promise<ReturnType>;
|
|
9
9
|
export type ResponseErrorWithLocation = [string, [number, NullableString]];
|
|
10
10
|
export type APIWithCallback<RequestArguments extends Array<unknown>, ResponseType> = (connection: Connection, ...args: [...RequestArguments, ...Partial<CallbackArguments<ResponseType>>]) => void;
|
|
@@ -37,5 +37,6 @@ export interface ProduceResponse {
|
|
|
37
37
|
nodeEndpoints?: ProduceResponseNodeEndpoint[];
|
|
38
38
|
}
|
|
39
39
|
export declare function createRequest(acks: number | undefined, timeout: number | undefined, topicData: MessageRecord[], options?: Partial<CreateRecordsBatchOptions>): Writer;
|
|
40
|
+
export declare function createRequestAsync(acks: number | undefined, timeout: number | undefined, topicData: MessageRecord[], options?: Partial<CreateRecordsBatchOptions>): Promise<Writer>;
|
|
40
41
|
export declare function parseResponse(_correlationId: number, apiKey: number, apiVersion: number, reader: Reader): ProduceResponse;
|
|
41
42
|
export declare const api: import("../definitions").API<[acks: number | undefined, timeout: number | undefined, topicData: MessageRecord[], options?: Partial<CreateRecordsBatchOptions> | undefined], boolean | ProduceResponse>;
|
|
@@ -37,5 +37,6 @@ export interface ProduceResponse {
|
|
|
37
37
|
nodeEndpoints?: ProduceResponseNodeEndpoint[];
|
|
38
38
|
}
|
|
39
39
|
export declare function createRequest(acks: number | undefined, timeout: number | undefined, topicData: MessageRecord[], options?: Partial<CreateRecordsBatchOptions>): Writer;
|
|
40
|
+
export declare function createRequestAsync(acks: number | undefined, timeout: number | undefined, topicData: MessageRecord[], options?: Partial<CreateRecordsBatchOptions>): Promise<Writer>;
|
|
40
41
|
export declare function parseResponse(_correlationId: number, apiKey: number, apiVersion: number, reader: Reader): ProduceResponse;
|
|
41
42
|
export declare const api: import("../definitions").API<[acks: number | undefined, timeout: number | undefined, topicData: MessageRecord[], options?: Partial<CreateRecordsBatchOptions> | undefined], boolean | ProduceResponse>;
|
|
@@ -25,5 +25,6 @@ export interface ProduceResponse {
|
|
|
25
25
|
throttleTimeMs: number;
|
|
26
26
|
}
|
|
27
27
|
export declare function createRequest(acks: number | undefined, timeout: number | undefined, topicData: MessageRecord[], options?: Partial<CreateRecordsBatchOptions>): Writer;
|
|
28
|
+
export declare function createRequestAsync(acks: number | undefined, timeout: number | undefined, topicData: MessageRecord[], options?: Partial<CreateRecordsBatchOptions>): Promise<Writer>;
|
|
28
29
|
export declare function parseResponse(_correlationId: number, apiKey: number, apiVersion: number, reader: Reader): ProduceResponse;
|
|
29
30
|
export declare const api: import("../definitions").API<[acks: number | undefined, timeout: number | undefined, topicData: MessageRecord[], options?: Partial<CreateRecordsBatchOptions> | undefined], boolean | ProduceResponse>;
|
|
@@ -25,5 +25,6 @@ export interface ProduceResponse {
|
|
|
25
25
|
throttleTimeMs: number;
|
|
26
26
|
}
|
|
27
27
|
export declare function createRequest(acks: number | undefined, timeout: number | undefined, topicData: MessageRecord[], options?: Partial<CreateRecordsBatchOptions>): Writer;
|
|
28
|
+
export declare function createRequestAsync(acks: number | undefined, timeout: number | undefined, topicData: MessageRecord[], options?: Partial<CreateRecordsBatchOptions>): Promise<Writer>;
|
|
28
29
|
export declare function parseResponse(_correlationId: number, apiKey: number, apiVersion: number, reader: Reader): ProduceResponse;
|
|
29
30
|
export declare const api: import("../definitions").API<[acks: number | undefined, timeout: number | undefined, topicData: MessageRecord[], options?: Partial<CreateRecordsBatchOptions> | undefined], boolean | ProduceResponse>;
|
|
@@ -25,5 +25,6 @@ export interface ProduceResponse {
|
|
|
25
25
|
throttleTimeMs: number;
|
|
26
26
|
}
|
|
27
27
|
export declare function createRequest(acks: number | undefined, timeout: number | undefined, topicData: MessageRecord[], options?: Partial<CreateRecordsBatchOptions>): Writer;
|
|
28
|
+
export declare function createRequestAsync(acks: number | undefined, timeout: number | undefined, topicData: MessageRecord[], options?: Partial<CreateRecordsBatchOptions>): Promise<Writer>;
|
|
28
29
|
export declare function parseResponse(_correlationId: number, apiKey: number, apiVersion: number, reader: Reader): ProduceResponse;
|
|
29
30
|
export declare const api: import("../definitions").API<[acks: number | undefined, timeout: number | undefined, topicData: MessageRecord[], options?: Partial<CreateRecordsBatchOptions> | undefined], boolean | ProduceResponse>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type CreateRecordsBatchOptions, type MessageRecord } from "../../protocol/records";
|
|
2
|
+
import { type Writer } from "../../protocol/writer";
|
|
3
|
+
export interface EncodedProducePartition {
|
|
4
|
+
partition: number;
|
|
5
|
+
records: Writer;
|
|
6
|
+
}
|
|
7
|
+
export interface EncodedProduceTopic {
|
|
8
|
+
topic: string;
|
|
9
|
+
partitions: EncodedProducePartition[];
|
|
10
|
+
}
|
|
11
|
+
export declare function encodeProduceTopicData(topicData: MessageRecord[], options: Partial<CreateRecordsBatchOptions>): Promise<EncodedProduceTopic[]>;
|
|
@@ -84,7 +84,7 @@ export declare class Base<OptionsType extends BaseOptions = BaseOptions, EventsT
|
|
|
84
84
|
[kMetadata](options: MetadataOptions, callback: CallbackWithPromise<ClusterMetadata>): void;
|
|
85
85
|
[kCheckNotClosed](callback: CallbackWithPromise<any>): boolean;
|
|
86
86
|
clearMetadata(): void;
|
|
87
|
-
[kPerformWithRetry]<ReturnType>(operationId: string, operation: (callback: Callback<ReturnType>, attempt: number) => void, callback: CallbackWithPromise<ReturnType>, attempt?: number, errors?: Error[], shouldSkipRetry?: (e: Error) => boolean): void | Promise<ReturnType>;
|
|
87
|
+
[kPerformWithRetry]<ReturnType>(operationId: string, operation: (callback: Callback<ReturnType>, attempt: number) => void, callback: CallbackWithPromise<ReturnType>, attempt?: number, errors?: Error[], shouldSkipRetry?: (e: Error) => boolean, retryLimit?: number): void | Promise<ReturnType>;
|
|
88
88
|
[kPerformDeduplicated]<ReturnType>(operationId: string, operation: (callback: CallbackWithPromise<ReturnType>) => void, callback: CallbackWithPromise<ReturnType>): void | Promise<ReturnType>;
|
|
89
89
|
[kGetApi]<RequestArguments extends Array<unknown>, ResponseType>(name: string, callback: Callback<API<RequestArguments, ResponseType>>): void;
|
|
90
90
|
[kGetConnection](broker: Broker, callback: Callback<Connection>): void;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type GroupAssignment } from "./types";
|
|
2
|
+
export declare const CONSUMER_PROTOCOL_LOWEST_VERSION = 0;
|
|
3
|
+
export declare const CONSUMER_PROTOCOL_HIGHEST_VERSION = 3;
|
|
4
|
+
export interface ConsumerProtocolSubscriptionData {
|
|
5
|
+
version: number;
|
|
6
|
+
topics: string[];
|
|
7
|
+
userData: Buffer;
|
|
8
|
+
ownedPartitions: GroupAssignment[];
|
|
9
|
+
generationId: number;
|
|
10
|
+
rackId: string | null;
|
|
11
|
+
}
|
|
12
|
+
export interface ConsumerProtocolAssignmentData {
|
|
13
|
+
version: number;
|
|
14
|
+
assignedPartitions: GroupAssignment[];
|
|
15
|
+
userData: Buffer;
|
|
16
|
+
}
|
|
17
|
+
export declare function encodeConsumerProtocolSubscription(data: {
|
|
18
|
+
version: number;
|
|
19
|
+
topics: string[];
|
|
20
|
+
userData?: Buffer | string;
|
|
21
|
+
ownedPartitions?: GroupAssignment[];
|
|
22
|
+
generationId?: number;
|
|
23
|
+
rackId?: string | null;
|
|
24
|
+
}): Buffer;
|
|
25
|
+
export declare function decodeConsumerProtocolSubscription(buffer: Buffer): ConsumerProtocolSubscriptionData;
|
|
26
|
+
export declare function decodeCooperativeStickyGeneration(userData: Buffer): number;
|
|
27
|
+
export declare function encodeConsumerProtocolAssignment(data: {
|
|
28
|
+
version: number;
|
|
29
|
+
assignedPartitions: GroupAssignment[];
|
|
30
|
+
userData?: Buffer | string | null;
|
|
31
|
+
}): Buffer;
|
|
32
|
+
export declare function decodeConsumerProtocolAssignment(buffer: Buffer): ConsumerProtocolAssignmentData;
|
|
@@ -6,12 +6,13 @@ import { Base, type BaseEvents, kCreateConnectionPool } from "../base/base";
|
|
|
6
6
|
import { type ClusterMetadata } from "../base/types";
|
|
7
7
|
import { MessagesStream } from "./messages-stream";
|
|
8
8
|
import { TopicsMap } from "./topics-map";
|
|
9
|
-
import { type CommitOptions, type ConsumeOptions, type ConsumerGroupJoinPayload, type ConsumerGroupLeavePayload, type ConsumerGroupRebalancePayload, type ConsumerHeartbeatErrorPayload, type ConsumerHeartbeatPayload, type ConsumerHeartbeatStalledPayload, type ConsumerOptions, type FetchOptions, type GetLagOptions, type GroupAssignment, type GroupOptions, type ListCommitsOptions, type ListOffsetsOptions, type Offsets, type OffsetsWithTimestamps } from "./types";
|
|
9
|
+
import { type CommitOptions, type ConsumeOptions, type ConsumerGroupJoinPayload, type ConsumerGroupLeavePayload, type ConsumerGroupAutocommitErrorPayload, type ConsumerGroupRebalancePayload, type ConsumerHeartbeatErrorPayload, type ConsumerHeartbeatPayload, type ConsumerHeartbeatStalledPayload, type ConsumerOptions, type FetchOptions, type GetLagOptions, type GroupAssignment, type GroupOptions, type ListCommitsOptions, type ListOffsetsOptions, type Offsets, type OffsetsWithTimestamps } from "./types";
|
|
10
10
|
export interface ConsumerEvents extends BaseEvents {
|
|
11
11
|
'consumer:group:join': (payload: ConsumerGroupJoinPayload) => void;
|
|
12
12
|
'consumer:group:leave': (payload: ConsumerGroupLeavePayload) => void;
|
|
13
13
|
'consumer:group:rejoin': () => void;
|
|
14
14
|
'consumer:group:rebalance': (payload: ConsumerGroupRebalancePayload) => void;
|
|
15
|
+
'consumer:group:autocommit:error': (payload: ConsumerGroupAutocommitErrorPayload) => void;
|
|
15
16
|
'consumer:heartbeat:start': (payload?: ConsumerHeartbeatPayload) => void;
|
|
16
17
|
'consumer:heartbeat:cancel': (payload: ConsumerHeartbeatPayload) => void;
|
|
17
18
|
'consumer:heartbeat:end': (payload?: ConsumerHeartbeatPayload) => void;
|
|
@@ -33,8 +34,8 @@ export declare class Consumer<Key = Buffer, Value = Buffer, HeaderKey = Buffer,
|
|
|
33
34
|
get lastHeartbeat(): Date | null;
|
|
34
35
|
get coordinatorId(): number | null;
|
|
35
36
|
get streamContext(): unknown;
|
|
36
|
-
close(force: boolean | CallbackWithPromise<void>, callback?: CallbackWithPromise<void>): void;
|
|
37
37
|
close(force?: boolean): Promise<void>;
|
|
38
|
+
close(force: boolean | CallbackWithPromise<void>, callback?: CallbackWithPromise<void>): void;
|
|
38
39
|
isActive(): boolean;
|
|
39
40
|
consume(options: ConsumeOptions<Key, Value, HeaderKey, HeaderValue>, callback: CallbackWithPromise<MessagesStream<Key, Value, HeaderKey, HeaderValue>>): void;
|
|
40
41
|
consume(options: ConsumeOptions<Key, Value, HeaderKey, HeaderValue>): Promise<MessagesStream<Key, Value, HeaderKey, HeaderValue>>;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Readable } from 'node:stream';
|
|
2
2
|
import { type CallbackWithPromise } from "../../apis/callbacks";
|
|
3
|
+
import type { Callback } from "../../apis/definitions";
|
|
3
4
|
import type { ConnectionPool } from "../../network/connection-pool";
|
|
4
5
|
import { type Message } from "../../protocol/records";
|
|
5
|
-
import { kAutocommit, kInstance, kRefreshOffsetsAndFetch } from "../../symbols";
|
|
6
|
+
import { kAutocommit, kInstance, kRefreshOffsetsAndFetch, kUpdateCommittedOffset } from "../../symbols";
|
|
6
7
|
import { kConnections, kInspect } from "../base/base";
|
|
7
8
|
import type { Consumer } from "./consumer";
|
|
8
9
|
import { type CommitOptionsPartition, type ConsumeOptions } from "./types";
|
|
@@ -79,7 +80,8 @@ export declare class MessagesStream<Key, Value, HeaderKey, HeaderValue> extends
|
|
|
79
80
|
_construct(callback: (error?: Error) => void): void;
|
|
80
81
|
_destroy(error: Error | null, callback: (error?: Error | null) => void): void;
|
|
81
82
|
_read(): void;
|
|
82
|
-
[
|
|
83
|
+
[kUpdateCommittedOffset](topic: string, partition: number, offset: bigint): void;
|
|
84
|
+
[kAutocommit](callback?: Callback<void>): void;
|
|
83
85
|
[kRefreshOffsetsAndFetch](): void;
|
|
84
86
|
[kInspect](...args: unknown[]): void;
|
|
85
87
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
import { type ClusterMetadata } from "../base/types";
|
|
2
2
|
import { type ExtendedGroupProtocolSubscription, type GroupPartitionsAssignments } from "./types";
|
|
3
|
-
export declare
|
|
3
|
+
export declare const ROUNDROBIN_ASSIGNOR = "roundrobin";
|
|
4
|
+
export declare const COOPERATIVE_STICKY_ASSIGNOR = "cooperative-sticky";
|
|
5
|
+
export declare function roundRobinAssigner(_current: string, members: Map<string, ExtendedGroupProtocolSubscription>, topics: Set<string>, metadata: ClusterMetadata): GroupPartitionsAssignments[];
|
|
6
|
+
export declare function cooperativeStickyAssigner(_current: string, members: Map<string, ExtendedGroupProtocolSubscription>, topics: Set<string>, metadata: ClusterMetadata): GroupPartitionsAssignments[];
|
|
@@ -11,6 +11,10 @@ export interface GroupProtocolSubscription {
|
|
|
11
11
|
version: number;
|
|
12
12
|
metadata?: Buffer | string;
|
|
13
13
|
}
|
|
14
|
+
export interface TopicPartitionAssignment {
|
|
15
|
+
topic: string;
|
|
16
|
+
partition: number;
|
|
17
|
+
}
|
|
14
18
|
export interface GroupAssignment {
|
|
15
19
|
topic: string;
|
|
16
20
|
partitions: number[];
|
|
@@ -21,6 +25,9 @@ export interface GroupPartitionsAssignments {
|
|
|
21
25
|
}
|
|
22
26
|
export interface ExtendedGroupProtocolSubscription extends Omit<GroupProtocolSubscription, 'name'> {
|
|
23
27
|
topics?: string[];
|
|
28
|
+
ownedPartitions?: GroupAssignment[];
|
|
29
|
+
generationId?: number;
|
|
30
|
+
rackId?: string | null;
|
|
24
31
|
memberId: string;
|
|
25
32
|
}
|
|
26
33
|
export type Offsets = Map<string, bigint[]>;
|
|
@@ -163,6 +170,10 @@ export interface ConsumerGroupLeavePayload {
|
|
|
163
170
|
export interface ConsumerGroupRebalancePayload {
|
|
164
171
|
groupId: string;
|
|
165
172
|
}
|
|
173
|
+
export interface ConsumerGroupAutocommitErrorPayload {
|
|
174
|
+
groupId: string;
|
|
175
|
+
error: Error;
|
|
176
|
+
}
|
|
166
177
|
export interface ConsumerHeartbeatPayload {
|
|
167
178
|
groupId?: string;
|
|
168
179
|
memberId?: string | null;
|
|
@@ -15,8 +15,8 @@ export declare class Producer<Key = Buffer, Value = Buffer, HeaderKey = Buffer,
|
|
|
15
15
|
get transaction(): Transaction<Key, Value, HeaderKey, HeaderValue> | undefined;
|
|
16
16
|
get coordinatorId(): number | undefined;
|
|
17
17
|
get streamsCount(): number;
|
|
18
|
-
close(force: boolean | CallbackWithPromise<void>, callback?: CallbackWithPromise<void>): void;
|
|
19
18
|
close(force?: boolean): Promise<void>;
|
|
19
|
+
close(force: boolean | CallbackWithPromise<void>, callback?: CallbackWithPromise<void>): void;
|
|
20
20
|
initIdempotentProducer(options: ProduceOptions<Key, Value, HeaderKey, HeaderValue>, callback: CallbackWithPromise<ProducerInfo>): void;
|
|
21
21
|
initIdempotentProducer(options: ProduceOptions<Key, Value, HeaderKey, HeaderValue>): Promise<ProducerInfo>;
|
|
22
22
|
send(options: SendOptions<Key, Value, HeaderKey, HeaderValue> & {
|
|
@@ -94,6 +94,6 @@ export declare class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
94
94
|
ready(): Promise<void>;
|
|
95
95
|
close(callback: CallbackWithPromise<void>): void;
|
|
96
96
|
close(): Promise<void>;
|
|
97
|
-
send<ReturnType>(apiKey: number, apiVersion: number, createPayload: () => Writer
|
|
97
|
+
send<ReturnType>(apiKey: number, apiVersion: number, createPayload: () => Writer | Promise<Writer>, responseParser: ResponseParser<ReturnType>, hasRequestHeaderTaggedFields: boolean, hasResponseHeaderTaggedFields: boolean, callback: Callback<ReturnType>): void;
|
|
98
98
|
reauthenticate(): void;
|
|
99
99
|
}
|