@platformatic/kafka 1.27.0 → 1.29.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 (54) hide show
  1. package/README.md +14 -7
  2. package/dist/apis/admin/describe-cluster-v0.d.ts +2 -2
  3. package/dist/apis/admin/describe-cluster-v0.js +1 -1
  4. package/dist/apis/admin/list-groups-v4.d.ts +2 -2
  5. package/dist/apis/admin/list-groups-v4.js +1 -1
  6. package/dist/apis/admin/list-transactions-v0.d.ts +2 -2
  7. package/dist/apis/admin/list-transactions-v0.js +1 -1
  8. package/dist/apis/consumer/join-group-v6.d.ts +2 -2
  9. package/dist/apis/consumer/join-group-v6.js +1 -1
  10. package/dist/apis/consumer/join-group-v7.d.ts +2 -2
  11. package/dist/apis/consumer/join-group-v7.js +1 -1
  12. package/dist/apis/consumer/offset-commit-v8.d.ts +2 -2
  13. package/dist/apis/consumer/sync-group-v4.d.ts +2 -2
  14. package/dist/apis/consumer/sync-group-v4.js +1 -1
  15. package/dist/clients/admin/admin.d.ts +3 -1
  16. package/dist/clients/admin/admin.js +88 -7
  17. package/dist/clients/admin/options.d.ts +43 -0
  18. package/dist/clients/admin/options.js +33 -0
  19. package/dist/clients/admin/types.d.ts +19 -0
  20. package/dist/clients/base/base.js +6 -1
  21. package/dist/clients/consumer/messages-stream.js +41 -12
  22. package/dist/clients/producer/index.d.ts +1 -0
  23. package/dist/clients/producer/index.js +1 -0
  24. package/dist/clients/producer/options.d.ts +63 -0
  25. package/dist/clients/producer/options.js +18 -0
  26. package/dist/clients/producer/producer-stream.d.ts +19 -0
  27. package/dist/clients/producer/producer-stream.js +187 -0
  28. package/dist/clients/producer/producer.d.ts +6 -3
  29. package/dist/clients/producer/producer.js +55 -3
  30. package/dist/clients/producer/types.d.ts +24 -0
  31. package/dist/clients/producer/types.js +6 -1
  32. package/dist/diagnostic.d.ts +2 -2
  33. package/dist/network/connection.js +13 -2
  34. package/dist/protocol/sasl/scram-sha.d.ts +2 -2
  35. package/dist/protocol/sasl/scram-sha.js +35 -27
  36. package/dist/typescript-4/dist/apis/admin/describe-cluster-v0.d.ts +2 -2
  37. package/dist/typescript-4/dist/apis/admin/list-groups-v4.d.ts +2 -2
  38. package/dist/typescript-4/dist/apis/admin/list-transactions-v0.d.ts +2 -2
  39. package/dist/typescript-4/dist/apis/consumer/join-group-v6.d.ts +2 -2
  40. package/dist/typescript-4/dist/apis/consumer/join-group-v7.d.ts +2 -2
  41. package/dist/typescript-4/dist/apis/consumer/offset-commit-v8.d.ts +2 -2
  42. package/dist/typescript-4/dist/apis/consumer/sync-group-v4.d.ts +2 -2
  43. package/dist/typescript-4/dist/clients/admin/admin.d.ts +3 -1
  44. package/dist/typescript-4/dist/clients/admin/options.d.ts +43 -0
  45. package/dist/typescript-4/dist/clients/admin/types.d.ts +19 -0
  46. package/dist/typescript-4/dist/clients/producer/index.d.ts +1 -0
  47. package/dist/typescript-4/dist/clients/producer/options.d.ts +64 -1
  48. package/dist/typescript-4/dist/clients/producer/producer-stream.d.ts +19 -0
  49. package/dist/typescript-4/dist/clients/producer/producer.d.ts +6 -3
  50. package/dist/typescript-4/dist/clients/producer/types.d.ts +25 -1
  51. package/dist/typescript-4/dist/diagnostic.d.ts +2 -2
  52. package/dist/typescript-4/dist/protocol/sasl/scram-sha.d.ts +2 -2
  53. package/dist/version.js +1 -1
  54. package/package.json +3 -3
