@drarzter/kafka-client 0.9.4 → 0.10.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 (170) hide show
  1. package/README.md +625 -8
  2. package/dist/chunk-CMO7SMVK.mjs +4814 -0
  3. package/dist/chunk-CMO7SMVK.mjs.map +1 -0
  4. package/dist/cli/dlq.d.ts +119 -0
  5. package/dist/cli/dlq.d.ts.map +1 -0
  6. package/dist/cli/index.d.ts +3 -0
  7. package/dist/cli/index.d.ts.map +1 -0
  8. package/dist/{chunk-SM4FZKAZ.mjs → cli/index.js} +964 -264
  9. package/dist/cli/index.js.map +1 -0
  10. package/dist/cli/index.mjs +355 -0
  11. package/dist/cli/index.mjs.map +1 -0
  12. package/dist/client/config/from-env.d.ts +188 -0
  13. package/dist/client/config/from-env.d.ts.map +1 -0
  14. package/dist/client/config/index.d.ts +2 -0
  15. package/dist/client/config/index.d.ts.map +1 -0
  16. package/dist/client/errors.d.ts +67 -0
  17. package/dist/client/errors.d.ts.map +1 -0
  18. package/dist/client/kafka.client/admin/ops.d.ts +114 -0
  19. package/dist/client/kafka.client/admin/ops.d.ts.map +1 -0
  20. package/dist/client/kafka.client/consumer/features/delayed.d.ts +24 -0
  21. package/dist/client/kafka.client/consumer/features/delayed.d.ts.map +1 -0
  22. package/dist/client/kafka.client/consumer/features/dlq-replay.d.ts +52 -0
  23. package/dist/client/kafka.client/consumer/features/dlq-replay.d.ts.map +1 -0
  24. package/dist/client/kafka.client/consumer/features/routed.d.ts +4 -0
  25. package/dist/client/kafka.client/consumer/features/routed.d.ts.map +1 -0
  26. package/dist/client/kafka.client/consumer/features/snapshot.d.ts +10 -0
  27. package/dist/client/kafka.client/consumer/features/snapshot.d.ts.map +1 -0
  28. package/dist/client/kafka.client/consumer/features/window.d.ts +5 -0
  29. package/dist/client/kafka.client/consumer/features/window.d.ts.map +1 -0
  30. package/dist/client/kafka.client/consumer/handler.d.ts +149 -0
  31. package/dist/client/kafka.client/consumer/handler.d.ts.map +1 -0
  32. package/dist/client/kafka.client/consumer/ops.d.ts +51 -0
  33. package/dist/client/kafka.client/consumer/ops.d.ts.map +1 -0
  34. package/dist/client/kafka.client/consumer/pipeline.d.ts +167 -0
  35. package/dist/client/kafka.client/consumer/pipeline.d.ts.map +1 -0
  36. package/dist/client/kafka.client/consumer/queue.d.ts +37 -0
  37. package/dist/client/kafka.client/consumer/queue.d.ts.map +1 -0
  38. package/dist/client/kafka.client/consumer/retry-topic.d.ts +65 -0
  39. package/dist/client/kafka.client/consumer/retry-topic.d.ts.map +1 -0
  40. package/dist/client/kafka.client/consumer/setup.d.ts +63 -0
  41. package/dist/client/kafka.client/consumer/setup.d.ts.map +1 -0
  42. package/dist/client/kafka.client/consumer/start.d.ts +7 -0
  43. package/dist/client/kafka.client/consumer/start.d.ts.map +1 -0
  44. package/dist/client/kafka.client/consumer/stop.d.ts +19 -0
  45. package/dist/client/kafka.client/consumer/stop.d.ts.map +1 -0
  46. package/dist/client/kafka.client/consumer/subscribe-retry.d.ts +4 -0
  47. package/dist/client/kafka.client/consumer/subscribe-retry.d.ts.map +1 -0
  48. package/dist/client/kafka.client/context.d.ts +72 -0
  49. package/dist/client/kafka.client/context.d.ts.map +1 -0
  50. package/dist/client/kafka.client/index.d.ts +155 -0
  51. package/dist/client/kafka.client/index.d.ts.map +1 -0
  52. package/dist/client/kafka.client/infra/circuit-breaker.manager.d.ts +61 -0
  53. package/dist/client/kafka.client/infra/circuit-breaker.manager.d.ts.map +1 -0
  54. package/dist/client/kafka.client/infra/dedup.store.d.ts +28 -0
  55. package/dist/client/kafka.client/infra/dedup.store.d.ts.map +1 -0
  56. package/dist/client/kafka.client/infra/inflight.tracker.d.ts +22 -0
  57. package/dist/client/kafka.client/infra/inflight.tracker.d.ts.map +1 -0
  58. package/dist/client/kafka.client/infra/metrics.manager.d.ts +67 -0
  59. package/dist/client/kafka.client/infra/metrics.manager.d.ts.map +1 -0
  60. package/dist/client/kafka.client/producer/lifecycle.d.ts +41 -0
  61. package/dist/client/kafka.client/producer/lifecycle.d.ts.map +1 -0
  62. package/dist/client/kafka.client/producer/ops.d.ts +70 -0
  63. package/dist/client/kafka.client/producer/ops.d.ts.map +1 -0
  64. package/dist/client/kafka.client/producer/send.d.ts +21 -0
  65. package/dist/client/kafka.client/producer/send.d.ts.map +1 -0
  66. package/dist/client/kafka.client/validate-options.d.ts +11 -0
  67. package/dist/client/kafka.client/validate-options.d.ts.map +1 -0
  68. package/dist/client/message/envelope.d.ts +105 -0
  69. package/dist/client/message/envelope.d.ts.map +1 -0
  70. package/dist/client/message/schema-registry.d.ts +105 -0
  71. package/dist/client/message/schema-registry.d.ts.map +1 -0
  72. package/dist/client/message/topic.d.ts +138 -0
  73. package/dist/client/message/topic.d.ts.map +1 -0
  74. package/dist/client/message/versioned-schema.d.ts +53 -0
  75. package/dist/client/message/versioned-schema.d.ts.map +1 -0
  76. package/dist/client/outbox/index.d.ts +4 -0
  77. package/dist/client/outbox/index.d.ts.map +1 -0
  78. package/dist/client/outbox/outbox.relay.d.ts +90 -0
  79. package/dist/client/outbox/outbox.relay.d.ts.map +1 -0
  80. package/dist/client/outbox/outbox.store.d.ts +42 -0
  81. package/dist/client/outbox/outbox.store.d.ts.map +1 -0
  82. package/dist/client/outbox/outbox.types.d.ts +144 -0
  83. package/dist/client/outbox/outbox.types.d.ts.map +1 -0
  84. package/dist/client/security/acl.d.ts +108 -0
  85. package/dist/client/security/acl.d.ts.map +1 -0
  86. package/dist/client/security/index.d.ts +5 -0
  87. package/dist/client/security/index.d.ts.map +1 -0
  88. package/dist/client/security/providers.d.ts +88 -0
  89. package/dist/client/security/providers.d.ts.map +1 -0
  90. package/dist/client/security/resolve-security.d.ts +19 -0
  91. package/dist/client/security/resolve-security.d.ts.map +1 -0
  92. package/dist/client/security/security.types.d.ts +76 -0
  93. package/dist/client/security/security.types.d.ts.map +1 -0
  94. package/dist/client/transport/confluent.transport.d.ts +32 -0
  95. package/dist/client/transport/confluent.transport.d.ts.map +1 -0
  96. package/dist/client/transport/transport.interface.d.ts +216 -0
  97. package/dist/client/transport/transport.interface.d.ts.map +1 -0
  98. package/dist/client/types/admin.interface.d.ts +174 -0
  99. package/dist/client/types/admin.interface.d.ts.map +1 -0
  100. package/dist/client/types/admin.types.d.ts +140 -0
  101. package/dist/client/types/admin.types.d.ts.map +1 -0
  102. package/dist/client/types/client.d.ts +21 -0
  103. package/dist/client/types/client.d.ts.map +1 -0
  104. package/dist/client/types/common.d.ts +84 -0
  105. package/dist/client/types/common.d.ts.map +1 -0
  106. package/dist/client/types/config.types.d.ts +150 -0
  107. package/dist/client/types/config.types.d.ts.map +1 -0
  108. package/dist/client/types/consumer.interface.d.ts +115 -0
  109. package/dist/client/types/consumer.interface.d.ts.map +1 -0
  110. package/dist/{consumer.types-fFCag3VJ.d.mts → client/types/consumer.types.d.ts} +62 -383
  111. package/dist/client/types/consumer.types.d.ts.map +1 -0
  112. package/dist/client/types/dedup.types.d.ts +50 -0
  113. package/dist/client/types/dedup.types.d.ts.map +1 -0
  114. package/dist/client/types/lifecycle.interface.d.ts +72 -0
  115. package/dist/client/types/lifecycle.interface.d.ts.map +1 -0
  116. package/dist/client/types/producer.interface.d.ts +52 -0
  117. package/dist/client/types/producer.interface.d.ts.map +1 -0
  118. package/dist/client/types/producer.types.d.ts +90 -0
  119. package/dist/client/types/producer.types.d.ts.map +1 -0
  120. package/dist/client/types.d.ts +8 -0
  121. package/dist/client/types.d.ts.map +1 -0
  122. package/dist/core.d.ts +10 -314
  123. package/dist/core.d.ts.map +1 -0
  124. package/dist/core.js +1325 -73
  125. package/dist/core.js.map +1 -1
  126. package/dist/core.mjs +39 -3
  127. package/dist/index.d.ts +7 -128
  128. package/dist/index.d.ts.map +1 -0
  129. package/dist/index.js +1342 -73
  130. package/dist/index.js.map +1 -1
  131. package/dist/index.mjs +56 -3
  132. package/dist/index.mjs.map +1 -1
  133. package/dist/nest/kafka.constants.d.ts +5 -0
  134. package/dist/nest/kafka.constants.d.ts.map +1 -0
  135. package/dist/nest/kafka.decorator.d.ts +49 -0
  136. package/dist/nest/kafka.decorator.d.ts.map +1 -0
  137. package/dist/nest/kafka.explorer.d.ts +17 -0
  138. package/dist/nest/kafka.explorer.d.ts.map +1 -0
  139. package/dist/nest/kafka.health.d.ts +7 -0
  140. package/dist/nest/kafka.health.d.ts.map +1 -0
  141. package/dist/nest/kafka.module.d.ts +61 -0
  142. package/dist/nest/kafka.module.d.ts.map +1 -0
  143. package/dist/otel.d.ts +83 -5
  144. package/dist/otel.d.ts.map +1 -0
  145. package/dist/otel.js +100 -6
  146. package/dist/otel.js.map +1 -1
  147. package/dist/otel.mjs +98 -5
  148. package/dist/otel.mjs.map +1 -1
  149. package/dist/testing/client.mock.d.ts +47 -0
  150. package/dist/testing/client.mock.d.ts.map +1 -0
  151. package/dist/testing/index.d.ts +4 -0
  152. package/dist/testing/index.d.ts.map +1 -0
  153. package/dist/testing/test.container.d.ts +63 -0
  154. package/dist/testing/test.container.d.ts.map +1 -0
  155. package/dist/{testing.d.mts → testing/transport.fake.d.ts} +7 -111
  156. package/dist/testing/transport.fake.d.ts.map +1 -0
  157. package/dist/testing.d.ts +2 -318
  158. package/dist/testing.d.ts.map +1 -0
  159. package/dist/testing.js +26 -0
  160. package/dist/testing.js.map +1 -1
  161. package/dist/testing.mjs +26 -0
  162. package/dist/testing.mjs.map +1 -1
  163. package/package.json +21 -8
  164. package/dist/chunk-SM4FZKAZ.mjs.map +0 -1
  165. package/dist/client-1irhGEu0.d.mts +0 -751
  166. package/dist/client-BpFjkHhr.d.ts +0 -751
  167. package/dist/consumer.types-fFCag3VJ.d.ts +0 -958
  168. package/dist/core.d.mts +0 -314
  169. package/dist/index.d.mts +0 -128
  170. package/dist/otel.d.mts +0 -27
