@autofleet/kafka 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,`__esModule`,{value:!0});const e={info:(...e)=>console.log(`[INFO]`,...e),error:(...e)=>console.error(`[ERROR]`,...e),warn:(...e)=>console.warn(`[WARN]`,...e),debug:(...e)=>console.debug(`[DEBUG]`,...e)};var t=e,n=class extends Error{constructor(e){super(e),this.name=`KafkaError`}};const r=`x-timestamp`,i=`autofleet-kafka-producer`;var a=class e{constructor(e,n){this._isConnected=!1,this.gracefulShutdownStarted=!1,this.logger=e.logger??t,this.producer=n,this.logger.info(`Kafka: Initialized Kafka producer`,{clientId:e.clientId||i,brokers:e.brokers}),e.dontGracefulShutdown||this.setupGracefulShutdown()}static async create(t){if(!t.brokers||t.brokers.length===0)throw new n(`At least one broker is required`);let{Producer:r,stringSerializers:a}=await import(`@platformatic/kafka`);return new e(t,new r({bootstrapBrokers:t.brokers,clientId:t.clientId||i,serializers:a}))}setupGracefulShutdown(){this.logger.info(`Kafka: [graceful-shutdown] adding graceful shutdown for process.pid ${process.pid}`),process.on(`SIGTERM`,async()=>{await this.gracefulShutdown(`SIGTERM`)}),process.on(`SIGINT`,async()=>{await this.gracefulShutdown(`SIGINT`)})}async gracefulShutdown(e){if(!this.gracefulShutdownStarted){this.gracefulShutdownStarted=!0,this.logger.info(`Kafka: [graceful-shutdown] received ${e}! Disconnecting producer...`);try{await this.disconnect(),this.logger.info(`Kafka: [graceful-shutdown] producer disconnected successfully`)}catch(e){throw this.logger.error(`Kafka: [graceful-shutdown] error during shutdown`,{error:e}),e}}}get isConnected(){return this._isConnected}async ping(){if(!this._isConnected)try{let e=await this.producer.metadata({topics:[]});this._isConnected=!0,this.logger.info(`Kafka: Successfully connected to cluster`,{clusterId:e.id,brokers:e.brokers.size})}catch(e){throw this.logger.error(`Kafka: Failed to connect to brokers`,{error:e}),new n(`Failed to connect to Kafka brokers: ${e.message}`)}}async publish(e,t,i){if(!e)throw new n(`Topic name is required`);await this.ping();try{let n={[r]:Date.now().toString(),...i?.headers},a=await this.producer.send({messages:[{topic:e,value:JSON.stringify(t),key:i?.key,partition:i?.partition,headers:n}]});return this.logger.debug(`Kafka: Published message to topic ${e}`,{topic:e}),[{topic:e,partition:i?.partition??0,offset:a?.offsets?.[0]?.offset?.toString()??`0`}]}catch(r){let i=r;throw this.logger.error(`Kafka: Error publishing to topic ${e}`,{error:r,value:t}),new n(`Failed to publish to topic ${e}: ${i.message||`Unknown error`}`)}}async publishBatch(e){if(!e.topic)throw new n(`Topic name is required`);if(!e.messages||e.messages.length===0)throw new n(`At least one message is required`);await this.ping();try{let t=e.messages.map(t=>({topic:e.topic,value:JSON.stringify(t.value),key:t.key,partition:t.partition,headers:{[r]:Date.now().toString(),...t.headers}})),n=await this.producer.send({messages:t});return this.logger.debug(`Kafka: Published ${t.length} messages to topic ${e.topic}`,{topic:e.topic,count:t.length}),t.map((t,r)=>({topic:e.topic,partition:t.partition??0,offset:n?.offsets?.[r]?.offset?.toString()??r.toString()}))}catch(t){let r=t;throw this.logger.error(`Kafka: Error publishing batch to topic ${e.topic}`,{error:t}),new n(`Failed to publish batch to topic ${e.topic}: ${r.message||`Unknown error`}`)}}async disconnect(){if(!this._isConnected){this.logger.debug(`Kafka: Producer already disconnected`);return}this.logger.info(`Kafka: Disconnecting producer`);try{await this.producer.close(),this._isConnected=!1,this.logger.info(`Kafka: Producer disconnected successfully`)}catch(e){throw this.logger.error(`Kafka: Error disconnecting producer`,{error:e}),new n(`Failed to disconnect producer: ${e.message}`)}}},o=a;exports.KafkaError=n,exports.default=o;
|
|
1
|
+
Object.defineProperty(exports,`__esModule`,{value:!0});const e={info:(...e)=>console.log(`[INFO]`,...e),error:(...e)=>console.error(`[ERROR]`,...e),warn:(...e)=>console.warn(`[WARN]`,...e),debug:(...e)=>console.debug(`[DEBUG]`,...e)};var t=e,n=class extends Error{constructor(e){super(e),this.name=`KafkaError`}};const r=`x-timestamp`,i=`autofleet-kafka-producer`;var a=class e{constructor(e,n){this._isConnected=!1,this.gracefulShutdownStarted=!1,this.logger=e.logger??t,this.producer=n,this.logger.info(`Kafka: Initialized Kafka producer`,{clientId:e.clientId||i,brokers:e.brokers}),e.dontGracefulShutdown||this.setupGracefulShutdown()}static async create(t){if(!t.brokers||t.brokers.length===0)throw new n(`At least one broker is required`);let{Producer:r,stringSerializers:a}=await import(`@platformatic/kafka`);return new e(t,new r({bootstrapBrokers:t.brokers,clientId:t.clientId||i,serializers:a,autocreateTopics:t.autoCreateTopics??!1,sasl:t.sasl}))}setupGracefulShutdown(){this.logger.info(`Kafka: [graceful-shutdown] adding graceful shutdown for process.pid ${process.pid}`),process.on(`SIGTERM`,async()=>{await this.gracefulShutdown(`SIGTERM`)}),process.on(`SIGINT`,async()=>{await this.gracefulShutdown(`SIGINT`)})}async gracefulShutdown(e){if(!this.gracefulShutdownStarted){this.gracefulShutdownStarted=!0,this.logger.info(`Kafka: [graceful-shutdown] received ${e}! Disconnecting producer...`);try{await this.disconnect(),this.logger.info(`Kafka: [graceful-shutdown] producer disconnected successfully`)}catch(e){throw this.logger.error(`Kafka: [graceful-shutdown] error during shutdown`,{error:e}),e}}}get isConnected(){return this._isConnected}async ping(){if(!this._isConnected)try{let e=await this.producer.metadata({topics:[]});this._isConnected=!0,this.logger.info(`Kafka: Successfully connected to cluster`,{clusterId:e.id,brokers:e.brokers.size})}catch(e){throw this.logger.error(`Kafka: Failed to connect to brokers`,{error:e}),new n(`Failed to connect to Kafka brokers: ${e.message}`)}}async publish(e,t,i){if(!e)throw new n(`Topic name is required`);await this.ping();try{let n={[r]:Date.now().toString(),...i?.headers},a=await this.producer.send({messages:[{topic:e,value:JSON.stringify(t),key:i?.key,partition:i?.partition,headers:n}]});return this.logger.debug(`Kafka: Published message to topic ${e}`,{topic:e}),[{topic:e,partition:i?.partition??0,offset:a?.offsets?.[0]?.offset?.toString()??`0`}]}catch(r){let i=r;throw this.logger.error(`Kafka: Error publishing to topic ${e}`,{error:r,value:t}),new n(`Failed to publish to topic ${e}: ${i.message||`Unknown error`}`)}}async publishBatch(e){if(!e.topic)throw new n(`Topic name is required`);if(!e.messages||e.messages.length===0)throw new n(`At least one message is required`);await this.ping();try{let t=e.messages.map(t=>({topic:e.topic,value:JSON.stringify(t.value),key:t.key,partition:t.partition,headers:{[r]:Date.now().toString(),...t.headers}})),n=await this.producer.send({messages:t});return this.logger.debug(`Kafka: Published ${t.length} messages to topic ${e.topic}`,{topic:e.topic,count:t.length}),t.map((t,r)=>({topic:e.topic,partition:t.partition??0,offset:n?.offsets?.[r]?.offset?.toString()??r.toString()}))}catch(t){let r=t;throw this.logger.error(`Kafka: Error publishing batch to topic ${e.topic}`,{error:t}),new n(`Failed to publish batch to topic ${e.topic}: ${r.message||`Unknown error`}`)}}async disconnect(){if(!this._isConnected){this.logger.debug(`Kafka: Producer already disconnected`);return}this.logger.info(`Kafka: Disconnecting producer`);try{await this.producer.close(),this._isConnected=!1,this.logger.info(`Kafka: Producer disconnected successfully`)}catch(e){throw this.logger.error(`Kafka: Error disconnecting producer`,{error:e}),new n(`Failed to disconnect producer: ${e.message}`)}}},o=a;exports.KafkaError=n,exports.default=o;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["fallbackLogger: LoggerInstanceManager","fallbackLogger","headers: Record<string, string>"],"sources":["../src/logger.ts","../src/kafkaError.ts","../src/consts.ts","../src/index.ts"],"sourcesContent":["import type { LoggerInstanceManager } from '@autofleet/logger';\n\n/* eslint-disable no-console */\nconst fallbackLogger: LoggerInstanceManager = {\n info: (...args: unknown[]) => console.log('[INFO]', ...args),\n error: (...args: unknown[]) => console.error('[ERROR]', ...args),\n warn: (...args: unknown[]) => console.warn('[WARN]', ...args),\n debug: (...args: unknown[]) => console.debug('[DEBUG]', ...args),\n} as LoggerInstanceManager;\n/* eslint-enable no-console */\n\nexport default fallbackLogger;\n","export default class KafkaError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'KafkaError';\n }\n}\n","export const TIMESTAMP_HEADER = 'x-timestamp';\nexport const CORRELATION_ID_HEADER = 'x-correlation-id';\nexport const SOURCE_HEADER = 'x-source';\n\nexport const DEFAULT_CLIENT_ID = 'autofleet-kafka-producer';\nexport const DEFAULT_TIMEOUT = 30000; // 30 seconds\nexport const DEFAULT_RETRY = {\n retries: 5,\n initialRetryTime: 300,\n maxRetryTime: 30000,\n};\n","import type { LoggerInstanceManager } from '@autofleet/logger';\nimport type { Producer } from '@platformatic/kafka/dist/clients/producer/index.ts';\nimport fallbackLogger from './logger';\nimport KafkaError from './kafkaError';\nimport {\n DEFAULT_CLIENT_ID,\n TIMESTAMP_HEADER,\n} from './consts';\nimport type {\n KafkaOptions,\n PublishOptions,\n PublishBatchOptions,\n RecordMetadata,\n} from './types';\n\nexport interface IAfKafka {\n isConnected: boolean;\n ping(): Promise<void>;\n publish<T = unknown>(topic: string, value: T, options?: PublishOptions): Promise<RecordMetadata[]>;\n publishBatch(options: PublishBatchOptions): Promise<RecordMetadata[]>;\n disconnect(): Promise<void>;\n}\n\nclass AfKafka implements IAfKafka {\n private producer!: Producer<string, string, string, string>;\n private readonly logger: LoggerInstanceManager;\n private _isConnected = false;\n private gracefulShutdownStarted = false;\n\n private constructor(options: KafkaOptions, producer: Producer<string, string, string, string>) {\n this.logger = options.logger ?? fallbackLogger;\n this.producer = producer;\n\n this.logger.info('Kafka: Initialized Kafka producer', {\n clientId: options.clientId || DEFAULT_CLIENT_ID,\n brokers: options.brokers,\n });\n\n if (!options.dontGracefulShutdown) {\n this.setupGracefulShutdown();\n }\n }\n\n /**\n * Create a new Kafka producer instance\n */\n static async create(options: KafkaOptions): Promise<AfKafka> {\n if (!options.brokers || options.brokers.length === 0) {\n throw new KafkaError('At least one broker is required');\n }\n\n // Dynamic import of ESM-only package\n const { Producer, stringSerializers } = await import('@platformatic/kafka');\n\n const producer = new Producer({\n bootstrapBrokers: options.brokers,\n clientId: options.clientId || DEFAULT_CLIENT_ID,\n serializers: stringSerializers,\n });\n\n return new AfKafka(options, producer);\n }\n\n private setupGracefulShutdown(): void {\n this.logger.info(`Kafka: [graceful-shutdown] adding graceful shutdown for process.pid ${process.pid}`);\n\n process.on('SIGTERM', async () => {\n await this.gracefulShutdown('SIGTERM');\n });\n\n process.on('SIGINT', async () => {\n await this.gracefulShutdown('SIGINT');\n });\n }\n\n private async gracefulShutdown(signal: string): Promise<void> {\n if (this.gracefulShutdownStarted) {\n return;\n }\n\n this.gracefulShutdownStarted = true;\n\n this.logger.info(`Kafka: [graceful-shutdown] received ${signal}! Disconnecting producer...`);\n\n try {\n await this.disconnect();\n this.logger.info('Kafka: [graceful-shutdown] producer disconnected successfully');\n } catch (error) {\n this.logger.error('Kafka: [graceful-shutdown] error during shutdown', { error });\n throw error;\n }\n }\n\n get isConnected(): boolean {\n return this._isConnected;\n }\n\n /**\n * Ping Kafka brokers to verify connectivity\n */\n async ping(): Promise<void> {\n if (this._isConnected) {\n return;\n }\n\n try {\n // Fetch metadata to verify connection\n const metadata = await this.producer.metadata({ topics: [] });\n this._isConnected = true;\n\n this.logger.info('Kafka: Successfully connected to cluster', {\n clusterId: metadata.id,\n brokers: metadata.brokers.size,\n });\n } catch (error) {\n this.logger.error('Kafka: Failed to connect to brokers', { error });\n throw new KafkaError(`Failed to connect to Kafka brokers: ${(error as Error).message}`);\n }\n }\n\n /**\n * Publish a single message to a topic\n */\n async publish<T = unknown>(\n topic: string,\n value: T,\n options?: PublishOptions,\n ): Promise<RecordMetadata[]> {\n if (!topic) {\n throw new KafkaError('Topic name is required');\n }\n\n await this.ping();\n\n try {\n const headers: Record<string, string> = {\n [TIMESTAMP_HEADER]: Date.now().toString(),\n ...options?.headers,\n };\n\n const result = await this.producer.send({\n messages: [{\n topic,\n value: JSON.stringify(value),\n key: options?.key,\n partition: options?.partition,\n headers,\n }],\n });\n\n this.logger.debug(`Kafka: Published message to topic ${topic}`, {\n topic,\n });\n\n // Map ProduceResult to RecordMetadata\n return [{\n topic,\n partition: options?.partition ?? 0,\n offset: result?.offsets?.[0]?.offset?.toString() ?? '0',\n }];\n } catch (error) {\n const err = error as { message?: string; };\n this.logger.error(`Kafka: Error publishing to topic ${topic}`, { error, value });\n throw new KafkaError(`Failed to publish to topic ${topic}: ${err.message || 'Unknown error'}`);\n }\n }\n\n /**\n * Publish multiple messages in a batch\n */\n async publishBatch(options: PublishBatchOptions): Promise<RecordMetadata[]> {\n if (!options.topic) {\n throw new KafkaError('Topic name is required');\n }\n\n if (!options.messages || options.messages.length === 0) {\n throw new KafkaError('At least one message is required');\n }\n\n await this.ping();\n\n try {\n const messages = options.messages.map(msg => ({\n topic: options.topic,\n value: JSON.stringify(msg.value),\n key: msg.key,\n partition: msg.partition,\n headers: {\n [TIMESTAMP_HEADER]: Date.now().toString(),\n ...msg.headers,\n },\n }));\n\n const result = await this.producer.send({ messages });\n\n this.logger.debug(`Kafka: Published ${messages.length} messages to topic ${options.topic}`, {\n topic: options.topic,\n count: messages.length,\n });\n\n // Map ProduceResult to RecordMetadata array\n return messages.map((msg, idx) => ({\n topic: options.topic,\n partition: msg.partition ?? 0,\n offset: result?.offsets?.[idx]?.offset?.toString() ?? idx.toString(),\n }));\n } catch (error) {\n const err = error as { message?: string; };\n this.logger.error(`Kafka: Error publishing batch to topic ${options.topic}`, { error });\n throw new KafkaError(`Failed to publish batch to topic ${options.topic}: ${err.message || 'Unknown error'}`);\n }\n }\n\n /**\n * Disconnect the producer and clean up resources\n */\n async disconnect(): Promise<void> {\n if (!this._isConnected) {\n this.logger.debug('Kafka: Producer already disconnected');\n return;\n }\n\n this.logger.info('Kafka: Disconnecting producer');\n\n try {\n await this.producer.close();\n this._isConnected = false;\n this.logger.info('Kafka: Producer disconnected successfully');\n } catch (error) {\n this.logger.error('Kafka: Error disconnecting producer', { error });\n throw new KafkaError(`Failed to disconnect producer: ${(error as Error).message}`);\n }\n }\n}\n\nexport default AfKafka;\nexport { KafkaError };\nexport type {\n KafkaOptions,\n PublishOptions,\n PublishBatchOptions,\n RecordMetadata,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["fallbackLogger: LoggerInstanceManager","fallbackLogger","headers: Record<string, string>"],"sources":["../src/logger.ts","../src/kafkaError.ts","../src/consts.ts","../src/index.ts"],"sourcesContent":["import type { LoggerInstanceManager } from '@autofleet/logger';\n\n/* eslint-disable no-console */\nconst fallbackLogger: LoggerInstanceManager = {\n info: (...args: unknown[]) => console.log('[INFO]', ...args),\n error: (...args: unknown[]) => console.error('[ERROR]', ...args),\n warn: (...args: unknown[]) => console.warn('[WARN]', ...args),\n debug: (...args: unknown[]) => console.debug('[DEBUG]', ...args),\n} as LoggerInstanceManager;\n/* eslint-enable no-console */\n\nexport default fallbackLogger;\n","export default class KafkaError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'KafkaError';\n }\n}\n","export const TIMESTAMP_HEADER = 'x-timestamp';\nexport const CORRELATION_ID_HEADER = 'x-correlation-id';\nexport const SOURCE_HEADER = 'x-source';\n\nexport const DEFAULT_CLIENT_ID = 'autofleet-kafka-producer';\nexport const DEFAULT_TIMEOUT = 30000; // 30 seconds\nexport const DEFAULT_RETRY = {\n retries: 5,\n initialRetryTime: 300,\n maxRetryTime: 30000,\n};\n","import type { LoggerInstanceManager } from '@autofleet/logger';\nimport type { Producer } from '@platformatic/kafka/dist/clients/producer/index.ts';\nimport fallbackLogger from './logger';\nimport KafkaError from './kafkaError';\nimport {\n DEFAULT_CLIENT_ID,\n TIMESTAMP_HEADER,\n} from './consts';\nimport type {\n KafkaOptions,\n PublishOptions,\n PublishBatchOptions,\n RecordMetadata,\n} from './types';\n\nexport interface IAfKafka {\n isConnected: boolean;\n ping(): Promise<void>;\n publish<T = unknown>(topic: string, value: T, options?: PublishOptions): Promise<RecordMetadata[]>;\n publishBatch(options: PublishBatchOptions): Promise<RecordMetadata[]>;\n disconnect(): Promise<void>;\n}\n\nclass AfKafka implements IAfKafka {\n private producer!: Producer<string, string, string, string>;\n private readonly logger: LoggerInstanceManager;\n private _isConnected = false;\n private gracefulShutdownStarted = false;\n\n private constructor(options: KafkaOptions, producer: Producer<string, string, string, string>) {\n this.logger = options.logger ?? fallbackLogger;\n this.producer = producer;\n\n this.logger.info('Kafka: Initialized Kafka producer', {\n clientId: options.clientId || DEFAULT_CLIENT_ID,\n brokers: options.brokers,\n });\n\n if (!options.dontGracefulShutdown) {\n this.setupGracefulShutdown();\n }\n }\n\n /**\n * Create a new Kafka producer instance\n */\n static async create(options: KafkaOptions): Promise<AfKafka> {\n if (!options.brokers || options.brokers.length === 0) {\n throw new KafkaError('At least one broker is required');\n }\n\n // Dynamic import of ESM-only package\n const { Producer, stringSerializers } = await import('@platformatic/kafka');\n\n const producer = new Producer({\n bootstrapBrokers: options.brokers,\n clientId: options.clientId || DEFAULT_CLIENT_ID,\n serializers: stringSerializers,\n autocreateTopics: options.autoCreateTopics ?? false,\n sasl: options.sasl,\n });\n\n return new AfKafka(options, producer);\n }\n\n private setupGracefulShutdown(): void {\n this.logger.info(`Kafka: [graceful-shutdown] adding graceful shutdown for process.pid ${process.pid}`);\n\n process.on('SIGTERM', async () => {\n await this.gracefulShutdown('SIGTERM');\n });\n\n process.on('SIGINT', async () => {\n await this.gracefulShutdown('SIGINT');\n });\n }\n\n private async gracefulShutdown(signal: string): Promise<void> {\n if (this.gracefulShutdownStarted) {\n return;\n }\n\n this.gracefulShutdownStarted = true;\n\n this.logger.info(`Kafka: [graceful-shutdown] received ${signal}! Disconnecting producer...`);\n\n try {\n await this.disconnect();\n this.logger.info('Kafka: [graceful-shutdown] producer disconnected successfully');\n } catch (error) {\n this.logger.error('Kafka: [graceful-shutdown] error during shutdown', { error });\n throw error;\n }\n }\n\n get isConnected(): boolean {\n return this._isConnected;\n }\n\n /**\n * Ping Kafka brokers to verify connectivity\n */\n async ping(): Promise<void> {\n if (this._isConnected) {\n return;\n }\n\n try {\n // Fetch metadata to verify connection\n const metadata = await this.producer.metadata({ topics: [] });\n this._isConnected = true;\n\n this.logger.info('Kafka: Successfully connected to cluster', {\n clusterId: metadata.id,\n brokers: metadata.brokers.size,\n });\n } catch (error) {\n this.logger.error('Kafka: Failed to connect to brokers', { error });\n throw new KafkaError(`Failed to connect to Kafka brokers: ${(error as Error).message}`);\n }\n }\n\n /**\n * Publish a single message to a topic\n */\n async publish<T = unknown>(\n topic: string,\n value: T,\n options?: PublishOptions,\n ): Promise<RecordMetadata[]> {\n if (!topic) {\n throw new KafkaError('Topic name is required');\n }\n\n await this.ping();\n\n try {\n const headers: Record<string, string> = {\n [TIMESTAMP_HEADER]: Date.now().toString(),\n ...options?.headers,\n };\n\n const result = await this.producer.send({\n messages: [{\n topic,\n value: JSON.stringify(value),\n key: options?.key,\n partition: options?.partition,\n headers,\n }],\n });\n\n this.logger.debug(`Kafka: Published message to topic ${topic}`, {\n topic,\n });\n\n // Map ProduceResult to RecordMetadata\n return [{\n topic,\n partition: options?.partition ?? 0,\n offset: result?.offsets?.[0]?.offset?.toString() ?? '0',\n }];\n } catch (error) {\n const err = error as { message?: string; };\n this.logger.error(`Kafka: Error publishing to topic ${topic}`, { error, value });\n throw new KafkaError(`Failed to publish to topic ${topic}: ${err.message || 'Unknown error'}`);\n }\n }\n\n /**\n * Publish multiple messages in a batch\n */\n async publishBatch(options: PublishBatchOptions): Promise<RecordMetadata[]> {\n if (!options.topic) {\n throw new KafkaError('Topic name is required');\n }\n\n if (!options.messages || options.messages.length === 0) {\n throw new KafkaError('At least one message is required');\n }\n\n await this.ping();\n\n try {\n const messages = options.messages.map(msg => ({\n topic: options.topic,\n value: JSON.stringify(msg.value),\n key: msg.key,\n partition: msg.partition,\n headers: {\n [TIMESTAMP_HEADER]: Date.now().toString(),\n ...msg.headers,\n },\n }));\n\n const result = await this.producer.send({ messages });\n\n this.logger.debug(`Kafka: Published ${messages.length} messages to topic ${options.topic}`, {\n topic: options.topic,\n count: messages.length,\n });\n\n // Map ProduceResult to RecordMetadata array\n return messages.map((msg, idx) => ({\n topic: options.topic,\n partition: msg.partition ?? 0,\n offset: result?.offsets?.[idx]?.offset?.toString() ?? idx.toString(),\n }));\n } catch (error) {\n const err = error as { message?: string; };\n this.logger.error(`Kafka: Error publishing batch to topic ${options.topic}`, { error });\n throw new KafkaError(`Failed to publish batch to topic ${options.topic}: ${err.message || 'Unknown error'}`);\n }\n }\n\n /**\n * Disconnect the producer and clean up resources\n */\n async disconnect(): Promise<void> {\n if (!this._isConnected) {\n this.logger.debug('Kafka: Producer already disconnected');\n return;\n }\n\n this.logger.info('Kafka: Disconnecting producer');\n\n try {\n await this.producer.close();\n this._isConnected = false;\n this.logger.info('Kafka: Producer disconnected successfully');\n } catch (error) {\n this.logger.error('Kafka: Error disconnecting producer', { error });\n throw new KafkaError(`Failed to disconnect producer: ${(error as Error).message}`);\n }\n }\n}\n\nexport default AfKafka;\nexport { KafkaError };\nexport type {\n KafkaOptions,\n PublishOptions,\n PublishBatchOptions,\n RecordMetadata,\n};\n"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LoggerInstanceManager } from "@autofleet/logger";
|
|
2
|
+
import { ConnectionOptions } from "@platformatic/kafka";
|
|
2
3
|
|
|
3
4
|
//#region src/kafkaError.d.ts
|
|
4
5
|
declare class KafkaError extends Error {
|
|
@@ -18,6 +19,12 @@ interface KafkaOptions {
|
|
|
18
19
|
* @default false
|
|
19
20
|
*/
|
|
20
21
|
dontGracefulShutdown?: boolean;
|
|
22
|
+
/** SASL authentication options */
|
|
23
|
+
sasl?: ConnectionOptions["sasl"];
|
|
24
|
+
/** Automatically create topics if they don't exist
|
|
25
|
+
* @default false
|
|
26
|
+
*/
|
|
27
|
+
autoCreateTopics?: boolean;
|
|
21
28
|
}
|
|
22
29
|
interface PublishOptions {
|
|
23
30
|
/** Custom headers to attach to the message */
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ConnectionOptions } from "@platformatic/kafka";
|
|
1
2
|
import { LoggerInstanceManager } from "@autofleet/logger";
|
|
2
3
|
|
|
3
4
|
//#region src/kafkaError.d.ts
|
|
@@ -18,6 +19,12 @@ interface KafkaOptions {
|
|
|
18
19
|
* @default false
|
|
19
20
|
*/
|
|
20
21
|
dontGracefulShutdown?: boolean;
|
|
22
|
+
/** SASL authentication options */
|
|
23
|
+
sasl?: ConnectionOptions["sasl"];
|
|
24
|
+
/** Automatically create topics if they don't exist
|
|
25
|
+
* @default false
|
|
26
|
+
*/
|
|
27
|
+
autoCreateTopics?: boolean;
|
|
21
28
|
}
|
|
22
29
|
interface PublishOptions {
|
|
23
30
|
/** Custom headers to attach to the message */
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e={info:(...e)=>console.log(`[INFO]`,...e),error:(...e)=>console.error(`[ERROR]`,...e),warn:(...e)=>console.warn(`[WARN]`,...e),debug:(...e)=>console.debug(`[DEBUG]`,...e)},t=class extends Error{constructor(e){super(e),this.name=`KafkaError`}};const n=`x-timestamp`,r=`autofleet-kafka-producer`;var i=class i{constructor(t,n){this._isConnected=!1,this.gracefulShutdownStarted=!1,this.logger=t.logger??e,this.producer=n,this.logger.info(`Kafka: Initialized Kafka producer`,{clientId:t.clientId||r,brokers:t.brokers}),t.dontGracefulShutdown||this.setupGracefulShutdown()}static async create(e){if(!e.brokers||e.brokers.length===0)throw new t(`At least one broker is required`);let{Producer:n,stringSerializers:a}=await import(`@platformatic/kafka`);return new i(e,new n({bootstrapBrokers:e.brokers,clientId:e.clientId||r,serializers:a}))}setupGracefulShutdown(){this.logger.info(`Kafka: [graceful-shutdown] adding graceful shutdown for process.pid ${process.pid}`),process.on(`SIGTERM`,async()=>{await this.gracefulShutdown(`SIGTERM`)}),process.on(`SIGINT`,async()=>{await this.gracefulShutdown(`SIGINT`)})}async gracefulShutdown(e){if(!this.gracefulShutdownStarted){this.gracefulShutdownStarted=!0,this.logger.info(`Kafka: [graceful-shutdown] received ${e}! Disconnecting producer...`);try{await this.disconnect(),this.logger.info(`Kafka: [graceful-shutdown] producer disconnected successfully`)}catch(e){throw this.logger.error(`Kafka: [graceful-shutdown] error during shutdown`,{error:e}),e}}}get isConnected(){return this._isConnected}async ping(){if(!this._isConnected)try{let e=await this.producer.metadata({topics:[]});this._isConnected=!0,this.logger.info(`Kafka: Successfully connected to cluster`,{clusterId:e.id,brokers:e.brokers.size})}catch(e){throw this.logger.error(`Kafka: Failed to connect to brokers`,{error:e}),new t(`Failed to connect to Kafka brokers: ${e.message}`)}}async publish(e,r,i){if(!e)throw new t(`Topic name is required`);await this.ping();try{let t={[n]:Date.now().toString(),...i?.headers},a=await this.producer.send({messages:[{topic:e,value:JSON.stringify(r),key:i?.key,partition:i?.partition,headers:t}]});return this.logger.debug(`Kafka: Published message to topic ${e}`,{topic:e}),[{topic:e,partition:i?.partition??0,offset:a?.offsets?.[0]?.offset?.toString()??`0`}]}catch(n){let i=n;throw this.logger.error(`Kafka: Error publishing to topic ${e}`,{error:n,value:r}),new t(`Failed to publish to topic ${e}: ${i.message||`Unknown error`}`)}}async publishBatch(e){if(!e.topic)throw new t(`Topic name is required`);if(!e.messages||e.messages.length===0)throw new t(`At least one message is required`);await this.ping();try{let t=e.messages.map(t=>({topic:e.topic,value:JSON.stringify(t.value),key:t.key,partition:t.partition,headers:{[n]:Date.now().toString(),...t.headers}})),r=await this.producer.send({messages:t});return this.logger.debug(`Kafka: Published ${t.length} messages to topic ${e.topic}`,{topic:e.topic,count:t.length}),t.map((t,n)=>({topic:e.topic,partition:t.partition??0,offset:r?.offsets?.[n]?.offset?.toString()??n.toString()}))}catch(n){let r=n;throw this.logger.error(`Kafka: Error publishing batch to topic ${e.topic}`,{error:n}),new t(`Failed to publish batch to topic ${e.topic}: ${r.message||`Unknown error`}`)}}async disconnect(){if(!this._isConnected){this.logger.debug(`Kafka: Producer already disconnected`);return}this.logger.info(`Kafka: Disconnecting producer`);try{await this.producer.close(),this._isConnected=!1,this.logger.info(`Kafka: Producer disconnected successfully`)}catch(e){throw this.logger.error(`Kafka: Error disconnecting producer`,{error:e}),new t(`Failed to disconnect producer: ${e.message}`)}}};export{t as KafkaError,i as default};
|
|
1
|
+
var e={info:(...e)=>console.log(`[INFO]`,...e),error:(...e)=>console.error(`[ERROR]`,...e),warn:(...e)=>console.warn(`[WARN]`,...e),debug:(...e)=>console.debug(`[DEBUG]`,...e)},t=class extends Error{constructor(e){super(e),this.name=`KafkaError`}};const n=`x-timestamp`,r=`autofleet-kafka-producer`;var i=class i{constructor(t,n){this._isConnected=!1,this.gracefulShutdownStarted=!1,this.logger=t.logger??e,this.producer=n,this.logger.info(`Kafka: Initialized Kafka producer`,{clientId:t.clientId||r,brokers:t.brokers}),t.dontGracefulShutdown||this.setupGracefulShutdown()}static async create(e){if(!e.brokers||e.brokers.length===0)throw new t(`At least one broker is required`);let{Producer:n,stringSerializers:a}=await import(`@platformatic/kafka`);return new i(e,new n({bootstrapBrokers:e.brokers,clientId:e.clientId||r,serializers:a,autocreateTopics:e.autoCreateTopics??!1,sasl:e.sasl}))}setupGracefulShutdown(){this.logger.info(`Kafka: [graceful-shutdown] adding graceful shutdown for process.pid ${process.pid}`),process.on(`SIGTERM`,async()=>{await this.gracefulShutdown(`SIGTERM`)}),process.on(`SIGINT`,async()=>{await this.gracefulShutdown(`SIGINT`)})}async gracefulShutdown(e){if(!this.gracefulShutdownStarted){this.gracefulShutdownStarted=!0,this.logger.info(`Kafka: [graceful-shutdown] received ${e}! Disconnecting producer...`);try{await this.disconnect(),this.logger.info(`Kafka: [graceful-shutdown] producer disconnected successfully`)}catch(e){throw this.logger.error(`Kafka: [graceful-shutdown] error during shutdown`,{error:e}),e}}}get isConnected(){return this._isConnected}async ping(){if(!this._isConnected)try{let e=await this.producer.metadata({topics:[]});this._isConnected=!0,this.logger.info(`Kafka: Successfully connected to cluster`,{clusterId:e.id,brokers:e.brokers.size})}catch(e){throw this.logger.error(`Kafka: Failed to connect to brokers`,{error:e}),new t(`Failed to connect to Kafka brokers: ${e.message}`)}}async publish(e,r,i){if(!e)throw new t(`Topic name is required`);await this.ping();try{let t={[n]:Date.now().toString(),...i?.headers},a=await this.producer.send({messages:[{topic:e,value:JSON.stringify(r),key:i?.key,partition:i?.partition,headers:t}]});return this.logger.debug(`Kafka: Published message to topic ${e}`,{topic:e}),[{topic:e,partition:i?.partition??0,offset:a?.offsets?.[0]?.offset?.toString()??`0`}]}catch(n){let i=n;throw this.logger.error(`Kafka: Error publishing to topic ${e}`,{error:n,value:r}),new t(`Failed to publish to topic ${e}: ${i.message||`Unknown error`}`)}}async publishBatch(e){if(!e.topic)throw new t(`Topic name is required`);if(!e.messages||e.messages.length===0)throw new t(`At least one message is required`);await this.ping();try{let t=e.messages.map(t=>({topic:e.topic,value:JSON.stringify(t.value),key:t.key,partition:t.partition,headers:{[n]:Date.now().toString(),...t.headers}})),r=await this.producer.send({messages:t});return this.logger.debug(`Kafka: Published ${t.length} messages to topic ${e.topic}`,{topic:e.topic,count:t.length}),t.map((t,n)=>({topic:e.topic,partition:t.partition??0,offset:r?.offsets?.[n]?.offset?.toString()??n.toString()}))}catch(n){let r=n;throw this.logger.error(`Kafka: Error publishing batch to topic ${e.topic}`,{error:n}),new t(`Failed to publish batch to topic ${e.topic}: ${r.message||`Unknown error`}`)}}async disconnect(){if(!this._isConnected){this.logger.debug(`Kafka: Producer already disconnected`);return}this.logger.info(`Kafka: Disconnecting producer`);try{await this.producer.close(),this._isConnected=!1,this.logger.info(`Kafka: Producer disconnected successfully`)}catch(e){throw this.logger.error(`Kafka: Error disconnecting producer`,{error:e}),new t(`Failed to disconnect producer: ${e.message}`)}}};export{t as KafkaError,i as default};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["fallbackLogger: LoggerInstanceManager","fallbackLogger","headers: Record<string, string>"],"sources":["../src/logger.ts","../src/kafkaError.ts","../src/consts.ts","../src/index.ts"],"sourcesContent":["import type { LoggerInstanceManager } from '@autofleet/logger';\n\n/* eslint-disable no-console */\nconst fallbackLogger: LoggerInstanceManager = {\n info: (...args: unknown[]) => console.log('[INFO]', ...args),\n error: (...args: unknown[]) => console.error('[ERROR]', ...args),\n warn: (...args: unknown[]) => console.warn('[WARN]', ...args),\n debug: (...args: unknown[]) => console.debug('[DEBUG]', ...args),\n} as LoggerInstanceManager;\n/* eslint-enable no-console */\n\nexport default fallbackLogger;\n","export default class KafkaError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'KafkaError';\n }\n}\n","export const TIMESTAMP_HEADER = 'x-timestamp';\nexport const CORRELATION_ID_HEADER = 'x-correlation-id';\nexport const SOURCE_HEADER = 'x-source';\n\nexport const DEFAULT_CLIENT_ID = 'autofleet-kafka-producer';\nexport const DEFAULT_TIMEOUT = 30000; // 30 seconds\nexport const DEFAULT_RETRY = {\n retries: 5,\n initialRetryTime: 300,\n maxRetryTime: 30000,\n};\n","import type { LoggerInstanceManager } from '@autofleet/logger';\nimport type { Producer } from '@platformatic/kafka/dist/clients/producer/index.ts';\nimport fallbackLogger from './logger';\nimport KafkaError from './kafkaError';\nimport {\n DEFAULT_CLIENT_ID,\n TIMESTAMP_HEADER,\n} from './consts';\nimport type {\n KafkaOptions,\n PublishOptions,\n PublishBatchOptions,\n RecordMetadata,\n} from './types';\n\nexport interface IAfKafka {\n isConnected: boolean;\n ping(): Promise<void>;\n publish<T = unknown>(topic: string, value: T, options?: PublishOptions): Promise<RecordMetadata[]>;\n publishBatch(options: PublishBatchOptions): Promise<RecordMetadata[]>;\n disconnect(): Promise<void>;\n}\n\nclass AfKafka implements IAfKafka {\n private producer!: Producer<string, string, string, string>;\n private readonly logger: LoggerInstanceManager;\n private _isConnected = false;\n private gracefulShutdownStarted = false;\n\n private constructor(options: KafkaOptions, producer: Producer<string, string, string, string>) {\n this.logger = options.logger ?? fallbackLogger;\n this.producer = producer;\n\n this.logger.info('Kafka: Initialized Kafka producer', {\n clientId: options.clientId || DEFAULT_CLIENT_ID,\n brokers: options.brokers,\n });\n\n if (!options.dontGracefulShutdown) {\n this.setupGracefulShutdown();\n }\n }\n\n /**\n * Create a new Kafka producer instance\n */\n static async create(options: KafkaOptions): Promise<AfKafka> {\n if (!options.brokers || options.brokers.length === 0) {\n throw new KafkaError('At least one broker is required');\n }\n\n // Dynamic import of ESM-only package\n const { Producer, stringSerializers } = await import('@platformatic/kafka');\n\n const producer = new Producer({\n bootstrapBrokers: options.brokers,\n clientId: options.clientId || DEFAULT_CLIENT_ID,\n serializers: stringSerializers,\n });\n\n return new AfKafka(options, producer);\n }\n\n private setupGracefulShutdown(): void {\n this.logger.info(`Kafka: [graceful-shutdown] adding graceful shutdown for process.pid ${process.pid}`);\n\n process.on('SIGTERM', async () => {\n await this.gracefulShutdown('SIGTERM');\n });\n\n process.on('SIGINT', async () => {\n await this.gracefulShutdown('SIGINT');\n });\n }\n\n private async gracefulShutdown(signal: string): Promise<void> {\n if (this.gracefulShutdownStarted) {\n return;\n }\n\n this.gracefulShutdownStarted = true;\n\n this.logger.info(`Kafka: [graceful-shutdown] received ${signal}! Disconnecting producer...`);\n\n try {\n await this.disconnect();\n this.logger.info('Kafka: [graceful-shutdown] producer disconnected successfully');\n } catch (error) {\n this.logger.error('Kafka: [graceful-shutdown] error during shutdown', { error });\n throw error;\n }\n }\n\n get isConnected(): boolean {\n return this._isConnected;\n }\n\n /**\n * Ping Kafka brokers to verify connectivity\n */\n async ping(): Promise<void> {\n if (this._isConnected) {\n return;\n }\n\n try {\n // Fetch metadata to verify connection\n const metadata = await this.producer.metadata({ topics: [] });\n this._isConnected = true;\n\n this.logger.info('Kafka: Successfully connected to cluster', {\n clusterId: metadata.id,\n brokers: metadata.brokers.size,\n });\n } catch (error) {\n this.logger.error('Kafka: Failed to connect to brokers', { error });\n throw new KafkaError(`Failed to connect to Kafka brokers: ${(error as Error).message}`);\n }\n }\n\n /**\n * Publish a single message to a topic\n */\n async publish<T = unknown>(\n topic: string,\n value: T,\n options?: PublishOptions,\n ): Promise<RecordMetadata[]> {\n if (!topic) {\n throw new KafkaError('Topic name is required');\n }\n\n await this.ping();\n\n try {\n const headers: Record<string, string> = {\n [TIMESTAMP_HEADER]: Date.now().toString(),\n ...options?.headers,\n };\n\n const result = await this.producer.send({\n messages: [{\n topic,\n value: JSON.stringify(value),\n key: options?.key,\n partition: options?.partition,\n headers,\n }],\n });\n\n this.logger.debug(`Kafka: Published message to topic ${topic}`, {\n topic,\n });\n\n // Map ProduceResult to RecordMetadata\n return [{\n topic,\n partition: options?.partition ?? 0,\n offset: result?.offsets?.[0]?.offset?.toString() ?? '0',\n }];\n } catch (error) {\n const err = error as { message?: string; };\n this.logger.error(`Kafka: Error publishing to topic ${topic}`, { error, value });\n throw new KafkaError(`Failed to publish to topic ${topic}: ${err.message || 'Unknown error'}`);\n }\n }\n\n /**\n * Publish multiple messages in a batch\n */\n async publishBatch(options: PublishBatchOptions): Promise<RecordMetadata[]> {\n if (!options.topic) {\n throw new KafkaError('Topic name is required');\n }\n\n if (!options.messages || options.messages.length === 0) {\n throw new KafkaError('At least one message is required');\n }\n\n await this.ping();\n\n try {\n const messages = options.messages.map(msg => ({\n topic: options.topic,\n value: JSON.stringify(msg.value),\n key: msg.key,\n partition: msg.partition,\n headers: {\n [TIMESTAMP_HEADER]: Date.now().toString(),\n ...msg.headers,\n },\n }));\n\n const result = await this.producer.send({ messages });\n\n this.logger.debug(`Kafka: Published ${messages.length} messages to topic ${options.topic}`, {\n topic: options.topic,\n count: messages.length,\n });\n\n // Map ProduceResult to RecordMetadata array\n return messages.map((msg, idx) => ({\n topic: options.topic,\n partition: msg.partition ?? 0,\n offset: result?.offsets?.[idx]?.offset?.toString() ?? idx.toString(),\n }));\n } catch (error) {\n const err = error as { message?: string; };\n this.logger.error(`Kafka: Error publishing batch to topic ${options.topic}`, { error });\n throw new KafkaError(`Failed to publish batch to topic ${options.topic}: ${err.message || 'Unknown error'}`);\n }\n }\n\n /**\n * Disconnect the producer and clean up resources\n */\n async disconnect(): Promise<void> {\n if (!this._isConnected) {\n this.logger.debug('Kafka: Producer already disconnected');\n return;\n }\n\n this.logger.info('Kafka: Disconnecting producer');\n\n try {\n await this.producer.close();\n this._isConnected = false;\n this.logger.info('Kafka: Producer disconnected successfully');\n } catch (error) {\n this.logger.error('Kafka: Error disconnecting producer', { error });\n throw new KafkaError(`Failed to disconnect producer: ${(error as Error).message}`);\n }\n }\n}\n\nexport default AfKafka;\nexport { KafkaError };\nexport type {\n KafkaOptions,\n PublishOptions,\n PublishBatchOptions,\n RecordMetadata,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["fallbackLogger: LoggerInstanceManager","fallbackLogger","headers: Record<string, string>"],"sources":["../src/logger.ts","../src/kafkaError.ts","../src/consts.ts","../src/index.ts"],"sourcesContent":["import type { LoggerInstanceManager } from '@autofleet/logger';\n\n/* eslint-disable no-console */\nconst fallbackLogger: LoggerInstanceManager = {\n info: (...args: unknown[]) => console.log('[INFO]', ...args),\n error: (...args: unknown[]) => console.error('[ERROR]', ...args),\n warn: (...args: unknown[]) => console.warn('[WARN]', ...args),\n debug: (...args: unknown[]) => console.debug('[DEBUG]', ...args),\n} as LoggerInstanceManager;\n/* eslint-enable no-console */\n\nexport default fallbackLogger;\n","export default class KafkaError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'KafkaError';\n }\n}\n","export const TIMESTAMP_HEADER = 'x-timestamp';\nexport const CORRELATION_ID_HEADER = 'x-correlation-id';\nexport const SOURCE_HEADER = 'x-source';\n\nexport const DEFAULT_CLIENT_ID = 'autofleet-kafka-producer';\nexport const DEFAULT_TIMEOUT = 30000; // 30 seconds\nexport const DEFAULT_RETRY = {\n retries: 5,\n initialRetryTime: 300,\n maxRetryTime: 30000,\n};\n","import type { LoggerInstanceManager } from '@autofleet/logger';\nimport type { Producer } from '@platformatic/kafka/dist/clients/producer/index.ts';\nimport fallbackLogger from './logger';\nimport KafkaError from './kafkaError';\nimport {\n DEFAULT_CLIENT_ID,\n TIMESTAMP_HEADER,\n} from './consts';\nimport type {\n KafkaOptions,\n PublishOptions,\n PublishBatchOptions,\n RecordMetadata,\n} from './types';\n\nexport interface IAfKafka {\n isConnected: boolean;\n ping(): Promise<void>;\n publish<T = unknown>(topic: string, value: T, options?: PublishOptions): Promise<RecordMetadata[]>;\n publishBatch(options: PublishBatchOptions): Promise<RecordMetadata[]>;\n disconnect(): Promise<void>;\n}\n\nclass AfKafka implements IAfKafka {\n private producer!: Producer<string, string, string, string>;\n private readonly logger: LoggerInstanceManager;\n private _isConnected = false;\n private gracefulShutdownStarted = false;\n\n private constructor(options: KafkaOptions, producer: Producer<string, string, string, string>) {\n this.logger = options.logger ?? fallbackLogger;\n this.producer = producer;\n\n this.logger.info('Kafka: Initialized Kafka producer', {\n clientId: options.clientId || DEFAULT_CLIENT_ID,\n brokers: options.brokers,\n });\n\n if (!options.dontGracefulShutdown) {\n this.setupGracefulShutdown();\n }\n }\n\n /**\n * Create a new Kafka producer instance\n */\n static async create(options: KafkaOptions): Promise<AfKafka> {\n if (!options.brokers || options.brokers.length === 0) {\n throw new KafkaError('At least one broker is required');\n }\n\n // Dynamic import of ESM-only package\n const { Producer, stringSerializers } = await import('@platformatic/kafka');\n\n const producer = new Producer({\n bootstrapBrokers: options.brokers,\n clientId: options.clientId || DEFAULT_CLIENT_ID,\n serializers: stringSerializers,\n autocreateTopics: options.autoCreateTopics ?? false,\n sasl: options.sasl,\n });\n\n return new AfKafka(options, producer);\n }\n\n private setupGracefulShutdown(): void {\n this.logger.info(`Kafka: [graceful-shutdown] adding graceful shutdown for process.pid ${process.pid}`);\n\n process.on('SIGTERM', async () => {\n await this.gracefulShutdown('SIGTERM');\n });\n\n process.on('SIGINT', async () => {\n await this.gracefulShutdown('SIGINT');\n });\n }\n\n private async gracefulShutdown(signal: string): Promise<void> {\n if (this.gracefulShutdownStarted) {\n return;\n }\n\n this.gracefulShutdownStarted = true;\n\n this.logger.info(`Kafka: [graceful-shutdown] received ${signal}! Disconnecting producer...`);\n\n try {\n await this.disconnect();\n this.logger.info('Kafka: [graceful-shutdown] producer disconnected successfully');\n } catch (error) {\n this.logger.error('Kafka: [graceful-shutdown] error during shutdown', { error });\n throw error;\n }\n }\n\n get isConnected(): boolean {\n return this._isConnected;\n }\n\n /**\n * Ping Kafka brokers to verify connectivity\n */\n async ping(): Promise<void> {\n if (this._isConnected) {\n return;\n }\n\n try {\n // Fetch metadata to verify connection\n const metadata = await this.producer.metadata({ topics: [] });\n this._isConnected = true;\n\n this.logger.info('Kafka: Successfully connected to cluster', {\n clusterId: metadata.id,\n brokers: metadata.brokers.size,\n });\n } catch (error) {\n this.logger.error('Kafka: Failed to connect to brokers', { error });\n throw new KafkaError(`Failed to connect to Kafka brokers: ${(error as Error).message}`);\n }\n }\n\n /**\n * Publish a single message to a topic\n */\n async publish<T = unknown>(\n topic: string,\n value: T,\n options?: PublishOptions,\n ): Promise<RecordMetadata[]> {\n if (!topic) {\n throw new KafkaError('Topic name is required');\n }\n\n await this.ping();\n\n try {\n const headers: Record<string, string> = {\n [TIMESTAMP_HEADER]: Date.now().toString(),\n ...options?.headers,\n };\n\n const result = await this.producer.send({\n messages: [{\n topic,\n value: JSON.stringify(value),\n key: options?.key,\n partition: options?.partition,\n headers,\n }],\n });\n\n this.logger.debug(`Kafka: Published message to topic ${topic}`, {\n topic,\n });\n\n // Map ProduceResult to RecordMetadata\n return [{\n topic,\n partition: options?.partition ?? 0,\n offset: result?.offsets?.[0]?.offset?.toString() ?? '0',\n }];\n } catch (error) {\n const err = error as { message?: string; };\n this.logger.error(`Kafka: Error publishing to topic ${topic}`, { error, value });\n throw new KafkaError(`Failed to publish to topic ${topic}: ${err.message || 'Unknown error'}`);\n }\n }\n\n /**\n * Publish multiple messages in a batch\n */\n async publishBatch(options: PublishBatchOptions): Promise<RecordMetadata[]> {\n if (!options.topic) {\n throw new KafkaError('Topic name is required');\n }\n\n if (!options.messages || options.messages.length === 0) {\n throw new KafkaError('At least one message is required');\n }\n\n await this.ping();\n\n try {\n const messages = options.messages.map(msg => ({\n topic: options.topic,\n value: JSON.stringify(msg.value),\n key: msg.key,\n partition: msg.partition,\n headers: {\n [TIMESTAMP_HEADER]: Date.now().toString(),\n ...msg.headers,\n },\n }));\n\n const result = await this.producer.send({ messages });\n\n this.logger.debug(`Kafka: Published ${messages.length} messages to topic ${options.topic}`, {\n topic: options.topic,\n count: messages.length,\n });\n\n // Map ProduceResult to RecordMetadata array\n return messages.map((msg, idx) => ({\n topic: options.topic,\n partition: msg.partition ?? 0,\n offset: result?.offsets?.[idx]?.offset?.toString() ?? idx.toString(),\n }));\n } catch (error) {\n const err = error as { message?: string; };\n this.logger.error(`Kafka: Error publishing batch to topic ${options.topic}`, { error });\n throw new KafkaError(`Failed to publish batch to topic ${options.topic}: ${err.message || 'Unknown error'}`);\n }\n }\n\n /**\n * Disconnect the producer and clean up resources\n */\n async disconnect(): Promise<void> {\n if (!this._isConnected) {\n this.logger.debug('Kafka: Producer already disconnected');\n return;\n }\n\n this.logger.info('Kafka: Disconnecting producer');\n\n try {\n await this.producer.close();\n this._isConnected = false;\n this.logger.info('Kafka: Producer disconnected successfully');\n } catch (error) {\n this.logger.error('Kafka: Error disconnecting producer', { error });\n throw new KafkaError(`Failed to disconnect producer: ${(error as Error).message}`);\n }\n }\n}\n\nexport default AfKafka;\nexport { KafkaError };\nexport type {\n KafkaOptions,\n PublishOptions,\n PublishBatchOptions,\n RecordMetadata,\n};\n"],"mappings":"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"}
|