package/README.md CHANGED
@@ -18,6 +18,10 @@ A modern, high-performance, pure TypeScript/JavaScript type safe client for Apac
18
18
 
19
19
  Supported Kafka version are from **3.5.0** to **4.0.0** and equivalent, edges included.
20
20
 
21
+ ## Supported KIPs
22
+
23
+ See the maintained list in [`docs/kips.md`](./docs/kips.md).
24
+
21
25
  ## Installation
22
26
 
23
27
  ```bash
@@ -51,6 +55,7 @@ await producer.send({
51
55
  })
52
56
 
53
57
  // Close the producer when done
58
+ // If you created producer streams with producer.asStream(), either close them first or use producer.close(true)
54
59
  await producer.close()
55
60
  ```
56
61
 
@@ -172,15 +177,17 @@ const producer = new Producer({
172
177
 
173
178
  // Send messages with schema IDs
174
179
  await producer.send({
175
- messages: [{
176
- topic: 'users',
177
- value: { id: 1, name: 'Alice' },
178
- metadata: {
179
- schemas: {
180
- value: 100 // Schema ID in the registry
180
+ messages: [
181
+ {
182
+ topic: 'users',
183
+ value: { id: 1, name: 'Alice' },
184
+ metadata: {
185
+ schemas: {
186
+ value: 100 // Schema ID in the registry
187
+ }
181
188
  }
182
189
  }
183
- }]
190
+ ]
184
191
  })
185
192
 
186
193
  // Consumer with schema registry
@@ -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.ts").API<[includeClusterAuthorizedOperations: boolean], DescribeClusterResponse>;
23
+ export declare const api: import("../definitions.ts").API<[includeClusterAuthorizedOperations: boolean, _endpointType: number], DescribeClusterResponse>;
@@ -5,7 +5,7 @@ import { createAPI } from "../definitions.js";
5
5
  DescribeCluster Request (Version: 0) => include_cluster_authorized_operations TAG_BUFFER
6
6
  include_cluster_authorized_operations => BOOLEAN
7
7
  */
8
- export function createRequest(includeClusterAuthorizedOperations) {
8
+ export function createRequest(includeClusterAuthorizedOperations, _endpointType) {
9
9
  return Writer.create().appendBoolean(includeClusterAuthorizedOperations).appendTaggedFields();
10
10
  }
11
11
  /*
@@ -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.ts").API<[statesFilter: ("PREPARING_REBALANCE" | "COMPLETING_REBALANCE" | "STABLE" | "DEAD" | "EMPTY")[]], ListGroupsResponse>;
17
+ export declare const api: import("../definitions.ts").API<[statesFilter: ("PREPARING_REBALANCE" | "COMPLETING_REBALANCE" | "STABLE" | "DEAD" | "EMPTY")[], _typesFilter: string[]], ListGroupsResponse>;
@@ -6,7 +6,7 @@ import { createAPI } from "../definitions.js";
6
6
  ListGroups Request (Version: 4) => [states_filter] TAG_BUFFER
7
7
  states_filter => COMPACT_STRING
8
8
  */
9
- export function createRequest(statesFilter) {
9
+ export function createRequest(statesFilter, _typesFilter) {
10
10
  return Writer.create()
11
11
  .appendArray(statesFilter, (w, s) => w.appendString(pascalCase(s, { normalize: true })), true, false)
12
12
  .appendTaggedFields();
@@ -13,6 +13,6 @@ export interface ListTransactionsResponse {
13
13
  unknownStateFilters: string[];
14
14
  transactionStates: ListTransactionsResponseTransactionState[];
15
15
  }
16
- export declare function createRequest(stateFilters: TransactionState[], producerIdFilters: bigint[]): Writer;
16
+ export declare function createRequest(stateFilters: TransactionState[], producerIdFilters: bigint[], _durationFilter: bigint): Writer;
17
17
  export declare function parseResponse(_correlationId: number, apiKey: number, apiVersion: number, reader: Reader): ListTransactionsResponse;
18
- export declare const api: import("../definitions.ts").API<[stateFilters: ("EMPTY" | "ONGOING" | "PREPARE_ABORT" | "COMMITTING" | "ABORTING" | "COMPLETE_COMMIT" | "COMPLETE_ABORT")[], producerIdFilters: bigint[]], ListTransactionsResponse>;
18
+ export declare const api: import("../definitions.ts").API<[stateFilters: ("EMPTY" | "ONGOING" | "PREPARE_ABORT" | "COMMITTING" | "ABORTING" | "COMPLETE_COMMIT" | "COMPLETE_ABORT")[], producerIdFilters: bigint[], _durationFilter: bigint], ListTransactionsResponse>;
@@ -6,7 +6,7 @@ import { createAPI } from "../definitions.js";
6
6
  state_filters => COMPACT_STRING
7
7
  producer_id_filters => INT64
8
8
  */
9
- export function createRequest(stateFilters, producerIdFilters) {
9
+ export function createRequest(stateFilters, producerIdFilters, _durationFilter) {
10
10
  return Writer.create()
11
11
  .appendArray(stateFilters, (w, t) => w.appendString(t), true, false)
12
12
  .appendArray(producerIdFilters, (w, p) => w.appendInt64(p), true, false)
@@ -22,6 +22,6 @@ export interface JoinGroupResponse {
22
22
  memberId: NullableString;
23
23
  members: JoinGroupResponseMember[];
24
24
  }
25
- export declare function createRequest(groupId: string, sessionTimeoutMs: number, rebalanceTimeoutMs: number, memberId: string, groupInstanceId: NullableString, protocolType: string, protocols: JoinGroupRequestProtocol[]): Writer;
25
+ export declare function createRequest(groupId: string, sessionTimeoutMs: number, rebalanceTimeoutMs: number, memberId: string, groupInstanceId: NullableString, protocolType: string, protocols: JoinGroupRequestProtocol[], _reason?: NullableString): Writer;
26
26
  export declare function parseResponse(_correlationId: number, apiKey: number, apiVersion: number, reader: Reader): JoinGroupResponse;
27
- export declare const api: import("../definitions.ts").API<[groupId: string, sessionTimeoutMs: number, rebalanceTimeoutMs: number, memberId: string, groupInstanceId: NullableString, protocolType: string, protocols: JoinGroupRequestProtocol[]], JoinGroupResponse>;
27
+ export declare const api: import("../definitions.ts").API<[groupId: string, sessionTimeoutMs: number, rebalanceTimeoutMs: number, memberId: string, groupInstanceId: NullableString, protocolType: string, protocols: JoinGroupRequestProtocol[], _reason?: NullableString], JoinGroupResponse>;
@@ -14,7 +14,7 @@ import { createAPI } from "../definitions.js";
14
14
  name => COMPACT_STRING
15
15
  metadata => COMPACT_BYTES
16
16
  */
17
- export function createRequest(groupId, sessionTimeoutMs, rebalanceTimeoutMs, memberId, groupInstanceId, protocolType, protocols) {
17
+ export function createRequest(groupId, sessionTimeoutMs, rebalanceTimeoutMs, memberId, groupInstanceId, protocolType, protocols, _reason) {
18
18
  return Writer.create()
19
19
  .appendString(groupId)
20
20
  .appendInt32(sessionTimeoutMs)
@@ -22,6 +22,6 @@ export interface JoinGroupResponse {
22
22
  memberId: NullableString;
23
23
  members: JoinGroupResponseMember[];
24
24
  }
25
- export declare function createRequest(groupId: string, sessionTimeoutMs: number, rebalanceTimeoutMs: number, memberId: string, groupInstanceId: NullableString, protocolType: string, protocols: JoinGroupRequestProtocol[]): Writer;
25
+ export declare function createRequest(groupId: string, sessionTimeoutMs: number, rebalanceTimeoutMs: number, memberId: string, groupInstanceId: NullableString, protocolType: string, protocols: JoinGroupRequestProtocol[], _reason?: NullableString): Writer;
26
26
  export declare function parseResponse(_correlationId: number, apiKey: number, apiVersion: number, reader: Reader): JoinGroupResponse;
27
- export declare const api: import("../definitions.ts").API<[groupId: string, sessionTimeoutMs: number, rebalanceTimeoutMs: number, memberId: string, groupInstanceId: NullableString, protocolType: string, protocols: JoinGroupRequestProtocol[]], JoinGroupResponse>;
27
+ export declare const api: import("../definitions.ts").API<[groupId: string, sessionTimeoutMs: number, rebalanceTimeoutMs: number, memberId: string, groupInstanceId: NullableString, protocolType: string, protocols: JoinGroupRequestProtocol[], _reason?: NullableString], JoinGroupResponse>;
@@ -14,7 +14,7 @@ import { createAPI } from "../definitions.js";
14
14
  name => COMPACT_STRING
15
15
  metadata => COMPACT_BYTES
16
16
  */
17
- export function createRequest(groupId, sessionTimeoutMs, rebalanceTimeoutMs, memberId, groupInstanceId, protocolType, protocols) {
17
+ export function createRequest(groupId, sessionTimeoutMs, rebalanceTimeoutMs, memberId, groupInstanceId, protocolType, protocols, _reason) {
18
18
  return Writer.create()
19
19
  .appendString(groupId)
20
20
  .appendInt32(sessionTimeoutMs)
@@ -24,6 +24,6 @@ export interface OffsetCommitResponse {
24
24
  throttleTimeMs: number;
25
25
  topics: OffsetCommitResponseTopic[];
26
26
  }
27
- export declare function createRequest(groupId: string, generationIdOrMemberEpoch: number, memberId: string, groupInstanceId: NullableString, topics: OffsetCommitRequestTopic[]): Writer;
27
+ export declare function createRequest(groupId: string, generationIdOrMemberEpoch: number, memberId: NullableString, groupInstanceId: NullableString, topics: OffsetCommitRequestTopic[]): Writer;
28
28
  export declare function parseResponse(_correlationId: number, apiKey: number, apiVersion: number, reader: Reader): OffsetCommitResponse;
29
- export declare const api: import("../definitions.ts").API<[groupId: string, generationIdOrMemberEpoch: number, memberId: string, groupInstanceId: NullableString, topics: OffsetCommitRequestTopic[]], OffsetCommitResponse>;
29
+ export declare const api: import("../definitions.ts").API<[groupId: string, generationIdOrMemberEpoch: number, memberId: NullableString, groupInstanceId: NullableString, topics: OffsetCommitRequestTopic[]], OffsetCommitResponse>;
@@ -13,6 +13,6 @@ export interface SyncGroupResponse {
13
13
  protocolName: NullableString;
14
14
  assignment: Buffer;
15
15
  }
16
- export declare function createRequest(groupId: string, generationId: number, memberId: string, groupInstanceId: NullableString, assignments: SyncGroupRequestAssignment[]): Writer;
16
+ export declare function createRequest(groupId: string, generationId: number, memberId: string, groupInstanceId: NullableString, _protocolType: NullableString, _protocolName: NullableString, assignments: SyncGroupRequestAssignment[]): Writer;
17
17
  export declare function parseResponse(_correlationId: number, apiKey: number, apiVersion: number, reader: Reader): SyncGroupResponse;
18
- export declare const api: import("../definitions.ts").API<[groupId: string, generationId: number, memberId: string, groupInstanceId: NullableString, assignments: SyncGroupRequestAssignment[]], SyncGroupResponse>;
18
+ export declare const api: import("../definitions.ts").API<[groupId: string, generationId: number, memberId: string, groupInstanceId: NullableString, _protocolType: NullableString, _protocolName: NullableString, assignments: SyncGroupRequestAssignment[]], SyncGroupResponse>;
@@ -12,7 +12,7 @@ import { createAPI } from "../definitions.js";
12
12
  assignment => COMPACT_BYTES
13
13
 
14
14
  */
15
- export function createRequest(groupId, generationId, memberId, groupInstanceId, assignments) {
15
+ export function createRequest(groupId, generationId, memberId, groupInstanceId, _protocolType, _protocolName, assignments) {
16
16
  return Writer.create()
17
17
  .appendString(groupId)
18
18
  .appendInt32(generationId)
@@ -5,7 +5,7 @@ import { type CallbackWithPromise } from '../../apis/callbacks.ts';
5
5
  import { type Callback } from '../../apis/definitions.ts';
6
6
  import { type Acl } from '../../apis/types.ts';
7
7
  import { Base } from '../base/base.ts';
8
- import { type AdminListOffsetsOptions, type AdminOptions, type AlterClientQuotasOptions, type AlterConfigsOptions, type AlterConsumerGroupOffsetsOptions, type BrokerLogDirDescription, type ConfigDescription, type CreateAclsOptions, type CreatedTopic, type CreatePartitionsOptions, type CreateTopicsOptions, type DeleteAclsOptions, type DeleteConsumerGroupOffsetsOptions, type DeleteGroupsOptions, type DeleteTopicsOptions, type DescribeAclsOptions, type DescribeClientQuotasOptions, type DescribeConfigsOptions, type DescribeGroupsOptions, type DescribeLogDirsOptions, type Group, type GroupBase, type IncrementalAlterConfigsOptions, type ListConsumerGroupOffsetsGroup, type ListConsumerGroupOffsetsOptions, type ListedOffsetsTopic, type ListGroupsOptions, type ListTopicsOptions, type RemoveMembersFromConsumerGroupOptions } from './types.ts';
8
+ import { type AdminListOffsetsOptions, type AdminOptions, type AlterClientQuotasOptions, type AlterConfigsOptions, type AlterConsumerGroupOffsetsOptions, type BrokerLogDirDescription, type ConfigDescription, type CreateAclsOptions, type CreatedTopic, type CreatePartitionsOptions, type CreateTopicsOptions, type DeleteAclsOptions, type DeleteConsumerGroupOffsetsOptions, type DeleteRecordsOptions, type DeleteGroupsOptions, type DeleteTopicsOptions, type DeletedRecordsTopic, type DescribeAclsOptions, type DescribeClientQuotasOptions, type DescribeConfigsOptions, type DescribeGroupsOptions, type DescribeLogDirsOptions, type Group, type GroupBase, type IncrementalAlterConfigsOptions, type ListConsumerGroupOffsetsGroup, type ListConsumerGroupOffsetsOptions, type ListedOffsetsTopic, type ListGroupsOptions, type ListTopicsOptions, type RemoveMembersFromConsumerGroupOptions } from './types.ts';
9
9
  export declare class Admin extends Base<AdminOptions> {
10
10
  #private;
11
11
  constructor(options: AdminOptions);
@@ -57,4 +57,6 @@ export declare class Admin extends Base<AdminOptions> {
57
57
  deleteAcls(options: DeleteAclsOptions): Promise<Acl[]>;
58
58
  listOffsets(options: AdminListOffsetsOptions, callback: CallbackWithPromise<ListedOffsetsTopic[]>): void;
59
59
  listOffsets(options: AdminListOffsetsOptions): Promise<ListedOffsetsTopic[]>;
60
+ deleteRecords(options: DeleteRecordsOptions, callback: CallbackWithPromise<DeletedRecordsTopic[]>): void;
61
+ deleteRecords(options: DeleteRecordsOptions): Promise<DeletedRecordsTopic[]>;
60
62
  }
@@ -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) {
@@ -37,6 +37,9 @@ export class MessagesStream extends Readable {
37
37
  #mode;
38
38
  #fallbackMode;
39
39
  #paused;
40
+ #refreshOffsetsInflight;
41
+ #refreshOffsetsPending;
42
+ #refreshOffsetsDestroyOnError;
40
43
  #fetches;
41
44
  #maxFetches;
42
45
  #options;
@@ -99,6 +102,9 @@ export class MessagesStream extends Readable {
99
102
  this.#offsetsCommitted = new Map();
100
103
  this.#partitionsEpochs = new Map();
101
104
  this.#paused = false;
105
+ this.#refreshOffsetsInflight = false;
106
+ this.#refreshOffsetsPending = false;
107
+ this.#refreshOffsetsDestroyOnError = false;
102
108
  this.#fetches = 0;
103
109
  this.#maxFetches = maxFetches ?? 0;
104
110
  this.#topics = structuredClone(options.topics);
@@ -144,14 +150,7 @@ export class MessagesStream extends Readable {
144
150
  // having some.
145
151
  this.#consumer.on('consumer:group:join', () => {
146
152
  this.#offsetsCommitted.clear();
147
- this.#refreshOffsets(error => {
148
- /* c8 ignore next 4 - Hard to test */
149
- if (error) {
150
- this.destroy(error);
151
- return;
152
- }
153
- this.#fetch();
154
- });
153
+ this.#scheduleRefreshOffsetsAndFetch();
155
154
  });
156
155
  if (consumer[kPrometheus]) {
157
156
  this.#metricsConsumedMessages = ensureMetric(consumer[kPrometheus], 'Counter', 'kafka_consumed_messages', 'Number of consumed Kafka messages');
@@ -291,7 +290,7 @@ export class MessagesStream extends Readable {
291
290
  return;
292
291
  }
293
292
  // No need to fetch if nobody is consuming the data
294
- if (this.readableFlowing === null || this.#paused) {
293
+ if (this.readableFlowing === null || this.#paused || this.#refreshOffsetsInflight || this.#refreshOffsetsPending) {
295
294
  return;
296
295
  }
297
296
  this.#consumer.metadata({ topics: this.#consumer.topics.current }, (error, metadata) => {
@@ -448,8 +447,11 @@ export class MessagesStream extends Readable {
448
447
  try {
449
448
  const headers = new Map();
450
449
  for (const [headerKey, headerValue] of record.headers) {
451
- headers.set(headerKeyDeserializer(headerKey ?? undefined, messageToConsume), headerValueDeserializer(headerValue ?? undefined, messageToConsume));
450
+ headers.set(
451
+ /* c8 ignore next 2 - Hard to test */
452
+ headerKeyDeserializer(headerKey ?? undefined, messageToConsume), headerValueDeserializer(headerValue ?? undefined, messageToConsume));
452
453
  }
454
+ /* c8 ignore next 2 - Hard to test */
453
455
  const key = keyDeserializer(record.key ?? undefined, headers, messageToConsume);
454
456
  const value = valueDeserializer(record.value ?? undefined, headers, messageToConsume);
455
457
  this.#metricsConsumedMessages?.inc();
@@ -595,11 +597,38 @@ export class MessagesStream extends Readable {
595
597
  });
596
598
  });
597
599
  }
598
- [kRefreshOffsetsAndFetch]() {
599
- this.#refreshOffsets(() => {
600
+ #scheduleRefreshOffsetsAndFetch(destroyOnError = true) {
601
+ this.#refreshOffsetsDestroyOnError ||= destroyOnError;
602
+ /* c8 ignore next 4 - Hard to test */
603
+ if (this.#refreshOffsetsInflight) {
604
+ this.#refreshOffsetsPending = true;
605
+ return;
606
+ }
607
+ this.#refreshOffsetsInflight = true;
608
+ this.#refreshOffsets(error => {
609
+ const shouldDestroyOnError = this.#refreshOffsetsDestroyOnError;
610
+ this.#refreshOffsetsInflight = false;
611
+ this.#refreshOffsetsDestroyOnError = false;
612
+ this.#refreshOffsetsPending = false;
613
+ /* c8 ignore next 9 - Hard to test */
614
+ if (error) {
615
+ if (shouldDestroyOnError) {
616
+ this.destroy(error);
617
+ }
618
+ return;
619
+ }
620
+ // A new one was scheduled while the previous one was inflight, we need to run it immediately
621
+ /* c8 ignore next 4 - Hard to test */
622
+ if (this.#refreshOffsetsPending) {
623
+ this.#scheduleRefreshOffsetsAndFetch(shouldDestroyOnError);
624
+ return;
625
+ }
600
626
  this.#fetch();
601
627
  });
602
628
  }
629
+ [kRefreshOffsetsAndFetch]() {
630
+ this.#scheduleRefreshOffsetsAndFetch(false);
631
+ }
603
632
  #assignOffsets(offsets, commits, callback) {
604
633
  for (const [topic, partitions] of offsets) {
605
634
  for (let i = 0; i < partitions.length; i++) {
@@ -1,3 +1,4 @@
1
1
  export * from './options.ts';
2
+ export * from './producer-stream.ts';
2
3
  export * from './producer.ts';
3
4
  export * from './types.ts';
@@ -1,3 +1,4 @@
1
1
  export * from "./options.js";
2
+ export * from "./producer-stream.js";
2
3
  export * from "./producer.js";
3
4
  export * from "./types.js";
@@ -155,3 +155,66 @@ export declare const sendOptionsSchema: {
155
155
  export declare const sendOptionsValidator: import("ajv").ValidateFunction<{
156
156
  [x: string]: {};
157
157
  }>;
158
+ export declare const defaultProducerStreamOptions: {
159
+ batchSize: number;
160
+ batchTime: number;
161
+ reportMode: "none";
162
+ };
163
+ export declare const producerStreamOptionsSchema: {
164
+ type: string;
165
+ properties: {
166
+ producerId: {
167
+ bigint: boolean;
168
+ };
169
+ producerEpoch: {
170
+ type: string;
171
+ };
172
+ idempotent: {
173
+ type: string;
174
+ };
175
+ transactionalId: {
176
+ type: string;
177
+ };
178
+ acks: {
179
+ type: string;
180
+ enumeration: {
181
+ allowed: (0 | 1 | -1)[];
182
+ errorMessage: string;
183
+ };
184
+ };
185
+ compression: {
186
+ type: string;
187
+ enumeration: {
188
+ allowed: import("../../protocol/compression.ts").CompressionAlgorithmValue[];
189
+ errorMessage: string;
190
+ };
191
+ };
192
+ partitioner: {
193
+ function: boolean;
194
+ };
195
+ autocreateTopics: {
196
+ type: string;
197
+ };
198
+ repeatOnStaleMetadata: {
199
+ type: string;
200
+ };
201
+ highWaterMark: {
202
+ type: string;
203
+ minimum: number;
204
+ };
205
+ batchSize: {
206
+ type: string;
207
+ minimum: number;
208
+ };
209
+ batchTime: {
210
+ type: string;
211
+ minimum: number;
212
+ };
213
+ reportMode: {
214
+ type: string;
215
+ enum: import("./types.ts").ProducerStreamReportModeValue[];
216
+ };
217
+ };
218
+ additionalProperties: boolean;
219
+ };
220
+ export declare const producerStreamOptionsValidator: import("ajv").ValidateFunction<unknown>;