package/dist/index.mjs CHANGED
@@ -1,21 +1,39 @@
1
1
  import {
2
2
  HEADER_CORRELATION_ID,
3
+ HEADER_DELAYED_TARGET,
4
+ HEADER_DELAYED_UNTIL,
3
5
  HEADER_EVENT_ID,
4
6
  HEADER_LAMPORT_CLOCK,
5
7
  HEADER_SCHEMA_VERSION,
6
8
  HEADER_TIMESTAMP,
7
9
  HEADER_TRACEPARENT,
10
+ InMemoryDedupStore,
11
+ InMemoryOutboxStore,
8
12
  KafkaClient,
9
13
  KafkaProcessingError,
10
14
  KafkaRetryExhaustedError,
11
15
  KafkaValidationError,
16
+ SchemaRegistryClient,
17
+ awsMskIamProvider,
12
18
  buildEnvelopeHeaders,
19
+ consumerOptionsFromEnv,
13
20
  decodeHeaders,
21
+ describeRequiredAcls,
14
22
  extractEnvelope,
23
+ gcpAccessTokenProvider,
15
24
  getEnvelopeContext,
25
+ kafkaClientConfigFromEnv,
26
+ mergeConsumerOptions,
27
+ registrySchema,
28
+ resolveSecurityOptions,
16
29
  runWithEnvelopeContext,
17
- topic
18
- } from "./chunk-SM4FZKAZ.mjs";
30
+ startOutboxRelay,
31
+ toError,
32
+ toKafkaAclCommands,
33
+ toMskIamPolicy,
34
+ topic,
35
+ versionedSchema
36
+ } from "./chunk-CMO7SMVK.mjs";
19
37
  import {
20
38
  __decorateClass,
21
39
  __decorateParam
@@ -68,11 +86,14 @@ var SubscribeTo = (topics, options) => {
68
86
  };
69
87
 
70
88
  // src/nest/kafka.explorer.ts
89
+ var wiredSubscriptions = /* @__PURE__ */ new WeakMap();
71
90
  var KafkaExplorer = class {
72
91
  constructor(discoveryService, moduleRef) {
73
92
  this.discoveryService = discoveryService;
74
93
  this.moduleRef = moduleRef;
75
94
  }
95
+ discoveryService;
96
+ moduleRef;
76
97
  logger = new Logger(KafkaExplorer.name);
77
98
  /**
78
99
  * Scan all NestJS providers for `@SubscribeTo()` metadata and wire each decorated
@@ -92,6 +113,14 @@ var KafkaExplorer = class {
92
113
  if (!metadata || metadata.length === 0) continue;
93
114
  for (const entry of metadata) {
94
115
  const token = getKafkaClientToken(entry.clientName);
116
+ const entryKey = `${token}:${String(entry.methodName)}`;
117
+ let wired = wiredSubscriptions.get(instance);
118
+ if (!wired) {
119
+ wired = /* @__PURE__ */ new Set();
120
+ wiredSubscriptions.set(instance, wired);
121
+ }
122
+ if (wired.has(entryKey)) continue;
123
+ wired.add(entryKey);
95
124
  let client;
96
125
  try {
97
126
  client = this.moduleRef.get(token, { strict: false });
@@ -181,6 +210,12 @@ var KafkaModule = class {
181
210
  instrumentation: options.instrumentation,
182
211
  onMessageLost: options.onMessageLost,
183
212
  onRebalance: options.onRebalance,
213
+ transactionalId: options.transactionalId,
214
+ clockRecovery: options.clockRecovery,
215
+ lagThrottle: options.lagThrottle,
216
+ onTtlExpired: options.onTtlExpired,
217
+ transport: options.transport,
218
+ security: options.security,
184
219
  logger: new Logger2(`KafkaClient:${options.clientId}`)
185
220
  }
186
221
  );
@@ -204,11 +239,15 @@ KafkaHealthIndicator = __decorateClass([
204
239
  ], KafkaHealthIndicator);
205
240
  export {
206
241
  HEADER_CORRELATION_ID,
242
+ HEADER_DELAYED_TARGET,
243
+ HEADER_DELAYED_UNTIL,
207
244
  HEADER_EVENT_ID,
208
245
  HEADER_LAMPORT_CLOCK,
209
246
  HEADER_SCHEMA_VERSION,
210
247
  HEADER_TIMESTAMP,
211
248
  HEADER_TRACEPARENT,
249
+ InMemoryDedupStore,
250
+ InMemoryOutboxStore,
212
251
  InjectKafkaClient,
213
252
  KAFKA_CLIENT,
214
253
  KAFKA_SUBSCRIBER_METADATA,
@@ -219,13 +258,27 @@ export {
219
258
  KafkaProcessingError,
220
259
  KafkaRetryExhaustedError,
221
260
  KafkaValidationError,
261
+ SchemaRegistryClient,
222
262
  SubscribeTo,
263
+ awsMskIamProvider,
223
264
  buildEnvelopeHeaders,
265
+ consumerOptionsFromEnv,
224
266
  decodeHeaders,
267
+ describeRequiredAcls,
225
268
  extractEnvelope,
269
+ gcpAccessTokenProvider,
226
270
  getEnvelopeContext,
227
271
  getKafkaClientToken,
272
+ kafkaClientConfigFromEnv,
273
+ mergeConsumerOptions,
274
+ registrySchema,
275
+ resolveSecurityOptions,
228
276
  runWithEnvelopeContext,
229
- topic
277
+ startOutboxRelay,
278
+ toError,
279
+ toKafkaAclCommands,
280
+ toMskIamPolicy,
281
+ topic,
282
+ versionedSchema
230
283
  };
231
284
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/nest/kafka.module.ts","../src/nest/kafka.constants.ts","../src/nest/kafka.explorer.ts","../src/nest/kafka.decorator.ts","../src/nest/kafka.health.ts"],"sourcesContent":["import { Module, DynamicModule, Provider, Logger } from \"@nestjs/common\";\nimport { DiscoveryModule } from \"@nestjs/core\";\nimport {\n KafkaClient,\n ClientId,\n GroupId,\n TopicMapConstraint,\n KafkaInstrumentation,\n KafkaClientOptions,\n} from \"../client/kafka.client\";\nimport { getKafkaClientToken } from \"./kafka.constants\";\nimport { KafkaExplorer } from \"./kafka.explorer\";\n\n/** Shared configuration fields for both `register()` and `registerAsync()`. */\ninterface KafkaModuleBaseOptions {\n /** Optional name for multi-client setups. Must match `@InjectKafkaClient(name)`. */\n name?: string;\n /** If true, makes KAFKA_CLIENT available globally without importing KafkaModule in every feature module. */\n isGlobal?: boolean;\n}\n\n/** Synchronous configuration for `KafkaModule.register()`. */\nexport interface KafkaModuleOptions extends KafkaModuleBaseOptions {\n /** Unique Kafka client identifier. */\n clientId: ClientId;\n /** Consumer group identifier. */\n groupId: GroupId;\n /** List of Kafka broker addresses. */\n brokers: string[];\n /** Auto-create topics via admin on first use (send/consume). Useful for development. */\n autoCreateTopics?: boolean;\n /** When `true`, string topic keys are validated against any schema previously registered via a TopicDescriptor. Default: `true`. */\n strictSchemas?: boolean;\n /** Number of partitions for auto-created topics. Default: `1`. */\n numPartitions?: number;\n /** Client-wide instrumentation hooks (e.g. OTel). Applied to both send and consume paths. */\n instrumentation?: KafkaInstrumentation[];\n /** Called when a message is dropped without being sent to a DLQ. @see `KafkaClientOptions.onMessageLost` */\n onMessageLost?: KafkaClientOptions[\"onMessageLost\"];\n /** Called whenever a consumer group rebalance occurs. @see `KafkaClientOptions.onRebalance` */\n onRebalance?: KafkaClientOptions[\"onRebalance\"];\n}\n\n/** Async configuration for `KafkaModule.registerAsync()` with dependency injection. */\nexport interface KafkaModuleAsyncOptions extends KafkaModuleBaseOptions {\n imports?: any[];\n useFactory: (\n ...args: any[]\n ) => KafkaModuleOptions | Promise<KafkaModuleOptions>;\n inject?: any[];\n}\n\n/**\n * NestJS dynamic module for registering type-safe Kafka clients.\n * Use `register()` for static config or `registerAsync()` for DI-based config.\n */\n@Module({})\nexport class KafkaModule {\n /** Register a Kafka client with static options. */\n static register<T extends TopicMapConstraint<T>>(\n options: KafkaModuleOptions,\n ): DynamicModule {\n const token = getKafkaClientToken(options.name);\n\n const kafkaClientProvider: Provider = {\n provide: token,\n useFactory: () => KafkaModule.buildClient<T>(options),\n };\n\n return {\n global: options.isGlobal ?? false,\n module: KafkaModule,\n imports: [DiscoveryModule],\n providers: [kafkaClientProvider, KafkaExplorer],\n exports: [kafkaClientProvider],\n };\n }\n\n /** Register a Kafka client with async/factory-based options. */\n static registerAsync<T extends TopicMapConstraint<T>>(\n asyncOptions: KafkaModuleAsyncOptions,\n ): DynamicModule {\n const token = getKafkaClientToken(asyncOptions.name);\n\n const kafkaClientProvider: Provider = {\n provide: token,\n useFactory: async (...args: any[]): Promise<KafkaClient<T>> =>\n KafkaModule.buildClient<T>(await asyncOptions.useFactory(...args)),\n inject: asyncOptions.inject || [],\n };\n\n return {\n global: asyncOptions.isGlobal ?? false,\n module: KafkaModule,\n imports: [...(asyncOptions.imports || []), DiscoveryModule],\n providers: [kafkaClientProvider, KafkaExplorer],\n exports: [kafkaClientProvider],\n };\n }\n\n private static async buildClient<T extends TopicMapConstraint<T>>(\n options: KafkaModuleOptions,\n ): Promise<KafkaClient<T>> {\n const client = new KafkaClient<T>(\n options.clientId,\n options.groupId,\n options.brokers,\n {\n autoCreateTopics: options.autoCreateTopics,\n strictSchemas: options.strictSchemas,\n numPartitions: options.numPartitions,\n instrumentation: options.instrumentation,\n onMessageLost: options.onMessageLost,\n onRebalance: options.onRebalance,\n logger: new Logger(`KafkaClient:${options.clientId}`),\n },\n );\n await client.connectProducer();\n return client;\n }\n}\n","/** Default DI token for the Kafka client. */\nexport const KAFKA_CLIENT = \"KAFKA_CLIENT\";\n\n/** Returns the DI token for a named (or default) Kafka client instance. */\nexport const getKafkaClientToken = (name?: string): string =>\n name ? `KAFKA_CLIENT_${name}` : KAFKA_CLIENT;\n","import { Inject, Injectable, OnModuleInit, Logger } from \"@nestjs/common\";\nimport { DiscoveryService, ModuleRef } from \"@nestjs/core\";\nimport { KafkaClient } from \"../client/kafka.client\";\nimport {\n KAFKA_SUBSCRIBER_METADATA,\n KafkaSubscriberMetadata,\n} from \"./kafka.decorator\";\nimport { getKafkaClientToken } from \"./kafka.constants\";\n\ninterface SubscriberEntry extends KafkaSubscriberMetadata {\n methodName: string | symbol;\n}\n\n/** Discovers `@SubscribeTo()` decorators and wires them to their Kafka clients on startup. */\n@Injectable()\nexport class KafkaExplorer implements OnModuleInit {\n private readonly logger = new Logger(KafkaExplorer.name);\n\n constructor(\n @Inject(DiscoveryService)\n private readonly discoveryService: DiscoveryService,\n @Inject(ModuleRef)\n private readonly moduleRef: ModuleRef,\n ) {}\n\n /**\n * Scan all NestJS providers for `@SubscribeTo()` metadata and wire each decorated\n * method to its Kafka client via `startConsumer` or `startBatchConsumer`.\n *\n * Called automatically by the NestJS lifecycle — do not invoke manually.\n */\n async onModuleInit() {\n const providers = this.discoveryService.getProviders();\n\n for (const wrapper of providers) {\n const { instance } = wrapper;\n if (!instance || typeof instance !== \"object\") continue;\n\n const metadata: SubscriberEntry[] | undefined = Reflect.getMetadata(\n KAFKA_SUBSCRIBER_METADATA,\n instance.constructor,\n );\n\n if (!metadata || metadata.length === 0) continue;\n\n for (const entry of metadata) {\n const token = getKafkaClientToken(entry.clientName);\n let client: KafkaClient<any>;\n\n try {\n client = this.moduleRef.get(token, { strict: false });\n } catch {\n this.logger.error(\n `KafkaClient \"${entry.clientName || \"default\"}\" not found for @SubscribeTo on ${instance.constructor.name}.${String(entry.methodName)}`,\n );\n continue;\n }\n\n const handler = (instance as any)[entry.methodName].bind(instance);\n\n const consumerOptions = { ...entry.options };\n if (entry.schemas) {\n consumerOptions.schemas = entry.schemas;\n }\n\n if (entry.batch) {\n await client.startBatchConsumer(\n entry.topics as any,\n async (envelopes: any[], meta: any) => {\n await handler(envelopes, meta);\n },\n consumerOptions,\n );\n } else {\n await client.startConsumer(\n entry.topics as any,\n async (envelope: any) => {\n await handler(envelope);\n },\n consumerOptions,\n );\n }\n\n this.logger.log(\n `Registered @SubscribeTo(${entry.topics.join(\", \")})${entry.batch ? \" [batch]\" : \"\"} on ${instance.constructor.name}.${String(entry.methodName)}`,\n );\n }\n }\n }\n}\n","import { Inject } from \"@nestjs/common\";\nimport { getKafkaClientToken } from \"./kafka.constants\";\nimport { ConsumerOptions } from \"../client/kafka.client\";\nimport { TopicDescriptor, SchemaLike } from \"../client/message/topic\";\n\n/** Reflect metadata key used to store `@SubscribeTo` entries on a class constructor. */\nexport const KAFKA_SUBSCRIBER_METADATA = \"KAFKA_SUBSCRIBER_METADATA\";\n\n/** Internal shape stored per `@SubscribeTo()` decoration on a class. */\nexport interface KafkaSubscriberMetadata {\n /** Resolved topic name strings (descriptors are unwrapped to their `__topic` string). */\n topics: string[];\n /** Per-topic schema validators extracted from `TopicDescriptor` objects (if any). */\n schemas?: Map<string, SchemaLike>;\n /** Additional consumer options forwarded to `startConsumer` / `startBatchConsumer`. */\n options?: ConsumerOptions;\n /** Named client identifier — resolves to `KAFKA_CLIENT_<clientName>` in the DI container. */\n clientName?: string;\n /** When `true`, routes to `startBatchConsumer` instead of `startConsumer`. */\n batch?: boolean;\n /** Name of the decorated method on the provider class. */\n methodName?: string | symbol;\n}\n\n/** Inject a `KafkaClient` instance. Pass a name to target a specific named client. */\nexport const InjectKafkaClient = (name?: string): ParameterDecorator =>\n Inject(getKafkaClientToken(name));\n\n/**\n * Method decorator that auto-subscribes the decorated method to one or more Kafka topics\n * when the NestJS module initialises.\n *\n * The decorated method receives a fully-decoded `EventEnvelope` for each message\n * (or an array of envelopes + `BatchMeta` when `batch: true`).\n *\n * @param topics One or more topic names or `TopicDescriptor` objects. Schemas embedded in\n * descriptors are automatically extracted and forwarded to the consumer.\n * @param options Consumer and routing options:\n * - All `ConsumerOptions` fields (`groupId`, `retry`, `dlq`, `fromBeginning`, …)\n * - `clientName` — target a named `KafkaClient` (resolves `KAFKA_CLIENT_<name>` from the DI container)\n * - `batch` — use `startBatchConsumer` instead of `startConsumer`\n *\n * @example\n * ```ts\n * @SubscribeTo('orders.created', { groupId: 'orders-svc', retry: { maxRetries: 3 } })\n * async handleOrder(envelope: EventEnvelope<Order>) { ... }\n *\n * @SubscribeTo(OrdersTopic, { batch: true })\n * async handleBatch(envelopes: EventEnvelope<Order>[], meta: BatchMeta) { ... }\n * ```\n */\nexport const SubscribeTo = (\n topics:\n | string\n | string[]\n | TopicDescriptor\n | TopicDescriptor[]\n | (string | TopicDescriptor)[],\n options?: ConsumerOptions & { clientName?: string; batch?: boolean },\n): MethodDecorator => {\n const arr = Array.isArray(topics) ? topics : [topics];\n const topicsArray = arr.map((t) => (typeof t === \"string\" ? t : t.__topic));\n\n // Extract schemas from descriptors that have them\n const schemas = new Map<string, SchemaLike>();\n for (const t of arr) {\n if (typeof t !== \"string\" && t.__schema) {\n schemas.set(t.__topic, t.__schema);\n }\n }\n\n const { clientName, batch, ...consumerOptions } = options || {};\n\n return (target, propertyKey, _descriptor) => {\n const existing: KafkaSubscriberMetadata[] =\n Reflect.getMetadata(KAFKA_SUBSCRIBER_METADATA, target.constructor) || [];\n\n Reflect.defineMetadata(\n KAFKA_SUBSCRIBER_METADATA,\n [\n ...existing,\n {\n topics: topicsArray,\n schemas: schemas.size > 0 ? schemas : undefined,\n options: Object.keys(consumerOptions).length\n ? consumerOptions\n : undefined,\n clientName,\n batch,\n methodName: propertyKey,\n },\n ],\n target.constructor,\n );\n };\n};\n","import { Injectable } from \"@nestjs/common\";\nimport type {\n IKafkaClient,\n KafkaHealthResult,\n TopicMapConstraint,\n} from \"../client/types\";\nexport type { KafkaHealthResult } from \"../client/types\";\n\n/** Health check service. Call `check(client)` to verify broker connectivity. */\n@Injectable()\nexport class KafkaHealthIndicator {\n async check<T extends TopicMapConstraint<T>>(\n client: IKafkaClient<T>,\n ): Promise<KafkaHealthResult> {\n return client.checkStatus();\n }\n}\n"],"mappings":"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","names":["Logger","Inject","Inject","Logger","Injectable","Injectable"]}
1
+ {"version":3,"sources":["../src/nest/kafka.module.ts","../src/nest/kafka.constants.ts","../src/nest/kafka.explorer.ts","../src/nest/kafka.decorator.ts","../src/nest/kafka.health.ts"],"sourcesContent":["import { Module, DynamicModule, Provider, Logger } from \"@nestjs/common\";\nimport { DiscoveryModule } from \"@nestjs/core\";\nimport {\n KafkaClient,\n ClientId,\n GroupId,\n TopicMapConstraint,\n KafkaInstrumentation,\n KafkaClientOptions,\n} from \"../client/kafka.client\";\nimport { getKafkaClientToken } from \"./kafka.constants\";\nimport { KafkaExplorer } from \"./kafka.explorer\";\n\n/** Shared configuration fields for both `register()` and `registerAsync()`. */\ninterface KafkaModuleBaseOptions {\n /** Optional name for multi-client setups. Must match `@InjectKafkaClient(name)`. */\n name?: string;\n /** If true, makes KAFKA_CLIENT available globally without importing KafkaModule in every feature module. */\n isGlobal?: boolean;\n}\n\n/** Synchronous configuration for `KafkaModule.register()`. */\nexport interface KafkaModuleOptions extends KafkaModuleBaseOptions {\n /** Unique Kafka client identifier. */\n clientId: ClientId;\n /** Consumer group identifier. */\n groupId: GroupId;\n /** List of Kafka broker addresses. */\n brokers: string[];\n /** Auto-create topics via admin on first use (send/consume). Useful for development. */\n autoCreateTopics?: boolean;\n /** When `true`, string topic keys are validated against any schema previously registered via a TopicDescriptor. Default: `true`. */\n strictSchemas?: boolean;\n /** Number of partitions for auto-created topics. Default: `1`. */\n numPartitions?: number;\n /** Client-wide instrumentation hooks (e.g. OTel). Applied to both send and consume paths. */\n instrumentation?: KafkaInstrumentation[];\n /** Called when a message is dropped without being sent to a DLQ. @see `KafkaClientOptions.onMessageLost` */\n onMessageLost?: KafkaClientOptions[\"onMessageLost\"];\n /** Called whenever a consumer group rebalance occurs. @see `KafkaClientOptions.onRebalance` */\n onRebalance?: KafkaClientOptions[\"onRebalance\"];\n /** Transactional producer ID — must be unique per process/replica. @see `KafkaClientOptions.transactionalId` */\n transactionalId?: KafkaClientOptions[\"transactionalId\"];\n /** Recover the Lamport clock from these topics on startup. @see `KafkaClientOptions.clockRecovery` */\n clockRecovery?: KafkaClientOptions[\"clockRecovery\"];\n /** Delay producer sends when consumer lag exceeds a threshold. @see `KafkaClientOptions.lagThrottle` */\n lagThrottle?: KafkaClientOptions[\"lagThrottle\"];\n /** Client-wide TTL expiry callback. @see `KafkaClientOptions.onTtlExpired` */\n onTtlExpired?: KafkaClientOptions[\"onTtlExpired\"];\n /** Custom transport implementation (e.g. `FakeTransport` in tests). @see `KafkaClientOptions.transport` */\n transport?: KafkaClientOptions[\"transport\"];\n /** Transport security (TLS + SASL, incl. MSK IAM / GCP OAUTHBEARER). @see `KafkaClientOptions.security` */\n security?: KafkaClientOptions[\"security\"];\n}\n\n/** Async configuration for `KafkaModule.registerAsync()` with dependency injection. */\nexport interface KafkaModuleAsyncOptions extends KafkaModuleBaseOptions {\n imports?: any[];\n useFactory: (\n ...args: any[]\n ) => KafkaModuleOptions | Promise<KafkaModuleOptions>;\n inject?: any[];\n}\n\n/**\n * NestJS dynamic module for registering type-safe Kafka clients.\n * Use `register()` for static config or `registerAsync()` for DI-based config.\n */\n@Module({})\nexport class KafkaModule {\n /** Register a Kafka client with static options. */\n static register<T extends TopicMapConstraint<T>>(\n options: KafkaModuleOptions,\n ): DynamicModule {\n const token = getKafkaClientToken(options.name);\n\n const kafkaClientProvider: Provider = {\n provide: token,\n useFactory: () => KafkaModule.buildClient<T>(options),\n };\n\n return {\n global: options.isGlobal ?? false,\n module: KafkaModule,\n imports: [DiscoveryModule],\n providers: [kafkaClientProvider, KafkaExplorer],\n exports: [kafkaClientProvider],\n };\n }\n\n /** Register a Kafka client with async/factory-based options. */\n static registerAsync<T extends TopicMapConstraint<T>>(\n asyncOptions: KafkaModuleAsyncOptions,\n ): DynamicModule {\n const token = getKafkaClientToken(asyncOptions.name);\n\n const kafkaClientProvider: Provider = {\n provide: token,\n useFactory: async (...args: any[]): Promise<KafkaClient<T>> =>\n KafkaModule.buildClient<T>(await asyncOptions.useFactory(...args)),\n inject: asyncOptions.inject || [],\n };\n\n return {\n global: asyncOptions.isGlobal ?? false,\n module: KafkaModule,\n imports: [...(asyncOptions.imports || []), DiscoveryModule],\n providers: [kafkaClientProvider, KafkaExplorer],\n exports: [kafkaClientProvider],\n };\n }\n\n private static async buildClient<T extends TopicMapConstraint<T>>(\n options: KafkaModuleOptions,\n ): Promise<KafkaClient<T>> {\n const client = new KafkaClient<T>(\n options.clientId,\n options.groupId,\n options.brokers,\n {\n autoCreateTopics: options.autoCreateTopics,\n strictSchemas: options.strictSchemas,\n numPartitions: options.numPartitions,\n instrumentation: options.instrumentation,\n onMessageLost: options.onMessageLost,\n onRebalance: options.onRebalance,\n transactionalId: options.transactionalId,\n clockRecovery: options.clockRecovery,\n lagThrottle: options.lagThrottle,\n onTtlExpired: options.onTtlExpired,\n transport: options.transport,\n security: options.security,\n logger: new Logger(`KafkaClient:${options.clientId}`),\n },\n );\n await client.connectProducer();\n return client;\n }\n}\n","/** Default DI token for the Kafka client. */\nexport const KAFKA_CLIENT = \"KAFKA_CLIENT\";\n\n/** Returns the DI token for a named (or default) Kafka client instance. */\nexport const getKafkaClientToken = (name?: string): string =>\n name ? `KAFKA_CLIENT_${name}` : KAFKA_CLIENT;\n","import { Inject, Injectable, OnModuleInit, Logger } from \"@nestjs/common\";\nimport { DiscoveryService, ModuleRef } from \"@nestjs/core\";\nimport { KafkaClient } from \"../client/kafka.client\";\nimport {\n KAFKA_SUBSCRIBER_METADATA,\n KafkaSubscriberMetadata,\n} from \"./kafka.decorator\";\nimport { getKafkaClientToken } from \"./kafka.constants\";\n\ninterface SubscriberEntry extends KafkaSubscriberMetadata {\n methodName: string | symbol;\n}\n\n/**\n * Process-level registry of already-wired subscriptions, keyed by provider\n * instance. Every `KafkaModule.register()` call contributes its own\n * `KafkaExplorer`, and each explorer scans ALL providers — without this guard\n * a multi-client app would wire every `@SubscribeTo` handler once per\n * registered module (duplicate consumers / \"called twice\" startup errors).\n * Keyed by instance (not constructor) so separate Nest apps in one process\n * (e.g. tests) still wire their own instances independently.\n */\nconst wiredSubscriptions = new WeakMap<object, Set<string>>();\n\n/** Discovers `@SubscribeTo()` decorators and wires them to their Kafka clients on startup. */\n@Injectable()\nexport class KafkaExplorer implements OnModuleInit {\n private readonly logger = new Logger(KafkaExplorer.name);\n\n constructor(\n @Inject(DiscoveryService)\n private readonly discoveryService: DiscoveryService,\n @Inject(ModuleRef)\n private readonly moduleRef: ModuleRef,\n ) {}\n\n /**\n * Scan all NestJS providers for `@SubscribeTo()` metadata and wire each decorated\n * method to its Kafka client via `startConsumer` or `startBatchConsumer`.\n *\n * Called automatically by the NestJS lifecycle — do not invoke manually.\n */\n async onModuleInit() {\n const providers = this.discoveryService.getProviders();\n\n for (const wrapper of providers) {\n const { instance } = wrapper;\n if (!instance || typeof instance !== \"object\") continue;\n\n const metadata: SubscriberEntry[] | undefined = Reflect.getMetadata(\n KAFKA_SUBSCRIBER_METADATA,\n instance.constructor,\n );\n\n if (!metadata || metadata.length === 0) continue;\n\n for (const entry of metadata) {\n const token = getKafkaClientToken(entry.clientName);\n\n const entryKey = `${token}:${String(entry.methodName)}`;\n let wired = wiredSubscriptions.get(instance);\n if (!wired) {\n wired = new Set();\n wiredSubscriptions.set(instance, wired);\n }\n if (wired.has(entryKey)) continue; // already wired by another KafkaExplorer instance\n wired.add(entryKey);\n\n let client: KafkaClient<any>;\n\n try {\n client = this.moduleRef.get(token, { strict: false });\n } catch {\n this.logger.error(\n `KafkaClient \"${entry.clientName || \"default\"}\" not found for @SubscribeTo on ${instance.constructor.name}.${String(entry.methodName)}`,\n );\n continue;\n }\n\n const handler = (instance as any)[entry.methodName].bind(instance);\n\n const consumerOptions = { ...entry.options };\n if (entry.schemas) {\n consumerOptions.schemas = entry.schemas;\n }\n\n if (entry.batch) {\n await client.startBatchConsumer(\n entry.topics as any,\n async (envelopes: any[], meta: any) => {\n await handler(envelopes, meta);\n },\n consumerOptions,\n );\n } else {\n await client.startConsumer(\n entry.topics as any,\n async (envelope: any) => {\n await handler(envelope);\n },\n consumerOptions,\n );\n }\n\n this.logger.log(\n `Registered @SubscribeTo(${entry.topics.join(\", \")})${entry.batch ? \" [batch]\" : \"\"} on ${instance.constructor.name}.${String(entry.methodName)}`,\n );\n }\n }\n }\n}\n","import { Inject } from \"@nestjs/common\";\nimport { getKafkaClientToken } from \"./kafka.constants\";\nimport { ConsumerOptions } from \"../client/kafka.client\";\nimport { TopicDescriptor, SchemaLike } from \"../client/message/topic\";\n\n/** Reflect metadata key used to store `@SubscribeTo` entries on a class constructor. */\nexport const KAFKA_SUBSCRIBER_METADATA = \"KAFKA_SUBSCRIBER_METADATA\";\n\n/** Internal shape stored per `@SubscribeTo()` decoration on a class. */\nexport interface KafkaSubscriberMetadata {\n /** Resolved topic name strings (descriptors are unwrapped to their `__topic` string). */\n topics: string[];\n /** Per-topic schema validators extracted from `TopicDescriptor` objects (if any). */\n schemas?: Map<string, SchemaLike>;\n /** Additional consumer options forwarded to `startConsumer` / `startBatchConsumer`. */\n options?: ConsumerOptions;\n /** Named client identifier — resolves to `KAFKA_CLIENT_<clientName>` in the DI container. */\n clientName?: string;\n /** When `true`, routes to `startBatchConsumer` instead of `startConsumer`. */\n batch?: boolean;\n /** Name of the decorated method on the provider class. */\n methodName?: string | symbol;\n}\n\n/** Inject a `KafkaClient` instance. Pass a name to target a specific named client. */\nexport const InjectKafkaClient = (name?: string): ParameterDecorator =>\n Inject(getKafkaClientToken(name));\n\n/**\n * Method decorator that auto-subscribes the decorated method to one or more Kafka topics\n * when the NestJS module initialises.\n *\n * The decorated method receives a fully-decoded `EventEnvelope` for each message\n * (or an array of envelopes + `BatchMeta` when `batch: true`).\n *\n * @param topics One or more topic names or `TopicDescriptor` objects. Schemas embedded in\n * descriptors are automatically extracted and forwarded to the consumer.\n * @param options Consumer and routing options:\n * - All `ConsumerOptions` fields (`groupId`, `retry`, `dlq`, `fromBeginning`, …)\n * - `clientName` — target a named `KafkaClient` (resolves `KAFKA_CLIENT_<name>` from the DI container)\n * - `batch` — use `startBatchConsumer` instead of `startConsumer`\n *\n * @example\n * ```ts\n * @SubscribeTo('orders.created', { groupId: 'orders-svc', retry: { maxRetries: 3 } })\n * async handleOrder(envelope: EventEnvelope<Order>) { ... }\n *\n * @SubscribeTo(OrdersTopic, { batch: true })\n * async handleBatch(envelopes: EventEnvelope<Order>[], meta: BatchMeta) { ... }\n * ```\n */\nexport const SubscribeTo = (\n topics:\n | string\n | string[]\n | TopicDescriptor\n | TopicDescriptor[]\n | (string | TopicDescriptor)[],\n options?: ConsumerOptions & { clientName?: string; batch?: boolean },\n): MethodDecorator => {\n const arr = Array.isArray(topics) ? topics : [topics];\n const topicsArray = arr.map((t) => (typeof t === \"string\" ? t : t.__topic));\n\n // Extract schemas from descriptors that have them\n const schemas = new Map<string, SchemaLike>();\n for (const t of arr) {\n if (typeof t !== \"string\" && t.__schema) {\n schemas.set(t.__topic, t.__schema);\n }\n }\n\n const { clientName, batch, ...consumerOptions } = options || {};\n\n return (target, propertyKey, _descriptor) => {\n const existing: KafkaSubscriberMetadata[] =\n Reflect.getMetadata(KAFKA_SUBSCRIBER_METADATA, target.constructor) || [];\n\n Reflect.defineMetadata(\n KAFKA_SUBSCRIBER_METADATA,\n [\n ...existing,\n {\n topics: topicsArray,\n schemas: schemas.size > 0 ? schemas : undefined,\n options: Object.keys(consumerOptions).length\n ? consumerOptions\n : undefined,\n clientName,\n batch,\n methodName: propertyKey,\n },\n ],\n target.constructor,\n );\n };\n};\n","import { Injectable } from \"@nestjs/common\";\nimport type {\n IKafkaClient,\n KafkaHealthResult,\n TopicMapConstraint,\n} from \"../client/types\";\nexport type { KafkaHealthResult } from \"../client/types\";\n\n/** Health check service. Call `check(client)` to verify broker connectivity. */\n@Injectable()\nexport class KafkaHealthIndicator {\n async check<T extends TopicMapConstraint<T>>(\n client: IKafkaClient<T>,\n ): Promise<KafkaHealthResult> {\n return client.checkStatus();\n }\n}\n"],"mappings":"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","names":["Logger","Inject","Inject","Logger","Injectable","Injectable"]}
@@ -0,0 +1,5 @@
1
+ /** Default DI token for the Kafka client. */
2
+ export declare const KAFKA_CLIENT = "KAFKA_CLIENT";
3
+ /** Returns the DI token for a named (or default) Kafka client instance. */
4
+ export declare const getKafkaClientToken: (name?: string) => string;
5
+ //# sourceMappingURL=kafka.constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kafka.constants.d.ts","sourceRoot":"","sources":["../../src/nest/kafka.constants.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C,2EAA2E;AAC3E,eAAO,MAAM,mBAAmB,GAAI,OAAO,MAAM,KAAG,MACN,CAAC"}
@@ -0,0 +1,49 @@
1
+ import { ConsumerOptions } from "../client/kafka.client";
2
+ import { TopicDescriptor, SchemaLike } from "../client/message/topic";
3
+ /** Reflect metadata key used to store `@SubscribeTo` entries on a class constructor. */
4
+ export declare const KAFKA_SUBSCRIBER_METADATA = "KAFKA_SUBSCRIBER_METADATA";
5
+ /** Internal shape stored per `@SubscribeTo()` decoration on a class. */
6
+ export interface KafkaSubscriberMetadata {
7
+ /** Resolved topic name strings (descriptors are unwrapped to their `__topic` string). */
8
+ topics: string[];
9
+ /** Per-topic schema validators extracted from `TopicDescriptor` objects (if any). */
10
+ schemas?: Map<string, SchemaLike>;
11
+ /** Additional consumer options forwarded to `startConsumer` / `startBatchConsumer`. */
12
+ options?: ConsumerOptions;
13
+ /** Named client identifier — resolves to `KAFKA_CLIENT_<clientName>` in the DI container. */
14
+ clientName?: string;
15
+ /** When `true`, routes to `startBatchConsumer` instead of `startConsumer`. */
16
+ batch?: boolean;
17
+ /** Name of the decorated method on the provider class. */
18
+ methodName?: string | symbol;
19
+ }
20
+ /** Inject a `KafkaClient` instance. Pass a name to target a specific named client. */
21
+ export declare const InjectKafkaClient: (name?: string) => ParameterDecorator;
22
+ /**
23
+ * Method decorator that auto-subscribes the decorated method to one or more Kafka topics
24
+ * when the NestJS module initialises.
25
+ *
26
+ * The decorated method receives a fully-decoded `EventEnvelope` for each message
27
+ * (or an array of envelopes + `BatchMeta` when `batch: true`).
28
+ *
29
+ * @param topics One or more topic names or `TopicDescriptor` objects. Schemas embedded in
30
+ * descriptors are automatically extracted and forwarded to the consumer.
31
+ * @param options Consumer and routing options:
32
+ * - All `ConsumerOptions` fields (`groupId`, `retry`, `dlq`, `fromBeginning`, …)
33
+ * - `clientName` — target a named `KafkaClient` (resolves `KAFKA_CLIENT_<name>` from the DI container)
34
+ * - `batch` — use `startBatchConsumer` instead of `startConsumer`
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * @SubscribeTo('orders.created', { groupId: 'orders-svc', retry: { maxRetries: 3 } })
39
+ * async handleOrder(envelope: EventEnvelope<Order>) { ... }
40
+ *
41
+ * @SubscribeTo(OrdersTopic, { batch: true })
42
+ * async handleBatch(envelopes: EventEnvelope<Order>[], meta: BatchMeta) { ... }
43
+ * ```
44
+ */
45
+ export declare const SubscribeTo: (topics: string | string[] | TopicDescriptor | TopicDescriptor[] | (string | TopicDescriptor)[], options?: ConsumerOptions & {
46
+ clientName?: string;
47
+ batch?: boolean;
48
+ }) => MethodDecorator;
49
+ //# sourceMappingURL=kafka.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kafka.decorator.d.ts","sourceRoot":"","sources":["../../src/nest/kafka.decorator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAEtE,wFAAwF;AACxF,eAAO,MAAM,yBAAyB,8BAA8B,CAAC;AAErE,wEAAwE;AACxE,MAAM,WAAW,uBAAuB;IACtC,yFAAyF;IACzF,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,qFAAqF;IACrF,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,uFAAuF;IACvF,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,6FAA6F;IAC7F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,0DAA0D;IAC1D,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC9B;AAED,sFAAsF;AACtF,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,KAAG,kBACf,CAAC;AAEpC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,WAAW,GACtB,QACI,MAAM,GACN,MAAM,EAAE,GACR,eAAe,GACf,eAAe,EAAE,GACjB,CAAC,MAAM,GAAG,eAAe,CAAC,EAAE,EAChC,UAAU,eAAe,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,KACnE,eAoCF,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { OnModuleInit } from "@nestjs/common";
2
+ import { DiscoveryService, ModuleRef } from "@nestjs/core";
3
+ /** Discovers `@SubscribeTo()` decorators and wires them to their Kafka clients on startup. */
4
+ export declare class KafkaExplorer implements OnModuleInit {
5
+ private readonly discoveryService;
6
+ private readonly moduleRef;
7
+ private readonly logger;
8
+ constructor(discoveryService: DiscoveryService, moduleRef: ModuleRef);
9
+ /**
10
+ * Scan all NestJS providers for `@SubscribeTo()` metadata and wire each decorated
11
+ * method to its Kafka client via `startConsumer` or `startBatchConsumer`.
12
+ *
13
+ * Called automatically by the NestJS lifecycle — do not invoke manually.
14
+ */
15
+ onModuleInit(): Promise<void>;
16
+ }
17
+ //# sourceMappingURL=kafka.explorer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kafka.explorer.d.ts","sourceRoot":"","sources":["../../src/nest/kafka.explorer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,YAAY,EAAU,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAuB3D,8FAA8F;AAC9F,qBACa,aAAc,YAAW,YAAY;IAK9C,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IAEjC,OAAO,CAAC,QAAQ,CAAC,SAAS;IAN5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;gBAItC,gBAAgB,EAAE,gBAAgB,EAElC,SAAS,EAAE,SAAS;IAGvC;;;;;OAKG;IACG,YAAY;CAoEnB"}
@@ -0,0 +1,7 @@
1
+ import type { IKafkaClient, KafkaHealthResult, TopicMapConstraint } from "../client/types";
2
+ export type { KafkaHealthResult } from "../client/types";
3
+ /** Health check service. Call `check(client)` to verify broker connectivity. */
4
+ export declare class KafkaHealthIndicator {
5
+ check<T extends TopicMapConstraint<T>>(client: IKafkaClient<T>): Promise<KafkaHealthResult>;
6
+ }
7
+ //# sourceMappingURL=kafka.health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kafka.health.d.ts","sourceRoot":"","sources":["../../src/nest/kafka.health.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,gFAAgF;AAChF,qBACa,oBAAoB;IACzB,KAAK,CAAC,CAAC,SAAS,kBAAkB,CAAC,CAAC,CAAC,EACzC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,GACtB,OAAO,CAAC,iBAAiB,CAAC;CAG9B"}
@@ -0,0 +1,61 @@
1
+ import { DynamicModule } from "@nestjs/common";
2
+ import { ClientId, GroupId, TopicMapConstraint, KafkaInstrumentation, KafkaClientOptions } from "../client/kafka.client";
3
+ /** Shared configuration fields for both `register()` and `registerAsync()`. */
4
+ interface KafkaModuleBaseOptions {
5
+ /** Optional name for multi-client setups. Must match `@InjectKafkaClient(name)`. */
6
+ name?: string;
7
+ /** If true, makes KAFKA_CLIENT available globally without importing KafkaModule in every feature module. */
8
+ isGlobal?: boolean;
9
+ }
10
+ /** Synchronous configuration for `KafkaModule.register()`. */
11
+ export interface KafkaModuleOptions extends KafkaModuleBaseOptions {
12
+ /** Unique Kafka client identifier. */
13
+ clientId: ClientId;
14
+ /** Consumer group identifier. */
15
+ groupId: GroupId;
16
+ /** List of Kafka broker addresses. */
17
+ brokers: string[];
18
+ /** Auto-create topics via admin on first use (send/consume). Useful for development. */
19
+ autoCreateTopics?: boolean;
20
+ /** When `true`, string topic keys are validated against any schema previously registered via a TopicDescriptor. Default: `true`. */
21
+ strictSchemas?: boolean;
22
+ /** Number of partitions for auto-created topics. Default: `1`. */
23
+ numPartitions?: number;
24
+ /** Client-wide instrumentation hooks (e.g. OTel). Applied to both send and consume paths. */
25
+ instrumentation?: KafkaInstrumentation[];
26
+ /** Called when a message is dropped without being sent to a DLQ. @see `KafkaClientOptions.onMessageLost` */
27
+ onMessageLost?: KafkaClientOptions["onMessageLost"];
28
+ /** Called whenever a consumer group rebalance occurs. @see `KafkaClientOptions.onRebalance` */
29
+ onRebalance?: KafkaClientOptions["onRebalance"];
30
+ /** Transactional producer ID — must be unique per process/replica. @see `KafkaClientOptions.transactionalId` */
31
+ transactionalId?: KafkaClientOptions["transactionalId"];
32
+ /** Recover the Lamport clock from these topics on startup. @see `KafkaClientOptions.clockRecovery` */
33
+ clockRecovery?: KafkaClientOptions["clockRecovery"];
34
+ /** Delay producer sends when consumer lag exceeds a threshold. @see `KafkaClientOptions.lagThrottle` */
35
+ lagThrottle?: KafkaClientOptions["lagThrottle"];
36
+ /** Client-wide TTL expiry callback. @see `KafkaClientOptions.onTtlExpired` */
37
+ onTtlExpired?: KafkaClientOptions["onTtlExpired"];
38
+ /** Custom transport implementation (e.g. `FakeTransport` in tests). @see `KafkaClientOptions.transport` */
39
+ transport?: KafkaClientOptions["transport"];
40
+ /** Transport security (TLS + SASL, incl. MSK IAM / GCP OAUTHBEARER). @see `KafkaClientOptions.security` */
41
+ security?: KafkaClientOptions["security"];
42
+ }
43
+ /** Async configuration for `KafkaModule.registerAsync()` with dependency injection. */
44
+ export interface KafkaModuleAsyncOptions extends KafkaModuleBaseOptions {
45
+ imports?: any[];
46
+ useFactory: (...args: any[]) => KafkaModuleOptions | Promise<KafkaModuleOptions>;
47
+ inject?: any[];
48
+ }
49
+ /**
50
+ * NestJS dynamic module for registering type-safe Kafka clients.
51
+ * Use `register()` for static config or `registerAsync()` for DI-based config.
52
+ */
53
+ export declare class KafkaModule {
54
+ /** Register a Kafka client with static options. */
55
+ static register<T extends TopicMapConstraint<T>>(options: KafkaModuleOptions): DynamicModule;
56
+ /** Register a Kafka client with async/factory-based options. */
57
+ static registerAsync<T extends TopicMapConstraint<T>>(asyncOptions: KafkaModuleAsyncOptions): DynamicModule;
58
+ private static buildClient;
59
+ }
60
+ export {};
61
+ //# sourceMappingURL=kafka.module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kafka.module.d.ts","sourceRoot":"","sources":["../../src/nest/kafka.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,aAAa,EAAoB,MAAM,gBAAgB,CAAC;AAEzE,OAAO,EAEL,QAAQ,EACR,OAAO,EACP,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,EACnB,MAAM,wBAAwB,CAAC;AAIhC,+EAA+E;AAC/E,UAAU,sBAAsB;IAC9B,oFAAoF;IACpF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4GAA4G;IAC5G,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,8DAA8D;AAC9D,MAAM,WAAW,kBAAmB,SAAQ,sBAAsB;IAChE,sCAAsC;IACtC,QAAQ,EAAE,QAAQ,CAAC;IACnB,iCAAiC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,sCAAsC;IACtC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,wFAAwF;IACxF,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,oIAAoI;IACpI,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kEAAkE;IAClE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6FAA6F;IAC7F,eAAe,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACzC,4GAA4G;IAC5G,aAAa,CAAC,EAAE,kBAAkB,CAAC,eAAe,CAAC,CAAC;IACpD,+FAA+F;IAC/F,WAAW,CAAC,EAAE,kBAAkB,CAAC,aAAa,CAAC,CAAC;IAChD,gHAAgH;IAChH,eAAe,CAAC,EAAE,kBAAkB,CAAC,iBAAiB,CAAC,CAAC;IACxD,sGAAsG;IACtG,aAAa,CAAC,EAAE,kBAAkB,CAAC,eAAe,CAAC,CAAC;IACpD,wGAAwG;IACxG,WAAW,CAAC,EAAE,kBAAkB,CAAC,aAAa,CAAC,CAAC;IAChD,8EAA8E;IAC9E,YAAY,CAAC,EAAE,kBAAkB,CAAC,cAAc,CAAC,CAAC;IAClD,2GAA2G;IAC3G,SAAS,CAAC,EAAE,kBAAkB,CAAC,WAAW,CAAC,CAAC;IAC5C,2GAA2G;IAC3G,QAAQ,CAAC,EAAE,kBAAkB,CAAC,UAAU,CAAC,CAAC;CAC3C;AAED,uFAAuF;AACvF,MAAM,WAAW,uBAAwB,SAAQ,sBAAsB;IACrE,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;IAChB,UAAU,EAAE,CACV,GAAG,IAAI,EAAE,GAAG,EAAE,KACX,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACtD,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;CAChB;AAED;;;GAGG;AACH,qBACa,WAAW;IACtB,mDAAmD;IACnD,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,kBAAkB,CAAC,CAAC,CAAC,EAC7C,OAAO,EAAE,kBAAkB,GAC1B,aAAa;IAiBhB,gEAAgE;IAChE,MAAM,CAAC,aAAa,CAAC,CAAC,SAAS,kBAAkB,CAAC,CAAC,CAAC,EAClD,YAAY,EAAE,uBAAuB,GACpC,aAAa;mBAmBK,WAAW;CA0BjC"}
package/dist/otel.d.ts CHANGED
@@ -1,5 +1,7 @@
1
- import { K as KafkaInstrumentation } from './consumer.types-fFCag3VJ.js';
2
-
1
+ import type { Meter } from "@opentelemetry/api";
2
+ import type { KafkaInstrumentation } from "./client/types";
3
+ import type { IKafkaAdmin } from "./client/types/admin.interface";
4
+ import type { TopicMapConstraint } from "./client/types/common";
3
5
  /**
4
6
  * Create a `KafkaInstrumentation` that automatically propagates
5
7
  * W3C Trace Context via Kafka headers.
@@ -22,6 +24,82 @@ import { K as KafkaInstrumentation } from './consumer.types-fFCag3VJ.js';
22
24
  * });
23
25
  * ```
24
26
  */
