@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.
Files changed (68) hide show
  1. package/README.md +6 -0
  2. package/dist/apis/definitions.d.ts +1 -1
  3. package/dist/apis/producer/produce-v10.d.ts +1 -0
  4. package/dist/apis/producer/produce-v10.js +26 -1
  5. package/dist/apis/producer/produce-v11.d.ts +1 -0
  6. package/dist/apis/producer/produce-v11.js +26 -1
  7. package/dist/apis/producer/produce-v7.d.ts +1 -0
  8. package/dist/apis/producer/produce-v7.js +23 -1
  9. package/dist/apis/producer/produce-v8.d.ts +1 -0
  10. package/dist/apis/producer/produce-v8.js +23 -1
  11. package/dist/apis/producer/produce-v9.d.ts +1 -0
  12. package/dist/apis/producer/produce-v9.js +26 -1
  13. package/dist/apis/producer/utils.d.ts +11 -0
  14. package/dist/apis/producer/utils.js +31 -0
  15. package/dist/clients/admin/admin.js +10 -13
  16. package/dist/clients/base/base.d.ts +1 -1
  17. package/dist/clients/base/base.js +6 -6
  18. package/dist/clients/base/options.d.ts +4 -0
  19. package/dist/clients/base/options.js +2 -1
  20. package/dist/clients/base/types.d.ts +1 -0
  21. package/dist/clients/consumer/consumer-protocol.d.ts +32 -0
  22. package/dist/clients/consumer/consumer-protocol.js +114 -0
  23. package/dist/clients/consumer/consumer.d.ts +3 -2
  24. package/dist/clients/consumer/consumer.js +305 -93
  25. package/dist/clients/consumer/index.d.ts +2 -0
  26. package/dist/clients/consumer/index.js +2 -0
  27. package/dist/clients/consumer/messages-stream.d.ts +4 -2
  28. package/dist/clients/consumer/messages-stream.js +126 -16
  29. package/dist/clients/consumer/partitions-assigners.d.ts +3 -0
  30. package/dist/clients/consumer/partitions-assigners.js +259 -0
  31. package/dist/clients/consumer/types.d.ts +11 -0
  32. package/dist/clients/producer/producer.d.ts +1 -1
  33. package/dist/clients/producer/producer.js +1 -1
  34. package/dist/errors.js +12 -1
  35. package/dist/network/connection.d.ts +1 -1
  36. package/dist/network/connection.js +83 -40
  37. package/dist/protocol/compression.d.ts +6 -0
  38. package/dist/protocol/compression.js +14 -1
  39. package/dist/protocol/records.d.ts +1 -0
  40. package/dist/protocol/records.js +40 -17
  41. package/dist/registries/confluent-schema-registry.d.ts +2 -1
  42. package/dist/registries/confluent-schema-registry.js +2 -1
  43. package/dist/symbols.d.ts +1 -0
  44. package/dist/symbols.js +1 -0
  45. package/dist/typescript-4/dist/apis/definitions.d.ts +1 -1
  46. package/dist/typescript-4/dist/apis/producer/produce-v10.d.ts +1 -0
  47. package/dist/typescript-4/dist/apis/producer/produce-v11.d.ts +1 -0
  48. package/dist/typescript-4/dist/apis/producer/produce-v7.d.ts +1 -0
  49. package/dist/typescript-4/dist/apis/producer/produce-v8.d.ts +1 -0
  50. package/dist/typescript-4/dist/apis/producer/produce-v9.d.ts +1 -0
  51. package/dist/typescript-4/dist/apis/producer/utils.d.ts +11 -0
  52. package/dist/typescript-4/dist/clients/base/base.d.ts +1 -1
  53. package/dist/typescript-4/dist/clients/base/options.d.ts +4 -0
  54. package/dist/typescript-4/dist/clients/base/types.d.ts +1 -0
  55. package/dist/typescript-4/dist/clients/consumer/consumer-protocol.d.ts +32 -0
  56. package/dist/typescript-4/dist/clients/consumer/consumer.d.ts +3 -2
  57. package/dist/typescript-4/dist/clients/consumer/index.d.ts +2 -0
  58. package/dist/typescript-4/dist/clients/consumer/messages-stream.d.ts +4 -2
  59. package/dist/typescript-4/dist/clients/consumer/partitions-assigners.d.ts +4 -1
  60. package/dist/typescript-4/dist/clients/consumer/types.d.ts +11 -0
  61. package/dist/typescript-4/dist/clients/producer/producer.d.ts +1 -1
  62. package/dist/typescript-4/dist/network/connection.d.ts +1 -1
  63. package/dist/typescript-4/dist/protocol/compression.d.ts +7 -1
  64. package/dist/typescript-4/dist/protocol/records.d.ts +1 -0
  65. package/dist/typescript-4/dist/registries/confluent-schema-registry.d.ts +2 -1
  66. package/dist/typescript-4/dist/symbols.d.ts +1 -0
  67. package/dist/version.js +1 -1
  68. 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
