@walkeros/server-destination-kafka 3.4.2 → 4.0.0-next-1777882869103
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.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/walkerOS.json +19 -82
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e,t=Object.defineProperty,
|
|
1
|
+
"use strict";var e,t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,o=Object.prototype.hasOwnProperty,i={};((e,r)=>{for(var n in r)t(e,n,{get:r[n],enumerable:!0})})(i,{DestinationKafka:()=>f,default:()=>k,destinationKafka:()=>u}),module.exports=(e=i,((e,i,a,s)=>{if(i&&"object"==typeof i||"function"==typeof i)for(let c of n(i))o.call(e,c)||c===a||t(e,c,{get:()=>i[c],enumerable:!(s=r(i,c))||s.enumerable});return e})(t({},"__esModule",{value:!0}),e));var a=require("@walkeros/core"),s={none:0,gzip:1,snappy:2,lz4:3,zstd:4};var c=require("@walkeros/core"),p=async function(e,{config:t,rule:r,data:n,collector:o,env:i,logger:a}){const p=t.settings,f=p?.kafka;if(!f)return void a.warn("Kafka settings missing");const u=f._producer;if(!u)return void a.warn("Kafka producer not initialized");const k=(0,c.isString)(r?.name)?r.name:e.name,l=r?.settings??{},g=(0,c.isString)(l.topic)?l.topic:f.topic,d=(0,c.isString)(l.key)?l.key:f.key,y=await async function(e,t,r,n){if(r){const t=await(0,c.getMappingValue)(e,r,{collector:n});if((0,c.isString)(t)&&t.length>0)return t}return t.replace(/\s+/g,"_")}(e,k,d,o),m=(0,c.isObject)(n)&&Object.keys(n).length>0?JSON.stringify(n):JSON.stringify(e),w={"content-type":"application/json",...f.headers??{}},b=i,h=function(e,t){const r=e??"gzip";if("none"===r)return 0;const n=t?.Kafka?.CompressionTypes;if(n)return{none:n.None,gzip:n.GZIP,snappy:n.Snappy,lz4:n.LZ4,zstd:n.ZSTD}[r]??n.GZIP;return s[r]??1}(f.compression,b),v={topic:g,messages:[{key:y,value:m,headers:w,timestamp:String(e.timestamp??Date.now())}],acks:f.acks??-1,compression:h};void 0!==f.timeout&&(v.timeout=f.timeout),a.debug("Kafka push",{topic:g,key:y,event:k});try{await u.send(v)}catch(e){a.error("Kafka push failed",{topic:g,error:e instanceof Error?e.message:String(e),event:k})}};var f={},u={type:"kafka",config:{},async init({config:e,logger:t,env:r}){const n=function(e={},t){const r=(e.settings??{}).kafka??{};r.brokers&&0!==r.brokers.length||t.throw("Config settings kafka.brokers missing"),r.topic||t.throw("Config settings kafka.topic missing");const n={kafka:{...r,brokers:r.brokers,topic:r.topic,clientId:r.clientId??"walkeros",acks:r.acks??-1,compression:r.compression??"gzip",idempotent:r.idempotent??!1,allowAutoTopicCreation:r.allowAutoTopicCreation??!1}};return{...e,settings:n}}(e,t),o=n.settings.kafka;if(o._producer)return n;let i;if(function(e){if(!(0,a.isObject)(e))return!1;const t=e;return"function"==typeof t.Kafka?.Kafka}(r)){const e=r;i=e.Kafka?.Kafka}if(!i)try{i=require("kafkajs").Kafka}catch(e){return t.throw(`Failed to load kafkajs: ${String(e)}`),n}const s=new i({clientId:o.clientId,brokers:o.brokers,ssl:o.ssl,sasl:o.sasl,connectionTimeout:o.connectionTimeout,requestTimeout:o.requestTimeout,retry:o.retry}),c={allowAutoTopicCreation:o.allowAutoTopicCreation,idempotent:o.idempotent},p=s.producer(c);try{await p.connect()}catch(e){return t.error("Kafka producer connect failed",{error:String(e)}),t.throw(`Kafka producer connect failed: ${String(e)}`),n}return o._producer=p,n},push:async(e,t)=>await p(e,t),async destroy({config:e}){const t=e?.settings,r=t?.kafka?._producer;if(r)try{await r.disconnect()}finally{t.kafka._producer=void 0}}},k=u;//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/push.ts","../src/types/index.ts"],"sourcesContent":["import type {\n Destination,\n Settings,\n Env,\n KafkaClientMock,\n KafkaClientConfig,\n KafkaClientConstructor,\n ProducerConfig,\n} from './types';\nimport { getConfig, isKafkaEnv } from './config';\nimport { push } from './push';\n\n// Types re-export\nexport * as DestinationKafka from './types';\n\nexport const destinationKafka: Destination = {\n type: 'kafka',\n\n config: {},\n\n async init({ config: partialConfig, logger, env }) {\n const config = getConfig(partialConfig, logger);\n const settings = config.settings as Settings;\n const kafka = settings.kafka;\n\n // Skip creation if a producer has already been wired in (testing).\n if (kafka._producer) return config;\n\n let Constructor: KafkaClientConstructor | undefined;\n\n // Prefer env-injected constructor (testing, dependency injection).\n if (isKafkaEnv(env)) {\n const envTyped = env as Env;\n Constructor = envTyped.Kafka?.Kafka;\n }\n\n // Production path: load real kafkajs SDK.\n if (!Constructor) {\n try {\n // Use dynamic require to allow tests to mock via jest.mock('kafkajs').\n const kafkajs = require('kafkajs') as {\n Kafka: KafkaClientConstructor;\n };\n Constructor = kafkajs.Kafka;\n } catch (err) {\n logger.throw(`Failed to load kafkajs: ${String(err)}`);\n return config;\n }\n }\n\n const clientConfig: KafkaClientConfig = {\n clientId: kafka.clientId,\n brokers: kafka.brokers,\n ssl: kafka.ssl,\n sasl: kafka.sasl,\n connectionTimeout: kafka.connectionTimeout,\n requestTimeout: kafka.requestTimeout,\n retry: kafka.retry,\n };\n\n const client: KafkaClientMock = new Constructor(clientConfig);\n\n const producerConfig: ProducerConfig = {\n allowAutoTopicCreation: kafka.allowAutoTopicCreation,\n idempotent: kafka.idempotent,\n };\n\n const producer = client.producer(producerConfig);\n\n try {\n await producer.connect();\n } catch (err) {\n logger.error('Kafka producer connect failed', { error: String(err) });\n logger.throw(`Kafka producer connect failed: ${String(err)}`);\n return config;\n }\n\n kafka._producer = producer;\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n async destroy({ config }) {\n const settings = config?.settings as Settings | undefined;\n const producer = settings?.kafka?._producer;\n if (producer) {\n try {\n await producer.disconnect();\n } finally {\n settings.kafka._producer = undefined;\n }\n }\n },\n};\n\nexport default destinationKafka;\n","import type {\n Config,\n Settings,\n KafkaSettings,\n PartialConfig,\n Env,\n CompressionType,\n CompressionTypesMap,\n} from './types';\nimport type { Logger } from '@walkeros/core';\nimport { isObject } from '@walkeros/core';\n\n/** Fallback compression codec map when env is not provided. */\nconst COMPRESSION_FALLBACK: Record<CompressionType, number> = {\n none: 0,\n gzip: 1,\n snappy: 2,\n lz4: 3,\n zstd: 4,\n};\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): Config {\n const raw = (partialConfig.settings ?? {}) as Partial<Settings>;\n const kafka: Partial<KafkaSettings> =\n raw.kafka ?? ({} as Partial<KafkaSettings>);\n\n if (!kafka.brokers || kafka.brokers.length === 0) {\n logger.throw('Config settings kafka.brokers missing');\n }\n if (!kafka.topic) {\n logger.throw('Config settings kafka.topic missing');\n }\n\n const kafkaSettings: KafkaSettings = {\n ...kafka,\n brokers: kafka.brokers as string[],\n topic: kafka.topic as string,\n clientId: kafka.clientId ?? 'walkeros',\n acks: kafka.acks ?? -1,\n compression: kafka.compression ?? 'gzip',\n idempotent: kafka.idempotent ?? false,\n allowAutoTopicCreation: kafka.allowAutoTopicCreation ?? false,\n };\n\n const settings: Settings = { kafka: kafkaSettings };\n\n return { ...partialConfig, settings };\n}\n\nexport function getCompressionType(\n compression: CompressionType | undefined,\n env: Env | undefined,\n): number {\n const codec = compression ?? 'gzip';\n if (codec === 'none') return 0;\n\n const types: CompressionTypesMap | undefined = env?.Kafka?.CompressionTypes;\n if (types) {\n const lookup: Record<CompressionType, number> = {\n none: types.None,\n gzip: types.GZIP,\n snappy: types.Snappy,\n lz4: types.LZ4,\n zstd: types.ZSTD,\n };\n return lookup[codec] ?? types.GZIP;\n }\n\n return COMPRESSION_FALLBACK[codec] ?? 1;\n}\n\nexport function isKafkaEnv(env: unknown): env is Env {\n if (!isObject(env)) return false;\n const maybe = env as { Kafka?: { Kafka?: unknown } };\n return typeof maybe.Kafka?.Kafka === 'function';\n}\n","import type {\n PushFn,\n KafkaSettings,\n Env,\n ProducerMessage,\n ProducerRecord,\n KafkaProducerMock,\n} from './types';\nimport type { Collector } from '@walkeros/core';\nimport { getMappingValue, isObject, isString } from '@walkeros/core';\nimport { getCompressionType } from './config';\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, collector, env, logger },\n) {\n const settings = config.settings as { kafka?: KafkaSettings } | undefined;\n const kafka: KafkaSettings | undefined = settings?.kafka;\n\n if (!kafka) {\n logger.warn('Kafka settings missing');\n return;\n }\n\n const producer = kafka._producer;\n if (!producer) {\n logger.warn('Kafka producer not initialized');\n return;\n }\n\n // Derive event name (rule.name overrides)\n const eventName = isString(rule?.name) ? rule.name : event.name;\n\n // Derive topic: rule override -> destination default\n const ruleSettings = rule?.settings ?? {};\n const topic = isString(ruleSettings.topic) ? ruleSettings.topic : kafka.topic;\n\n // Derive message key\n const keyPath = isString(ruleSettings.key) ? ruleSettings.key : kafka.key;\n const key = await deriveKey(event, eventName, keyPath, collector);\n\n // Serialize message value: mapped data (when present) -> event\n const value =\n isObject(data) && Object.keys(data).length > 0\n ? JSON.stringify(data)\n : JSON.stringify(event);\n\n // Build headers\n const headers: Record<string, string> = {\n 'content-type': 'application/json',\n ...(kafka.headers ?? {}),\n };\n\n // Resolve compression codec via env lookup\n const envTyped = env as Env | undefined;\n const compression = getCompressionType(kafka.compression, envTyped);\n\n const message: ProducerMessage = {\n key,\n value,\n headers,\n timestamp: String(event.timestamp ?? Date.now()),\n };\n\n const record: ProducerRecord = {\n topic,\n messages: [message],\n acks: kafka.acks ?? -1,\n compression,\n };\n\n if (kafka.timeout !== undefined) record.timeout = kafka.timeout;\n\n logger.debug('Kafka push', { topic, key, event: eventName });\n\n try {\n await (producer as KafkaProducerMock).send(record);\n } catch (error) {\n logger.error('Kafka push failed', {\n topic,\n error: error instanceof Error ? error.message : String(error),\n event: eventName,\n });\n }\n};\n\nasync function deriveKey(\n event: Parameters<PushFn>[0],\n eventName: string,\n keyPath: string | undefined,\n collector: Collector.Instance,\n): Promise<string> {\n if (keyPath) {\n const resolved = await getMappingValue(event, keyPath, { collector });\n if (isString(resolved) && resolved.length > 0) return resolved;\n }\n // Default: event name with space replaced for partition-friendly keys.\n return eventName.replace(/\\s+/g, '_');\n}\n","import type { Destination as CoreDestination } from '@walkeros/core';\nimport type { DestinationServer } from '@walkeros/server-core';\n\n/**\n * Mock-friendly Producer interface used by the destination.\n * Tests provide this via env.Kafka; production creates a real\n * kafkajs Producer and adapts it through settings._producer.\n */\nexport interface KafkaProducerMock {\n connect: () => Promise<void>;\n disconnect: () => Promise<void>;\n send: (record: ProducerRecord) => Promise<unknown>;\n}\n\n/**\n * Mock-friendly Kafka client interface (subset of kafkajs.Kafka).\n */\nexport interface KafkaClientMock {\n producer: (config?: ProducerConfig) => KafkaProducerMock;\n}\n\n/**\n * Constructor signature for the Kafka client. Accepts a config\n * object and returns a client with producer() factory.\n */\nexport type KafkaClientConstructor = new (\n config: KafkaClientConfig,\n) => KafkaClientMock;\n\nexport interface KafkaClientConfig {\n clientId?: string;\n brokers: string[];\n ssl?: boolean | Record<string, unknown>;\n sasl?: SASLConfig;\n connectionTimeout?: number;\n requestTimeout?: number;\n retry?: RetryConfig;\n}\n\nexport interface ProducerConfig {\n allowAutoTopicCreation?: boolean;\n idempotent?: boolean;\n}\n\nexport interface ProducerRecord {\n topic: string;\n messages: ProducerMessage[];\n acks?: number;\n compression?: number;\n timeout?: number;\n}\n\nexport interface ProducerMessage {\n key?: string;\n value: string;\n headers?: Record<string, string>;\n timestamp?: string;\n partition?: number;\n}\n\nexport interface CompressionTypesMap {\n None: number;\n GZIP: number;\n Snappy: number;\n LZ4: number;\n ZSTD: number;\n}\n\nexport type CompressionType = 'none' | 'gzip' | 'snappy' | 'lz4' | 'zstd';\n\nexport interface SASLConfig {\n mechanism:\n | 'plain'\n | 'scram-sha-256'\n | 'scram-sha-512'\n | 'aws'\n | 'oauthbearer';\n username?: string;\n password?: string;\n accessKeyId?: string;\n secretAccessKey?: string;\n sessionToken?: string;\n authorizationIdentity?: string;\n}\n\nexport interface RetryConfig {\n maxRetryTime?: number;\n initialRetryTime?: number;\n retries?: number;\n}\n\nexport interface KafkaSettings {\n // Connection\n brokers: string[];\n clientId?: string;\n ssl?: boolean | Record<string, unknown>;\n sasl?: SASLConfig;\n connectionTimeout?: number;\n requestTimeout?: number;\n\n // Producer\n topic: string;\n acks?: number;\n timeout?: number;\n compression?: CompressionType;\n idempotent?: boolean;\n allowAutoTopicCreation?: boolean;\n\n // Message\n key?: string;\n headers?: Record<string, string>;\n\n // Advanced\n retry?: RetryConfig;\n\n // Runtime -- set during init, not user-facing\n _producer?: KafkaProducerMock;\n}\n\nexport interface Settings {\n kafka: KafkaSettings;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {\n /** Override message key mapping path for this rule. */\n key?: string;\n /** Override topic for this rule. */\n topic?: string;\n}\n\n/**\n * Env -- optional Kafka SDK override. Production leaves this undefined\n * and the destination creates real Kafka client instances. Tests provide\n * mocks via env.Kafka.\n */\nexport interface Env extends DestinationServer.Env {\n Kafka?: {\n Kafka: KafkaClientConstructor;\n CompressionTypes: CompressionTypesMap;\n };\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACUA,kBAAyB;AAGzB,IAAM,uBAAwD;AAAA,EAC5D,MAAM;AAAA,EACN,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,MAAM;AACR;AAEO,SAAS,UACd,gBAA+B,CAAC,GAChC,QACQ;AAxBV;AAyBE,QAAM,OAAO,mBAAc,aAAd,YAA0B,CAAC;AACxC,QAAM,SACJ,SAAI,UAAJ,YAAc,CAAC;AAEjB,MAAI,CAAC,MAAM,WAAW,MAAM,QAAQ,WAAW,GAAG;AAChD,WAAO,MAAM,uCAAuC;AAAA,EACtD;AACA,MAAI,CAAC,MAAM,OAAO;AAChB,WAAO,MAAM,qCAAqC;AAAA,EACpD;AAEA,QAAM,gBAA+B;AAAA,IACnC,GAAG;AAAA,IACH,SAAS,MAAM;AAAA,IACf,OAAO,MAAM;AAAA,IACb,WAAU,WAAM,aAAN,YAAkB;AAAA,IAC5B,OAAM,WAAM,SAAN,YAAc;AAAA,IACpB,cAAa,WAAM,gBAAN,YAAqB;AAAA,IAClC,aAAY,WAAM,eAAN,YAAoB;AAAA,IAChC,yBAAwB,WAAM,2BAAN,YAAgC;AAAA,EAC1D;AAEA,QAAM,WAAqB,EAAE,OAAO,cAAc;AAElD,SAAO,EAAE,GAAG,eAAe,SAAS;AACtC;AAEO,SAAS,mBACd,aACA,KACQ;AAvDV;AAwDE,QAAM,QAAQ,oCAAe;AAC7B,MAAI,UAAU,OAAQ,QAAO;AAE7B,QAAM,SAAyC,gCAAK,UAAL,mBAAY;AAC3D,MAAI,OAAO;AACT,UAAM,SAA0C;AAAA,MAC9C,MAAM,MAAM;AAAA,MACZ,MAAM,MAAM;AAAA,MACZ,QAAQ,MAAM;AAAA,MACd,KAAK,MAAM;AAAA,MACX,MAAM,MAAM;AAAA,IACd;AACA,YAAO,YAAO,KAAK,MAAZ,YAAiB,MAAM;AAAA,EAChC;AAEA,UAAO,0BAAqB,KAAK,MAA1B,YAA+B;AACxC;AAEO,SAAS,WAAW,KAA0B;AA1ErD;AA2EE,MAAI,KAAC,sBAAS,GAAG,EAAG,QAAO;AAC3B,QAAM,QAAQ;AACd,SAAO,SAAO,WAAM,UAAN,mBAAa,WAAU;AACvC;;;ACrEA,IAAAA,eAAoD;AAG7C,IAAM,OAAe,eAC1B,OACA,EAAE,QAAQ,MAAM,MAAM,WAAW,KAAK,OAAO,GAC7C;AAfF;AAgBE,QAAM,WAAW,OAAO;AACxB,QAAM,QAAmC,qCAAU;AAEnD,MAAI,CAAC,OAAO;AACV,WAAO,KAAK,wBAAwB;AACpC;AAAA,EACF;AAEA,QAAM,WAAW,MAAM;AACvB,MAAI,CAAC,UAAU;AACb,WAAO,KAAK,gCAAgC;AAC5C;AAAA,EACF;AAGA,QAAM,gBAAY,uBAAS,6BAAM,IAAI,IAAI,KAAK,OAAO,MAAM;AAG3D,QAAM,gBAAe,kCAAM,aAAN,YAAkB,CAAC;AACxC,QAAM,YAAQ,uBAAS,aAAa,KAAK,IAAI,aAAa,QAAQ,MAAM;AAGxE,QAAM,cAAU,uBAAS,aAAa,GAAG,IAAI,aAAa,MAAM,MAAM;AACtE,QAAM,MAAM,MAAM,UAAU,OAAO,WAAW,SAAS,SAAS;AAGhE,QAAM,YACJ,uBAAS,IAAI,KAAK,OAAO,KAAK,IAAI,EAAE,SAAS,IACzC,KAAK,UAAU,IAAI,IACnB,KAAK,UAAU,KAAK;AAG1B,QAAM,UAAkC;AAAA,IACtC,gBAAgB;AAAA,IAChB,IAAI,WAAM,YAAN,YAAiB,CAAC;AAAA,EACxB;AAGA,QAAM,WAAW;AACjB,QAAM,cAAc,mBAAmB,MAAM,aAAa,QAAQ;AAElE,QAAM,UAA2B;AAAA,IAC/B;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,QAAO,WAAM,cAAN,YAAmB,KAAK,IAAI,CAAC;AAAA,EACjD;AAEA,QAAM,SAAyB;AAAA,IAC7B;AAAA,IACA,UAAU,CAAC,OAAO;AAAA,IAClB,OAAM,WAAM,SAAN,YAAc;AAAA,IACpB;AAAA,EACF;AAEA,MAAI,MAAM,YAAY,OAAW,QAAO,UAAU,MAAM;AAExD,SAAO,MAAM,cAAc,EAAE,OAAO,KAAK,OAAO,UAAU,CAAC;AAE3D,MAAI;AACF,UAAO,SAA+B,KAAK,MAAM;AAAA,EACnD,SAAS,OAAO;AACd,WAAO,MAAM,qBAAqB;AAAA,MAChC;AAAA,MACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC5D,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACF;AAEA,eAAe,UACb,OACA,WACA,SACA,WACiB;AACjB,MAAI,SAAS;AACX,UAAM,WAAW,UAAM,8BAAgB,OAAO,SAAS,EAAE,UAAU,CAAC;AACpE,YAAI,uBAAS,QAAQ,KAAK,SAAS,SAAS,EAAG,QAAO;AAAA,EACxD;AAEA,SAAO,UAAU,QAAQ,QAAQ,GAAG;AACtC;;;AClGA;;;AHeO,IAAM,mBAAgC;AAAA,EAC3C,MAAM;AAAA,EAEN,QAAQ,CAAC;AAAA,EAET,MAAM,KAAK,EAAE,QAAQ,eAAe,QAAQ,IAAI,GAAG;AApBrD;AAqBI,UAAM,SAAS,UAAU,eAAe,MAAM;AAC9C,UAAM,WAAW,OAAO;AACxB,UAAM,QAAQ,SAAS;AAGvB,QAAI,MAAM,UAAW,QAAO;AAE5B,QAAI;AAGJ,QAAI,WAAW,GAAG,GAAG;AACnB,YAAM,WAAW;AACjB,qBAAc,cAAS,UAAT,mBAAgB;AAAA,IAChC;AAGA,QAAI,CAAC,aAAa;AAChB,UAAI;AAEF,cAAM,UAAU,QAAQ,SAAS;AAGjC,sBAAc,QAAQ;AAAA,MACxB,SAAS,KAAK;AACZ,eAAO,MAAM,2BAA2B,OAAO,GAAG,CAAC,EAAE;AACrD,eAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,eAAkC;AAAA,MACtC,UAAU,MAAM;AAAA,MAChB,SAAS,MAAM;AAAA,MACf,KAAK,MAAM;AAAA,MACX,MAAM,MAAM;AAAA,MACZ,mBAAmB,MAAM;AAAA,MACzB,gBAAgB,MAAM;AAAA,MACtB,OAAO,MAAM;AAAA,IACf;AAEA,UAAM,SAA0B,IAAI,YAAY,YAAY;AAE5D,UAAM,iBAAiC;AAAA,MACrC,wBAAwB,MAAM;AAAA,MAC9B,YAAY,MAAM;AAAA,IACpB;AAEA,UAAM,WAAW,OAAO,SAAS,cAAc;AAE/C,QAAI;AACF,YAAM,SAAS,QAAQ;AAAA,IACzB,SAAS,KAAK;AACZ,aAAO,MAAM,iCAAiC,EAAE,OAAO,OAAO,GAAG,EAAE,CAAC;AACpE,aAAO,MAAM,kCAAkC,OAAO,GAAG,CAAC,EAAE;AAC5D,aAAO;AAAA,IACT;AAEA,UAAM,YAAY;AAElB,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,KAAK,OAAO,SAAS;AACzB,WAAO,MAAM,KAAK,OAAO,OAAO;AAAA,EAClC;AAAA,EAEA,MAAM,QAAQ,EAAE,OAAO,GAAG;AAtF5B;AAuFI,UAAM,WAAW,iCAAQ;AACzB,UAAM,YAAW,0CAAU,UAAV,mBAAiB;AAClC,QAAI,UAAU;AACZ,UAAI;AACF,cAAM,SAAS,WAAW;AAAA,MAC5B,UAAE;AACA,iBAAS,MAAM,YAAY;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,gBAAQ;","names":["import_core"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/push.ts","../src/types/index.ts"],"sourcesContent":["import type {\n Destination,\n Settings,\n Env,\n KafkaClientMock,\n KafkaClientConfig,\n KafkaClientConstructor,\n ProducerConfig,\n} from './types';\nimport { getConfig, isKafkaEnv } from './config';\nimport { push } from './push';\n\n// Types re-export\nexport * as DestinationKafka from './types';\n\nexport const destinationKafka: Destination = {\n type: 'kafka',\n\n config: {},\n\n async init({ config: partialConfig, logger, env }) {\n const config = getConfig(partialConfig, logger);\n const settings = config.settings as Settings;\n const kafka = settings.kafka;\n\n // Skip creation if a producer has already been wired in (testing).\n if (kafka._producer) return config;\n\n let Constructor: KafkaClientConstructor | undefined;\n\n // Prefer env-injected constructor (testing, dependency injection).\n if (isKafkaEnv(env)) {\n const envTyped = env as Env;\n Constructor = envTyped.Kafka?.Kafka;\n }\n\n // Production path: load real kafkajs SDK.\n if (!Constructor) {\n try {\n // Use dynamic require to allow tests to mock via jest.mock('kafkajs').\n const kafkajs = require('kafkajs') as {\n Kafka: KafkaClientConstructor;\n };\n Constructor = kafkajs.Kafka;\n } catch (err) {\n logger.throw(`Failed to load kafkajs: ${String(err)}`);\n return config;\n }\n }\n\n const clientConfig: KafkaClientConfig = {\n clientId: kafka.clientId,\n brokers: kafka.brokers,\n ssl: kafka.ssl,\n sasl: kafka.sasl,\n connectionTimeout: kafka.connectionTimeout,\n requestTimeout: kafka.requestTimeout,\n retry: kafka.retry,\n };\n\n const client: KafkaClientMock = new Constructor(clientConfig);\n\n const producerConfig: ProducerConfig = {\n allowAutoTopicCreation: kafka.allowAutoTopicCreation,\n idempotent: kafka.idempotent,\n };\n\n const producer = client.producer(producerConfig);\n\n try {\n await producer.connect();\n } catch (err) {\n logger.error('Kafka producer connect failed', { error: String(err) });\n logger.throw(`Kafka producer connect failed: ${String(err)}`);\n return config;\n }\n\n kafka._producer = producer;\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n async destroy({ config }) {\n const settings = config?.settings as Settings | undefined;\n const producer = settings?.kafka?._producer;\n if (producer) {\n try {\n await producer.disconnect();\n } finally {\n settings.kafka._producer = undefined;\n }\n }\n },\n};\n\nexport default destinationKafka;\n","import type {\n Config,\n Settings,\n KafkaSettings,\n PartialConfig,\n Env,\n CompressionType,\n CompressionTypesMap,\n} from './types';\nimport type { Logger } from '@walkeros/core';\nimport { isObject } from '@walkeros/core';\n\n/** Fallback compression codec map when env is not provided. */\nconst COMPRESSION_FALLBACK: Record<CompressionType, number> = {\n none: 0,\n gzip: 1,\n snappy: 2,\n lz4: 3,\n zstd: 4,\n};\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): Config {\n const raw = (partialConfig.settings ?? {}) as Partial<Settings>;\n const kafka: Partial<KafkaSettings> =\n raw.kafka ?? ({} as Partial<KafkaSettings>);\n\n if (!kafka.brokers || kafka.brokers.length === 0) {\n logger.throw('Config settings kafka.brokers missing');\n }\n if (!kafka.topic) {\n logger.throw('Config settings kafka.topic missing');\n }\n\n const kafkaSettings: KafkaSettings = {\n ...kafka,\n brokers: kafka.brokers as string[],\n topic: kafka.topic as string,\n clientId: kafka.clientId ?? 'walkeros',\n acks: kafka.acks ?? -1,\n compression: kafka.compression ?? 'gzip',\n idempotent: kafka.idempotent ?? false,\n allowAutoTopicCreation: kafka.allowAutoTopicCreation ?? false,\n };\n\n const settings: Settings = { kafka: kafkaSettings };\n\n return { ...partialConfig, settings };\n}\n\nexport function getCompressionType(\n compression: CompressionType | undefined,\n env: Env | undefined,\n): number {\n const codec = compression ?? 'gzip';\n if (codec === 'none') return 0;\n\n const types: CompressionTypesMap | undefined = env?.Kafka?.CompressionTypes;\n if (types) {\n const lookup: Record<CompressionType, number> = {\n none: types.None,\n gzip: types.GZIP,\n snappy: types.Snappy,\n lz4: types.LZ4,\n zstd: types.ZSTD,\n };\n return lookup[codec] ?? types.GZIP;\n }\n\n return COMPRESSION_FALLBACK[codec] ?? 1;\n}\n\nexport function isKafkaEnv(env: unknown): env is Env {\n if (!isObject(env)) return false;\n const maybe = env as { Kafka?: { Kafka?: unknown } };\n return typeof maybe.Kafka?.Kafka === 'function';\n}\n","import type {\n PushFn,\n KafkaSettings,\n Env,\n ProducerMessage,\n ProducerRecord,\n KafkaProducerMock,\n} from './types';\nimport type { Collector } from '@walkeros/core';\nimport { getMappingValue, isObject, isString } from '@walkeros/core';\nimport { getCompressionType } from './config';\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, collector, env, logger },\n) {\n const settings = config.settings as { kafka?: KafkaSettings } | undefined;\n const kafka: KafkaSettings | undefined = settings?.kafka;\n\n if (!kafka) {\n logger.warn('Kafka settings missing');\n return;\n }\n\n const producer = kafka._producer;\n if (!producer) {\n logger.warn('Kafka producer not initialized');\n return;\n }\n\n // Derive event name (rule.name overrides)\n const eventName = isString(rule?.name) ? rule.name : event.name;\n\n // Derive topic: rule override -> destination default\n const ruleSettings = rule?.settings ?? {};\n const topic = isString(ruleSettings.topic) ? ruleSettings.topic : kafka.topic;\n\n // Derive message key\n const keyPath = isString(ruleSettings.key) ? ruleSettings.key : kafka.key;\n const key = await deriveKey(event, eventName, keyPath, collector);\n\n // Serialize message value: mapped data (when present) -> event\n const value =\n isObject(data) && Object.keys(data).length > 0\n ? JSON.stringify(data)\n : JSON.stringify(event);\n\n // Build headers\n const headers: Record<string, string> = {\n 'content-type': 'application/json',\n ...(kafka.headers ?? {}),\n };\n\n // Resolve compression codec via env lookup\n const envTyped = env as Env | undefined;\n const compression = getCompressionType(kafka.compression, envTyped);\n\n const message: ProducerMessage = {\n key,\n value,\n headers,\n timestamp: String(event.timestamp ?? Date.now()),\n };\n\n const record: ProducerRecord = {\n topic,\n messages: [message],\n acks: kafka.acks ?? -1,\n compression,\n };\n\n if (kafka.timeout !== undefined) record.timeout = kafka.timeout;\n\n logger.debug('Kafka push', { topic, key, event: eventName });\n\n try {\n await (producer as KafkaProducerMock).send(record);\n } catch (error) {\n logger.error('Kafka push failed', {\n topic,\n error: error instanceof Error ? error.message : String(error),\n event: eventName,\n });\n }\n};\n\nasync function deriveKey(\n event: Parameters<PushFn>[0],\n eventName: string,\n keyPath: string | undefined,\n collector: Collector.Instance,\n): Promise<string> {\n if (keyPath) {\n const resolved = await getMappingValue(event, keyPath, { collector });\n if (isString(resolved) && resolved.length > 0) return resolved;\n }\n // Default: event name with space replaced for partition-friendly keys.\n return eventName.replace(/\\s+/g, '_');\n}\n","import type { Destination as CoreDestination } from '@walkeros/core';\nimport type { DestinationServer } from '@walkeros/server-core';\n\n/**\n * Mock-friendly Producer interface used by the destination.\n * Tests provide this via env.Kafka; production creates a real\n * kafkajs Producer and adapts it through settings._producer.\n */\nexport interface KafkaProducerMock {\n connect: () => Promise<void>;\n disconnect: () => Promise<void>;\n send: (record: ProducerRecord) => Promise<unknown>;\n}\n\n/**\n * Mock-friendly Kafka client interface (subset of kafkajs.Kafka).\n */\nexport interface KafkaClientMock {\n producer: (config?: ProducerConfig) => KafkaProducerMock;\n}\n\n/**\n * Constructor signature for the Kafka client. Accepts a config\n * object and returns a client with producer() factory.\n */\nexport type KafkaClientConstructor = new (\n config: KafkaClientConfig,\n) => KafkaClientMock;\n\nexport interface KafkaClientConfig {\n clientId?: string;\n brokers: string[];\n ssl?: boolean | Record<string, unknown>;\n sasl?: SASLConfig;\n connectionTimeout?: number;\n requestTimeout?: number;\n retry?: RetryConfig;\n}\n\nexport interface ProducerConfig {\n allowAutoTopicCreation?: boolean;\n idempotent?: boolean;\n}\n\nexport interface ProducerRecord {\n topic: string;\n messages: ProducerMessage[];\n acks?: number;\n compression?: number;\n timeout?: number;\n}\n\nexport interface ProducerMessage {\n key?: string;\n value: string;\n headers?: Record<string, string>;\n timestamp?: string;\n partition?: number;\n}\n\nexport interface CompressionTypesMap {\n None: number;\n GZIP: number;\n Snappy: number;\n LZ4: number;\n ZSTD: number;\n}\n\nexport type CompressionType = 'none' | 'gzip' | 'snappy' | 'lz4' | 'zstd';\n\nexport interface SASLConfig {\n mechanism:\n | 'plain'\n | 'scram-sha-256'\n | 'scram-sha-512'\n | 'aws'\n | 'oauthbearer';\n username?: string;\n password?: string;\n accessKeyId?: string;\n secretAccessKey?: string;\n sessionToken?: string;\n authorizationIdentity?: string;\n}\n\nexport interface RetryConfig {\n maxRetryTime?: number;\n initialRetryTime?: number;\n retries?: number;\n}\n\nexport interface KafkaSettings {\n // Connection\n brokers: string[];\n clientId?: string;\n ssl?: boolean | Record<string, unknown>;\n sasl?: SASLConfig;\n connectionTimeout?: number;\n requestTimeout?: number;\n\n // Producer\n topic: string;\n acks?: number;\n timeout?: number;\n compression?: CompressionType;\n idempotent?: boolean;\n allowAutoTopicCreation?: boolean;\n\n // Message\n key?: string;\n headers?: Record<string, string>;\n\n // Advanced\n retry?: RetryConfig;\n\n // Runtime -- set during init, not user-facing\n _producer?: KafkaProducerMock;\n}\n\nexport interface Settings {\n kafka: KafkaSettings;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {\n /** Override message key mapping path for this rule. */\n key?: string;\n /** Override topic for this rule. */\n topic?: string;\n}\n\n/**\n * Env -- optional Kafka SDK override. Production leaves this undefined\n * and the destination creates real Kafka client instances. Tests provide\n * mocks via env.Kafka.\n */\nexport interface Env extends DestinationServer.Env {\n Kafka?: {\n Kafka: KafkaClientConstructor;\n CompressionTypes: CompressionTypesMap;\n };\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACUA,kBAAyB;AAGzB,IAAM,uBAAwD;AAAA,EAC5D,MAAM;AAAA,EACN,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,MAAM;AACR;AAEO,SAAS,UACd,gBAA+B,CAAC,GAChC,QACQ;AACR,QAAM,MAAO,cAAc,YAAY,CAAC;AACxC,QAAM,QACJ,IAAI,SAAU,CAAC;AAEjB,MAAI,CAAC,MAAM,WAAW,MAAM,QAAQ,WAAW,GAAG;AAChD,WAAO,MAAM,uCAAuC;AAAA,EACtD;AACA,MAAI,CAAC,MAAM,OAAO;AAChB,WAAO,MAAM,qCAAqC;AAAA,EACpD;AAEA,QAAM,gBAA+B;AAAA,IACnC,GAAG;AAAA,IACH,SAAS,MAAM;AAAA,IACf,OAAO,MAAM;AAAA,IACb,UAAU,MAAM,YAAY;AAAA,IAC5B,MAAM,MAAM,QAAQ;AAAA,IACpB,aAAa,MAAM,eAAe;AAAA,IAClC,YAAY,MAAM,cAAc;AAAA,IAChC,wBAAwB,MAAM,0BAA0B;AAAA,EAC1D;AAEA,QAAM,WAAqB,EAAE,OAAO,cAAc;AAElD,SAAO,EAAE,GAAG,eAAe,SAAS;AACtC;AAEO,SAAS,mBACd,aACA,KACQ;AACR,QAAM,QAAQ,eAAe;AAC7B,MAAI,UAAU,OAAQ,QAAO;AAE7B,QAAM,QAAyC,KAAK,OAAO;AAC3D,MAAI,OAAO;AACT,UAAM,SAA0C;AAAA,MAC9C,MAAM,MAAM;AAAA,MACZ,MAAM,MAAM;AAAA,MACZ,QAAQ,MAAM;AAAA,MACd,KAAK,MAAM;AAAA,MACX,MAAM,MAAM;AAAA,IACd;AACA,WAAO,OAAO,KAAK,KAAK,MAAM;AAAA,EAChC;AAEA,SAAO,qBAAqB,KAAK,KAAK;AACxC;AAEO,SAAS,WAAW,KAA0B;AACnD,MAAI,KAAC,sBAAS,GAAG,EAAG,QAAO;AAC3B,QAAM,QAAQ;AACd,SAAO,OAAO,MAAM,OAAO,UAAU;AACvC;;;ACrEA,IAAAA,eAAoD;AAG7C,IAAM,OAAe,eAC1B,OACA,EAAE,QAAQ,MAAM,MAAM,WAAW,KAAK,OAAO,GAC7C;AACA,QAAM,WAAW,OAAO;AACxB,QAAM,QAAmC,UAAU;AAEnD,MAAI,CAAC,OAAO;AACV,WAAO,KAAK,wBAAwB;AACpC;AAAA,EACF;AAEA,QAAM,WAAW,MAAM;AACvB,MAAI,CAAC,UAAU;AACb,WAAO,KAAK,gCAAgC;AAC5C;AAAA,EACF;AAGA,QAAM,gBAAY,uBAAS,MAAM,IAAI,IAAI,KAAK,OAAO,MAAM;AAG3D,QAAM,eAAe,MAAM,YAAY,CAAC;AACxC,QAAM,YAAQ,uBAAS,aAAa,KAAK,IAAI,aAAa,QAAQ,MAAM;AAGxE,QAAM,cAAU,uBAAS,aAAa,GAAG,IAAI,aAAa,MAAM,MAAM;AACtE,QAAM,MAAM,MAAM,UAAU,OAAO,WAAW,SAAS,SAAS;AAGhE,QAAM,YACJ,uBAAS,IAAI,KAAK,OAAO,KAAK,IAAI,EAAE,SAAS,IACzC,KAAK,UAAU,IAAI,IACnB,KAAK,UAAU,KAAK;AAG1B,QAAM,UAAkC;AAAA,IACtC,gBAAgB;AAAA,IAChB,GAAI,MAAM,WAAW,CAAC;AAAA,EACxB;AAGA,QAAM,WAAW;AACjB,QAAM,cAAc,mBAAmB,MAAM,aAAa,QAAQ;AAElE,QAAM,UAA2B;AAAA,IAC/B;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,OAAO,MAAM,aAAa,KAAK,IAAI,CAAC;AAAA,EACjD;AAEA,QAAM,SAAyB;AAAA,IAC7B;AAAA,IACA,UAAU,CAAC,OAAO;AAAA,IAClB,MAAM,MAAM,QAAQ;AAAA,IACpB;AAAA,EACF;AAEA,MAAI,MAAM,YAAY,OAAW,QAAO,UAAU,MAAM;AAExD,SAAO,MAAM,cAAc,EAAE,OAAO,KAAK,OAAO,UAAU,CAAC;AAE3D,MAAI;AACF,UAAO,SAA+B,KAAK,MAAM;AAAA,EACnD,SAAS,OAAO;AACd,WAAO,MAAM,qBAAqB;AAAA,MAChC;AAAA,MACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC5D,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACF;AAEA,eAAe,UACb,OACA,WACA,SACA,WACiB;AACjB,MAAI,SAAS;AACX,UAAM,WAAW,UAAM,8BAAgB,OAAO,SAAS,EAAE,UAAU,CAAC;AACpE,YAAI,uBAAS,QAAQ,KAAK,SAAS,SAAS,EAAG,QAAO;AAAA,EACxD;AAEA,SAAO,UAAU,QAAQ,QAAQ,GAAG;AACtC;;;AClGA;;;AHeO,IAAM,mBAAgC;AAAA,EAC3C,MAAM;AAAA,EAEN,QAAQ,CAAC;AAAA,EAET,MAAM,KAAK,EAAE,QAAQ,eAAe,QAAQ,IAAI,GAAG;AACjD,UAAM,SAAS,UAAU,eAAe,MAAM;AAC9C,UAAM,WAAW,OAAO;AACxB,UAAM,QAAQ,SAAS;AAGvB,QAAI,MAAM,UAAW,QAAO;AAE5B,QAAI;AAGJ,QAAI,WAAW,GAAG,GAAG;AACnB,YAAM,WAAW;AACjB,oBAAc,SAAS,OAAO;AAAA,IAChC;AAGA,QAAI,CAAC,aAAa;AAChB,UAAI;AAEF,cAAM,UAAU,QAAQ,SAAS;AAGjC,sBAAc,QAAQ;AAAA,MACxB,SAAS,KAAK;AACZ,eAAO,MAAM,2BAA2B,OAAO,GAAG,CAAC,EAAE;AACrD,eAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,eAAkC;AAAA,MACtC,UAAU,MAAM;AAAA,MAChB,SAAS,MAAM;AAAA,MACf,KAAK,MAAM;AAAA,MACX,MAAM,MAAM;AAAA,MACZ,mBAAmB,MAAM;AAAA,MACzB,gBAAgB,MAAM;AAAA,MACtB,OAAO,MAAM;AAAA,IACf;AAEA,UAAM,SAA0B,IAAI,YAAY,YAAY;AAE5D,UAAM,iBAAiC;AAAA,MACrC,wBAAwB,MAAM;AAAA,MAC9B,YAAY,MAAM;AAAA,IACpB;AAEA,UAAM,WAAW,OAAO,SAAS,cAAc;AAE/C,QAAI;AACF,YAAM,SAAS,QAAQ;AAAA,IACzB,SAAS,KAAK;AACZ,aAAO,MAAM,iCAAiC,EAAE,OAAO,OAAO,GAAG,EAAE,CAAC;AACpE,aAAO,MAAM,kCAAkC,OAAO,GAAG,CAAC,EAAE;AAC5D,aAAO;AAAA,IACT;AAEA,UAAM,YAAY;AAElB,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,KAAK,OAAO,SAAS;AACzB,WAAO,MAAM,KAAK,OAAO,OAAO;AAAA,EAClC;AAAA,EAEA,MAAM,QAAQ,EAAE,OAAO,GAAG;AACxB,UAAM,WAAW,QAAQ;AACzB,UAAM,WAAW,UAAU,OAAO;AAClC,QAAI,UAAU;AACZ,UAAI;AACF,cAAM,SAAS,WAAW;AAAA,MAC5B,UAAE;AACA,iBAAS,MAAM,YAAY;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,gBAAQ;","names":["import_core"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var e=(e=>"undefined"!=typeof require?require:"undefined"!=typeof Proxy?new Proxy(e,{get:(e,
|
|
1
|
+
var e=(e=>"undefined"!=typeof require?require:"undefined"!=typeof Proxy?new Proxy(e,{get:(e,t)=>("undefined"!=typeof require?require:e)[t]}):e)(function(e){if("undefined"!=typeof require)return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});import{isObject as t}from"@walkeros/core";var r={none:0,gzip:1,snappy:2,lz4:3,zstd:4};import{getMappingValue as o,isObject as n,isString as i}from"@walkeros/core";var a=async function(e,{config:t,rule:a,data:s,collector:c,env:f,logger:p}){const u=t.settings,k=u?.kafka;if(!k)return void p.warn("Kafka settings missing");const d=k._producer;if(!d)return void p.warn("Kafka producer not initialized");const l=i(a?.name)?a.name:e.name,g=a?.settings??{},y=i(g.topic)?g.topic:k.topic,m=i(g.key)?g.key:k.key,w=await async function(e,t,r,n){if(r){const t=await o(e,r,{collector:n});if(i(t)&&t.length>0)return t}return t.replace(/\s+/g,"_")}(e,l,m,c),h=n(s)&&Object.keys(s).length>0?JSON.stringify(s):JSON.stringify(e),v={"content-type":"application/json",...k.headers??{}},K=f,b=function(e,t){const o=e??"gzip";if("none"===o)return 0;const n=t?.Kafka?.CompressionTypes;if(n)return{none:n.None,gzip:n.GZIP,snappy:n.Snappy,lz4:n.LZ4,zstd:n.ZSTD}[o]??n.GZIP;return r[o]??1}(k.compression,K),T={topic:y,messages:[{key:w,value:h,headers:v,timestamp:String(e.timestamp??Date.now())}],acks:k.acks??-1,compression:b};void 0!==k.timeout&&(T.timeout=k.timeout),p.debug("Kafka push",{topic:y,key:w,event:l});try{await d.send(T)}catch(e){p.error("Kafka push failed",{topic:y,error:e instanceof Error?e.message:String(e),event:l})}};var s={},c={type:"kafka",config:{},async init({config:r,logger:o,env:n}){const i=function(e={},t){const r=(e.settings??{}).kafka??{};r.brokers&&0!==r.brokers.length||t.throw("Config settings kafka.brokers missing"),r.topic||t.throw("Config settings kafka.topic missing");const o={kafka:{...r,brokers:r.brokers,topic:r.topic,clientId:r.clientId??"walkeros",acks:r.acks??-1,compression:r.compression??"gzip",idempotent:r.idempotent??!1,allowAutoTopicCreation:r.allowAutoTopicCreation??!1}};return{...e,settings:o}}(r,o),a=i.settings.kafka;if(a._producer)return i;let s;if(function(e){if(!t(e))return!1;const r=e;return"function"==typeof r.Kafka?.Kafka}(n)){const e=n;s=e.Kafka?.Kafka}if(!s)try{s=e("kafkajs").Kafka}catch(e){return o.throw(`Failed to load kafkajs: ${String(e)}`),i}const c=new s({clientId:a.clientId,brokers:a.brokers,ssl:a.ssl,sasl:a.sasl,connectionTimeout:a.connectionTimeout,requestTimeout:a.requestTimeout,retry:a.retry}),f={allowAutoTopicCreation:a.allowAutoTopicCreation,idempotent:a.idempotent},p=c.producer(f);try{await p.connect()}catch(e){return o.error("Kafka producer connect failed",{error:String(e)}),o.throw(`Kafka producer connect failed: ${String(e)}`),i}return a._producer=p,i},push:async(e,t)=>await a(e,t),async destroy({config:e}){const t=e?.settings,r=t?.kafka?._producer;if(r)try{await r.disconnect()}finally{t.kafka._producer=void 0}}},f=c;export{s as DestinationKafka,f as default,c as destinationKafka};//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts","../src/push.ts","../src/types/index.ts","../src/index.ts"],"sourcesContent":["import type {\n Config,\n Settings,\n KafkaSettings,\n PartialConfig,\n Env,\n CompressionType,\n CompressionTypesMap,\n} from './types';\nimport type { Logger } from '@walkeros/core';\nimport { isObject } from '@walkeros/core';\n\n/** Fallback compression codec map when env is not provided. */\nconst COMPRESSION_FALLBACK: Record<CompressionType, number> = {\n none: 0,\n gzip: 1,\n snappy: 2,\n lz4: 3,\n zstd: 4,\n};\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): Config {\n const raw = (partialConfig.settings ?? {}) as Partial<Settings>;\n const kafka: Partial<KafkaSettings> =\n raw.kafka ?? ({} as Partial<KafkaSettings>);\n\n if (!kafka.brokers || kafka.brokers.length === 0) {\n logger.throw('Config settings kafka.brokers missing');\n }\n if (!kafka.topic) {\n logger.throw('Config settings kafka.topic missing');\n }\n\n const kafkaSettings: KafkaSettings = {\n ...kafka,\n brokers: kafka.brokers as string[],\n topic: kafka.topic as string,\n clientId: kafka.clientId ?? 'walkeros',\n acks: kafka.acks ?? -1,\n compression: kafka.compression ?? 'gzip',\n idempotent: kafka.idempotent ?? false,\n allowAutoTopicCreation: kafka.allowAutoTopicCreation ?? false,\n };\n\n const settings: Settings = { kafka: kafkaSettings };\n\n return { ...partialConfig, settings };\n}\n\nexport function getCompressionType(\n compression: CompressionType | undefined,\n env: Env | undefined,\n): number {\n const codec = compression ?? 'gzip';\n if (codec === 'none') return 0;\n\n const types: CompressionTypesMap | undefined = env?.Kafka?.CompressionTypes;\n if (types) {\n const lookup: Record<CompressionType, number> = {\n none: types.None,\n gzip: types.GZIP,\n snappy: types.Snappy,\n lz4: types.LZ4,\n zstd: types.ZSTD,\n };\n return lookup[codec] ?? types.GZIP;\n }\n\n return COMPRESSION_FALLBACK[codec] ?? 1;\n}\n\nexport function isKafkaEnv(env: unknown): env is Env {\n if (!isObject(env)) return false;\n const maybe = env as { Kafka?: { Kafka?: unknown } };\n return typeof maybe.Kafka?.Kafka === 'function';\n}\n","import type {\n PushFn,\n KafkaSettings,\n Env,\n ProducerMessage,\n ProducerRecord,\n KafkaProducerMock,\n} from './types';\nimport type { Collector } from '@walkeros/core';\nimport { getMappingValue, isObject, isString } from '@walkeros/core';\nimport { getCompressionType } from './config';\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, collector, env, logger },\n) {\n const settings = config.settings as { kafka?: KafkaSettings } | undefined;\n const kafka: KafkaSettings | undefined = settings?.kafka;\n\n if (!kafka) {\n logger.warn('Kafka settings missing');\n return;\n }\n\n const producer = kafka._producer;\n if (!producer) {\n logger.warn('Kafka producer not initialized');\n return;\n }\n\n // Derive event name (rule.name overrides)\n const eventName = isString(rule?.name) ? rule.name : event.name;\n\n // Derive topic: rule override -> destination default\n const ruleSettings = rule?.settings ?? {};\n const topic = isString(ruleSettings.topic) ? ruleSettings.topic : kafka.topic;\n\n // Derive message key\n const keyPath = isString(ruleSettings.key) ? ruleSettings.key : kafka.key;\n const key = await deriveKey(event, eventName, keyPath, collector);\n\n // Serialize message value: mapped data (when present) -> event\n const value =\n isObject(data) && Object.keys(data).length > 0\n ? JSON.stringify(data)\n : JSON.stringify(event);\n\n // Build headers\n const headers: Record<string, string> = {\n 'content-type': 'application/json',\n ...(kafka.headers ?? {}),\n };\n\n // Resolve compression codec via env lookup\n const envTyped = env as Env | undefined;\n const compression = getCompressionType(kafka.compression, envTyped);\n\n const message: ProducerMessage = {\n key,\n value,\n headers,\n timestamp: String(event.timestamp ?? Date.now()),\n };\n\n const record: ProducerRecord = {\n topic,\n messages: [message],\n acks: kafka.acks ?? -1,\n compression,\n };\n\n if (kafka.timeout !== undefined) record.timeout = kafka.timeout;\n\n logger.debug('Kafka push', { topic, key, event: eventName });\n\n try {\n await (producer as KafkaProducerMock).send(record);\n } catch (error) {\n logger.error('Kafka push failed', {\n topic,\n error: error instanceof Error ? error.message : String(error),\n event: eventName,\n });\n }\n};\n\nasync function deriveKey(\n event: Parameters<PushFn>[0],\n eventName: string,\n keyPath: string | undefined,\n collector: Collector.Instance,\n): Promise<string> {\n if (keyPath) {\n const resolved = await getMappingValue(event, keyPath, { collector });\n if (isString(resolved) && resolved.length > 0) return resolved;\n }\n // Default: event name with space replaced for partition-friendly keys.\n return eventName.replace(/\\s+/g, '_');\n}\n","import type { Destination as CoreDestination } from '@walkeros/core';\nimport type { DestinationServer } from '@walkeros/server-core';\n\n/**\n * Mock-friendly Producer interface used by the destination.\n * Tests provide this via env.Kafka; production creates a real\n * kafkajs Producer and adapts it through settings._producer.\n */\nexport interface KafkaProducerMock {\n connect: () => Promise<void>;\n disconnect: () => Promise<void>;\n send: (record: ProducerRecord) => Promise<unknown>;\n}\n\n/**\n * Mock-friendly Kafka client interface (subset of kafkajs.Kafka).\n */\nexport interface KafkaClientMock {\n producer: (config?: ProducerConfig) => KafkaProducerMock;\n}\n\n/**\n * Constructor signature for the Kafka client. Accepts a config\n * object and returns a client with producer() factory.\n */\nexport type KafkaClientConstructor = new (\n config: KafkaClientConfig,\n) => KafkaClientMock;\n\nexport interface KafkaClientConfig {\n clientId?: string;\n brokers: string[];\n ssl?: boolean | Record<string, unknown>;\n sasl?: SASLConfig;\n connectionTimeout?: number;\n requestTimeout?: number;\n retry?: RetryConfig;\n}\n\nexport interface ProducerConfig {\n allowAutoTopicCreation?: boolean;\n idempotent?: boolean;\n}\n\nexport interface ProducerRecord {\n topic: string;\n messages: ProducerMessage[];\n acks?: number;\n compression?: number;\n timeout?: number;\n}\n\nexport interface ProducerMessage {\n key?: string;\n value: string;\n headers?: Record<string, string>;\n timestamp?: string;\n partition?: number;\n}\n\nexport interface CompressionTypesMap {\n None: number;\n GZIP: number;\n Snappy: number;\n LZ4: number;\n ZSTD: number;\n}\n\nexport type CompressionType = 'none' | 'gzip' | 'snappy' | 'lz4' | 'zstd';\n\nexport interface SASLConfig {\n mechanism:\n | 'plain'\n | 'scram-sha-256'\n | 'scram-sha-512'\n | 'aws'\n | 'oauthbearer';\n username?: string;\n password?: string;\n accessKeyId?: string;\n secretAccessKey?: string;\n sessionToken?: string;\n authorizationIdentity?: string;\n}\n\nexport interface RetryConfig {\n maxRetryTime?: number;\n initialRetryTime?: number;\n retries?: number;\n}\n\nexport interface KafkaSettings {\n // Connection\n brokers: string[];\n clientId?: string;\n ssl?: boolean | Record<string, unknown>;\n sasl?: SASLConfig;\n connectionTimeout?: number;\n requestTimeout?: number;\n\n // Producer\n topic: string;\n acks?: number;\n timeout?: number;\n compression?: CompressionType;\n idempotent?: boolean;\n allowAutoTopicCreation?: boolean;\n\n // Message\n key?: string;\n headers?: Record<string, string>;\n\n // Advanced\n retry?: RetryConfig;\n\n // Runtime -- set during init, not user-facing\n _producer?: KafkaProducerMock;\n}\n\nexport interface Settings {\n kafka: KafkaSettings;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {\n /** Override message key mapping path for this rule. */\n key?: string;\n /** Override topic for this rule. */\n topic?: string;\n}\n\n/**\n * Env -- optional Kafka SDK override. Production leaves this undefined\n * and the destination creates real Kafka client instances. Tests provide\n * mocks via env.Kafka.\n */\nexport interface Env extends DestinationServer.Env {\n Kafka?: {\n Kafka: KafkaClientConstructor;\n CompressionTypes: CompressionTypesMap;\n };\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n","import type {\n Destination,\n Settings,\n Env,\n KafkaClientMock,\n KafkaClientConfig,\n KafkaClientConstructor,\n ProducerConfig,\n} from './types';\nimport { getConfig, isKafkaEnv } from './config';\nimport { push } from './push';\n\n// Types re-export\nexport * as DestinationKafka from './types';\n\nexport const destinationKafka: Destination = {\n type: 'kafka',\n\n config: {},\n\n async init({ config: partialConfig, logger, env }) {\n const config = getConfig(partialConfig, logger);\n const settings = config.settings as Settings;\n const kafka = settings.kafka;\n\n // Skip creation if a producer has already been wired in (testing).\n if (kafka._producer) return config;\n\n let Constructor: KafkaClientConstructor | undefined;\n\n // Prefer env-injected constructor (testing, dependency injection).\n if (isKafkaEnv(env)) {\n const envTyped = env as Env;\n Constructor = envTyped.Kafka?.Kafka;\n }\n\n // Production path: load real kafkajs SDK.\n if (!Constructor) {\n try {\n // Use dynamic require to allow tests to mock via jest.mock('kafkajs').\n const kafkajs = require('kafkajs') as {\n Kafka: KafkaClientConstructor;\n };\n Constructor = kafkajs.Kafka;\n } catch (err) {\n logger.throw(`Failed to load kafkajs: ${String(err)}`);\n return config;\n }\n }\n\n const clientConfig: KafkaClientConfig = {\n clientId: kafka.clientId,\n brokers: kafka.brokers,\n ssl: kafka.ssl,\n sasl: kafka.sasl,\n connectionTimeout: kafka.connectionTimeout,\n requestTimeout: kafka.requestTimeout,\n retry: kafka.retry,\n };\n\n const client: KafkaClientMock = new Constructor(clientConfig);\n\n const producerConfig: ProducerConfig = {\n allowAutoTopicCreation: kafka.allowAutoTopicCreation,\n idempotent: kafka.idempotent,\n };\n\n const producer = client.producer(producerConfig);\n\n try {\n await producer.connect();\n } catch (err) {\n logger.error('Kafka producer connect failed', { error: String(err) });\n logger.throw(`Kafka producer connect failed: ${String(err)}`);\n return config;\n }\n\n kafka._producer = producer;\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n async destroy({ config }) {\n const settings = config?.settings as Settings | undefined;\n const producer = settings?.kafka?._producer;\n if (producer) {\n try {\n await producer.disconnect();\n } finally {\n settings.kafka._producer = undefined;\n }\n }\n },\n};\n\nexport default destinationKafka;\n"],"mappings":"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","names":["isObject","isObject"]}
|
|
1
|
+
{"version":3,"sources":["../src/config.ts","../src/push.ts","../src/types/index.ts","../src/index.ts"],"sourcesContent":["import type {\n Config,\n Settings,\n KafkaSettings,\n PartialConfig,\n Env,\n CompressionType,\n CompressionTypesMap,\n} from './types';\nimport type { Logger } from '@walkeros/core';\nimport { isObject } from '@walkeros/core';\n\n/** Fallback compression codec map when env is not provided. */\nconst COMPRESSION_FALLBACK: Record<CompressionType, number> = {\n none: 0,\n gzip: 1,\n snappy: 2,\n lz4: 3,\n zstd: 4,\n};\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): Config {\n const raw = (partialConfig.settings ?? {}) as Partial<Settings>;\n const kafka: Partial<KafkaSettings> =\n raw.kafka ?? ({} as Partial<KafkaSettings>);\n\n if (!kafka.brokers || kafka.brokers.length === 0) {\n logger.throw('Config settings kafka.brokers missing');\n }\n if (!kafka.topic) {\n logger.throw('Config settings kafka.topic missing');\n }\n\n const kafkaSettings: KafkaSettings = {\n ...kafka,\n brokers: kafka.brokers as string[],\n topic: kafka.topic as string,\n clientId: kafka.clientId ?? 'walkeros',\n acks: kafka.acks ?? -1,\n compression: kafka.compression ?? 'gzip',\n idempotent: kafka.idempotent ?? false,\n allowAutoTopicCreation: kafka.allowAutoTopicCreation ?? false,\n };\n\n const settings: Settings = { kafka: kafkaSettings };\n\n return { ...partialConfig, settings };\n}\n\nexport function getCompressionType(\n compression: CompressionType | undefined,\n env: Env | undefined,\n): number {\n const codec = compression ?? 'gzip';\n if (codec === 'none') return 0;\n\n const types: CompressionTypesMap | undefined = env?.Kafka?.CompressionTypes;\n if (types) {\n const lookup: Record<CompressionType, number> = {\n none: types.None,\n gzip: types.GZIP,\n snappy: types.Snappy,\n lz4: types.LZ4,\n zstd: types.ZSTD,\n };\n return lookup[codec] ?? types.GZIP;\n }\n\n return COMPRESSION_FALLBACK[codec] ?? 1;\n}\n\nexport function isKafkaEnv(env: unknown): env is Env {\n if (!isObject(env)) return false;\n const maybe = env as { Kafka?: { Kafka?: unknown } };\n return typeof maybe.Kafka?.Kafka === 'function';\n}\n","import type {\n PushFn,\n KafkaSettings,\n Env,\n ProducerMessage,\n ProducerRecord,\n KafkaProducerMock,\n} from './types';\nimport type { Collector } from '@walkeros/core';\nimport { getMappingValue, isObject, isString } from '@walkeros/core';\nimport { getCompressionType } from './config';\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, collector, env, logger },\n) {\n const settings = config.settings as { kafka?: KafkaSettings } | undefined;\n const kafka: KafkaSettings | undefined = settings?.kafka;\n\n if (!kafka) {\n logger.warn('Kafka settings missing');\n return;\n }\n\n const producer = kafka._producer;\n if (!producer) {\n logger.warn('Kafka producer not initialized');\n return;\n }\n\n // Derive event name (rule.name overrides)\n const eventName = isString(rule?.name) ? rule.name : event.name;\n\n // Derive topic: rule override -> destination default\n const ruleSettings = rule?.settings ?? {};\n const topic = isString(ruleSettings.topic) ? ruleSettings.topic : kafka.topic;\n\n // Derive message key\n const keyPath = isString(ruleSettings.key) ? ruleSettings.key : kafka.key;\n const key = await deriveKey(event, eventName, keyPath, collector);\n\n // Serialize message value: mapped data (when present) -> event\n const value =\n isObject(data) && Object.keys(data).length > 0\n ? JSON.stringify(data)\n : JSON.stringify(event);\n\n // Build headers\n const headers: Record<string, string> = {\n 'content-type': 'application/json',\n ...(kafka.headers ?? {}),\n };\n\n // Resolve compression codec via env lookup\n const envTyped = env as Env | undefined;\n const compression = getCompressionType(kafka.compression, envTyped);\n\n const message: ProducerMessage = {\n key,\n value,\n headers,\n timestamp: String(event.timestamp ?? Date.now()),\n };\n\n const record: ProducerRecord = {\n topic,\n messages: [message],\n acks: kafka.acks ?? -1,\n compression,\n };\n\n if (kafka.timeout !== undefined) record.timeout = kafka.timeout;\n\n logger.debug('Kafka push', { topic, key, event: eventName });\n\n try {\n await (producer as KafkaProducerMock).send(record);\n } catch (error) {\n logger.error('Kafka push failed', {\n topic,\n error: error instanceof Error ? error.message : String(error),\n event: eventName,\n });\n }\n};\n\nasync function deriveKey(\n event: Parameters<PushFn>[0],\n eventName: string,\n keyPath: string | undefined,\n collector: Collector.Instance,\n): Promise<string> {\n if (keyPath) {\n const resolved = await getMappingValue(event, keyPath, { collector });\n if (isString(resolved) && resolved.length > 0) return resolved;\n }\n // Default: event name with space replaced for partition-friendly keys.\n return eventName.replace(/\\s+/g, '_');\n}\n","import type { Destination as CoreDestination } from '@walkeros/core';\nimport type { DestinationServer } from '@walkeros/server-core';\n\n/**\n * Mock-friendly Producer interface used by the destination.\n * Tests provide this via env.Kafka; production creates a real\n * kafkajs Producer and adapts it through settings._producer.\n */\nexport interface KafkaProducerMock {\n connect: () => Promise<void>;\n disconnect: () => Promise<void>;\n send: (record: ProducerRecord) => Promise<unknown>;\n}\n\n/**\n * Mock-friendly Kafka client interface (subset of kafkajs.Kafka).\n */\nexport interface KafkaClientMock {\n producer: (config?: ProducerConfig) => KafkaProducerMock;\n}\n\n/**\n * Constructor signature for the Kafka client. Accepts a config\n * object and returns a client with producer() factory.\n */\nexport type KafkaClientConstructor = new (\n config: KafkaClientConfig,\n) => KafkaClientMock;\n\nexport interface KafkaClientConfig {\n clientId?: string;\n brokers: string[];\n ssl?: boolean | Record<string, unknown>;\n sasl?: SASLConfig;\n connectionTimeout?: number;\n requestTimeout?: number;\n retry?: RetryConfig;\n}\n\nexport interface ProducerConfig {\n allowAutoTopicCreation?: boolean;\n idempotent?: boolean;\n}\n\nexport interface ProducerRecord {\n topic: string;\n messages: ProducerMessage[];\n acks?: number;\n compression?: number;\n timeout?: number;\n}\n\nexport interface ProducerMessage {\n key?: string;\n value: string;\n headers?: Record<string, string>;\n timestamp?: string;\n partition?: number;\n}\n\nexport interface CompressionTypesMap {\n None: number;\n GZIP: number;\n Snappy: number;\n LZ4: number;\n ZSTD: number;\n}\n\nexport type CompressionType = 'none' | 'gzip' | 'snappy' | 'lz4' | 'zstd';\n\nexport interface SASLConfig {\n mechanism:\n | 'plain'\n | 'scram-sha-256'\n | 'scram-sha-512'\n | 'aws'\n | 'oauthbearer';\n username?: string;\n password?: string;\n accessKeyId?: string;\n secretAccessKey?: string;\n sessionToken?: string;\n authorizationIdentity?: string;\n}\n\nexport interface RetryConfig {\n maxRetryTime?: number;\n initialRetryTime?: number;\n retries?: number;\n}\n\nexport interface KafkaSettings {\n // Connection\n brokers: string[];\n clientId?: string;\n ssl?: boolean | Record<string, unknown>;\n sasl?: SASLConfig;\n connectionTimeout?: number;\n requestTimeout?: number;\n\n // Producer\n topic: string;\n acks?: number;\n timeout?: number;\n compression?: CompressionType;\n idempotent?: boolean;\n allowAutoTopicCreation?: boolean;\n\n // Message\n key?: string;\n headers?: Record<string, string>;\n\n // Advanced\n retry?: RetryConfig;\n\n // Runtime -- set during init, not user-facing\n _producer?: KafkaProducerMock;\n}\n\nexport interface Settings {\n kafka: KafkaSettings;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {\n /** Override message key mapping path for this rule. */\n key?: string;\n /** Override topic for this rule. */\n topic?: string;\n}\n\n/**\n * Env -- optional Kafka SDK override. Production leaves this undefined\n * and the destination creates real Kafka client instances. Tests provide\n * mocks via env.Kafka.\n */\nexport interface Env extends DestinationServer.Env {\n Kafka?: {\n Kafka: KafkaClientConstructor;\n CompressionTypes: CompressionTypesMap;\n };\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n","import type {\n Destination,\n Settings,\n Env,\n KafkaClientMock,\n KafkaClientConfig,\n KafkaClientConstructor,\n ProducerConfig,\n} from './types';\nimport { getConfig, isKafkaEnv } from './config';\nimport { push } from './push';\n\n// Types re-export\nexport * as DestinationKafka from './types';\n\nexport const destinationKafka: Destination = {\n type: 'kafka',\n\n config: {},\n\n async init({ config: partialConfig, logger, env }) {\n const config = getConfig(partialConfig, logger);\n const settings = config.settings as Settings;\n const kafka = settings.kafka;\n\n // Skip creation if a producer has already been wired in (testing).\n if (kafka._producer) return config;\n\n let Constructor: KafkaClientConstructor | undefined;\n\n // Prefer env-injected constructor (testing, dependency injection).\n if (isKafkaEnv(env)) {\n const envTyped = env as Env;\n Constructor = envTyped.Kafka?.Kafka;\n }\n\n // Production path: load real kafkajs SDK.\n if (!Constructor) {\n try {\n // Use dynamic require to allow tests to mock via jest.mock('kafkajs').\n const kafkajs = require('kafkajs') as {\n Kafka: KafkaClientConstructor;\n };\n Constructor = kafkajs.Kafka;\n } catch (err) {\n logger.throw(`Failed to load kafkajs: ${String(err)}`);\n return config;\n }\n }\n\n const clientConfig: KafkaClientConfig = {\n clientId: kafka.clientId,\n brokers: kafka.brokers,\n ssl: kafka.ssl,\n sasl: kafka.sasl,\n connectionTimeout: kafka.connectionTimeout,\n requestTimeout: kafka.requestTimeout,\n retry: kafka.retry,\n };\n\n const client: KafkaClientMock = new Constructor(clientConfig);\n\n const producerConfig: ProducerConfig = {\n allowAutoTopicCreation: kafka.allowAutoTopicCreation,\n idempotent: kafka.idempotent,\n };\n\n const producer = client.producer(producerConfig);\n\n try {\n await producer.connect();\n } catch (err) {\n logger.error('Kafka producer connect failed', { error: String(err) });\n logger.throw(`Kafka producer connect failed: ${String(err)}`);\n return config;\n }\n\n kafka._producer = producer;\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n async destroy({ config }) {\n const settings = config?.settings as Settings | undefined;\n const producer = settings?.kafka?._producer;\n if (producer) {\n try {\n await producer.disconnect();\n } finally {\n settings.kafka._producer = undefined;\n }\n }\n },\n};\n\nexport default destinationKafka;\n"],"mappings":"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","names":["isObject","isObject"]}
|
package/dist/walkerOS.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$meta": {
|
|
3
3
|
"package": "@walkeros/server-destination-kafka",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "4.0.0-next-1777882869103",
|
|
5
5
|
"type": "destination",
|
|
6
6
|
"platform": [
|
|
7
7
|
"server"
|
|
@@ -263,35 +263,21 @@
|
|
|
263
263
|
"entity": "child",
|
|
264
264
|
"data": {
|
|
265
265
|
"is": "subordinated"
|
|
266
|
-
},
|
|
267
|
-
"nested": [],
|
|
268
|
-
"context": {
|
|
269
|
-
"element": [
|
|
270
|
-
"child",
|
|
271
|
-
0
|
|
272
|
-
]
|
|
273
266
|
}
|
|
274
267
|
}
|
|
275
268
|
],
|
|
276
269
|
"consent": {
|
|
277
270
|
"functional": true
|
|
278
271
|
},
|
|
279
|
-
"id": "
|
|
272
|
+
"id": "a2c2db697e566658",
|
|
280
273
|
"trigger": "load",
|
|
281
274
|
"entity": "page",
|
|
282
275
|
"action": "view",
|
|
283
276
|
"timestamp": 1700000100,
|
|
284
277
|
"timing": 3.14,
|
|
285
|
-
"group": "gr0up",
|
|
286
|
-
"count": 1,
|
|
287
|
-
"version": {
|
|
288
|
-
"source": "3.4.2",
|
|
289
|
-
"tagging": 1
|
|
290
|
-
},
|
|
291
278
|
"source": {
|
|
292
|
-
"type": "
|
|
293
|
-
"
|
|
294
|
-
"previous_id": "http://remotehost:9001"
|
|
279
|
+
"type": "collector",
|
|
280
|
+
"schema": "4"
|
|
295
281
|
}
|
|
296
282
|
},
|
|
297
283
|
"out": [
|
|
@@ -351,35 +337,21 @@
|
|
|
351
337
|
"entity": "child",
|
|
352
338
|
"data": {
|
|
353
339
|
"is": "subordinated"
|
|
354
|
-
},
|
|
355
|
-
"nested": [],
|
|
356
|
-
"context": {
|
|
357
|
-
"element": [
|
|
358
|
-
"child",
|
|
359
|
-
0
|
|
360
|
-
]
|
|
361
340
|
}
|
|
362
341
|
}
|
|
363
342
|
],
|
|
364
343
|
"consent": {
|
|
365
344
|
"functional": true
|
|
366
345
|
},
|
|
367
|
-
"id": "
|
|
346
|
+
"id": "460e8cd75b7b4268",
|
|
368
347
|
"trigger": "test",
|
|
369
348
|
"entity": "debug",
|
|
370
349
|
"action": "noise",
|
|
371
350
|
"timestamp": 1700000105,
|
|
372
351
|
"timing": 3.14,
|
|
373
|
-
"group": "gr0up",
|
|
374
|
-
"count": 1,
|
|
375
|
-
"version": {
|
|
376
|
-
"source": "3.4.2",
|
|
377
|
-
"tagging": 1
|
|
378
|
-
},
|
|
379
352
|
"source": {
|
|
380
|
-
"type": "
|
|
381
|
-
"
|
|
382
|
-
"previous_id": "http://remotehost:9001"
|
|
353
|
+
"type": "collector",
|
|
354
|
+
"schema": "4"
|
|
383
355
|
}
|
|
384
356
|
},
|
|
385
357
|
"mapping": {
|
|
@@ -415,35 +387,21 @@
|
|
|
415
387
|
"entity": "child",
|
|
416
388
|
"data": {
|
|
417
389
|
"is": "subordinated"
|
|
418
|
-
},
|
|
419
|
-
"nested": [],
|
|
420
|
-
"context": {
|
|
421
|
-
"element": [
|
|
422
|
-
"child",
|
|
423
|
-
0
|
|
424
|
-
]
|
|
425
390
|
}
|
|
426
391
|
}
|
|
427
392
|
],
|
|
428
393
|
"consent": {
|
|
429
394
|
"functional": true
|
|
430
395
|
},
|
|
431
|
-
"id": "
|
|
396
|
+
"id": "ad8e6be83c09c751",
|
|
432
397
|
"trigger": "test",
|
|
433
398
|
"entity": "user",
|
|
434
399
|
"action": "signup",
|
|
435
400
|
"timestamp": 1700000103,
|
|
436
401
|
"timing": 3.14,
|
|
437
|
-
"group": "gr0up",
|
|
438
|
-
"count": 1,
|
|
439
|
-
"version": {
|
|
440
|
-
"source": "3.4.2",
|
|
441
|
-
"tagging": 1
|
|
442
|
-
},
|
|
443
402
|
"source": {
|
|
444
|
-
"type": "
|
|
445
|
-
"
|
|
446
|
-
"previous_id": "http://remotehost:9001"
|
|
403
|
+
"type": "collector",
|
|
404
|
+
"schema": "4"
|
|
447
405
|
}
|
|
448
406
|
},
|
|
449
407
|
"settings": {
|
|
@@ -554,22 +512,15 @@
|
|
|
554
512
|
"consent": {
|
|
555
513
|
"functional": true
|
|
556
514
|
},
|
|
557
|
-
"id": "
|
|
515
|
+
"id": "9dedfdd16ff1311b",
|
|
558
516
|
"trigger": "load",
|
|
559
517
|
"entity": "order",
|
|
560
518
|
"action": "complete",
|
|
561
519
|
"timestamp": 1700000102,
|
|
562
520
|
"timing": 3.14,
|
|
563
|
-
"group": "gr0up",
|
|
564
|
-
"count": 1,
|
|
565
|
-
"version": {
|
|
566
|
-
"source": "3.4.2",
|
|
567
|
-
"tagging": 1
|
|
568
|
-
},
|
|
569
521
|
"source": {
|
|
570
|
-
"type": "
|
|
571
|
-
"
|
|
572
|
-
"previous_id": "http://remotehost:9001"
|
|
522
|
+
"type": "collector",
|
|
523
|
+
"schema": "4"
|
|
573
524
|
}
|
|
574
525
|
},
|
|
575
526
|
"mapping": {
|
|
@@ -683,22 +634,15 @@
|
|
|
683
634
|
"consent": {
|
|
684
635
|
"functional": true
|
|
685
636
|
},
|
|
686
|
-
"id": "
|
|
637
|
+
"id": "9dadb68d4af0d4f2",
|
|
687
638
|
"trigger": "load",
|
|
688
639
|
"entity": "order",
|
|
689
640
|
"action": "complete",
|
|
690
641
|
"timestamp": 1700000101,
|
|
691
642
|
"timing": 3.14,
|
|
692
|
-
"group": "gr0up",
|
|
693
|
-
"count": 1,
|
|
694
|
-
"version": {
|
|
695
|
-
"source": "3.4.2",
|
|
696
|
-
"tagging": 1
|
|
697
|
-
},
|
|
698
643
|
"source": {
|
|
699
|
-
"type": "
|
|
700
|
-
"
|
|
701
|
-
"previous_id": "http://remotehost:9001"
|
|
644
|
+
"type": "collector",
|
|
645
|
+
"schema": "4"
|
|
702
646
|
}
|
|
703
647
|
},
|
|
704
648
|
"mapping": {
|
|
@@ -802,22 +746,15 @@
|
|
|
802
746
|
"consent": {
|
|
803
747
|
"functional": true
|
|
804
748
|
},
|
|
805
|
-
"id": "
|
|
749
|
+
"id": "aa3829b489ae88f6",
|
|
806
750
|
"trigger": "load",
|
|
807
751
|
"entity": "order",
|
|
808
752
|
"action": "complete",
|
|
809
753
|
"timestamp": 1700000104,
|
|
810
754
|
"timing": 3.14,
|
|
811
|
-
"group": "gr0up",
|
|
812
|
-
"count": 1,
|
|
813
|
-
"version": {
|
|
814
|
-
"source": "3.4.2",
|
|
815
|
-
"tagging": 1
|
|
816
|
-
},
|
|
817
755
|
"source": {
|
|
818
|
-
"type": "
|
|
819
|
-
"
|
|
820
|
-
"previous_id": "http://remotehost:9001"
|
|
756
|
+
"type": "collector",
|
|
757
|
+
"schema": "4"
|
|
821
758
|
}
|
|
822
759
|
},
|
|
823
760
|
"mapping": {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walkeros/server-destination-kafka",
|
|
3
3
|
"description": "Apache Kafka server destination for walkerOS (kafkajs, JSON serialization, GZIP compression)",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "4.0.0-next-1777882869103",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
@@ -35,11 +35,11 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"kafkajs": "^2.2.4",
|
|
38
|
-
"@walkeros/core": "
|
|
39
|
-
"@walkeros/server-core": "
|
|
38
|
+
"@walkeros/core": "4.0.0-next-1777882869103",
|
|
39
|
+
"@walkeros/server-core": "4.0.0-next-1777882869103"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@walkeros/collector": "
|
|
42
|
+
"@walkeros/collector": "4.0.0-next-1777882869103"
|
|
43
43
|
},
|
|
44
44
|
"repository": {
|
|
45
45
|
"url": "git+https://github.com/elbwalker/walkerOS.git",
|