@platformatic/kafka 1.28.0 → 1.30.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 (64) hide show
  1. package/README.md +14 -8
  2. package/dist/apis/admin/alter-partition-reassignments-v0.d.ts +2 -2
  3. package/dist/apis/admin/alter-partition-reassignments-v0.js +1 -1
  4. package/dist/apis/admin/alter-partition-reassignments-v1.d.ts +30 -0
  5. package/dist/apis/admin/alter-partition-reassignments-v1.js +71 -0
  6. package/dist/apis/admin/describe-cluster-v0.d.ts +2 -2
  7. package/dist/apis/admin/describe-cluster-v0.js +1 -1
  8. package/dist/apis/admin/index.d.ts +2 -0
  9. package/dist/apis/admin/index.js +2 -0
  10. package/dist/apis/admin/list-groups-v4.d.ts +2 -2
  11. package/dist/apis/admin/list-groups-v4.js +1 -1
  12. package/dist/apis/admin/list-transactions-v0.d.ts +3 -2
  13. package/dist/apis/admin/list-transactions-v0.js +1 -1
  14. package/dist/apis/admin/list-transactions-v1.d.ts +3 -2
  15. package/dist/apis/admin/list-transactions-v1.js +1 -1
  16. package/dist/apis/admin/list-transactions-v2.d.ts +20 -0
  17. package/dist/apis/admin/list-transactions-v2.js +49 -0
  18. package/dist/apis/consumer/consumer-group-heartbeat-v0.d.ts +2 -2
  19. package/dist/apis/consumer/consumer-group-heartbeat-v0.js +1 -1
  20. package/dist/apis/consumer/consumer-group-heartbeat-v1.d.ts +27 -0
  21. package/dist/apis/consumer/consumer-group-heartbeat-v1.js +70 -0
  22. package/dist/apis/consumer/index.d.ts +1 -0
  23. package/dist/apis/consumer/index.js +1 -0
  24. package/dist/apis/consumer/join-group-v6.d.ts +2 -2
  25. package/dist/apis/consumer/join-group-v6.js +1 -1
  26. package/dist/apis/consumer/join-group-v7.d.ts +2 -2
  27. package/dist/apis/consumer/join-group-v7.js +1 -1
  28. package/dist/apis/consumer/offset-commit-v8.d.ts +2 -2
  29. package/dist/apis/consumer/sync-group-v4.d.ts +2 -2
  30. package/dist/apis/consumer/sync-group-v4.js +1 -1
  31. package/dist/clients/admin/admin.d.ts +3 -1
  32. package/dist/clients/admin/admin.js +88 -7
  33. package/dist/clients/admin/options.d.ts +43 -0
  34. package/dist/clients/admin/options.js +33 -0
  35. package/dist/clients/admin/types.d.ts +19 -0
  36. package/dist/clients/base/base.js +6 -1
  37. package/dist/clients/consumer/consumer.js +17 -3
  38. package/dist/clients/consumer/messages-stream.js +5 -0
  39. package/dist/clients/producer/producer.js +4 -0
  40. package/dist/network/connection.js +13 -2
  41. package/dist/protocol/sasl/scram-sha.d.ts +2 -2
  42. package/dist/protocol/sasl/scram-sha.js +35 -27
  43. package/dist/registries/abstract.js +4 -0
  44. package/dist/typescript-4/dist/apis/admin/alter-partition-reassignments-v0.d.ts +2 -2
  45. package/dist/typescript-4/dist/apis/admin/alter-partition-reassignments-v1.d.ts +30 -0
  46. package/dist/typescript-4/dist/apis/admin/describe-cluster-v0.d.ts +2 -2
  47. package/dist/typescript-4/dist/apis/admin/index.d.ts +2 -0
  48. package/dist/typescript-4/dist/apis/admin/list-groups-v4.d.ts +2 -2
  49. package/dist/typescript-4/dist/apis/admin/list-transactions-v0.d.ts +3 -2
  50. package/dist/typescript-4/dist/apis/admin/list-transactions-v1.d.ts +3 -2
  51. package/dist/typescript-4/dist/apis/admin/list-transactions-v2.d.ts +20 -0
  52. package/dist/typescript-4/dist/apis/consumer/consumer-group-heartbeat-v0.d.ts +2 -2
  53. package/dist/typescript-4/dist/apis/consumer/consumer-group-heartbeat-v1.d.ts +27 -0
  54. package/dist/typescript-4/dist/apis/consumer/index.d.ts +1 -0
  55. package/dist/typescript-4/dist/apis/consumer/join-group-v6.d.ts +2 -2
  56. package/dist/typescript-4/dist/apis/consumer/join-group-v7.d.ts +2 -2
  57. package/dist/typescript-4/dist/apis/consumer/offset-commit-v8.d.ts +2 -2
  58. package/dist/typescript-4/dist/apis/consumer/sync-group-v4.d.ts +2 -2
  59. package/dist/typescript-4/dist/clients/admin/admin.d.ts +3 -1
  60. package/dist/typescript-4/dist/clients/admin/options.d.ts +43 -0
  61. package/dist/typescript-4/dist/clients/admin/types.d.ts +19 -0
  62. package/dist/typescript-4/dist/protocol/sasl/scram-sha.d.ts +2 -2
  63. package/dist/version.js +1 -1
  64. package/package.json +2 -2
