@drarzter/kafka-client 0.7.1 → 0.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/core.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { T as TopicMapConstraint, I as IKafkaClient, C as ClientId, G as GroupId, a as KafkaClientOptions, c as TopicDescriptor, w as SendOptions, B as BatchMessageItem, A as TransactionContext, l as EventEnvelope, b as ConsumerOptions, h as ConsumerHandle, e as BatchMeta, k as DlqReplayOptions, d as KafkaHealthResult, t as KafkaMetrics } from './types-BEIGjmV6.js';
2
- export { f as BeforeConsumeResult, g as CircuitBreakerOptions, i as ConsumerInterceptor, D as DeduplicationOptions, j as DlqReason, E as EnvelopeHeaderOptions, H as HEADER_CORRELATION_ID, m as HEADER_EVENT_ID, n as HEADER_LAMPORT_CLOCK, o as HEADER_SCHEMA_VERSION, p as HEADER_TIMESTAMP, q as HEADER_TRACEPARENT, r as InferSchema, K as KafkaInstrumentation, s as KafkaLogger, M as MessageHeaders, u as MessageLostContext, R as RetryOptions, S as SchemaLike, v as SchemaParseContext, x as SubscribeRetryOptions, y as TTopicMessageMap, z as TopicsFrom, F as TtlExpiredContext, J as buildEnvelopeHeaders, L as decodeHeaders, N as extractEnvelope, O as getEnvelopeContext, P as runWithEnvelopeContext, Q as topic } from './types-BEIGjmV6.js';
1
+ import { T as TopicMapConstraint, I as IKafkaClient, C as ClientId, G as GroupId, a as KafkaClientOptions, c as TopicDescriptor, z as SendOptions, M as MessageHeaders, B as BatchMessageItem, f as BatchSendOptions, O as TransactionContext, o as EventEnvelope, b as ConsumerOptions, k as ConsumerHandle, e as BatchMeta, n as DlqReplayOptions, d as KafkaHealthResult, j as ConsumerGroupSummary, J as TopicDescription, w as KafkaMetrics } from './types-4qWrf2aJ.js';
2
+ export { g as BeforeConsumeResult, h as CircuitBreakerOptions, i as CompressionType, l as ConsumerInterceptor, D as DeduplicationOptions, m as DlqReason, E as EnvelopeHeaderOptions, H as HEADER_CORRELATION_ID, p as HEADER_EVENT_ID, q as HEADER_LAMPORT_CLOCK, r as HEADER_SCHEMA_VERSION, s as HEADER_TIMESTAMP, t as HEADER_TRACEPARENT, u as InferSchema, K as KafkaInstrumentation, v as KafkaLogger, x as MessageLostContext, R as RetryOptions, S as SchemaLike, y as SchemaParseContext, A as SubscribeRetryOptions, F as TTopicMessageMap, L as TopicPartitionInfo, N as TopicsFrom, P as TtlExpiredContext, Q as buildEnvelopeHeaders, U as decodeHeaders, V as extractEnvelope, W as getEnvelopeContext, X as runWithEnvelopeContext, Y as topic } from './types-4qWrf2aJ.js';
3
3
 
4
4
  /**
5
5
  * Type-safe Kafka client.
@@ -16,7 +16,6 @@ declare class KafkaClient<T extends TopicMapConstraint<T>> implements IKafkaClie
16
16
  /** Maps transactionalId → Producer for each active retry level consumer. */
17
17
  private readonly retryTxProducers;
18
18
  private readonly consumers;
19
- private readonly admin;
20
19
  private readonly logger;
21
20
  private readonly autoCreateTopicsEnabled;
22
21
  private readonly strictSchemasEnabled;
@@ -36,27 +35,54 @@ declare class KafkaClient<T extends TopicMapConstraint<T>> implements IKafkaClie
36
35
  private readonly onRebalance;
37
36
  /** Transactional producer ID — configurable via `KafkaClientOptions.transactionalId`. */
