@drarzter/kafka-client 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +102 -10
- package/dist/{chunk-YCKN2YEC.mjs → chunk-VGUALBZH.mjs} +61 -29
- package/dist/chunk-VGUALBZH.mjs.map +1 -0
- package/dist/core.d.mts +6 -3
- package/dist/core.d.ts +6 -3
- package/dist/core.js +60 -28
- package/dist/core.js.map +1 -1
- package/dist/core.mjs +1 -1
- package/dist/{envelope-QK1trQu4.d.mts → envelope-C66_h8r_.d.mts} +27 -3
- package/dist/{envelope-QK1trQu4.d.ts → envelope-C66_h8r_.d.ts} +27 -3
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +61 -34
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -7
- package/dist/index.mjs.map +1 -1
- package/dist/otel.d.mts +1 -1
- package/dist/otel.d.ts +1 -1
- package/dist/otel.js +1 -1
- package/dist/otel.js.map +1 -1
- package/dist/otel.mjs +1 -1
- package/dist/otel.mjs.map +1 -1
- package/dist/testing.d.mts +2 -2
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +1 -1
- package/dist/testing.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-YCKN2YEC.mjs.map +0 -1
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* ```
|
|
10
10
|
*/
|
|
11
11
|
interface SchemaLike<T = any> {
|
|
12
|
-
parse(data: unknown): T
|
|
12
|
+
parse(data: unknown): T | Promise<T>;
|
|
13
13
|
}
|
|
14
14
|
/** Infer the output type from a SchemaLike. */
|
|
15
15
|
type InferSchema<S extends SchemaLike> = S extends SchemaLike<infer T> ? T : never;
|
|
@@ -158,8 +158,10 @@ interface ConsumerOptions<T extends TopicMapConstraint<T> = TTopicMessageMap> {
|
|
|
158
158
|
interface RetryOptions {
|
|
159
159
|
/** Maximum number of retry attempts before giving up. */
|
|
160
160
|
maxRetries: number;
|
|
161
|
-
/** Base delay
|
|
161
|
+
/** Base delay for exponential backoff in ms. Default: `1000`. */
|
|
162
162
|
backoffMs?: number;
|
|
163
|
+
/** Maximum delay cap for exponential backoff in ms. Default: `30000`. */
|
|
164
|
+
maxBackoffMs?: number;
|
|
163
165
|
}
|
|
164
166
|
/**
|
|
165
167
|
* Interceptor hooks for consumer message processing.
|
|
@@ -202,6 +204,8 @@ interface TransactionContext<T extends TopicMapConstraint<T>> {
|
|
|
202
204
|
/** Interface describing all public methods of the Kafka client. */
|
|
203
205
|
interface IKafkaClient<T extends TopicMapConstraint<T>> {
|
|
204
206
|
checkStatus(): Promise<{
|
|
207
|
+
status: 'up';
|
|
208
|
+
clientId: string;
|
|
205
209
|
topics: string[];
|
|
206
210
|
}>;
|
|
207
211
|
startConsumer<K extends Array<keyof T>>(topics: K, handleMessage: (envelope: EventEnvelope<T[K[number]]>) => Promise<void>, options?: ConsumerOptions<T>): Promise<void>;
|
|
@@ -224,6 +228,20 @@ interface KafkaLogger {
|
|
|
224
228
|
warn(message: string, ...args: any[]): void;
|
|
225
229
|
error(message: string, ...args: any[]): void;
|
|
226
230
|
}
|
|
231
|
+
/**
|
|
232
|
+
* Context passed to `onMessageLost` when a message is silently dropped
|
|
233
|
+
* (handler threw and `dlq` is not enabled).
|
|
234
|
+
*/
|
|
235
|
+
interface MessageLostContext {
|
|
236
|
+
/** Topic the message was consumed from. */
|
|
237
|
+
topic: string;
|
|
238
|
+
/** Error that caused the message to be dropped. */
|
|
239
|
+
error: Error;
|
|
240
|
+
/** Number of processing attempts (0 = validation failure, before handler ran). */
|
|
241
|
+
attempt: number;
|
|
242
|
+
/** Original Kafka message headers (correlationId, traceparent, etc.). */
|
|
243
|
+
headers: MessageHeaders;
|
|
244
|
+
}
|
|
227
245
|
/** Options for `KafkaClient` constructor. */
|
|
228
246
|
interface KafkaClientOptions {
|
|
229
247
|
/** Auto-create topics via admin before the first `sendMessage`, `sendBatch`, or `transaction` for each topic. Useful for development — not recommended in production. */
|
|
@@ -236,6 +254,12 @@ interface KafkaClientOptions {
|
|
|
236
254
|
numPartitions?: number;
|
|
237
255
|
/** Client-wide instrumentation hooks (e.g. OTel). Applied to both send and consume paths. */
|
|
238
256
|
instrumentation?: KafkaInstrumentation[];
|
|
257
|
+
/**
|
|
258
|
+
* Called when a message is dropped without being sent to a DLQ.
|
|
259
|
+
* Fires when the handler throws after all retries, or schema validation fails — and `dlq` is not enabled.
|
|
260
|
+
* Use this to alert, log to external systems, or trigger fallback logic.
|
|
261
|
+
*/
|
|
262
|
+
onMessageLost?: (ctx: MessageLostContext) => void | Promise<void>;
|
|
239
263
|
}
|
|
240
264
|
/** Options for consumer subscribe retry when topic doesn't exist yet. */
|
|
241
265
|
interface SubscribeRetryOptions {
|
|
@@ -316,4 +340,4 @@ declare function decodeHeaders(raw: Record<string, Buffer | string | (Buffer | s
|
|
|
316
340
|
*/
|
|
317
341
|
declare function extractEnvelope<T>(payload: T, headers: MessageHeaders, topic: string, partition: number, offset: string): EventEnvelope<T>;
|
|
318
342
|
|
|
319
|
-
export { type BatchMessageItem as B, type ClientId as C, type EnvelopeHeaderOptions as E, type GroupId as G, HEADER_CORRELATION_ID as H, type IKafkaClient as I, type KafkaInstrumentation as K, type MessageHeaders as M, type RetryOptions as R, type SchemaLike as S, type TopicMapConstraint as T, type ConsumerOptions as a, type TopicDescriptor as b, type BatchMeta as c, type ConsumerInterceptor as d, type EventEnvelope as e, HEADER_EVENT_ID as f, HEADER_SCHEMA_VERSION as g, HEADER_TIMESTAMP as h, HEADER_TRACEPARENT as i, type InferSchema as j, type KafkaClientOptions as k, type KafkaLogger as l, type
|
|
343
|
+
export { type BatchMessageItem as B, type ClientId as C, type EnvelopeHeaderOptions as E, type GroupId as G, HEADER_CORRELATION_ID as H, type IKafkaClient as I, type KafkaInstrumentation as K, type MessageHeaders as M, type RetryOptions as R, type SchemaLike as S, type TopicMapConstraint as T, type ConsumerOptions as a, type TopicDescriptor as b, type BatchMeta as c, type ConsumerInterceptor as d, type EventEnvelope as e, HEADER_EVENT_ID as f, HEADER_SCHEMA_VERSION as g, HEADER_TIMESTAMP as h, HEADER_TRACEPARENT as i, type InferSchema as j, type KafkaClientOptions as k, type KafkaLogger as l, type MessageLostContext as m, type SendOptions as n, type SubscribeRetryOptions as o, type TTopicMessageMap as p, type TopicsFrom as q, type TransactionContext as r, buildEnvelopeHeaders as s, decodeHeaders as t, extractEnvelope as u, getEnvelopeContext as v, runWithEnvelopeContext as w, topic as x };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { KafkaClient } from './core.mjs';
|
|
2
2
|
export { KafkaProcessingError, KafkaRetryExhaustedError, KafkaValidationError } from './core.mjs';
|
|
3
|
-
import { T as TopicMapConstraint, C as ClientId, G as GroupId, K as KafkaInstrumentation, S as SchemaLike, a as ConsumerOptions, b as TopicDescriptor } from './envelope-
|
|
4
|
-
export { B as BatchMessageItem, c as BatchMeta, d as ConsumerInterceptor, E as EnvelopeHeaderOptions, e as EventEnvelope, H as HEADER_CORRELATION_ID, f as HEADER_EVENT_ID, g as HEADER_SCHEMA_VERSION, h as HEADER_TIMESTAMP, i as HEADER_TRACEPARENT, I as IKafkaClient, j as InferSchema, k as KafkaClientOptions, l as KafkaLogger, M as MessageHeaders, R as RetryOptions,
|
|
3
|
+
import { T as TopicMapConstraint, C as ClientId, G as GroupId, K as KafkaInstrumentation, S as SchemaLike, a as ConsumerOptions, b as TopicDescriptor } from './envelope-C66_h8r_.mjs';
|
|
4
|
+
export { B as BatchMessageItem, c as BatchMeta, d as ConsumerInterceptor, E as EnvelopeHeaderOptions, e as EventEnvelope, H as HEADER_CORRELATION_ID, f as HEADER_EVENT_ID, g as HEADER_SCHEMA_VERSION, h as HEADER_TIMESTAMP, i as HEADER_TRACEPARENT, I as IKafkaClient, j as InferSchema, k as KafkaClientOptions, l as KafkaLogger, M as MessageHeaders, m as MessageLostContext, R as RetryOptions, n as SendOptions, o as SubscribeRetryOptions, p as TTopicMessageMap, q as TopicsFrom, r as TransactionContext, s as buildEnvelopeHeaders, t as decodeHeaders, u as extractEnvelope, v as getEnvelopeContext, w as runWithEnvelopeContext, x as topic } from './envelope-C66_h8r_.mjs';
|
|
5
5
|
import { DynamicModule, OnModuleInit } from '@nestjs/common';
|
|
6
6
|
import { DiscoveryService, ModuleRef } from '@nestjs/core';
|
|
7
7
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { KafkaClient } from './core.js';
|
|
2
2
|
export { KafkaProcessingError, KafkaRetryExhaustedError, KafkaValidationError } from './core.js';
|
|
3
|
-
import { T as TopicMapConstraint, C as ClientId, G as GroupId, K as KafkaInstrumentation, S as SchemaLike, a as ConsumerOptions, b as TopicDescriptor } from './envelope-
|
|
4
|
-
export { B as BatchMessageItem, c as BatchMeta, d as ConsumerInterceptor, E as EnvelopeHeaderOptions, e as EventEnvelope, H as HEADER_CORRELATION_ID, f as HEADER_EVENT_ID, g as HEADER_SCHEMA_VERSION, h as HEADER_TIMESTAMP, i as HEADER_TRACEPARENT, I as IKafkaClient, j as InferSchema, k as KafkaClientOptions, l as KafkaLogger, M as MessageHeaders, R as RetryOptions,
|
|
3
|
+
import { T as TopicMapConstraint, C as ClientId, G as GroupId, K as KafkaInstrumentation, S as SchemaLike, a as ConsumerOptions, b as TopicDescriptor } from './envelope-C66_h8r_.js';
|
|
4
|
+
export { B as BatchMessageItem, c as BatchMeta, d as ConsumerInterceptor, E as EnvelopeHeaderOptions, e as EventEnvelope, H as HEADER_CORRELATION_ID, f as HEADER_EVENT_ID, g as HEADER_SCHEMA_VERSION, h as HEADER_TIMESTAMP, i as HEADER_TRACEPARENT, I as IKafkaClient, j as InferSchema, k as KafkaClientOptions, l as KafkaLogger, M as MessageHeaders, m as MessageLostContext, R as RetryOptions, n as SendOptions, o as SubscribeRetryOptions, p as TTopicMessageMap, q as TopicsFrom, r as TransactionContext, s as buildEnvelopeHeaders, t as decodeHeaders, u as extractEnvelope, v as getEnvelopeContext, w as runWithEnvelopeContext, x as topic } from './envelope-C66_h8r_.js';
|
|
5
5
|
import { DynamicModule, OnModuleInit } from '@nestjs/common';
|
|
6
6
|
import { DiscoveryService, ModuleRef } from '@nestjs/core';
|
|
7
7
|
|
package/dist/index.js
CHANGED
|
@@ -172,7 +172,7 @@ async function validateWithSchema(message, raw, topic2, schemaMap, interceptors,
|
|
|
172
172
|
const schema = schemaMap.get(topic2);
|
|
173
173
|
if (!schema) return message;
|
|
174
174
|
try {
|
|
175
|
-
return schema.parse(message);
|
|
175
|
+
return await schema.parse(message);
|
|
176
176
|
} catch (error) {
|
|
177
177
|
const err = toError(error);
|
|
178
178
|
const validationError = new KafkaValidationError(topic2, message, {
|
|
@@ -182,20 +182,36 @@ async function validateWithSchema(message, raw, topic2, schemaMap, interceptors,
|
|
|
182
182
|
`Schema validation failed for topic ${topic2}:`,
|
|
183
183
|
err.message
|
|
184
184
|
);
|
|
185
|
-
if (dlq)
|
|
186
|
-
|
|
185
|
+
if (dlq) {
|
|
186
|
+
await sendToDlq(topic2, raw, deps, {
|
|
187
|
+
error: validationError,
|
|
188
|
+
attempt: 0,
|
|
189
|
+
originalHeaders: deps.originalHeaders
|
|
190
|
+
});
|
|
191
|
+
} else {
|
|
192
|
+
await deps.onMessageLost?.({ topic: topic2, error: validationError, attempt: 0, headers: deps.originalHeaders ?? {} });
|
|
193
|
+
}
|
|
194
|
+
const errorEnvelope = extractEnvelope(message, deps.originalHeaders ?? {}, topic2, -1, "");
|
|
187
195
|
for (const interceptor of interceptors) {
|
|
188
196
|
await interceptor.onError?.(errorEnvelope, validationError);
|
|
189
197
|
}
|
|
190
198
|
return null;
|
|
191
199
|
}
|
|
192
200
|
}
|
|
193
|
-
async function sendToDlq(topic2, rawMessage, deps) {
|
|
201
|
+
async function sendToDlq(topic2, rawMessage, deps, meta) {
|
|
194
202
|
const dlqTopic = `${topic2}.dlq`;
|
|
203
|
+
const headers = {
|
|
204
|
+
...meta?.originalHeaders ?? {},
|
|
205
|
+
"x-dlq-original-topic": topic2,
|
|
206
|
+
"x-dlq-failed-at": (/* @__PURE__ */ new Date()).toISOString(),
|
|
207
|
+
"x-dlq-error-message": meta?.error.message ?? "unknown",
|
|
208
|
+
"x-dlq-error-stack": meta?.error.stack?.slice(0, 2e3) ?? "",
|
|
209
|
+
"x-dlq-attempt-count": String(meta?.attempt ?? 0)
|
|
210
|
+
};
|
|
195
211
|
try {
|
|
196
212
|
await deps.producer.send({
|
|
197
213
|
topic: dlqTopic,
|
|
198
|
-
messages: [{ value: rawMessage }]
|
|
214
|
+
messages: [{ value: rawMessage, headers }]
|
|
199
215
|
});
|
|
200
216
|
deps.logger.warn(`Message sent to DLQ: ${dlqTopic}`);
|
|
201
217
|
} catch (error) {
|
|
@@ -209,6 +225,7 @@ async function executeWithRetry(fn, ctx, deps) {
|
|
|
209
225
|
const { envelope, rawMessages, interceptors, dlq, retry, isBatch } = ctx;
|
|
210
226
|
const maxAttempts = retry ? retry.maxRetries + 1 : 1;
|
|
211
227
|
const backoffMs = retry?.backoffMs ?? 1e3;
|
|
228
|
+
const maxBackoffMs = retry?.maxBackoffMs ?? 3e4;
|
|
212
229
|
const envelopes = Array.isArray(envelope) ? envelope : [envelope];
|
|
213
230
|
const topic2 = envelopes[0]?.topic ?? "unknown";
|
|
214
231
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
@@ -267,12 +284,25 @@ async function executeWithRetry(fn, ctx, deps) {
|
|
|
267
284
|
);
|
|
268
285
|
if (isLastAttempt) {
|
|
269
286
|
if (dlq) {
|
|
287
|
+
const dlqMeta = {
|
|
288
|
+
error: err,
|
|
289
|
+
attempt,
|
|
290
|
+
originalHeaders: envelopes[0]?.headers
|
|
291
|
+
};
|
|
270
292
|
for (const raw of rawMessages) {
|
|
271
|
-
await sendToDlq(topic2, raw, deps);
|
|
293
|
+
await sendToDlq(topic2, raw, deps, dlqMeta);
|
|
272
294
|
}
|
|
295
|
+
} else {
|
|
296
|
+
await deps.onMessageLost?.({
|
|
297
|
+
topic: topic2,
|
|
298
|
+
error: err,
|
|
299
|
+
attempt,
|
|
300
|
+
headers: envelopes[0]?.headers ?? {}
|
|
301
|
+
});
|
|
273
302
|
}
|
|
274
303
|
} else {
|
|
275
|
-
|
|
304
|
+
const cap = Math.min(backoffMs * 2 ** (attempt - 1), maxBackoffMs);
|
|
305
|
+
await sleep(Math.random() * cap);
|
|
276
306
|
}
|
|
277
307
|
}
|
|
278
308
|
}
|
|
@@ -314,6 +344,7 @@ var KafkaClient = class {
|
|
|
314
344
|
schemaRegistry = /* @__PURE__ */ new Map();
|
|
315
345
|
runningConsumers = /* @__PURE__ */ new Map();
|
|
316
346
|
instrumentation;
|
|
347
|
+
onMessageLost;
|
|
317
348
|
isAdminConnected = false;
|
|
318
349
|
clientId;
|
|
319
350
|
constructor(clientId, groupId, brokers, options) {
|
|
@@ -328,6 +359,7 @@ var KafkaClient = class {
|
|
|
328
359
|
this.strictSchemasEnabled = options?.strictSchemas ?? true;
|
|
329
360
|
this.numPartitions = options?.numPartitions ?? 1;
|
|
330
361
|
this.instrumentation = options?.instrumentation ?? [];
|
|
362
|
+
this.onMessageLost = options?.onMessageLost;
|
|
331
363
|
this.kafka = new KafkaClass({
|
|
332
364
|
kafkaJS: {
|
|
333
365
|
clientId: this.clientId,
|
|
@@ -343,7 +375,7 @@ var KafkaClient = class {
|
|
|
343
375
|
this.admin = this.kafka.admin();
|
|
344
376
|
}
|
|
345
377
|
async sendMessage(topicOrDesc, message, options = {}) {
|
|
346
|
-
const payload = this.buildSendPayload(topicOrDesc, [
|
|
378
|
+
const payload = await this.buildSendPayload(topicOrDesc, [
|
|
347
379
|
{
|
|
348
380
|
value: message,
|
|
349
381
|
key: options.key,
|
|
@@ -360,7 +392,7 @@ var KafkaClient = class {
|
|
|
360
392
|
}
|
|
361
393
|
}
|
|
362
394
|
async sendBatch(topicOrDesc, messages) {
|
|
363
|
-
const payload = this.buildSendPayload(topicOrDesc, messages);
|
|
395
|
+
const payload = await this.buildSendPayload(topicOrDesc, messages);
|
|
364
396
|
await this.ensureTopic(payload.topic);
|
|
365
397
|
await this.producer.send(payload);
|
|
366
398
|
for (const inst of this.instrumentation) {
|
|
@@ -384,7 +416,7 @@ var KafkaClient = class {
|
|
|
384
416
|
try {
|
|
385
417
|
const ctx = {
|
|
386
418
|
send: async (topicOrDesc, message, options = {}) => {
|
|
387
|
-
const payload = this.buildSendPayload(topicOrDesc, [
|
|
419
|
+
const payload = await this.buildSendPayload(topicOrDesc, [
|
|
388
420
|
{
|
|
389
421
|
value: message,
|
|
390
422
|
key: options.key,
|
|
@@ -398,7 +430,7 @@ var KafkaClient = class {
|
|
|
398
430
|
await tx.send(payload);
|
|
399
431
|
},
|
|
400
432
|
sendBatch: async (topicOrDesc, messages) => {
|
|
401
|
-
const payload = this.buildSendPayload(topicOrDesc, messages);
|
|
433
|
+
const payload = await this.buildSendPayload(topicOrDesc, messages);
|
|
402
434
|
await this.ensureTopic(payload.topic);
|
|
403
435
|
await tx.send(payload);
|
|
404
436
|
}
|
|
@@ -429,7 +461,7 @@ var KafkaClient = class {
|
|
|
429
461
|
}
|
|
430
462
|
async startConsumer(topics, handleMessage, options = {}) {
|
|
431
463
|
const { consumer, schemaMap, gid, dlq, interceptors, retry } = await this.setupConsumer(topics, "eachMessage", options);
|
|
432
|
-
const deps = { logger: this.logger, producer: this.producer, instrumentation: this.instrumentation };
|
|
464
|
+
const deps = { logger: this.logger, producer: this.producer, instrumentation: this.instrumentation, onMessageLost: this.onMessageLost };
|
|
433
465
|
await consumer.run({
|
|
434
466
|
eachMessage: async ({ topic: topic2, partition, message }) => {
|
|
435
467
|
if (!message.value) {
|
|
@@ -439,6 +471,7 @@ var KafkaClient = class {
|
|
|
439
471
|
const raw = message.value.toString();
|
|
440
472
|
const parsed = parseJsonMessage(raw, topic2, this.logger);
|
|
441
473
|
if (parsed === null) return;
|
|
474
|
+
const headers = decodeHeaders(message.headers);
|
|
442
475
|
const validated = await validateWithSchema(
|
|
443
476
|
parsed,
|
|
444
477
|
raw,
|
|
@@ -446,10 +479,9 @@ var KafkaClient = class {
|
|
|
446
479
|
schemaMap,
|
|
447
480
|
interceptors,
|
|
448
481
|
dlq,
|
|
449
|
-
deps
|
|
482
|
+
{ ...deps, originalHeaders: headers }
|
|
450
483
|
);
|
|
451
484
|
if (validated === null) return;
|
|
452
|
-
const headers = decodeHeaders(message.headers);
|
|
453
485
|
const envelope = extractEnvelope(
|
|
454
486
|
validated,
|
|
455
487
|
headers,
|
|
@@ -471,7 +503,7 @@ var KafkaClient = class {
|
|
|
471
503
|
}
|
|
472
504
|
async startBatchConsumer(topics, handleBatch, options = {}) {
|
|
473
505
|
const { consumer, schemaMap, gid, dlq, interceptors, retry } = await this.setupConsumer(topics, "eachBatch", options);
|
|
474
|
-
const deps = { logger: this.logger, producer: this.producer, instrumentation: this.instrumentation };
|
|
506
|
+
const deps = { logger: this.logger, producer: this.producer, instrumentation: this.instrumentation, onMessageLost: this.onMessageLost };
|
|
475
507
|
await consumer.run({
|
|
476
508
|
eachBatch: async ({
|
|
477
509
|
batch,
|
|
@@ -491,6 +523,7 @@ var KafkaClient = class {
|
|
|
491
523
|
const raw = message.value.toString();
|
|
492
524
|
const parsed = parseJsonMessage(raw, batch.topic, this.logger);
|
|
493
525
|
if (parsed === null) continue;
|
|
526
|
+
const headers = decodeHeaders(message.headers);
|
|
494
527
|
const validated = await validateWithSchema(
|
|
495
528
|
parsed,
|
|
496
529
|
raw,
|
|
@@ -498,10 +531,9 @@ var KafkaClient = class {
|
|
|
498
531
|
schemaMap,
|
|
499
532
|
interceptors,
|
|
500
533
|
dlq,
|
|
501
|
-
deps
|
|
534
|
+
{ ...deps, originalHeaders: headers }
|
|
502
535
|
);
|
|
503
536
|
if (validated === null) continue;
|
|
504
|
-
const headers = decodeHeaders(message.headers);
|
|
505
537
|
envelopes.push(
|
|
506
538
|
extractEnvelope(validated, headers, batch.topic, batch.partition, message.offset)
|
|
507
539
|
);
|
|
@@ -542,14 +574,14 @@ var KafkaClient = class {
|
|
|
542
574
|
this.runningConsumers.clear();
|
|
543
575
|
this.logger.log("All consumers disconnected");
|
|
544
576
|
}
|
|
545
|
-
/** Check broker connectivity and return available topics. */
|
|
577
|
+
/** Check broker connectivity and return status, clientId, and available topics. */
|
|
546
578
|
async checkStatus() {
|
|
547
579
|
if (!this.isAdminConnected) {
|
|
548
580
|
await this.admin.connect();
|
|
549
581
|
this.isAdminConnected = true;
|
|
550
582
|
}
|
|
551
583
|
const topics = await this.admin.listTopics();
|
|
552
|
-
return { topics };
|
|
584
|
+
return { status: "up", clientId: this.clientId, topics };
|
|
553
585
|
}
|
|
554
586
|
getClientId() {
|
|
555
587
|
return this.clientId;
|
|
@@ -611,13 +643,13 @@ var KafkaClient = class {
|
|
|
611
643
|
}
|
|
612
644
|
}
|
|
613
645
|
/** Validate message against schema. Pure — no side-effects on registry. */
|
|
614
|
-
validateMessage(topicOrDesc, message) {
|
|
646
|
+
async validateMessage(topicOrDesc, message) {
|
|
615
647
|
if (topicOrDesc?.__schema) {
|
|
616
|
-
return topicOrDesc.__schema.parse(message);
|
|
648
|
+
return await topicOrDesc.__schema.parse(message);
|
|
617
649
|
}
|
|
618
650
|
if (this.strictSchemasEnabled && typeof topicOrDesc === "string") {
|
|
619
651
|
const schema = this.schemaRegistry.get(topicOrDesc);
|
|
620
|
-
if (schema) return schema.parse(message);
|
|
652
|
+
if (schema) return await schema.parse(message);
|
|
621
653
|
}
|
|
622
654
|
return message;
|
|
623
655
|
}
|
|
@@ -626,12 +658,11 @@ var KafkaClient = class {
|
|
|
626
658
|
* Handles: topic resolution, schema registration, validation, JSON serialization,
|
|
627
659
|
* envelope header generation, and instrumentation hooks.
|
|
628
660
|
*/
|
|
629
|
-
buildSendPayload(topicOrDesc, messages) {
|
|
661
|
+
async buildSendPayload(topicOrDesc, messages) {
|
|
630
662
|
this.registerSchema(topicOrDesc);
|
|
631
663
|
const topic2 = this.resolveTopicName(topicOrDesc);
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
messages: messages.map((m) => {
|
|
664
|
+
const builtMessages = await Promise.all(
|
|
665
|
+
messages.map(async (m) => {
|
|
635
666
|
const envelopeHeaders = buildEnvelopeHeaders({
|
|
636
667
|
correlationId: m.correlationId,
|
|
637
668
|
schemaVersion: m.schemaVersion,
|
|
@@ -642,12 +673,13 @@ var KafkaClient = class {
|
|
|
642
673
|
inst.beforeSend?.(topic2, envelopeHeaders);
|
|
643
674
|
}
|
|
644
675
|
return {
|
|
645
|
-
value: JSON.stringify(this.validateMessage(topicOrDesc, m.value)),
|
|
676
|
+
value: JSON.stringify(await this.validateMessage(topicOrDesc, m.value)),
|
|
646
677
|
key: m.key ?? null,
|
|
647
678
|
headers: envelopeHeaders
|
|
648
679
|
};
|
|
649
680
|
})
|
|
650
|
-
|
|
681
|
+
);
|
|
682
|
+
return { topic: topic2, messages: builtMessages };
|
|
651
683
|
}
|
|
652
684
|
/** Shared consumer setup: groupId check, schema map, connect, subscribe. */
|
|
653
685
|
async setupConsumer(topics, mode, options) {
|
|
@@ -917,12 +949,7 @@ var import_common4 = require("@nestjs/common");
|
|
|
917
949
|
var KafkaHealthIndicator = class {
|
|
918
950
|
async check(client) {
|
|
919
951
|
try {
|
|
920
|
-
|
|
921
|
-
return {
|
|
922
|
-
status: "up",
|
|
923
|
-
clientId: client.clientId,
|
|
924
|
-
topics
|
|
925
|
-
};
|
|
952
|
+
return await client.checkStatus();
|
|
926
953
|
} catch (error) {
|
|
927
954
|
return {
|
|
928
955
|
status: "down",
|