25
- declare function otelInstrumentation(): KafkaInstrumentation;
26
-
27
- export { otelInstrumentation };
27
+ export declare function otelInstrumentation(): KafkaInstrumentation;
28
+ /**
29
+ * Create a `KafkaInstrumentation` that records OpenTelemetry **metrics** for
30
+ * both the send and consume paths.
31
+ *
32
+ * Requires `@opentelemetry/api` as a peer dependency. Instruments are created
33
+ * once per instrumentation instance (not per message), so a single call to this
34
+ * factory registers all counters/histograms exactly once.
35
+ *
36
+ * Recorded instruments (all under meter `@drarzter/kafka-client`):
37
+ *
38
+ * | Instrument | Type | Attributes | Recorded in |
39
+ * |---|---|---|---|
40
+ * | `kafka.client.messages.sent` | Counter | `topic` | `afterSend` |
41
+ * | `kafka.client.messages.processed` | Counter | `topic` | `onMessage` |
42
+ * | `kafka.client.messages.retried` | Counter | `topic` | `onRetry` |
43
+ * | `kafka.client.messages.dlq` | Counter | `topic`, `reason` | `onDlq` |
44
+ * | `kafka.client.messages.duplicate` | Counter | `topic`, `strategy` | `onDuplicate` |
45
+ * | `kafka.client.consume.errors` | Counter | `topic` | `onConsumeError` |
46
+ * | `kafka.client.consume.duration` | Histogram (ms) | `topic` | `beforeConsume` → `cleanup()` |
47
+ *
48
+ * Composes with `otelInstrumentation()` (traces): list both in
49
+ * `instrumentation`. They share nothing and can be added in any order.
50
+ *
51
+ * @param options.meter - Override the meter used to create instruments.
52
+ * Defaults to `metrics.getMeter("@drarzter/kafka-client")`.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * import {
57
+ * otelInstrumentation,
58
+ * otelMetricsInstrumentation,
59
+ * } from '@drarzter/kafka-client/otel';
60
+ *
61
+ * const kafka = new KafkaClient('my-app', 'my-group', brokers, {
62
+ * instrumentation: [otelInstrumentation(), otelMetricsInstrumentation()],
63
+ * });
64
+ * ```
65
+ */
66
+ export declare function otelMetricsInstrumentation(options?: {
67
+ meter?: Meter;
68
+ }): KafkaInstrumentation;
69
+ /**
70
+ * Register an OpenTelemetry **ObservableGauge** `kafka.client.consumer.lag`
71
+ * that reports per-partition consumer lag by polling `kafka.getConsumerLag()`
72
+ * on each metric collection cycle.
73
+ *
74
+ * Requires `@opentelemetry/api` as a peer dependency. Accepts any object
75
+ * implementing the `IKafkaAdmin` sub-interface (i.e. any `KafkaClient`).
76
+ *
77
+ * The async callback swallows errors silently — a broker query failure during
78
+ * a collection cycle simply reports no lag samples for that cycle rather than
79
+ * throwing inside the OTel metric reader.
80
+ *
81
+ * Gauge attributes: `topic`, `partition`, and `groupId` (empty string when the
82
+ * client's default group is used).
83
+ *
84
+ * @param kafka - The client (or any `IKafkaAdmin`) to poll for lag.
85
+ * @param options.meter - Override the meter. Defaults to
86
+ * `metrics.getMeter("@drarzter/kafka-client")`.
87
+ * @param options.groupId - Consumer group to query. Defaults to the client's
88
+ * constructor group.
89
+ * @returns An unregister function that removes the observable callback. Call it
90
+ * on shutdown to stop observing.
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * import { otelLagGauge } from '@drarzter/kafka-client/otel';
95
+ *
96
+ * const unregister = otelLagGauge(kafka, { groupId: 'billing-service' });
97
+ * // ...later, on shutdown:
98
+ * unregister();
99
+ * ```
100
+ */
101
+ export declare function otelLagGauge<T extends TopicMapConstraint<T>>(kafka: IKafkaAdmin<T>, options?: {
102
+ meter?: Meter;
103
+ groupId?: string;
104
+ }): () => void;
105
+ //# sourceMappingURL=otel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otel.d.ts","sourceRoot":"","sources":["../src/otel.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,KAAK,EAAoB,MAAM,oBAAoB,CAAC;AAClE,OAAO,KAAK,EAAuB,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAGhE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,mBAAmB,IAAI,oBAAoB,CA0D1D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,CAAC,EAAE;IACnD,KAAK,CAAC,EAAE,KAAK,CAAC;CACf,GAAG,oBAAoB,CA4EvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,kBAAkB,CAAC,CAAC,CAAC,EAC1D,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,EACrB,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,KAAK,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5C,MAAM,IAAI,CA4BZ"}
package/dist/otel.js CHANGED
@@ -20,13 +20,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/otel.ts
21
21
  var otel_exports = {};