@@ -4,7 +4,7 @@ import { adminAclsChannel, adminClientQuotasChannel, adminConfigsChannel, adminC
4
4
  import { MultipleErrors } from "../../errors.js";
5
5
  import { Reader } from "../../protocol/reader.js";
6
6
  import { Base, kAfterCreate, kCheckNotClosed, kConnections, kGetApi, kGetBootstrapConnection, kGetConnection, kMetadata, kOptions, kPerformDeduplicated, kPerformWithRetry, kValidateOptions } from "../base/base.js";
7
- import { adminListOffsetsOptionsValidator, alterClientQuotasOptionsValidator, alterConfigsOptionsValidator, alterConsumerGroupOffsetsOptionsValidator, createAclsOptionsValidator, createPartitionsOptionsValidator, createTopicsOptionsValidator, deleteAclsOptionsValidator, deleteConsumerGroupOffsetsOptionsValidator, deleteGroupsOptionsValidator, deleteTopicsOptionsValidator, describeAclsOptionsValidator, describeClientQuotasOptionsValidator, describeConfigsOptionsValidator, describeGroupsOptionsValidator, describeLogDirsOptionsValidator, incrementalAlterConfigsOptionsValidator, listConsumerGroupOffsetsOptionsValidator, listGroupsOptionsValidator, listTopicsOptionsValidator, removeMembersFromConsumerGroupOptionsValidator } from "./options.js";
7
+ import { adminListOffsetsOptionsValidator, alterClientQuotasOptionsValidator, alterConfigsOptionsValidator, alterConsumerGroupOffsetsOptionsValidator, createAclsOptionsValidator, createPartitionsOptionsValidator, createTopicsOptionsValidator, deleteAclsOptionsValidator, deleteConsumerGroupOffsetsOptionsValidator, deleteRecordsOptionsValidator, deleteGroupsOptionsValidator, deleteTopicsOptionsValidator, describeAclsOptionsValidator, describeClientQuotasOptionsValidator, describeConfigsOptionsValidator, describeGroupsOptionsValidator, describeLogDirsOptionsValidator, incrementalAlterConfigsOptionsValidator, listConsumerGroupOffsetsOptionsValidator, listGroupsOptionsValidator, listTopicsOptionsValidator, removeMembersFromConsumerGroupOptionsValidator } from "./options.js";
8
8
  export class Admin extends Base {
9
9
  #controller = null;
10
10
  constructor(options) {
@@ -334,6 +334,21 @@ export class Admin extends Base {
334
334
  adminOffsetsChannel.traceCallback(this.#listOffsets, 1, createDiagnosticContext({ client: this, operation: 'listOffsets', options }), this, options, callback);
335
335
  return callback[kCallbackPromise];
336
336
  }
337
+ deleteRecords(options, callback) {
338
+ if (!callback) {
339
+ callback = createPromisifiedCallback();
340
+ }
341
+ if (this[kCheckNotClosed](callback)) {
342
+ return callback[kCallbackPromise];
343
+ }
344
+ const validationError = this[kValidateOptions](options, deleteRecordsOptionsValidator, '/options', false);
345
+ if (validationError) {
346
+ callback(validationError);
347
+ return callback[kCallbackPromise];
348
+ }
349
+ adminOffsetsChannel.traceCallback(this.#deleteRecords, 1, createDiagnosticContext({ client: this, operation: 'deleteRecords', options }), this, options, callback);
350
+ return callback[kCallbackPromise];
351
+ }
337
352
  #getControllerConnection(callback) {
338
353
  if (this.#controller) {
339
354
  this[kConnections].get(this.#controller, callback);
@@ -518,12 +533,7 @@ export class Admin extends Base {
518
533
  return;
519
534
  }
520
535
  /* c8 ignore next 5 */
521
- if (api.version === 4) {
522
- api(connection, options.states ?? [], retryCallback);
523
- }
524
- else {
525
- api(connection, options.states ?? [], options.types, retryCallback);
526
- }
536
+ api(connection, options.states ?? [], options.types, retryCallback);
527
537
  });
528
538
  }, concurrentCallback, 0);
529
539
  });
@@ -1276,6 +1286,77 @@ export class Admin extends Base {
1276
1286
  })));
1277
1287
  }, 0);
1278
1288
  }