- const writer = Writer.create();
278
- writer.appendInt16(apiKey).appendInt16(apiVersion).appendInt32(correlationId).appendString(this.#clientId, false);
279
- if (hasRequestHeaderTaggedFields) {
280
- writer.appendTaggedFields();
281
- }
282
- let payload;
283
- try {
284
- payload = createPayload();
285
- }
286
- catch (err) {
287
- diagnostic.error = err;
288
- connectionsApiChannel.error.publish(diagnostic);
289
- return callback(err);
290
- }
291
- writer.appendFrom(payload).prependLength();
292
- const request = {
293
- correlationId,
294
- apiKey,
295
- apiVersion,
296
- parser: responseParser,
297
- payload: writer.buffer,
298
- callback: null, // Will be set later
299
- hasResponseHeaderTaggedFields,
300
- noResponse: payload.context.noResponse ?? false,
301
- diagnostic,
302
- timeoutHandle: null,
303
- timedOut: false
304
- };
305
- this.#requestsQueue.push(fastQueueCallback => {
306
- request.callback = fastQueueCallback;
307
- if (!request.noResponse) {
308
- request.timeoutHandle = setTimeout(this.#onRequestTimeout.bind(this, request), this.#options.requestTimeout);
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
- if (this.#socketMustBeDrained) {
311
- this.#afterDrainRequests.push(request);
312
- return false;
349
+ catch (error) {
350
+ onPayloadError(error);
313
351
  }
314
- return this.#sendRequest(request);
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.callback(new TimeoutError('Request timed out'), null);
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.callback(error, undefined);
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[];
@@ -58,11 +58,11 @@ export function readRecord(reader) {
58
58
  headers: reader.readVarIntArray(r => [r.readVarIntBytes(), r.readVarIntBytes()])
59
59
  };
60
60
  }
61
- export function createRecordsBatch(messages, options = {}) {
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
- let buffer = new DynamicBuffer();
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
- // Set the compression, if any
89
- if ((options.compression ?? 'none') !== 'none') {
90
- const algorithm = compressionsAlgorithms[options.compression];
91
- if (!algorithm) {
92
- throw new UnsupportedCompressionError(`Unsupported compression algorithm ${options.compression}`);
93
- }
94
- attributes |= algorithm.bitmask;
95
- const compressed = algorithm.compressSync(buffer.buffer);
96
- buffer = new DynamicBuffer(compressed);
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 { type CredentialProvider, UserError } from '../index.ts';
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 { EMPTY_BUFFER, MultipleErrors, NetworkError, TimeoutError, UnsupportedFormatError, UserError } from "../index.js";
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;
@@ -199,6 +199,10 @@ export declare const metadataOptionsSchema: {
199
199
  type: string;
200
200
  minimum: number;
201
201
  };
202
+ retries: {
203
+ type: string;
204
+ minimum: number;
205
+ };
202
206
  };
203
207
  additionalProperties: boolean;
204
208
  };
@@ -48,4 +48,5 @@ export interface MetadataOptions {
48
48
  autocreateTopics?: boolean;
49
49
  forceUpdate?: boolean;
50
50
  metadataMaxAge?: number;
51
+ retries?: number;
51
52
  }
@@ -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,5 +1,7 @@
1
1
  export * from "./consumer";
2
+ export * from "./consumer-protocol";
2
3
  export * from "./messages-stream";
3
4
  export * from "./options";
5
+ export * from "./partitions-assigners";
4
6
  export * from "./topics-map";
5
7
  export * from "./types";
@@ -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
- [kAutocommit](): void;
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 function roundRobinAssigner(_current: string, members: Map<string, ExtendedGroupProtocolSubscription>, topics: Set<string>, metadata: ClusterMetadata): GroupPartitionsAssignments[];
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, responseParser: ResponseParser<ReturnType>, hasRequestHeaderTaggedFields: boolean, hasResponseHeaderTaggedFields: boolean, callback: Callback<ReturnType>): void;
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
  }