38
37
  private readonly txId;
39
- /** Per-topic event counters, lazily created on first event. Aggregated by `getMetrics()`. */
40
- private readonly _topicMetrics;
41
38
  /** Monotonically increasing Lamport clock stamped on every outgoing message. */
42
39
  private _lamportClock;
43
40
  /** Per-groupId deduplication state: `"topic:partition"` → last processed clock. */
44
41
  private readonly dedupStates;
45
- /** Circuit breaker state per `"${gid}:${topic}:${partition}"` key. */
46
- private readonly circuitStates;
47
- /** Circuit breaker config per groupId, set at startConsumer/startBatchConsumer time. */
48
- private readonly circuitConfigs;
49
- private isAdminConnected;
50
- private inFlightTotal;
51
- private readonly drainResolvers;
42
+ private readonly circuitBreaker;
43
+ private readonly adminOps;
44
+ private readonly metrics;
45
+ private readonly inFlight;
52
46
  readonly clientId: ClientId;
47
+ private readonly _producerOpsDeps;
48
+ private readonly _consumerOpsDeps;
49
+ private readonly _retryTopicDeps;
50
+ /** DLQ header keys added by the pipeline — stripped before re-publishing. */
51
+ private static readonly DLQ_HEADER_KEYS;
53
52
  constructor(clientId: ClientId, groupId: GroupId, brokers: string[], options?: KafkaClientOptions);
54
- /** Send a single typed message. Accepts a topic key or a TopicDescriptor. */
53
+ /**
54
+ * Send a single typed message. Accepts a topic key or a `TopicDescriptor`.
55
+ *
56
+ * @param topic Topic key from the `TopicMessageMap` or a `TopicDescriptor` object.
57
+ * @param message Message payload — validated against the topic schema when one is registered.
58
+ * @param options Optional per-send settings: `key`, `headers`, `correlationId`, `compression`, etc.
59
+ */
55
60
  sendMessage<D extends TopicDescriptor<string & keyof T, T[string & keyof T]>>(descriptor: D, message: D["__type"], options?: SendOptions): Promise<void>;
56
61
  sendMessage<K extends keyof T>(topic: K, message: T[K], options?: SendOptions): Promise<void>;
57
- /** Send multiple typed messages in one call. Accepts a topic key or a TopicDescriptor. */
58
- sendBatch<D extends TopicDescriptor<string & keyof T, T[string & keyof T]>>(descriptor: D, messages: Array<BatchMessageItem<D["__type"]>>): Promise<void>;
59
- sendBatch<K extends keyof T>(topic: K, messages: Array<BatchMessageItem<T[K]>>): Promise<void>;
62
+ /**
63
+ * Send a null-value (tombstone) message. Used with log-compacted topics to signal
64
+ * that a key's record should be removed during the next compaction cycle.
65
+ *
66
+ * Tombstones skip envelope headers, schema validation, and Lamport clock stamping.
67
+ * Both `beforeSend` and `afterSend` instrumentation hooks are still called so tracing works correctly.
68
+ *
69
+ * @param topic Topic name.
70
+ * @param key Partition key identifying the record to tombstone.
71
+ * @param headers Optional custom Kafka headers.
72
+ */
73
+ sendTombstone(topic: string, key: string, headers?: MessageHeaders): Promise<void>;
74
+ /**
75
+ * Send multiple typed messages in a single Kafka produce request. Accepts a topic key or a `TopicDescriptor`.
76
+ *
77
+ * Each item in `messages` can carry its own `key`, `headers`, `correlationId`, and `schemaVersion`.
78
+ * The `key` is used for partition routing — messages with the same key always land on the same partition.
79
+ *
80
+ * @param topic Topic key from the `TopicMessageMap` or a `TopicDescriptor` object.
81
+ * @param messages Array of messages to send.
82
+ * @param options Optional batch-level settings: `compression` codec.
83
+ */
84
+ sendBatch<D extends TopicDescriptor<string & keyof T, T[string & keyof T]>>(descriptor: D, messages: Array<BatchMessageItem<D["__type"]>>, options?: BatchSendOptions): Promise<void>;
85
+ sendBatch<K extends keyof T>(topic: K, messages: Array<BatchMessageItem<T[K]>>, options?: BatchSendOptions): Promise<void>;
60
86
  /** Execute multiple sends atomically. Commits on success, aborts on error. */