22
22
  __export(otel_exports, {
23
- otelInstrumentation: () => otelInstrumentation
23
+ otelInstrumentation: () => otelInstrumentation,
24
+ otelLagGauge: () => otelLagGauge,
25
+ otelMetricsInstrumentation: () => otelMetricsInstrumentation
24
26
  });
25
27
  module.exports = __toCommonJS(otel_exports);
26
28
  var import_api = require("@opentelemetry/api");
27
29
  function otelInstrumentation() {
28
30
  const tracer = import_api.trace.getTracer("@drarzter/kafka-client");
29
- const activeSpans = /* @__PURE__ */ new Map();
31
+ const activeSpans = /* @__PURE__ */ new WeakMap();
30
32
  return {
31
33
  beforeSend(_topic, headers) {
32
34
  import_api.propagation.inject(import_api.context.active(), headers);
@@ -50,11 +52,11 @@ function otelInstrumentation() {
50
52
  parentCtx
51
53
  );
52
54
  const spanCtx = import_api.trace.setSpan(parentCtx, span);
53
- activeSpans.set(envelope.eventId, span);
55
+ activeSpans.set(envelope, span);
54
56
  return {
55
57
  cleanup() {
56
58
  span.end();
57
- activeSpans.delete(envelope.eventId);
59
+ activeSpans.delete(envelope);
58
60
  },
59
61
  wrap(fn) {
60
62
  return import_api.context.with(spanCtx, fn);
@@ -62,7 +64,7 @@ function otelInstrumentation() {
62
64
  };
63
65
  },
64
66
  onConsumeError(envelope, error) {
65
- const span = activeSpans.get(envelope.eventId);
67
+ const span = activeSpans.get(envelope);
66
68
  if (span) {
67
69
  span.setStatus({ code: import_api.SpanStatusCode.ERROR, message: error.message });
68
70
  span.recordException(error);
@@ -70,8 +72,100 @@ function otelInstrumentation() {
70
72
  }
71
73
  };
72
74
  }
75
+ function otelMetricsInstrumentation(options) {
76
+ const meter = options?.meter ?? import_api.metrics.getMeter("@drarzter/kafka-client");
77
+ const sentCounter = meter.createCounter("kafka.client.messages.sent", {
78
+ description: "Number of messages successfully sent to Kafka."
79
+ });
80
+ const processedCounter = meter.createCounter(
81
+ "kafka.client.messages.processed",
82
+ {
83
+ description: "Number of messages successfully processed by a consumer."
84
+ }
85
+ );
86
+ const retriedCounter = meter.createCounter("kafka.client.messages.retried", {
87
+ description: "Number of messages queued for retry."
88
+ });
89
+ const dlqCounter = meter.createCounter("kafka.client.messages.dlq", {
90
+ description: "Number of messages routed to a DLQ topic."
91
+ });
92
+ const duplicateCounter = meter.createCounter(
93
+ "kafka.client.messages.duplicate",
94
+ {
95
+ description: "Number of Lamport-clock duplicate messages detected."
96
+ }
97
+ );
98
+ const consumeErrorsCounter = meter.createCounter(
99
+ "kafka.client.consume.errors",
100
+ {
101
+ description: "Number of consumer handler errors."
102
+ }
103
+ );
104
+ const consumeDuration = meter.createHistogram(
105
+ "kafka.client.consume.duration",
106
+ {
107
+ description: "Consumer handler duration.",
108
+ unit: "ms"
109
+ }
110
+ );
111
+ return {
112
+ afterSend(topic) {
113
+ sentCounter.add(1, { topic });
114
+ },
115
+ beforeConsume(envelope) {
116
+ const topic = envelope.topic;
117
+ const start = Date.now();
118
+ return {
119
+ cleanup() {
120
+ consumeDuration.record(Date.now() - start, { topic });
121
+ }
122
+ };
123
+ },
124
+ onConsumeError(envelope, _error) {
125
+ consumeErrorsCounter.add(1, { topic: envelope.topic });
126
+ },
127
+ onRetry(envelope, _attempt, _max) {
128
+ retriedCounter.add(1, { topic: envelope.topic });
129
+ },
130
+ onDlq(envelope, reason) {
131
+ dlqCounter.add(1, { topic: envelope.topic, reason });
132
+ },
133
+ onDuplicate(envelope, strategy) {
134
+ duplicateCounter.add(1, { topic: envelope.topic, strategy });
135
+ },
136
+ onMessage(envelope) {
137
+ processedCounter.add(1, { topic: envelope.topic });
138
+ }
139
+ };
140
+ }
141
+ function otelLagGauge(kafka, options) {
142
+ const meter = options?.meter ?? import_api.metrics.getMeter("@drarzter/kafka-client");
143
+ const groupId = options?.groupId;
144
+ const gauge = meter.createObservableGauge("kafka.client.consumer.lag", {
145
+ description: "Consumer group lag per topic partition."
146
+ });
147
+ const callback = async (result) => {
148
+ try {
149
+ const lag = await kafka.getConsumerLag(groupId);
150
+ for (const entry of lag) {
151
+ result.observe(entry.lag, {
152
+ topic: entry.topic,
153
+ partition: entry.partition,
154
+ groupId: groupId ?? ""
155
+ });
156
+ }
157
+ } catch {
158
+ }
159
+ };
160
+ gauge.addCallback(callback);
161
+ return () => {
162
+ gauge.removeCallback(callback);
163
+ };
164
+ }
73
165
  // Annotate the CommonJS export names for ESM import in node:
74
166
  0 && (module.exports = {
75
- otelInstrumentation
167
+ otelInstrumentation,
168
+ otelLagGauge,
169
+ otelMetricsInstrumentation
76
170
  });
77
171
  //# sourceMappingURL=otel.js.map