1289
+ #deleteRecords(options, callback) {
1290
+ this[kMetadata]({ topics: options.topics.map(topic => topic.name) }, (error, metadata) => {
1291
+ if (error) {
1292
+ callback(error);
1293
+ return;
1294
+ }
1295
+ const requestsByLeader = new Map();
1296
+ for (const topic of options.topics) {
1297
+ for (const partition of topic.partitions) {
1298
+ const { leader } = metadata.topics.get(topic.name).partitions[partition.partition];
1299
+ let leaderRequests = requestsByLeader.get(leader);
1300
+ if (!leaderRequests) {
1301
+ leaderRequests = new Map();
1302
+ requestsByLeader.set(leader, leaderRequests);
1303
+ }
1304
+ let topicRequest = leaderRequests.get(topic.name);
1305
+ if (!topicRequest) {
1306
+ topicRequest = { name: topic.name, partitions: [] };
1307
+ leaderRequests.set(topic.name, topicRequest);
1308
+ }
1309
+ topicRequest.partitions.push({
1310
+ partitionIndex: partition.partition,
1311
+ offset: partition.offset
1312
+ });
1313
+ }
1314
+ }
1315
+ const requests = new Map();
1316
+ for (const [leader, topics] of requestsByLeader) {
1317
+ requests.set(leader, Array.from(topics.values()));
1318
+ }
1319
+ runConcurrentCallbacks('Deleting records failed.', requests, ([leader, requests], concurrentCallback) => {
1320
+ this[kGetConnection](metadata.brokers.get(leader), (error, connection) => {
1321
+ if (error) {
1322
+ concurrentCallback(error);
1323
+ return;
1324
+ }
1325
+ this[kPerformWithRetry]('deleteRecords', retryCallback => {
1326
+ this[kGetApi]('DeleteRecords', (error, api) => {
1327
+ if (error) {
1328
+ retryCallback(error);
1329
+ return;
1330
+ }
1331
+ api(connection, Array.from(requests.values()), this[kOptions].timeout, retryCallback);
1332
+ });
1333
+ }, concurrentCallback, 0);
1334
+ });
1335
+ }, (error, responses) => {
1336
+ if (error) {
1337
+ callback(error);
1338
+ return;
1339
+ }
1340
+ const deletedRecordsByTopic = new Map();
1341
+ for (const response of responses) {
1342
+ for (const topic of response.topics) {
1343
+ let topicDeletedRecords = deletedRecordsByTopic.get(topic.name);
1344
+ if (!topicDeletedRecords) {
1345
+ topicDeletedRecords = { name: topic.name, partitions: [] };
1346
+ deletedRecordsByTopic.set(topic.name, topicDeletedRecords);
1347
+ }
1348
+ for (const partition of topic.partitions) {
1349
+ topicDeletedRecords.partitions.push({
1350
+ partition: partition.partitionIndex,
1351
+ lowWatermark: partition.lowWatermark
1352
+ });
1353
+ }
1354
+ }
1355
+ }
1356
+ callback(null, Array.from(deletedRecordsByTopic.values()));
1357
+ });
1358
+ });
1359
+ }
1279
1360
  #listOffsets(options, callback) {