61
87
  transaction(fn: (ctx: TransactionContext<T>) => Promise<void>): Promise<void>;
62
88
  /**
@@ -68,10 +94,36 @@ declare class KafkaClient<T extends TopicMapConstraint<T>> implements IKafkaClie
68
94
  * @internal Not part of `IKafkaClient` — use `disconnect()` for full teardown.
69
95
  */
70
96
  disconnectProducer(): Promise<void>;
71
- /** Subscribe to topics and start consuming messages with the given handler. */
97
+ /**
98
+ * Subscribe to one or more topics and start consuming messages one at a time.
99
+ *
100
+ * Each message is delivered to `handleMessage` as a fully-decoded `EventEnvelope`.
101
+ * The call blocks until the consumer is connected and the subscription is set up,
102
+ * then returns a `ConsumerHandle` with a `stop()` method for clean shutdown.
103
+ *
104
+ * @param topics Array of topic keys, `TopicDescriptor` objects, or `RegExp` patterns.
105
+ * Regex patterns cannot be combined with `retryTopics: true`.
106
+ * @param handleMessage Async handler called for every message. Throw to trigger retries.
107
+ * @param options Consumer configuration — `groupId`, `retry`, `dlq`, `circuitBreaker`, etc.
108
+ * @returns A handle with `{ groupId, stop() }` for managing the consumer lifecycle.
109
+ */
72
110
  startConsumer<K extends Array<keyof T>>(topics: K, handleMessage: (envelope: EventEnvelope<T[K[number]]>) => Promise<void>, options?: ConsumerOptions<T>): Promise<ConsumerHandle>;
73
111
  startConsumer<D extends TopicDescriptor<string & keyof T, T[string & keyof T]>>(topics: D[], handleMessage: (envelope: EventEnvelope<D["__type"]>) => Promise<void>, options?: ConsumerOptions<T>): Promise<ConsumerHandle>;
74
- /** Subscribe to topics and consume messages in batches. */
112
+ /**
113
+ * Subscribe to one or more topics and consume messages in batches.
114
+ *
115
+ * `handleBatch` receives an array of decoded `EventEnvelope` objects together with
116
+ * batch metadata (topic, partition, high-watermark offset). Prefer this over
117
+ * `startConsumer` when throughput matters more than per-message latency.
118
+ *
119
+ * Set `autoCommit: false` in options when the handler calls `resolveOffset()` or
120
+ * `commitOffsetsIfNecessary()` directly, to avoid offset conflicts.
121
+ *
122
+ * @param topics Array of topic keys, `TopicDescriptor` objects, or `RegExp` patterns.
123
+ * @param handleBatch Async handler called with each batch of decoded messages.
124
+ * @param options Consumer configuration — `groupId`, `retry`, `dlq`, `autoCommit`, etc.
125
+ * @returns A handle with `{ groupId, stop() }` for managing the consumer lifecycle.
126
+ */
75
127
  startBatchConsumer<K extends Array<keyof T>>(topics: K, handleBatch: (envelopes: EventEnvelope<T[K[number]]>[], meta: BatchMeta) => Promise<void>, options?: ConsumerOptions<T>): Promise<ConsumerHandle>;
76
128
  startBatchConsumer<D extends TopicDescriptor<string & keyof T, T[string & keyof T]>>(topics: D[], handleBatch: (envelopes: EventEnvelope<D["__type"]>[], meta: BatchMeta) => Promise<void>, options?: ConsumerOptions<T>): Promise<ConsumerHandle>;
