@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.
- package/README.md +625 -8
- package/dist/chunk-CMO7SMVK.mjs +4814 -0
- package/dist/chunk-CMO7SMVK.mjs.map +1 -0
- package/dist/cli/dlq.d.ts +119 -0
- package/dist/cli/dlq.d.ts.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/{chunk-SM4FZKAZ.mjs → cli/index.js} +964 -264
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/index.mjs +355 -0
- package/dist/cli/index.mjs.map +1 -0
- package/dist/client/config/from-env.d.ts +188 -0
- package/dist/client/config/from-env.d.ts.map +1 -0
- package/dist/client/config/index.d.ts +2 -0
- package/dist/client/config/index.d.ts.map +1 -0
- package/dist/client/errors.d.ts +67 -0
- package/dist/client/errors.d.ts.map +1 -0
- package/dist/client/kafka.client/admin/ops.d.ts +114 -0
- package/dist/client/kafka.client/admin/ops.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/features/delayed.d.ts +24 -0
- package/dist/client/kafka.client/consumer/features/delayed.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/features/dlq-replay.d.ts +52 -0
- package/dist/client/kafka.client/consumer/features/dlq-replay.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/features/routed.d.ts +4 -0
- package/dist/client/kafka.client/consumer/features/routed.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/features/snapshot.d.ts +10 -0
- package/dist/client/kafka.client/consumer/features/snapshot.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/features/window.d.ts +5 -0
- package/dist/client/kafka.client/consumer/features/window.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/handler.d.ts +149 -0
- package/dist/client/kafka.client/consumer/handler.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/ops.d.ts +51 -0
- package/dist/client/kafka.client/consumer/ops.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/pipeline.d.ts +167 -0
- package/dist/client/kafka.client/consumer/pipeline.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/queue.d.ts +37 -0
- package/dist/client/kafka.client/consumer/queue.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/retry-topic.d.ts +65 -0
- package/dist/client/kafka.client/consumer/retry-topic.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/setup.d.ts +63 -0
- package/dist/client/kafka.client/consumer/setup.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/start.d.ts +7 -0
- package/dist/client/kafka.client/consumer/start.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/stop.d.ts +19 -0
- package/dist/client/kafka.client/consumer/stop.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/subscribe-retry.d.ts +4 -0
- package/dist/client/kafka.client/consumer/subscribe-retry.d.ts.map +1 -0
- package/dist/client/kafka.client/context.d.ts +72 -0
- package/dist/client/kafka.client/context.d.ts.map +1 -0
- package/dist/client/kafka.client/index.d.ts +155 -0
- package/dist/client/kafka.client/index.d.ts.map +1 -0
- package/dist/client/kafka.client/infra/circuit-breaker.manager.d.ts +61 -0
- package/dist/client/kafka.client/infra/circuit-breaker.manager.d.ts.map +1 -0
- package/dist/client/kafka.client/infra/dedup.store.d.ts +28 -0
- package/dist/client/kafka.client/infra/dedup.store.d.ts.map +1 -0
- package/dist/client/kafka.client/infra/inflight.tracker.d.ts +22 -0
- package/dist/client/kafka.client/infra/inflight.tracker.d.ts.map +1 -0
- package/dist/client/kafka.client/infra/metrics.manager.d.ts +67 -0
- package/dist/client/kafka.client/infra/metrics.manager.d.ts.map +1 -0
- package/dist/client/kafka.client/producer/lifecycle.d.ts +41 -0
- package/dist/client/kafka.client/producer/lifecycle.d.ts.map +1 -0
- package/dist/client/kafka.client/producer/ops.d.ts +70 -0
- package/dist/client/kafka.client/producer/ops.d.ts.map +1 -0
- package/dist/client/kafka.client/producer/send.d.ts +21 -0
- package/dist/client/kafka.client/producer/send.d.ts.map +1 -0
- package/dist/client/kafka.client/validate-options.d.ts +11 -0
- package/dist/client/kafka.client/validate-options.d.ts.map +1 -0
- package/dist/client/message/envelope.d.ts +105 -0
- package/dist/client/message/envelope.d.ts.map +1 -0
- package/dist/client/message/schema-registry.d.ts +105 -0
- package/dist/client/message/schema-registry.d.ts.map +1 -0
- package/dist/client/message/topic.d.ts +138 -0
- package/dist/client/message/topic.d.ts.map +1 -0
- package/dist/client/message/versioned-schema.d.ts +53 -0
- package/dist/client/message/versioned-schema.d.ts.map +1 -0
- package/dist/client/outbox/index.d.ts +4 -0
- package/dist/client/outbox/index.d.ts.map +1 -0
- package/dist/client/outbox/outbox.relay.d.ts +90 -0
- package/dist/client/outbox/outbox.relay.d.ts.map +1 -0
- package/dist/client/outbox/outbox.store.d.ts +42 -0
- package/dist/client/outbox/outbox.store.d.ts.map +1 -0
- package/dist/client/outbox/outbox.types.d.ts +144 -0
- package/dist/client/outbox/outbox.types.d.ts.map +1 -0
- package/dist/client/security/acl.d.ts +108 -0
- package/dist/client/security/acl.d.ts.map +1 -0
- package/dist/client/security/index.d.ts +5 -0
- package/dist/client/security/index.d.ts.map +1 -0
- package/dist/client/security/providers.d.ts +88 -0
- package/dist/client/security/providers.d.ts.map +1 -0
- package/dist/client/security/resolve-security.d.ts +19 -0
- package/dist/client/security/resolve-security.d.ts.map +1 -0
- package/dist/client/security/security.types.d.ts +76 -0
- package/dist/client/security/security.types.d.ts.map +1 -0
- package/dist/client/transport/confluent.transport.d.ts +32 -0
- package/dist/client/transport/confluent.transport.d.ts.map +1 -0
- package/dist/client/transport/transport.interface.d.ts +216 -0
- package/dist/client/transport/transport.interface.d.ts.map +1 -0
- package/dist/client/types/admin.interface.d.ts +174 -0
- package/dist/client/types/admin.interface.d.ts.map +1 -0
- package/dist/client/types/admin.types.d.ts +140 -0
- package/dist/client/types/admin.types.d.ts.map +1 -0
- package/dist/client/types/client.d.ts +21 -0
- package/dist/client/types/client.d.ts.map +1 -0
- package/dist/client/types/common.d.ts +84 -0
- package/dist/client/types/common.d.ts.map +1 -0
- package/dist/client/types/config.types.d.ts +150 -0
- package/dist/client/types/config.types.d.ts.map +1 -0
- package/dist/client/types/consumer.interface.d.ts +115 -0
- package/dist/client/types/consumer.interface.d.ts.map +1 -0
- package/dist/{consumer.types-fFCag3VJ.d.mts → client/types/consumer.types.d.ts} +62 -383
- package/dist/client/types/consumer.types.d.ts.map +1 -0
- package/dist/client/types/dedup.types.d.ts +50 -0
- package/dist/client/types/dedup.types.d.ts.map +1 -0
- package/dist/client/types/lifecycle.interface.d.ts +72 -0
- package/dist/client/types/lifecycle.interface.d.ts.map +1 -0
- package/dist/client/types/producer.interface.d.ts +52 -0
- package/dist/client/types/producer.interface.d.ts.map +1 -0
- package/dist/client/types/producer.types.d.ts +90 -0
- package/dist/client/types/producer.types.d.ts.map +1 -0
- package/dist/client/types.d.ts +8 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/core.d.ts +10 -314
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +1325 -73
- package/dist/core.js.map +1 -1
- package/dist/core.mjs +39 -3
- package/dist/index.d.ts +7 -128
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1342 -73
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +56 -3
- package/dist/index.mjs.map +1 -1
- package/dist/nest/kafka.constants.d.ts +5 -0
- package/dist/nest/kafka.constants.d.ts.map +1 -0
- package/dist/nest/kafka.decorator.d.ts +49 -0
- package/dist/nest/kafka.decorator.d.ts.map +1 -0
- package/dist/nest/kafka.explorer.d.ts +17 -0
- package/dist/nest/kafka.explorer.d.ts.map +1 -0
- package/dist/nest/kafka.health.d.ts +7 -0
- package/dist/nest/kafka.health.d.ts.map +1 -0
- package/dist/nest/kafka.module.d.ts +61 -0
- package/dist/nest/kafka.module.d.ts.map +1 -0
- package/dist/otel.d.ts +83 -5
- package/dist/otel.d.ts.map +1 -0
- package/dist/otel.js +100 -6
- package/dist/otel.js.map +1 -1
- package/dist/otel.mjs +98 -5
- package/dist/otel.mjs.map +1 -1
- package/dist/testing/client.mock.d.ts +47 -0
- package/dist/testing/client.mock.d.ts.map +1 -0
- package/dist/testing/index.d.ts +4 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/test.container.d.ts +63 -0
- package/dist/testing/test.container.d.ts.map +1 -0
- package/dist/{testing.d.mts → testing/transport.fake.d.ts} +7 -111
- package/dist/testing/transport.fake.d.ts.map +1 -0
- package/dist/testing.d.ts +2 -318
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +26 -0
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +26 -0
- package/dist/testing.mjs.map +1 -1
- package/package.json +21 -8
- package/dist/chunk-SM4FZKAZ.mjs.map +0 -1
- package/dist/client-1irhGEu0.d.mts +0 -751
- package/dist/client-BpFjkHhr.d.ts +0 -751
- package/dist/consumer.types-fFCag3VJ.d.ts +0 -958
- package/dist/core.d.mts +0 -314
- package/dist/index.d.mts +0 -128
- 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
|
-
|
|
18
|
-
|
|
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
|
-
|
|
277
|
+
startOutboxRelay,
|
|
278
|
+
toError,
|
|
279
|
+
toKafkaAclCommands,
|
|
280
|
+
toMskIamPolicy,
|
|
281
|
+
topic,
|
|
282
|
+
versionedSchema
|
|
230
283
|
};
|
|
231
284
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -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":";;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,QAAiC,UAAAA,eAAc;AACxD,SAAS,uBAAuB;;;ACAzB,IAAM,eAAe;AAGrB,IAAM,sBAAsB,CAAC,SAClC,OAAO,gBAAgB,IAAI,KAAK;;;ACLlC,SAAS,UAAAC,SAAQ,YAA0B,cAAc;AACzD,SAAS,kBAAkB,iBAAiB;;;ACD5C,SAAS,cAAc;AAMhB,IAAM,4BAA4B;AAmBlC,IAAM,oBAAoB,CAAC,SAChC,OAAO,oBAAoB,IAAI,CAAC;AAyB3B,IAAM,cAAc,CACzB,QAMA,YACoB;AACpB,QAAM,MAAM,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,MAAM;AACpD,QAAM,cAAc,IAAI,IAAI,CAAC,MAAO,OAAO,MAAM,WAAW,IAAI,EAAE,OAAQ;AAG1E,QAAM,UAAU,oBAAI,IAAwB;AAC5C,aAAW,KAAK,KAAK;AACnB,QAAI,OAAO,MAAM,YAAY,EAAE,UAAU;AACvC,cAAQ,IAAI,EAAE,SAAS,EAAE,QAAQ;AAAA,IACnC;AAAA,EACF;AAEA,QAAM,EAAE,YAAY,OAAO,GAAG,gBAAgB,IAAI,WAAW,CAAC;AAE9D,SAAO,CAAC,QAAQ,aAAa,gBAAgB;AAC3C,UAAM,WACJ,QAAQ,YAAY,2BAA2B,OAAO,WAAW,KAAK,CAAC;AAEzE,YAAQ;AAAA,MACN;AAAA,MACA;AAAA,QACE,GAAG;AAAA,QACH;AAAA,UACE,QAAQ;AAAA,UACR,SAAS,QAAQ,OAAO,IAAI,UAAU;AAAA,UACtC,SAAS,OAAO,KAAK,eAAe,EAAE,SAClC,kBACA;AAAA,UACJ;AAAA,UACA;AAAA,UACA,YAAY;AAAA,QACd;AAAA,MACF;AAAA,MACA,OAAO;AAAA,IACT;AAAA,EACF;AACF;;;ADhFO,IAAM,gBAAN,MAA4C;AAAA,EAGjD,YAEmB,kBAEA,WACjB;AAHiB;AAEA;AAAA,EAChB;AAAA,EAPc,SAAS,IAAI,OAAO,cAAc,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAevD,MAAM,eAAe;AACnB,UAAM,YAAY,KAAK,iBAAiB,aAAa;AAErD,eAAW,WAAW,WAAW;AAC/B,YAAM,EAAE,SAAS,IAAI;AACrB,UAAI,CAAC,YAAY,OAAO,aAAa,SAAU;AAE/C,YAAM,WAA0C,QAAQ;AAAA,QACtD;AAAA,QACA,SAAS;AAAA,MACX;AAEA,UAAI,CAAC,YAAY,SAAS,WAAW,EAAG;AAExC,iBAAW,SAAS,UAAU;AAC5B,cAAM,QAAQ,oBAAoB,MAAM,UAAU;AAClD,YAAI;AAEJ,YAAI;AACF,mBAAS,KAAK,UAAU,IAAI,OAAO,EAAE,QAAQ,MAAM,CAAC;AAAA,QACtD,QAAQ;AACN,eAAK,OAAO;AAAA,YACV,gBAAgB,MAAM,cAAc,SAAS,mCAAmC,SAAS,YAAY,IAAI,IAAI,OAAO,MAAM,UAAU,CAAC;AAAA,UACvI;AACA;AAAA,QACF;AAEA,cAAM,UAAW,SAAiB,MAAM,UAAU,EAAE,KAAK,QAAQ;AAEjE,cAAM,kBAAkB,EAAE,GAAG,MAAM,QAAQ;AAC3C,YAAI,MAAM,SAAS;AACjB,0BAAgB,UAAU,MAAM;AAAA,QAClC;AAEA,YAAI,MAAM,OAAO;AACf,gBAAM,OAAO;AAAA,YACX,MAAM;AAAA,YACN,OAAO,WAAkB,SAAc;AACrC,oBAAM,QAAQ,WAAW,IAAI;AAAA,YAC/B;AAAA,YACA;AAAA,UACF;AAAA,QACF,OAAO;AACL,gBAAM,OAAO;AAAA,YACX,MAAM;AAAA,YACN,OAAO,aAAkB;AACvB,oBAAM,QAAQ,QAAQ;AAAA,YACxB;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAEA,aAAK,OAAO;AAAA,UACV,2BAA2B,MAAM,OAAO,KAAK,IAAI,CAAC,IAAI,MAAM,QAAQ,aAAa,EAAE,OAAO,SAAS,YAAY,IAAI,IAAI,OAAO,MAAM,UAAU,CAAC;AAAA,QACjJ;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AA1Ea,gBAAN;AAAA,EADN,WAAW;AAAA,EAKP,mBAAAC,QAAO,gBAAgB;AAAA,EAEvB,mBAAAA,QAAO,SAAS;AAAA,GANR;;;AF0CN,IAAM,cAAN,MAAkB;AAAA;AAAA,EAEvB,OAAO,SACL,SACe;AACf,UAAM,QAAQ,oBAAoB,QAAQ,IAAI;AAE9C,UAAM,sBAAgC;AAAA,MACpC,SAAS;AAAA,MACT,YAAY,MAAM,YAAY,YAAe,OAAO;AAAA,IACtD;AAEA,WAAO;AAAA,MACL,QAAQ,QAAQ,YAAY;AAAA,MAC5B,QAAQ;AAAA,MACR,SAAS,CAAC,eAAe;AAAA,MACzB,WAAW,CAAC,qBAAqB,aAAa;AAAA,MAC9C,SAAS,CAAC,mBAAmB;AAAA,IAC/B;AAAA,EACF;AAAA;AAAA,EAGA,OAAO,cACL,cACe;AACf,UAAM,QAAQ,oBAAoB,aAAa,IAAI;AAEnD,UAAM,sBAAgC;AAAA,MACpC,SAAS;AAAA,MACT,YAAY,UAAU,SACpB,YAAY,YAAe,MAAM,aAAa,WAAW,GAAG,IAAI,CAAC;AAAA,MACnE,QAAQ,aAAa,UAAU,CAAC;AAAA,IAClC;AAEA,WAAO;AAAA,MACL,QAAQ,aAAa,YAAY;AAAA,MACjC,QAAQ;AAAA,MACR,SAAS,CAAC,GAAI,aAAa,WAAW,CAAC,GAAI,eAAe;AAAA,MAC1D,WAAW,CAAC,qBAAqB,aAAa;AAAA,MAC9C,SAAS,CAAC,mBAAmB;AAAA,IAC/B;AAAA,EACF;AAAA,EAEA,aAAqB,YACnB,SACyB;AACzB,UAAM,SAAS,IAAI;AAAA,MACjB,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR;AAAA,QACE,kBAAkB,QAAQ;AAAA,QAC1B,eAAe,QAAQ;AAAA,QACvB,eAAe,QAAQ;AAAA,QACvB,iBAAiB,QAAQ;AAAA,QACzB,eAAe,QAAQ;AAAA,QACvB,aAAa,QAAQ;AAAA,QACrB,QAAQ,IAAIC,QAAO,eAAe,QAAQ,QAAQ,EAAE;AAAA,MACtD;AAAA,IACF;AACA,UAAM,OAAO,gBAAgB;AAC7B,WAAO;AAAA,EACT;AACF;AA/Da,cAAN;AAAA,EADN,OAAO,CAAC,CAAC;AAAA,GACG;;;AIzDb,SAAS,cAAAC,mBAAkB;AAUpB,IAAM,uBAAN,MAA2B;AAAA,EAChC,MAAM,MACJ,QAC4B;AAC5B,WAAO,OAAO,YAAY;AAAA,EAC5B;AACF;AANa,uBAAN;AAAA,EADNC,YAAW;AAAA,GACC;","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 {
|
|
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
|
-
|
|
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
|
|
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
|
|
55
|
+
activeSpans.set(envelope, span);
|
|
54
56
|
return {
|
|
55
57
|
cleanup() {
|
|
56
58
|
span.end();
|
|
57
|
-
activeSpans.delete(envelope
|
|
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
|
|
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
|