1280
1361
  this[kMetadata]({ topics: options.topics.map(topic => topic.name) }, (error, metadata) => {
1281
1362
  if (error) {
@@ -484,6 +484,46 @@ export declare const deleteConsumerGroupOffsetsOptionsSchema: {
484
484
  required: string[];
485
485
  additionalProperties: boolean;
486
486
  };
487
+ export declare const deleteRecordsOptionsSchema: {
488
+ type: string;
489
+ properties: {
490
+ topics: {
491
+ type: string;
492
+ items: {
493
+ type: string;
494
+ properties: {
495
+ name: {
496
+ type: string;
497
+ minLength: number;
498
+ };
499
+ partitions: {
500
+ type: string;
501
+ items: {
502
+ type: string;
503
+ properties: {
504
+ partition: {
505
+ type: string;
506
+ minimum: number;
507
+ };
508
+ offset: {
509
+ bigint: boolean;
510
+ };
511
+ };
512
+ required: string[];
513
+ additionalProperties: boolean;
514
+ };
515
+ minItems: number;
516
+ };
517
+ };
518
+ required: string[];
519
+ additionalProperties: boolean;
520
+ };
521
+ minItems: number;
522
+ };
523
+ };
524
+ required: string[];
525
+ additionalProperties: boolean;
526
+ };
487
527
  export declare const describeConfigsOptionsSchema: {
488
528
  type: string;
489
529
  properties: {
@@ -881,6 +921,9 @@ export declare const alterConsumerGroupOffsetsOptionsValidator: import("ajv").Va
881
921
  export declare const deleteConsumerGroupOffsetsOptionsValidator: import("ajv").ValidateFunction<{
882
922
  [x: string]: {};
883
923
  }>;
924
+ export declare const deleteRecordsOptionsValidator: import("ajv").ValidateFunction<{
925
+ [x: string]: {};
926
+ }>;
884
927
  export declare const listConsumerGroupOffsetsOptionsValidator: import("ajv").ValidateFunction<{
885
928
  [x: string]: {};
886
929
  }>;
@@ -343,6 +343,38 @@ export const deleteConsumerGroupOffsetsOptionsSchema = {
343
343
  required: ['groupId', 'topics'],
344
344
  additionalProperties: false
345
345
  };
346
+ export const deleteRecordsOptionsSchema = {
347
+ type: 'object',
348
+ properties: {
349
+ topics: {
350
+ type: 'array',
351
+ items: {
352
+ type: 'object',
353
+ properties: {
354
+ name: { type: 'string', minLength: 1 },
355
+ partitions: {
356
+ type: 'array',
357
+ items: {
358
+ type: 'object',
359
+ properties: {
360
+ partition: { type: 'number', minimum: 0 },
361
+ offset: { bigint: true }
362
+ },
363
+ required: ['partition', 'offset'],
364
+ additionalProperties: false
365
+ },
366
+ minItems: 1
367
+ }
368
+ },
369
+ required: ['name', 'partitions'],
370
+ additionalProperties: false
371
+ },
372
+ minItems: 1
373
+ }
374
+ },
375
+ required: ['topics'],
376
+ additionalProperties: false
377
+ };
346
378
  export const describeConfigsOptionsSchema = {
347
379
  type: 'object',
348
380
  properties: {
@@ -568,6 +600,7 @@ export const alterClientQuotasOptionsValidator = ajv.compile(alterClientQuotasOp
568
600
  export const describeLogDirsOptionsValidator = ajv.compile(describeLogDirsOptionsSchema);
569
601
  export const alterConsumerGroupOffsetsOptionsValidator = ajv.compile(alterConsumerGroupOffsetsOptionsSchema);
570
602
  export const deleteConsumerGroupOffsetsOptionsValidator = ajv.compile(deleteConsumerGroupOffsetsOptionsSchema);
603
+ export const deleteRecordsOptionsValidator = ajv.compile(deleteRecordsOptionsSchema);
571
604
  export const listConsumerGroupOffsetsOptionsValidator = ajv.compile(listConsumerGroupOffsetsOptionsSchema);
572
605
  export const describeConfigsOptionsValidator = ajv.compile(describeConfigsOptionsSchema);
573
606
  export const alterConfigsOptionsValidator = ajv.compile(alterConfigsOptionsSchema);
@@ -139,6 +139,25 @@ export interface DeleteConsumerGroupOffsetsOptions {
139
139
  partitionIndexes: number[];
140
140
  }[];
141
141
  }
142
+ export interface DeleteRecordsPartitionOffset {
143
+ partition: number;
144
+ offset: bigint;
145
+ }
146
+ export interface DeleteRecordsTopic {
147
+ name: string;
148
+ partitions: DeleteRecordsPartitionOffset[];
149
+ }
150
+ export interface DeleteRecordsOptions {
151
+ topics: DeleteRecordsTopic[];
152
+ }
153
+ export interface DeletedRecordsPartition {
154
+ partition: number;
155
+ lowWatermark: bigint;
156
+ }
157
+ export interface DeletedRecordsTopic {
158
+ name: string;
159
+ partitions: DeletedRecordsPartition[];
160
+ }
142
161
  export interface DescribeConfigsOptions {
143
162
  resources: DescribeConfigsRequestResource[];
144
163
  includeSynonyms?: boolean;
@@ -312,7 +312,12 @@ export class Base extends TypedEventEmitter {
312
312
  this[kConnections].get(broker, callback);
313
313
  }
314
314
  [kGetBootstrapConnection](callback) {
315
- this[kConnections].getFirstAvailable(this[kBootstrapBrokers], callback);
315
+ if (!this.#metadata) {
316
+ this[kConnections].getFirstAvailable(this[kBootstrapBrokers], callback);
317
+ return;
318
+ }
319
+ const discovered = Array.from(this.#metadata.brokers.values());
320
+ this[kConnections].getFirstAvailable([...this[kBootstrapBrokers], ...discovered], callback);
316
321
  }
317
322
  [kValidateOptions](target, validator, targetName, throwOnErrors = true) {
318
323
  if (!this[kOptions].strict) {
@@ -1,3 +1,4 @@
1
+ import { randomUUID } from 'node:crypto';
1
2
  import { createPromisifiedCallback, kCallbackPromise, runConcurrentCallbacks } from "../../apis/callbacks.js";
2
3
  import { FetchIsolationLevels, FindCoordinatorKeyTypes } from "../../apis/enumerations.js";
3
4
  import { consumerCommitsChannel, consumerConsumesChannel, consumerFetchesChannel, consumerGroupChannel, consumerHeartbeatChannel, consumerLagChannel, consumerOffsetsChannel, createDiagnosticContext } from "../../diagnostic.js";
@@ -700,8 +701,9 @@ export class Consumer extends Base {
700
701
  groupCallback(error);
701
702
  return;
702
703
  }
703
- api(connection, this.groupId, this.memberId || '', this.#memberEpoch, this.groupInstanceId, null, // rackId
704
- options.rebalanceTimeout, this.topics.current, this.#groupRemoteAssignor, this.#assignments, groupCallback);
704
+ const memberId = this.#getConsumerGroupHeartbeatMemberId(api.version);
705
+ api(connection, this.groupId, memberId, this.#memberEpoch, this.groupInstanceId, null, // rackId
706
+ options.rebalanceTimeout, this.topics.current, null, this.#groupRemoteAssignor, this.#assignments, groupCallback);
705
707
  });
706
708
  }, (error, response) => {
707
709
  if (this[kClosed]) {
@@ -849,10 +851,12 @@ export class Consumer extends Base {
849
851
  groupCallback(error);
850
852
  return;
851
853
  }
852
- api(connection, this.groupId, this.memberId, -1, // memberEpoch = -1 signals leave
854
+ const memberId = this.#getConsumerGroupHeartbeatMemberId(api.version);
855
+ api(connection, this.groupId, memberId, -1, // memberEpoch = -1 signals leave
853
856
  this.groupInstanceId, null, // rackId
854
857
  0, // rebalanceTimeout
855
858
  [], // subscribedTopicNames
859
+ null, // subscribedTopicRegex
856
860
  this.#groupRemoteAssignor, [], // topicPartitions
857
861
  groupCallback);
858
862
  });
@@ -865,6 +869,16 @@ export class Consumer extends Base {
865
869
  callback(null);
866
870
  });
867
871
  }
872
+ #getConsumerGroupHeartbeatMemberId(apiVersion) {
873
+ if (this.memberId) {
874
+ return this.memberId;
875
+ }
876
+ if (apiVersion >= 1) {
877
+ this.memberId = randomUUID();
878
+ return this.memberId;
879
+ }
880
+ return '';
881
+ }
868
882
  #performConsume(options, trackTopics, callback) {
869
883
  // Subscribe all topics
870
884
  let joinNeeded = this.memberId === null;
@@ -599,6 +599,7 @@ export class MessagesStream extends Readable {
599
599
  }
600
600
  #scheduleRefreshOffsetsAndFetch(destroyOnError = true) {
601
601
  this.#refreshOffsetsDestroyOnError ||= destroyOnError;
602
+ /* c8 ignore next 4 - Hard to test */
602
603
  if (this.#refreshOffsetsInflight) {
603
604
  this.#refreshOffsetsPending = true;
604
605
  return;
@@ -707,6 +708,10 @@ export class MessagesStream extends Readable {
707
708
  }
708
709
  }
709
710
  }
711
+ if (requests.length === 0) {
712
+ this.#pushRecords(metadata, topicIds, response, requestedOffsets);
713
+ return;
714
+ }
710
715
  runAsyncSeries((request, cb) => {
711
716
  const [data, type, message] = request;
712
717
  const result = hook(data, type, message, cb);
@@ -726,6 +726,10 @@ export class Producer extends Base {
726
726
  }
727
727
  }
728
728
  }
729
+ if (requests.length === 0) {
730
+ this.#send(options, callback);
731
+ return;
732
+ }
729
733
  runAsyncSeries((request, cb) => {
730
734
  const [data, type, message] = request;
731
735
  const result = hook(data, type, message, cb);
@@ -126,7 +126,14 @@ export class Connection extends TypedEventEmitter {
126
126
  connectionsConnectsChannel.asyncEnd.publish(diagnosticContext);
127
127
  };
128
128
  const connectingSocketErrorHandler = (error) => {
129
- this.#onConnectionError(host, port, diagnosticContext, error);
129
+ let cause = error;
130
+ const tlsConnectionError = error;
131
+ if (this.#options.tls &&
132
+ tlsConnectionError.code === 'ECONNRESET' &&
133
+ tlsConnectionError.message.includes('secure TLS connection was established')) {
134
+ cause = new UserError('TLS handshake failed. Please verify the broker supports TLS.', { cause: error });
135
+ }
136
+ this.#onConnectionError(host, port, diagnosticContext, cause);
130
137
  };
131
138
  this.emit('connecting');
132
139
  this.#host = host;
@@ -404,9 +411,13 @@ export class Connection extends TypedEventEmitter {
404
411
  if (sessionLifetimeMs > 0) {
405
412
  this.#reauthenticationTimeout = setTimeout(this.reauthenticate.bind(this), Number(sessionLifetimeMs) * 0.8);
406
413
  }
407
- if (this.#status === ConnectionStatuses.CONNECTED || this.#status === ConnectionStatuses.REAUTHENTICATING) {
414
+ const isReauthenticating = this.#status === ConnectionStatuses.REAUTHENTICATING;
415
+ if (this.#status === ConnectionStatuses.CONNECTED || isReauthenticating) {
408
416
  this.#status = ConnectionStatuses.CONNECTED;
409
417
  this.emit('sasl:authentication:extended', authBytes);
418
+ if (isReauthenticating) {
419
+ this.emit('connect');
420
+ }
410
421
  }
411
422
  else {
412
423
  this.emit('sasl:authentication', authBytes);
@@ -8,7 +8,7 @@ export interface ScramAlgorithmDefinition {
8
8
  }
9
9
  export interface ScramCryptoModule {
10
10
  h: (definition: ScramAlgorithmDefinition, data: string | Buffer) => Buffer;
11
- hi: (definition: ScramAlgorithmDefinition, password: string, salt: Buffer, iterations: number) => Buffer;
11
+ hi: (definition: ScramAlgorithmDefinition, password: string, salt: Buffer, iterations: number) => Promise<Buffer>;
12
12
  hmac: (definition: ScramAlgorithmDefinition, key: Buffer, data: string | Buffer) => Buffer;
13
13
  xor: (a: Buffer, b: Buffer) => Buffer;
14
14
  }
@@ -31,7 +31,7 @@ export declare function createNonce(): string;
31
31
  export declare function sanitizeString(str: string): string;
32
32
  export declare function parseParameters(data: Buffer): Record<string, string>;
33
33
  export declare function h(definition: ScramAlgorithmDefinition, data: string | Buffer): Buffer;
34
- export declare function hi(definition: ScramAlgorithmDefinition, password: string, salt: Buffer, iterations: number): Buffer;
34
+ export declare function hi(definition: ScramAlgorithmDefinition, password: string, salt: Buffer, iterations: number): Promise<Buffer>;
35
35
  export declare function hmac(definition: ScramAlgorithmDefinition, key: Buffer, data: string | Buffer): Buffer;
36
36
  export declare function xor(a: Buffer, b: Buffer): Buffer;
37
37
  export declare const defaultCrypto: ScramCryptoModule;
@@ -1,4 +1,5 @@
1
- import { createHash, createHmac, pbkdf2Sync, randomBytes } from 'node:crypto';
1
+ import { createHash, createHmac, pbkdf2, randomBytes } from 'node:crypto';
2
+ import { promisify } from 'node:util';
2
3
  import { createPromisifiedCallback, kCallbackPromise } from "../../apis/callbacks.js";
3
4
  import { AuthenticationError } from "../../errors.js";
4
5
  import { getCredential } from "./utils.js";
@@ -38,8 +39,9 @@ export function parseParameters(data) {
38
39
  export function h(definition, data) {
39
40
  return createHash(definition.algorithm).update(data).digest();
40
41
  }
42
+ const pbkdf2Async = promisify(pbkdf2);
41
43
  export function hi(definition, password, salt, iterations) {
42
- return pbkdf2Sync(password, salt, iterations, definition.keyLength, definition.algorithm);
44
+ return pbkdf2Async(password, salt, iterations, definition.keyLength, definition.algorithm);
43
45
  }
44
46
  export function hmac(definition, key, data) {
45
47
  return createHmac(definition.algorithm, key).update(data).digest();
@@ -93,31 +95,37 @@ function performAuthentication(connection, algorithm, definition, authenticateAP
93
95
  // ClientProof := ClientKey XOR ClientSignature
94
96
  // ServerKey := HMAC(SaltedPassword, "Server Key")
95
97
  // ServerSignature := HMAC(ServerKey, AuthMessage)
96
- const saltedPassword = hi(definition, password, salt, iterations);
97
- const clientKey = hmac(definition, saltedPassword, HMAC_CLIENT_KEY);
98
- const storedKey = h(definition, clientKey);
99
- const clientFinalMessageWithoutProof = `c=${GS2_HEADER_BASE64},r=${serverNonce}`;
100
- const authMessage = `${clientFirstMessageBare},${serverFirstMessage},${clientFinalMessageWithoutProof}`;
101
- const clientSignature = hmac(definition, storedKey, authMessage);
102
- const clientProof = xor(clientKey, clientSignature);
103
- const serverKey = hmac(definition, saltedPassword, HMAC_SERVER_KEY);
104
- const serverSignature = hmac(definition, serverKey, authMessage);
105
- authenticateAPI(connection, Buffer.from(`${clientFinalMessageWithoutProof},p=${clientProof.toString('base64')}`), (error, lastResponse) => {
106
- if (error) {
107
- callback(new AuthenticationError('SASL authentication failed.', { cause: error }));
108
- return;
109
- }
110
- // Send the last message to the server
111
- const lastData = parseParameters(lastResponse.authBytes);
112
- if (lastData.e) {
113
- callback(new AuthenticationError(lastData.e));
114
- return;
115
- }
116
- else if (lastData.v !== serverSignature.toString('base64')) {
117
- callback(new AuthenticationError('Invalid server signature.'));
118
- return;
119
- }
120
- callback(null, lastResponse);
98
+ hi(definition, password, salt, iterations)
99
+ .then(saltedPassword => {
100
+ const clientKey = hmac(definition, saltedPassword, HMAC_CLIENT_KEY);
101
+ const storedKey = h(definition, clientKey);
102
+ const clientFinalMessageWithoutProof = `c=${GS2_HEADER_BASE64},r=${serverNonce}`;
103
+ const authMessage = `${clientFirstMessageBare},${serverFirstMessage},${clientFinalMessageWithoutProof}`;
104
+ const clientSignature = hmac(definition, storedKey, authMessage);
105
+ const clientProof = xor(clientKey, clientSignature);
106
+ const serverKey = hmac(definition, saltedPassword, HMAC_SERVER_KEY);
107
+ const serverSignature = hmac(definition, serverKey, authMessage);
108
+ authenticateAPI(connection, Buffer.from(`${clientFinalMessageWithoutProof},p=${clientProof.toString('base64')}`), (error, lastResponse) => {
109
+ if (error) {
110
+ callback(new AuthenticationError('SASL authentication failed.', { cause: error }));
111
+ return;
112
+ }
113
+ // Send the last message to the server
114
+ const lastData = parseParameters(lastResponse.authBytes);
115
+ if (lastData.e) {
116
+ callback(new AuthenticationError(lastData.e));
117
+ return;
118
+ }
119
+ else if (lastData.v !== serverSignature.toString('base64')) {
120
+ callback(new AuthenticationError('Invalid server signature.'));
121
+ return;
122
+ }
123
+ callback(null, lastResponse);
124
+ });
125
+ })
126
+ /* c8 ignore next 3 - Hard to test */
127
+ .catch(error => {
128
+ callback(new AuthenticationError('SASL authentication failed.', { cause: error }));
121
129
  });
122
130
  });
123
131
  }
@@ -1,4 +1,8 @@
1
1
  export function runAsyncSeries(operation, collection, index, callback) {
2
+ if (collection.length === 0 || index >= collection.length) {
3
+ callback(null);
4
+ return;
5
+ }
2
6
  operation(collection[index], error => {
3
7
  if (error) {
4
8
  callback(error);
@@ -25,6 +25,6 @@ export interface AlterPartitionReassignmentsResponse {
25
25
  errorMessage: NullableString;
26
26
  responses: AlterPartitionReassignmentsResponseResponse[];
27
27
  }
28
- export declare function createRequest(timeoutMs: number, topics: AlterPartitionReassignmentsRequestTopic[]): Writer;
28
+ export declare function createRequest(timeoutMs: number, _allowReplicationFactorChange: boolean, topics: AlterPartitionReassignmentsRequestTopic[]): Writer;
29
29
  export declare function parseResponse(_correlationId: number, apiKey: number, apiVersion: number, reader: Reader): AlterPartitionReassignmentsResponse;
30
- export declare const api: import("../definitions").API<[timeoutMs: number, topics: AlterPartitionReassignmentsRequestTopic[]], AlterPartitionReassignmentsResponse>;
30
+ export declare const api: import("../definitions").API<[timeoutMs: number, _allowReplicationFactorChange: boolean, topics: AlterPartitionReassignmentsRequestTopic[]], AlterPartitionReassignmentsResponse>;
@@ -0,0 +1,30 @@
1
+ import { type NullableString } from "../../protocol/definitions";
2
+ import { type Reader } from "../../protocol/reader";
3
+ import { Writer } from "../../protocol/writer";
4
+ export interface AlterPartitionReassignmentsRequestPartition {
5
+ partitionIndex: number;
6
+ replicas: number[];
7
+ }
8
+ export interface AlterPartitionReassignmentsRequestTopic {
9
+ name: string;
10
+ partitions: AlterPartitionReassignmentsRequestPartition[];
11
+ }
12
+ export type AlterPartitionReassignmentsRequest = Parameters<typeof createRequest>;
13
+ export interface AlterPartitionReassignmentsResponsePartition {
14
+ partitionIndex: number;
15
+ errorCode: number;
16
+ errorMessage: NullableString;
17
+ }
18
+ export interface AlterPartitionReassignmentsResponseResponse {
19
+ name: string;
20
+ partitions: AlterPartitionReassignmentsResponsePartition[];
21
+ }
22
+ export interface AlterPartitionReassignmentsResponse {
23
+ throttleTimeMs: number;
24
+ errorCode: number;
25
+ errorMessage: NullableString;
26
+ responses: AlterPartitionReassignmentsResponseResponse[];
27
+ }
28
+ export declare function createRequest(timeoutMs: number, allowReplicationFactorChange: boolean, topics: AlterPartitionReassignmentsRequestTopic[]): Writer;
29
+ export declare function parseResponse(_correlationId: number, apiKey: number, apiVersion: number, reader: Reader): AlterPartitionReassignmentsResponse;
30
+ export declare const api: import("../definitions").API<[timeoutMs: number, allowReplicationFactorChange: boolean, topics: AlterPartitionReassignmentsRequestTopic[]], AlterPartitionReassignmentsResponse>;
@@ -18,6 +18,6 @@ export interface DescribeClusterResponse {
18
18
  brokers: DescribeClusterResponseBroker[];
19
19
  clusterAuthorizedOperations: number;
20
20
  }
21
- export declare function createRequest(includeClusterAuthorizedOperations: boolean): Writer;
21
+ export declare function createRequest(includeClusterAuthorizedOperations: boolean, _endpointType: number): Writer;
22
22
  export declare function parseResponse(_correlationId: number, apiKey: number, apiVersion: number, reader: Reader): DescribeClusterResponse;
23
- export declare const api: import("../definitions").API<[includeClusterAuthorizedOperations: boolean], DescribeClusterResponse>;
23
+ export declare const api: import("../definitions").API<[includeClusterAuthorizedOperations: boolean, _endpointType: number], DescribeClusterResponse>;
@@ -1,6 +1,7 @@
1
1
  export * as alterClientQuotasV1 from "./alter-client-quotas-v1";
2
2
  export * as alterConfigsV2 from "./alter-configs-v2";
3
3
  export * as alterPartitionReassignmentsV0 from "./alter-partition-reassignments-v0";
4
+ export * as alterPartitionReassignmentsV1 from "./alter-partition-reassignments-v1";
4
5
  export * as alterPartitionV3 from "./alter-partition-v3";
5
6
  export * as alterReplicaLogDirsV2 from "./alter-replica-log-dirs-v2";
6
7
  export * as alterUserScramCredentialsV0 from "./alter-user-scram-credentials-v0";
@@ -43,6 +44,7 @@ export * as listGroupsV5 from "./list-groups-v5";
43
44
  export * as listPartitionReassignmentsV0 from "./list-partition-reassignments-v0";
44
45
  export * as listTransactionsV0 from "./list-transactions-v0";
45
46
  export * as listTransactionsV1 from "./list-transactions-v1";
47
+ export * as listTransactionsV2 from "./list-transactions-v2";
46
48
  export * as offsetDeleteV0 from "./offset-delete-v0";
47
49
  export * as renewDelegationTokenV2 from "./renew-delegation-token-v2";
48
50
  export * as unregisterBrokerV0 from "./unregister-broker-v0";
@@ -12,6 +12,6 @@ export interface ListGroupsResponse {
12
12
  errorCode: number;
13
13
  groups: ListGroupsResponseGroup[];
14
14
  }
15
- export declare function createRequest(statesFilter: ConsumerGroupStateValue[]): Writer;
15
+ export declare function createRequest(statesFilter: ConsumerGroupStateValue[], _typesFilter: string[]): Writer;
16
16
  export declare function parseResponse(_correlationId: number, apiKey: number, apiVersion: number, reader: Reader): ListGroupsResponse;
17
- export declare const api: import("../definitions").API<[statesFilter: ("PREPARING_REBALANCE" | "COMPLETING_REBALANCE" | "STABLE" | "DEAD" | "EMPTY")[]], ListGroupsResponse>;
17
+ export declare const api: import("../definitions").API<[statesFilter: ("PREPARING_REBALANCE" | "COMPLETING_REBALANCE" | "STABLE" | "DEAD" | "EMPTY")[], _typesFilter: string[]], ListGroupsResponse>;
@@ -1,3 +1,4 @@
1
+ import { type NullableString } from "../../protocol/definitions";
1
2
  import { type Reader } from "../../protocol/reader";
2
3
  import { Writer } from "../../protocol/writer";
3
4
  import { type TransactionState } from "../enumerations";
@@ -13,6 +14,6 @@ export interface ListTransactionsResponse {
13
14
  unknownStateFilters: string[];
14
15
  transactionStates: ListTransactionsResponseTransactionState[];
15
16
  }
16
- export declare function createRequest(stateFilters: TransactionState[], producerIdFilters: bigint[]): Writer;
17
+ export declare function createRequest(stateFilters: TransactionState[], producerIdFilters: bigint[], _durationFilter: bigint, _transactionalIdPattern: NullableString): Writer;
17
18
  export declare function parseResponse(_correlationId: number, apiKey: number, apiVersion: number, reader: Reader): ListTransactionsResponse;
18
- export declare const api: import("../definitions").API<[stateFilters: ("EMPTY" | "ONGOING" | "PREPARE_ABORT" | "COMMITTING" | "ABORTING" | "COMPLETE_COMMIT" | "COMPLETE_ABORT")[], producerIdFilters: bigint[]], ListTransactionsResponse>;
19
+ export declare const api: import("../definitions").API<[stateFilters: ("EMPTY" | "ONGOING" | "PREPARE_ABORT" | "COMMITTING" | "ABORTING" | "COMPLETE_COMMIT" | "COMPLETE_ABORT")[], producerIdFilters: bigint[], _durationFilter: bigint, _transactionalIdPattern: NullableString], ListTransactionsResponse>;
@@ -1,3 +1,4 @@
1
+ import { type NullableString } from "../../protocol/definitions";
1
2
  import { type Reader } from "../../protocol/reader";
2
3
  import { Writer } from "../../protocol/writer";
3
4
  import { type TransactionState } from "../enumerations";
@@ -13,6 +14,6 @@ export interface ListTransactionsResponse {
13
14
  unknownStateFilters: string[];
14
15
  transactionStates: ListTransactionsResponseTransactionState[];
15
16
  }
16
- export declare function createRequest(stateFilters: TransactionState[], producerIdFilters: bigint[], durationFilter: bigint): Writer;
17
+ export declare function createRequest(stateFilters: TransactionState[], producerIdFilters: bigint[], durationFilter: bigint, _transactionalIdPattern: NullableString): Writer;
17
18
  export declare function parseResponse(_correlationId: number, apiKey: number, apiVersion: number, reader: Reader): ListTransactionsResponse;
18
- export declare const api: import("../definitions").API<[stateFilters: ("EMPTY" | "ONGOING" | "PREPARE_ABORT" | "COMMITTING" | "ABORTING" | "COMPLETE_COMMIT" | "COMPLETE_ABORT")[], producerIdFilters: bigint[], durationFilter: bigint], ListTransactionsResponse>;
19
+ export declare const api: import("../definitions").API<[stateFilters: ("EMPTY" | "ONGOING" | "PREPARE_ABORT" | "COMMITTING" | "ABORTING" | "COMPLETE_COMMIT" | "COMPLETE_ABORT")[], producerIdFilters: bigint[], durationFilter: bigint, _transactionalIdPattern: NullableString], ListTransactionsResponse>;
@@ -0,0 +1,20 @@
1
+ import { type NullableString } from "../../protocol/definitions";
2
+ import { type Reader } from "../../protocol/reader";
3
+ import { Writer } from "../../protocol/writer";
4
+ import { type TransactionState } from "../enumerations";
5
+ export type ListTransactionsRequest = Parameters<typeof createRequest>;
6
+ export interface ListTransactionsResponseTransactionState {
7
+ transactionalId: string;
8
+ producerId: bigint;
9
+ transactionState: string;
10
+ }
11
+ export interface ListTransactionsResponse {
12
+ throttleTimeMs: number;
13
+ errorCode: number;
14
+ errorMessage: NullableString;
15
+ unknownStateFilters: string[];
16
+ transactionStates: ListTransactionsResponseTransactionState[];
17
+ }
18
+ export declare function createRequest(stateFilters: TransactionState[], producerIdFilters: bigint[], durationFilter: bigint, transactionalIdPattern: NullableString): Writer;
19
+ export declare function parseResponse(_correlationId: number, apiKey: number, apiVersion: number, reader: Reader): ListTransactionsResponse;
20
+ export declare const api: import("../definitions").API<[stateFilters: ("EMPTY" | "ONGOING" | "PREPARE_ABORT" | "COMMITTING" | "ABORTING" | "COMPLETE_COMMIT" | "COMPLETE_ABORT")[], producerIdFilters: bigint[], durationFilter: bigint, transactionalIdPattern: NullableString], ListTransactionsResponse>;
@@ -22,6 +22,6 @@ export interface ConsumerGroupHeartbeatResponse {
22
22
  heartbeatIntervalMs: number;
23
23
  assignment: ConsumerGroupHeartbeatResponseAssignment | null;
24
24
  }
25
- export declare function createRequest(groupId: string, memberId: string, memberEpoch: number, instanceId: NullableString, rackId: NullableString, rebalanceTimeoutMs: number, subscribedTopicNames: string[] | null, serverAssignor: NullableString, topicPartitions: ConsumerGroupHeartbeatRequestTopicPartition[]): Writer;
25
+ export declare function createRequest(groupId: string, memberId: string, memberEpoch: number, instanceId: NullableString, rackId: NullableString, rebalanceTimeoutMs: number, subscribedTopicNames: string[] | null, _subscribedTopicRegex: NullableString, serverAssignor: NullableString, topicPartitions: ConsumerGroupHeartbeatRequestTopicPartition[]): Writer;
26
26
  export declare function parseResponse(_correlationId: number, apiKey: number, apiVersion: number, reader: Reader): ConsumerGroupHeartbeatResponse;
27
- export declare const api: import("../definitions").API<[groupId: string, memberId: string, memberEpoch: number, instanceId: NullableString, rackId: NullableString, rebalanceTimeoutMs: number, subscribedTopicNames: string[] | null, serverAssignor: NullableString, topicPartitions: ConsumerGroupHeartbeatRequestTopicPartition[]], ConsumerGroupHeartbeatResponse>;
27
+ export declare const api: import("../definitions").API<[groupId: string, memberId: string, memberEpoch: number, instanceId: NullableString, rackId: NullableString, rebalanceTimeoutMs: number, subscribedTopicNames: string[] | null, _subscribedTopicRegex: NullableString, serverAssignor: NullableString, topicPartitions: ConsumerGroupHeartbeatRequestTopicPartition[]], ConsumerGroupHeartbeatResponse>;