77
129
  /**
@@ -84,11 +136,31 @@ declare class KafkaClient<T extends TopicMapConstraint<T>> implements IKafkaClie
84
136
  * }
85
137
  */
86
138
  consume<K extends keyof T & string>(topic: K, options?: ConsumerOptions<T>): AsyncIterableIterator<EventEnvelope<T[K]>>;
139
+ /**
140
+ * Stop all consumers or a specific group.
141
+ *
142
+ * If `groupId` is unspecified, all active consumers are stopped.
143
+ * If `groupId` is specified, only the consumer with that group ID is stopped.
144
+ *
145
+ * @throws {Error} if the consumer fails to disconnect.
146
+ */
87
147
  stopConsumer(groupId?: string): Promise<void>;
148
+ /**
149
+ * Temporarily stop delivering messages from specific partitions without disconnecting the consumer.
150
+ *
151
+ * @param groupId Consumer group to pause. Defaults to the client's default groupId.
152
+ * @param assignments Topic-partition pairs to pause.
153
+ */
88
154
  pauseConsumer(groupId: string | undefined, assignments: Array<{
89
155
  topic: string;
90
156
  partitions: number[];
91
157
  }>): void;
158
+ /**
159
+ * Resume message delivery for previously paused topic-partitions.
160
+ *
161
+ * @param {string|undefined} groupId Consumer group to resume. Defaults to the client's default groupId.
162
+ * @param {Array<{ topic: string; partitions: number[] }>} assignments Topic-partition pairs to resume.
163
+ */
92
164
  resumeConsumer(groupId: string | undefined, assignments: Array<{
93
165
  topic: string;
94
166
  partitions: number[];
@@ -97,8 +169,17 @@ declare class KafkaClient<T extends TopicMapConstraint<T>> implements IKafkaClie
97
169
  private pauseTopicAllPartitions;
98
170
  /** Resume all assigned partitions of a topic for a consumer group (used for queue backpressure). */
99
171
  private resumeTopicAllPartitions;
100
- /** DLQ header keys added by `sendToDlq` — stripped before re-publishing. */
101
- private static readonly DLQ_HEADER_KEYS;
172
+ /**
173
+ * Re-publish messages from a dead letter queue back to the original topic.
174
+ *
175
+ * Messages are consumed from `<topic>.dlq` and re-published to `<topic>`.
176
+ * The original topic is determined by the `x-dlq-original-topic` header.
177
+ * The `x-dlq-*` headers are stripped before re-publishing.
178
+ *
179
+ * @param topic - The topic to replay from `<topic>.dlq`
180
+ * @param options - Options for replay
181
+ * @returns { replayed: number; skipped: number } - counts of re-published vs skipped messages
182
+ */
102
183
  replayDlq(topic: string, options?: DlqReplayOptions): Promise<{
103
184
  replayed: number;
104
185
  skipped: number;
@@ -114,11 +195,30 @@ declare class KafkaClient<T extends TopicMapConstraint<T>> implements IKafkaClie
114
195
  partition: number;
115
196
  offset: string;
116
197
  }>): Promise<void>;
198
+ /**
199
+ * Seek specific topic-partition pairs to the offset nearest to a given timestamp
200
+ * (in milliseconds) for a stopped consumer group.
201
+ * Throws if the group is still running — call `stopConsumer(groupId)` first.
202
+ * Assignments are grouped by topic and committed via `admin.setOffsets`.
203
+ * If no offset exists at the requested timestamp (e.g. empty partition or
204
+ * future timestamp), the partition falls back to `-1` (end of topic — new messages only).
205
+ */
117
206
  seekToTimestamp(groupId: string | undefined, assignments: Array<{
118
207
  topic: string;
119
208
  partition: number;
120
209
  timestamp: number;
121
210
  }>): Promise<void>;
211
+ /**
212
+ * Returns the current circuit breaker state for a specific topic partition.
213
+ * Returns `undefined` when no circuit state exists — either `circuitBreaker` is not
214
+ * configured for the group, or the circuit has never been tripped.
215
+ *
216
+ * @param topic Topic name.
217
+ * @param partition Partition index.
218
+ * @param groupId Consumer group. Defaults to the client's default groupId.
219
+ *
220
+ * @returns `{ status, failures, windowSize }` snapshot for a given partition or `undefined` if no state exists.
221
+ */
122
222
  getCircuitState(topic: string, partition: number, groupId?: string): {
123
223
  status: "closed" | "open" | "half-open";
124
224
  failures: number;
@@ -142,8 +242,41 @@ declare class KafkaClient<T extends TopicMapConstraint<T>> implements IKafkaClie
142
242
  }>>;
143
243
  /** Check broker connectivity. Never throws — returns a discriminated union. */
144
244
  checkStatus(): Promise<KafkaHealthResult>;
245
+ /**
246
+ * List all consumer groups known to the broker.
247
+ * Useful for monitoring which groups are active and their current state.
248
+ */
249
+ listConsumerGroups(): Promise<ConsumerGroupSummary[]>;
250
+ /**
251
+ * Describe topics — returns partition layout, leader, replicas, and ISR.
252
+ * @param topics Topic names to describe. Omit to describe all topics.
253
+ */
254
+ describeTopics(topics?: string[]): Promise<TopicDescription[]>;
255
+ /**
256
+ * Delete records from a topic up to (but not including) the given offsets.
257
+ * All messages with offsets **before** the given offset are deleted.
258
+ */
259
+ deleteRecords(topic: string, partitions: Array<{
260
+ partition: number;
261
+ offset: string;
262
+ }>): Promise<void>;
263
+ /** Return the client ID provided during `KafkaClient` construction. */
145
264
  getClientId(): ClientId;
265
+ /**
266
+ * Return a snapshot of internal event counters accumulated since client creation
267
+ * (or since the last `resetMetrics()` call).
268
+ *
269
+ * @param topic Topic name to scope the snapshot to. When omitted, counters are
270
+ * aggregated across all topics. If the topic has no recorded events yet, returns
271
+ * a zero-valued snapshot.
272
+ * @returns Read-only `KafkaMetrics` snapshot: `processedCount`, `retryCount`, `dlqCount`, `dedupCount`.
273
+ */
146
274
  getMetrics(topic?: string): Readonly<KafkaMetrics>;
275
+ /**
276
+ * Reset internal event counters to zero.
277
+ *
278
+ * @param topic Topic name to reset. When omitted, all topics are reset.
279
+ */
147
280
  resetMetrics(topic?: string): void;
148
281
  /** Gracefully disconnect producer, all consumers, and admin. */
149
282
  disconnect(drainTimeoutMs?: number): Promise<void>;
@@ -159,60 +292,38 @@ declare class KafkaClient<T extends TopicMapConstraint<T>> implements IKafkaClie
159
292
  * NestJS apps get drain for free via `onModuleDestroy` → `disconnect()`.
160
293
  */
161
294
  enableGracefulShutdown(signals?: NodeJS.Signals[], drainTimeoutMs?: number): void;
162
- private trackInFlight;
163
- private waitForDrain;
164
295
  private preparePayload;
165
- private notifyAfterSend;
166
- private metricsFor;
167
- private notifyRetry;
168
- private notifyDlq;
169
- private notifyDuplicate;
170
- private notifyMessage;
171
296
  /**
172
297
  * Start a timer that logs a warning if `fn` hasn't resolved within `timeoutMs`.
173
298
  * The handler itself is not cancelled — the warning is diagnostic only.
174
299
  */
175
300
  private wrapWithTimeoutWarning;
176
- /**
177
- * When `retryTopics: true` and `autoCreateTopics: false`, verify that every
178
- * `<topic>.retry.<level>` topic already exists. Throws a clear error at startup
179
- * rather than silently discovering missing topics on the first handler failure.
180
- */
181
- private validateRetryTopicsExist;
182
- /**
183
- * When `autoCreateTopics` is disabled, verify that `<topic>.dlq` exists for every
184
- * consumed topic. Throws a clear error at startup rather than silently discovering
185
- * missing DLQ topics on the first handler failure.
186
- */
187
- private validateDlqTopicsExist;
188
- /**
189
- * When `deduplication.strategy: 'topic'` and `autoCreateTopics: false`, verify
190
- * that every `<topic>.duplicates` destination topic already exists. Throws a
191
- * clear error at startup rather than silently dropping duplicates on first hit.
192
- */
193
- private validateDuplicatesTopicsExist;
194
- /**
195
- * Connect the admin client if not already connected.
196
- * The flag is only set to `true` after a successful connect — if `admin.connect()`
197
- * throws the flag remains `false` so the next call will retry the connection.
198
- */
199
- private ensureAdminConnected;
200
301
  /**
201
302
  * Create and connect a transactional producer for EOS retry routing.
202
303
  * Each retry level consumer gets its own producer with a unique `transactionalId`
203
304
  * so Kafka can fence stale producers on restart without affecting other levels.
204
305
  */
205
306
  private createRetryTxProducer;
307
+ /**
308
+ * Ensure that a topic exists by creating it if it doesn't already exist.
309
+ * If `autoCreateTopics` is disabled, returns immediately.
310
+ * Concurrent calls for the same topic are deduplicated.
311
+ */
206
312
  private ensureTopic;
207
313
  /** Shared consumer setup: groupId check, schema map, connect, subscribe. */
208
314
  private setupConsumer;
209
315
  /** Create or retrieve the deduplication context for a consumer group. */
210
316
  private resolveDeduplicationContext;
211
- private get producerOpsDeps();
212
- private get consumerOpsDeps();
317
+ /** Guard checks shared by startConsumer and startBatchConsumer. */
318
+ private validateTopicConsumerOpts;
319
+ /** Create EOS transactional producer context for atomic main → retry.1 routing. */
320
+ private makeEosMainContext;
321
+ /** Start companion retry-level consumers and register them under the main groupId. */
322
+ private launchRetryChain;
213
323
  /** Build MessageHandlerDeps with circuit breaker callbacks bound to the given groupId. */
214
324
  private messageDepsFor;
215
- private get retryTopicDeps();
325
+ /** Build the deps object passed to retry topic consumers. */
326
+ private buildRetryTopicDeps;
216
327
  }
217
328
 
218
329
  /** Error thrown when a consumer message handler fails. */
@@ -241,4 +352,4 @@ declare class KafkaRetryExhaustedError extends KafkaProcessingError {
241
352
  });
242
353
  }
243
354
 
244
- export { BatchMessageItem, BatchMeta, ClientId, ConsumerHandle, ConsumerOptions, DlqReplayOptions, EventEnvelope, GroupId, IKafkaClient, KafkaClient, KafkaClientOptions, KafkaHealthResult, KafkaMetrics, KafkaProcessingError, KafkaRetryExhaustedError, KafkaValidationError, SendOptions, TopicDescriptor, TopicMapConstraint, TransactionContext };
355
+ export { BatchMessageItem, BatchMeta, BatchSendOptions, ClientId, ConsumerGroupSummary, ConsumerHandle, ConsumerOptions, DlqReplayOptions, EventEnvelope, GroupId, IKafkaClient, KafkaClient, KafkaClientOptions, KafkaHealthResult, KafkaMetrics, KafkaProcessingError, KafkaRetryExhaustedError, KafkaValidationError, MessageHeaders, SendOptions, TopicDescription, TopicDescriptor, TopicMapConstraint, TransactionContext };