@drarzter/kafka-client 0.5.6 → 0.5.7
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 +33 -17
- package/dist/{chunk-6B72MJPU.mjs → chunk-TD2AE774.mjs} +198 -127
- package/dist/chunk-TD2AE774.mjs.map +1 -0
- package/dist/core.d.mts +7 -9
- package/dist/core.d.ts +7 -9
- package/dist/core.js +197 -126
- package/dist/core.js.map +1 -1
- package/dist/core.mjs +1 -1
- package/dist/index.d.mts +3 -13
- package/dist/index.d.ts +3 -13
- package/dist/index.js +198 -135
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -10
- package/dist/index.mjs.map +1 -1
- package/dist/otel.d.mts +1 -1
- package/dist/otel.d.ts +1 -1
- package/dist/otel.js +9 -4
- package/dist/otel.js.map +1 -1
- package/dist/otel.mjs +9 -4
- package/dist/otel.mjs.map +1 -1
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/{envelope-LeO5e3ob.d.mts → types-DwERZ6ql.d.mts} +96 -83
- package/dist/{envelope-LeO5e3ob.d.ts → types-DwERZ6ql.d.ts} +96 -83
- package/package.json +1 -1
- package/dist/chunk-6B72MJPU.mjs.map +0 -1
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: [\n kafkaClientProvider,\n KafkaModule.buildDestroyProvider(token),\n KafkaExplorer,\n ],\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: [\n kafkaClientProvider,\n KafkaModule.buildDestroyProvider(token),\n KafkaExplorer,\n ],\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 private static buildDestroyProvider<T extends TopicMapConstraint<T>>(\n token: string,\n ): Provider {\n return {\n provide: `${token}_DESTROY`,\n useFactory: (client: KafkaClient<T>) => ({\n onModuleDestroy: () => client.disconnect(),\n }),\n inject: [token],\n };\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 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\nexport const KAFKA_SUBSCRIBER_METADATA = \"KAFKA_SUBSCRIBER_METADATA\";\n\nexport interface KafkaSubscriberMetadata {\n topics: string[];\n schemas?: Map<string, SchemaLike>;\n options?: ConsumerOptions;\n clientName?: string;\n batch?: boolean;\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 * Decorator that auto-subscribes a method to Kafka topics on module init.\n * The decorated method receives `(message, topic)` for each consumed message.\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 { KafkaClient, TopicMapConstraint } from \"../client/kafka.client\";\n\n/** Result returned by `KafkaHealthIndicator.check()`. */\nexport type KafkaHealthResult =\n | { status: \"up\"; clientId: string; topics: string[] }\n | { status: \"down\"; clientId: string; error: string };\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: KafkaClient<T>,\n ): Promise<KafkaHealthResult> {\n try {\n return await client.checkStatus();\n } catch (error) {\n return {\n status: \"down\",\n clientId: client.clientId,\n error: error instanceof Error ? error.message : String(error),\n };\n }\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}\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: [\n kafkaClientProvider,\n KafkaModule.buildDestroyProvider(token),\n KafkaExplorer,\n ],\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: [\n kafkaClientProvider,\n KafkaModule.buildDestroyProvider(token),\n KafkaExplorer,\n ],\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 private static buildDestroyProvider<T extends TopicMapConstraint<T>>(\n token: string,\n ): Provider {\n return {\n provide: `${token}_DESTROY`,\n useFactory: (client: KafkaClient<T>) => ({\n onModuleDestroy: () => client.disconnect(),\n }),\n inject: [token],\n };\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 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\nexport const KAFKA_SUBSCRIBER_METADATA = \"KAFKA_SUBSCRIBER_METADATA\";\n\nexport interface KafkaSubscriberMetadata {\n topics: string[];\n schemas?: Map<string, SchemaLike>;\n options?: ConsumerOptions;\n clientName?: string;\n batch?: boolean;\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 * Decorator that auto-subscribes a method to Kafka topics on module init.\n * The decorated method receives `(message, topic)` for each consumed message.\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 { KafkaClient, TopicMapConstraint } from \"../client/kafka.client\";\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: KafkaClient<T>,\n ): Promise<import(\"../client/types\").KafkaHealthResult> {\n return client.checkStatus();\n }\n}\n"],"mappings":"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","names":["Logger","Inject","Inject","Logger","Injectable","Injectable"]}
|
package/dist/otel.d.mts
CHANGED
package/dist/otel.d.ts
CHANGED
package/dist/otel.js
CHANGED
|
@@ -26,8 +26,9 @@ module.exports = __toCommonJS(otel_exports);
|
|
|
26
26
|
var import_api = require("@opentelemetry/api");
|
|
27
27
|
function otelInstrumentation() {
|
|
28
28
|
const tracer = import_api.trace.getTracer("@drarzter/kafka-client");
|
|
29
|
+
const activeSpans = /* @__PURE__ */ new Map();
|
|
29
30
|
return {
|
|
30
|
-
beforeSend(
|
|
31
|
+
beforeSend(_topic, headers) {
|
|
31
32
|
import_api.propagation.inject(import_api.context.active(), headers);
|
|
32
33
|
},
|
|
33
34
|
afterSend(_topic) {
|
|
@@ -48,10 +49,14 @@ function otelInstrumentation() {
|
|
|
48
49
|
},
|
|
49
50
|
parentCtx
|
|
50
51
|
);
|
|
51
|
-
|
|
52
|
+
activeSpans.set(envelope.eventId, span);
|
|
53
|
+
return () => {
|
|
54
|
+
span.end();
|
|
55
|
+
activeSpans.delete(envelope.eventId);
|
|
56
|
+
};
|
|
52
57
|
},
|
|
53
|
-
onConsumeError(
|
|
54
|
-
const span =
|
|
58
|
+
onConsumeError(envelope, error) {
|
|
59
|
+
const span = activeSpans.get(envelope.eventId);
|
|
55
60
|
if (span) {
|
|
56
61
|
span.setStatus({ code: import_api.SpanStatusCode.ERROR, message: error.message });
|
|
57
62
|
span.recordException(error);
|
package/dist/otel.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/otel.ts"],"sourcesContent":["import {\n trace,\n context,\n propagation,\n SpanKind,\n SpanStatusCode,\n} from \"@opentelemetry/api\";\nimport type { KafkaInstrumentation } from \"./client/types\";\nimport type { EventEnvelope } from \"./client/message/envelope\";\n\n/**\n * Create a `KafkaInstrumentation` that automatically propagates\n * W3C Trace Context via Kafka headers.\n *\n * Requires `@opentelemetry/api` as a peer dependency.\n *\n * **Send path:** injects `traceparent` into message headers from the\n * active OpenTelemetry context.\n *\n * **Consume path:** extracts `traceparent` from message headers,\n * starts a `CONSUMER` span as a child of the extracted context,\n * and ends it when the handler completes.\n *\n * @example\n * ```ts\n * import { otelInstrumentation } from '@drarzter/kafka-client/otel';\n *\n * const kafka = new KafkaClient('my-app', 'my-group', brokers, {\n * instrumentation: [otelInstrumentation()],\n * });\n * ```\n */\nexport function otelInstrumentation(): KafkaInstrumentation {\n const tracer = trace.getTracer(\"@drarzter/kafka-client\");\n\n return {\n beforeSend(
|
|
1
|
+
{"version":3,"sources":["../src/otel.ts"],"sourcesContent":["import {\n trace,\n context,\n propagation,\n SpanKind,\n SpanStatusCode,\n} from \"@opentelemetry/api\";\nimport type { KafkaInstrumentation } from \"./client/types\";\nimport type { EventEnvelope } from \"./client/message/envelope\";\n\n/**\n * Create a `KafkaInstrumentation` that automatically propagates\n * W3C Trace Context via Kafka headers.\n *\n * Requires `@opentelemetry/api` as a peer dependency.\n *\n * **Send path:** injects `traceparent` into message headers from the\n * active OpenTelemetry context.\n *\n * **Consume path:** extracts `traceparent` from message headers,\n * starts a `CONSUMER` span as a child of the extracted context,\n * and ends it when the handler completes.\n *\n * @example\n * ```ts\n * import { otelInstrumentation } from '@drarzter/kafka-client/otel';\n *\n * const kafka = new KafkaClient('my-app', 'my-group', brokers, {\n * instrumentation: [otelInstrumentation()],\n * });\n * ```\n */\nexport function otelInstrumentation(): KafkaInstrumentation {\n const tracer = trace.getTracer(\"@drarzter/kafka-client\");\n // Keyed by eventId so beforeConsume/onConsumeError can share the span reference\n // without requiring the span to be set as the active context.\n const activeSpans = new Map<string, ReturnType<typeof tracer.startSpan>>();\n\n return {\n beforeSend(_topic: string, headers: Record<string, string>) {\n propagation.inject(context.active(), headers);\n },\n\n afterSend(_topic: string) {\n // Span management for producers is left to the caller's OTel setup.\n // We only inject context — creating producer spans here would be\n // inaccurate since buildSendPayload runs synchronously per-message.\n },\n\n beforeConsume(envelope: EventEnvelope<any>) {\n const parentCtx = propagation.extract(context.active(), envelope.headers);\n const span = tracer.startSpan(\n `kafka.consume ${envelope.topic}`,\n {\n kind: SpanKind.CONSUMER,\n attributes: {\n \"messaging.system\": \"kafka\",\n \"messaging.destination.name\": envelope.topic,\n \"messaging.message.id\": envelope.eventId,\n \"messaging.kafka.partition\": envelope.partition,\n \"messaging.kafka.offset\": envelope.offset,\n },\n },\n parentCtx,\n );\n activeSpans.set(envelope.eventId, span);\n return () => {\n span.end();\n activeSpans.delete(envelope.eventId);\n };\n },\n\n onConsumeError(envelope: EventEnvelope<any>, error: Error) {\n const span = activeSpans.get(envelope.eventId);\n if (span) {\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });\n span.recordException(error);\n }\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAMO;AA0BA,SAAS,sBAA4C;AAC1D,QAAM,SAAS,iBAAM,UAAU,wBAAwB;AAGvD,QAAM,cAAc,oBAAI,IAAiD;AAEzE,SAAO;AAAA,IACL,WAAW,QAAgB,SAAiC;AAC1D,6BAAY,OAAO,mBAAQ,OAAO,GAAG,OAAO;AAAA,IAC9C;AAAA,IAEA,UAAU,QAAgB;AAAA,IAI1B;AAAA,IAEA,cAAc,UAA8B;AAC1C,YAAM,YAAY,uBAAY,QAAQ,mBAAQ,OAAO,GAAG,SAAS,OAAO;AACxE,YAAM,OAAO,OAAO;AAAA,QAClB,iBAAiB,SAAS,KAAK;AAAA,QAC/B;AAAA,UACE,MAAM,oBAAS;AAAA,UACf,YAAY;AAAA,YACV,oBAAoB;AAAA,YACpB,8BAA8B,SAAS;AAAA,YACvC,wBAAwB,SAAS;AAAA,YACjC,6BAA6B,SAAS;AAAA,YACtC,0BAA0B,SAAS;AAAA,UACrC;AAAA,QACF;AAAA,QACA;AAAA,MACF;AACA,kBAAY,IAAI,SAAS,SAAS,IAAI;AACtC,aAAO,MAAM;AACX,aAAK,IAAI;AACT,oBAAY,OAAO,SAAS,OAAO;AAAA,MACrC;AAAA,IACF;AAAA,IAEA,eAAe,UAA8B,OAAc;AACzD,YAAM,OAAO,YAAY,IAAI,SAAS,OAAO;AAC7C,UAAI,MAAM;AACR,aAAK,UAAU,EAAE,MAAM,0BAAe,OAAO,SAAS,MAAM,QAAQ,CAAC;AACrE,aAAK,gBAAgB,KAAK;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
package/dist/otel.mjs
CHANGED
|
@@ -10,8 +10,9 @@ import {
|
|
|
10
10
|
} from "@opentelemetry/api";
|
|
11
11
|
function otelInstrumentation() {
|
|
12
12
|
const tracer = trace.getTracer("@drarzter/kafka-client");
|
|
13
|
+
const activeSpans = /* @__PURE__ */ new Map();
|
|
13
14
|
return {
|
|
14
|
-
beforeSend(
|
|
15
|
+
beforeSend(_topic, headers) {
|
|
15
16
|
propagation.inject(context.active(), headers);
|
|
16
17
|
},
|
|
17
18
|
afterSend(_topic) {
|
|
@@ -32,10 +33,14 @@ function otelInstrumentation() {
|
|
|
32
33
|
},
|
|
33
34
|
parentCtx
|
|
34
35
|
);
|
|
35
|
-
|
|
36
|
+
activeSpans.set(envelope.eventId, span);
|
|
37
|
+
return () => {
|
|
38
|
+
span.end();
|
|
39
|
+
activeSpans.delete(envelope.eventId);
|
|
40
|
+
};
|
|
36
41
|
},
|
|
37
|
-
onConsumeError(
|
|
38
|
-
const span =
|
|
42
|
+
onConsumeError(envelope, error) {
|
|
43
|
+
const span = activeSpans.get(envelope.eventId);
|
|
39
44
|
if (span) {
|
|
40
45
|
span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
|
|
41
46
|
span.recordException(error);
|
package/dist/otel.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/otel.ts"],"sourcesContent":["import {\n trace,\n context,\n propagation,\n SpanKind,\n SpanStatusCode,\n} from \"@opentelemetry/api\";\nimport type { KafkaInstrumentation } from \"./client/types\";\nimport type { EventEnvelope } from \"./client/message/envelope\";\n\n/**\n * Create a `KafkaInstrumentation` that automatically propagates\n * W3C Trace Context via Kafka headers.\n *\n * Requires `@opentelemetry/api` as a peer dependency.\n *\n * **Send path:** injects `traceparent` into message headers from the\n * active OpenTelemetry context.\n *\n * **Consume path:** extracts `traceparent` from message headers,\n * starts a `CONSUMER` span as a child of the extracted context,\n * and ends it when the handler completes.\n *\n * @example\n * ```ts\n * import { otelInstrumentation } from '@drarzter/kafka-client/otel';\n *\n * const kafka = new KafkaClient('my-app', 'my-group', brokers, {\n * instrumentation: [otelInstrumentation()],\n * });\n * ```\n */\nexport function otelInstrumentation(): KafkaInstrumentation {\n const tracer = trace.getTracer(\"@drarzter/kafka-client\");\n\n return {\n beforeSend(
|
|
1
|
+
{"version":3,"sources":["../src/otel.ts"],"sourcesContent":["import {\n trace,\n context,\n propagation,\n SpanKind,\n SpanStatusCode,\n} from \"@opentelemetry/api\";\nimport type { KafkaInstrumentation } from \"./client/types\";\nimport type { EventEnvelope } from \"./client/message/envelope\";\n\n/**\n * Create a `KafkaInstrumentation` that automatically propagates\n * W3C Trace Context via Kafka headers.\n *\n * Requires `@opentelemetry/api` as a peer dependency.\n *\n * **Send path:** injects `traceparent` into message headers from the\n * active OpenTelemetry context.\n *\n * **Consume path:** extracts `traceparent` from message headers,\n * starts a `CONSUMER` span as a child of the extracted context,\n * and ends it when the handler completes.\n *\n * @example\n * ```ts\n * import { otelInstrumentation } from '@drarzter/kafka-client/otel';\n *\n * const kafka = new KafkaClient('my-app', 'my-group', brokers, {\n * instrumentation: [otelInstrumentation()],\n * });\n * ```\n */\nexport function otelInstrumentation(): KafkaInstrumentation {\n const tracer = trace.getTracer(\"@drarzter/kafka-client\");\n // Keyed by eventId so beforeConsume/onConsumeError can share the span reference\n // without requiring the span to be set as the active context.\n const activeSpans = new Map<string, ReturnType<typeof tracer.startSpan>>();\n\n return {\n beforeSend(_topic: string, headers: Record<string, string>) {\n propagation.inject(context.active(), headers);\n },\n\n afterSend(_topic: string) {\n // Span management for producers is left to the caller's OTel setup.\n // We only inject context — creating producer spans here would be\n // inaccurate since buildSendPayload runs synchronously per-message.\n },\n\n beforeConsume(envelope: EventEnvelope<any>) {\n const parentCtx = propagation.extract(context.active(), envelope.headers);\n const span = tracer.startSpan(\n `kafka.consume ${envelope.topic}`,\n {\n kind: SpanKind.CONSUMER,\n attributes: {\n \"messaging.system\": \"kafka\",\n \"messaging.destination.name\": envelope.topic,\n \"messaging.message.id\": envelope.eventId,\n \"messaging.kafka.partition\": envelope.partition,\n \"messaging.kafka.offset\": envelope.offset,\n },\n },\n parentCtx,\n );\n activeSpans.set(envelope.eventId, span);\n return () => {\n span.end();\n activeSpans.delete(envelope.eventId);\n };\n },\n\n onConsumeError(envelope: EventEnvelope<any>, error: Error) {\n const span = activeSpans.get(envelope.eventId);\n if (span) {\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });\n span.recordException(error);\n }\n },\n };\n}\n"],"mappings":";;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AA0BA,SAAS,sBAA4C;AAC1D,QAAM,SAAS,MAAM,UAAU,wBAAwB;AAGvD,QAAM,cAAc,oBAAI,IAAiD;AAEzE,SAAO;AAAA,IACL,WAAW,QAAgB,SAAiC;AAC1D,kBAAY,OAAO,QAAQ,OAAO,GAAG,OAAO;AAAA,IAC9C;AAAA,IAEA,UAAU,QAAgB;AAAA,IAI1B;AAAA,IAEA,cAAc,UAA8B;AAC1C,YAAM,YAAY,YAAY,QAAQ,QAAQ,OAAO,GAAG,SAAS,OAAO;AACxE,YAAM,OAAO,OAAO;AAAA,QAClB,iBAAiB,SAAS,KAAK;AAAA,QAC/B;AAAA,UACE,MAAM,SAAS;AAAA,UACf,YAAY;AAAA,YACV,oBAAoB;AAAA,YACpB,8BAA8B,SAAS;AAAA,YACvC,wBAAwB,SAAS;AAAA,YACjC,6BAA6B,SAAS;AAAA,YACtC,0BAA0B,SAAS;AAAA,UACrC;AAAA,QACF;AAAA,QACA;AAAA,MACF;AACA,kBAAY,IAAI,SAAS,SAAS,IAAI;AACtC,aAAO,MAAM;AACX,aAAK,IAAI;AACT,oBAAY,OAAO,SAAS,OAAO;AAAA,MACrC;AAAA,IACF;AAAA,IAEA,eAAe,UAA8B,OAAc;AACzD,YAAM,OAAO,YAAY,IAAI,SAAS,OAAO;AAC7C,UAAI,MAAM;AACR,aAAK,UAAU,EAAE,MAAM,eAAe,OAAO,SAAS,MAAM,QAAQ,CAAC;AACrE,aAAK,gBAAgB,KAAK;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
package/dist/testing.d.mts
CHANGED
package/dist/testing.d.ts
CHANGED
|
@@ -32,8 +32,8 @@ interface TopicDescriptor<N extends string = string, M extends Record<string, an
|
|
|
32
32
|
*
|
|
33
33
|
* @example
|
|
34
34
|
* ```ts
|
|
35
|
-
* // Without schema — type
|
|
36
|
-
* const OrderCreated = topic('order.created')<{ orderId: string; amount: number }>();
|
|
35
|
+
* // Without schema — explicit type via .type<T>():
|
|
36
|
+
* const OrderCreated = topic('order.created').type<{ orderId: string; amount: number }>();
|
|
37
37
|
*
|
|
38
38
|
* // With schema — type inferred from schema:
|
|
39
39
|
* const OrderCreated = topic('order.created').schema(z.object({
|
|
@@ -50,16 +50,17 @@ interface TopicDescriptor<N extends string = string, M extends Record<string, an
|
|
|
50
50
|
* ```
|
|
51
51
|
*/
|
|
52
52
|
declare function topic<N extends string>(name: N): {
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
/** Provide an explicit message type without a runtime schema. */
|
|
54
|
+
type: <M extends Record<string, any>>() => TopicDescriptor<N, M>;
|
|
55
|
+
schema: <S extends SchemaLike<Record<string, any>>>(schema: S) => TopicDescriptor<N, InferSchema<S>>;
|
|
55
56
|
};
|
|
56
57
|
/**
|
|
57
58
|
* Build a topic-message map type from a union of TopicDescriptors.
|
|
58
59
|
*
|
|
59
60
|
* @example
|
|
60
61
|
* ```ts
|
|
61
|
-
* const OrderCreated = topic('order.created')<{ orderId: string }>();
|
|
62
|
-
* const OrderCompleted = topic('order.completed')<{ completedAt: string }>();
|
|
62
|
+
* const OrderCreated = topic('order.created').type<{ orderId: string }>();
|
|
63
|
+
* const OrderCompleted = topic('order.completed').type<{ completedAt: string }>();
|
|
63
64
|
*
|
|
64
65
|
* type MyTopics = TopicsFrom<typeof OrderCreated | typeof OrderCompleted>;
|
|
65
66
|
* // { 'order.created': { orderId: string }; 'order.completed': { completedAt: string } }
|
|
@@ -69,6 +70,77 @@ type TopicsFrom<D extends TopicDescriptor<any, any>> = {
|
|
|
69
70
|
[K in D as K["__topic"]]: K["__type"];
|
|
70
71
|
};
|
|
71
72
|
|
|
73
|
+
declare const HEADER_EVENT_ID = "x-event-id";
|
|
74
|
+
declare const HEADER_CORRELATION_ID = "x-correlation-id";
|
|
75
|
+
declare const HEADER_TIMESTAMP = "x-timestamp";
|
|
76
|
+
declare const HEADER_SCHEMA_VERSION = "x-schema-version";
|
|
77
|
+
declare const HEADER_TRACEPARENT = "traceparent";
|
|
78
|
+
/**
|
|
79
|
+
* Typed wrapper combining a parsed message payload with Kafka metadata
|
|
80
|
+
* and envelope headers.
|
|
81
|
+
*
|
|
82
|
+
* On **send**, the library auto-generates envelope headers
|
|
83
|
+
* (`x-event-id`, `x-correlation-id`, `x-timestamp`, `x-schema-version`).
|
|
84
|
+
*
|
|
85
|
+
* On **consume**, the library extracts those headers and assembles
|
|
86
|
+
* an `EventEnvelope` that is passed to the handler.
|
|
87
|
+
*/
|
|
88
|
+
interface EventEnvelope<T> {
|
|
89
|
+
/** Deserialized + validated message body. */
|
|
90
|
+
payload: T;
|
|
91
|
+
/** Topic the message was produced to / consumed from. */
|
|
92
|
+
topic: string;
|
|
93
|
+
/** Kafka partition (consume-side only, `-1` on send). */
|
|
94
|
+
partition: number;
|
|
95
|
+
/** Kafka offset (consume-side only, empty string on send). */
|
|
96
|
+
offset: string;
|
|
97
|
+
/** ISO-8601 timestamp set by the producer. */
|
|
98
|
+
timestamp: string;
|
|
99
|
+
/** Unique ID for this event (UUID v4). */
|
|
100
|
+
eventId: string;
|
|
101
|
+
/** Correlation ID — auto-propagated via AsyncLocalStorage. */
|
|
102
|
+
correlationId: string;
|
|
103
|
+
/** Schema version of the payload. */
|
|
104
|
+
schemaVersion: number;
|
|
105
|
+
/** W3C Trace Context `traceparent` header (set by OTel instrumentation). */
|
|
106
|
+
traceparent?: string;
|
|
107
|
+
/** All decoded Kafka headers for extensibility. */
|
|
108
|
+
headers: MessageHeaders;
|
|
109
|
+
}
|
|
110
|
+
interface EnvelopeCtx {
|
|
111
|
+
correlationId: string;
|
|
112
|
+
traceparent?: string;
|
|
113
|
+
}
|
|
114
|
+
/** Read the current envelope context (correlationId / traceparent) from ALS. */
|
|
115
|
+
declare function getEnvelopeContext(): EnvelopeCtx | undefined;
|
|
116
|
+
/** Execute `fn` inside an envelope context so nested sends inherit correlationId. */
|
|
117
|
+
declare function runWithEnvelopeContext<R>(ctx: EnvelopeCtx, fn: () => R): R;
|
|
118
|
+
/** Options accepted by `buildEnvelopeHeaders`. */
|
|
119
|
+
interface EnvelopeHeaderOptions {
|
|
120
|
+
correlationId?: string;
|
|
121
|
+
schemaVersion?: number;
|
|
122
|
+
eventId?: string;
|
|
123
|
+
headers?: MessageHeaders;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Generate envelope headers for the send path.
|
|
127
|
+
*
|
|
128
|
+
* Priority for `correlationId`:
|
|
129
|
+
* explicit option → ALS context → new UUID.
|
|
130
|
+
*/
|
|
131
|
+
declare function buildEnvelopeHeaders(options?: EnvelopeHeaderOptions): MessageHeaders;
|
|
132
|
+
/**
|
|
133
|
+
* Decode kafkajs headers (`Record<string, Buffer | string | undefined>`)
|
|
134
|
+
* into plain `Record<string, string>`.
|
|
135
|
+
*/
|
|
136
|
+
declare function decodeHeaders(raw: Record<string, Buffer | string | (Buffer | string)[] | undefined> | undefined): MessageHeaders;
|
|
137
|
+
/**
|
|
138
|
+
* Build an `EventEnvelope` from a consumed kafkajs message.
|
|
139
|
+
* Tolerates missing envelope headers — generates defaults so messages
|
|
140
|
+
* from non-envelope producers still work.
|
|
141
|
+
*/
|
|
142
|
+
declare function extractEnvelope<T>(payload: T, headers: MessageHeaders, topic: string, partition: number, offset: string): EventEnvelope<T>;
|
|
143
|
+
|
|
72
144
|
/**
|
|
73
145
|
* Mapping of topic names to their message types.
|
|
74
146
|
* Define this interface to get type-safe publish/subscribe across your app.
|
|
@@ -165,6 +237,12 @@ interface ConsumerOptions<T extends TopicMapConstraint<T> = TTopicMessageMap> {
|
|
|
165
237
|
* On exhaustion, messages go to `<topic>.dlq` (if `dlq: true`) or `onMessageLost`.
|
|
166
238
|
*/
|
|
167
239
|
retryTopics?: boolean;
|
|
240
|
+
/**
|
|
241
|
+
* Timeout (ms) for waiting until each retry level consumer receives partition
|
|
242
|
+
* assignments after `startConsumer` connects. Default: `10000`.
|
|
243
|
+
* Increase this when the broker is slow to rebalance.
|
|
244
|
+
*/
|
|
245
|
+
retryTopicAssignmentTimeoutMs?: number;
|
|
168
246
|
/**
|
|
169
247
|
* Log a warning if the message handler has not resolved within this window (ms).
|
|
170
248
|
* The handler is not cancelled — this is a diagnostic aid to surface stuck handlers
|
|
@@ -226,13 +304,19 @@ interface ConsumerHandle {
|
|
|
226
304
|
/** Stop this consumer. Equivalent to calling `client.stopConsumer(groupId)`. */
|
|
227
305
|
stop(): Promise<void>;
|
|
228
306
|
}
|
|
307
|
+
/** Result returned by `KafkaClient.checkStatus()`. */
|
|
308
|
+
type KafkaHealthResult = {
|
|
309
|
+
status: "up";
|
|
310
|
+
clientId: string;
|
|
311
|
+
topics: string[];
|
|
312
|
+
} | {
|
|
313
|
+
status: "down";
|
|
314
|
+
clientId: string;
|
|
315
|
+
error: string;
|
|
316
|
+
};
|
|
229
317
|
/** Interface describing all public methods of the Kafka client. */
|
|
230
318
|
interface IKafkaClient<T extends TopicMapConstraint<T>> {
|
|
231
|
-
checkStatus(): Promise<
|
|
232
|
-
status: "up";
|
|
233
|
-
clientId: string;
|
|
234
|
-
topics: string[];
|
|
235
|
-
}>;
|
|
319
|
+
checkStatus(): Promise<KafkaHealthResult>;
|
|
236
320
|
/**
|
|
237
321
|
* Query the consumer group lag per partition using the admin API.
|
|
238
322
|
* Lag = (broker high-watermark offset) − (last committed offset).
|
|
@@ -325,75 +409,4 @@ interface SubscribeRetryOptions {
|
|
|
325
409
|
backoffMs?: number;
|
|
326
410
|
}
|
|
327
411
|
|
|
328
|
-
|
|
329
|
-
declare const HEADER_CORRELATION_ID = "x-correlation-id";
|
|
330
|
-
declare const HEADER_TIMESTAMP = "x-timestamp";
|
|
331
|
-
declare const HEADER_SCHEMA_VERSION = "x-schema-version";
|
|
332
|
-
declare const HEADER_TRACEPARENT = "traceparent";
|
|
333
|
-
/**
|
|
334
|
-
* Typed wrapper combining a parsed message payload with Kafka metadata
|
|
335
|
-
* and envelope headers.
|
|
336
|
-
*
|
|
337
|
-
* On **send**, the library auto-generates envelope headers
|
|
338
|
-
* (`x-event-id`, `x-correlation-id`, `x-timestamp`, `x-schema-version`).
|
|
339
|
-
*
|
|
340
|
-
* On **consume**, the library extracts those headers and assembles
|
|
341
|
-
* an `EventEnvelope` that is passed to the handler.
|
|
342
|
-
*/
|
|
343
|
-
interface EventEnvelope<T> {
|
|
344
|
-
/** Deserialized + validated message body. */
|
|
345
|
-
payload: T;
|
|
346
|
-
/** Topic the message was produced to / consumed from. */
|
|
347
|
-
topic: string;
|
|
348
|
-
/** Kafka partition (consume-side only, `-1` on send). */
|
|
349
|
-
partition: number;
|
|
350
|
-
/** Kafka offset (consume-side only, empty string on send). */
|
|
351
|
-
offset: string;
|
|
352
|
-
/** ISO-8601 timestamp set by the producer. */
|
|
353
|
-
timestamp: string;
|
|
354
|
-
/** Unique ID for this event (UUID v4). */
|
|
355
|
-
eventId: string;
|
|
356
|
-
/** Correlation ID — auto-propagated via AsyncLocalStorage. */
|
|
357
|
-
correlationId: string;
|
|
358
|
-
/** Schema version of the payload. */
|
|
359
|
-
schemaVersion: number;
|
|
360
|
-
/** W3C Trace Context `traceparent` header (set by OTel instrumentation). */
|
|
361
|
-
traceparent?: string;
|
|
362
|
-
/** All decoded Kafka headers for extensibility. */
|
|
363
|
-
headers: MessageHeaders;
|
|
364
|
-
}
|
|
365
|
-
interface EnvelopeCtx {
|
|
366
|
-
correlationId: string;
|
|
367
|
-
traceparent?: string;
|
|
368
|
-
}
|
|
369
|
-
/** Read the current envelope context (correlationId / traceparent) from ALS. */
|
|
370
|
-
declare function getEnvelopeContext(): EnvelopeCtx | undefined;
|
|
371
|
-
/** Execute `fn` inside an envelope context so nested sends inherit correlationId. */
|
|
372
|
-
declare function runWithEnvelopeContext<R>(ctx: EnvelopeCtx, fn: () => R): R;
|
|
373
|
-
/** Options accepted by `buildEnvelopeHeaders`. */
|
|
374
|
-
interface EnvelopeHeaderOptions {
|
|
375
|
-
correlationId?: string;
|
|
376
|
-
schemaVersion?: number;
|
|
377
|
-
eventId?: string;
|
|
378
|
-
headers?: MessageHeaders;
|
|
379
|
-
}
|
|
380
|
-
/**
|
|
381
|
-
* Generate envelope headers for the send path.
|
|
382
|
-
*
|
|
383
|
-
* Priority for `correlationId`:
|
|
384
|
-
* explicit option → ALS context → new UUID.
|
|
385
|
-
*/
|
|
386
|
-
declare function buildEnvelopeHeaders(options?: EnvelopeHeaderOptions): MessageHeaders;
|
|
387
|
-
/**
|
|
388
|
-
* Decode kafkajs headers (`Record<string, Buffer | string | undefined>`)
|
|
389
|
-
* into plain `Record<string, string>`.
|
|
390
|
-
*/
|
|
391
|
-
declare function decodeHeaders(raw: Record<string, Buffer | string | (Buffer | string)[] | undefined> | undefined): MessageHeaders;
|
|
392
|
-
/**
|
|
393
|
-
* Build an `EventEnvelope` from a consumed kafkajs message.
|
|
394
|
-
* Tolerates missing envelope headers — generates defaults so messages
|
|
395
|
-
* from non-envelope producers still work.
|
|
396
|
-
*/
|
|
397
|
-
declare function extractEnvelope<T>(payload: T, headers: MessageHeaders, topic: string, partition: number, offset: string): EventEnvelope<T>;
|
|
398
|
-
|
|
399
|
-
export { type BatchMessageItem as B, type ClientId as C, type EnvelopeHeaderOptions as E, type GroupId as G, HEADER_CORRELATION_ID as H, type IKafkaClient as I, type KafkaInstrumentation as K, type MessageHeaders as M, type RetryOptions as R, type SchemaLike as S, type TopicMapConstraint as T, type KafkaClientOptions as a, type ConsumerOptions as b, type TopicDescriptor as c, type BatchMeta as d, type ConsumerHandle as e, type ConsumerInterceptor as f, type EventEnvelope as g, HEADER_EVENT_ID as h, HEADER_SCHEMA_VERSION as i, HEADER_TIMESTAMP as j, HEADER_TRACEPARENT as k, type InferSchema as l, type KafkaLogger as m, type MessageLostContext as n, type SendOptions as o, type SubscribeRetryOptions as p, type TTopicMessageMap as q, type TopicsFrom as r, type TransactionContext as s, buildEnvelopeHeaders as t, decodeHeaders as u, extractEnvelope as v, getEnvelopeContext as w, runWithEnvelopeContext as x, topic as y };
|
|
412
|
+
export { type BatchMessageItem as B, type ClientId as C, type EnvelopeHeaderOptions as E, type GroupId as G, HEADER_CORRELATION_ID as H, type IKafkaClient as I, type KafkaInstrumentation as K, type MessageHeaders as M, type RetryOptions as R, type SchemaLike as S, type TopicMapConstraint as T, type KafkaClientOptions as a, type ConsumerOptions as b, type TopicDescriptor as c, type KafkaHealthResult as d, type BatchMeta as e, type ConsumerHandle as f, type ConsumerInterceptor as g, type EventEnvelope as h, HEADER_EVENT_ID as i, HEADER_SCHEMA_VERSION as j, HEADER_TIMESTAMP as k, HEADER_TRACEPARENT as l, type InferSchema as m, type KafkaLogger as n, type MessageLostContext as o, type SendOptions as p, type SubscribeRetryOptions as q, type TTopicMessageMap as r, type TopicsFrom as s, type TransactionContext as t, buildEnvelopeHeaders as u, decodeHeaders as v, extractEnvelope as w, getEnvelopeContext as x, runWithEnvelopeContext as y, topic as z };
|