{"version":3,"sources":["../src/config.ts","../src/push.ts","../src/schemaRegistry.ts","../src/setup.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\nconst UNKNOWN_TOPIC_CODE = 3;\nconst UNKNOWN_TOPIC_TYPE = 'UNKNOWN_TOPIC_OR_PARTITION';\n\nfunction hasCodeOrType(\n  err: unknown,\n): err is { code?: unknown; type?: unknown } {\n  return (\n    typeof err === 'object' && err !== null && ('code' in err || 'type' in err)\n  );\n}\n\nfunction isUnknownTopicError(err: unknown): boolean {\n  if (!hasCodeOrType(err)) return false;\n  return err.code === UNKNOWN_TOPIC_CODE || err.type === UNKNOWN_TOPIC_TYPE;\n}\n\nexport const push: PushFn = async function (\n  event,\n  { config, rule, data, collector, env, logger, id },\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    if (isUnknownTopicError(error)) {\n      const brokers = (kafka.brokers ?? []).join(',');\n      logger.error(\n        `Kafka topic \"${topic}\" not found on cluster ${brokers}. ` +\n          `Run \"walkeros setup destination.${id}\" with explicit ` +\n          `{ numPartitions, replicationFactor } to create it.`,\n        {\n          topic,\n          brokers,\n          event: eventName,\n          originalError: error instanceof Error ? error.message : String(error),\n        },\n      );\n    } else {\n      logger.error('Kafka push failed', {\n        topic,\n        error: error instanceof Error ? error.message : String(error),\n        event: eventName,\n      });\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","// schemaRegistry.ts\nimport type { Logger } from '@walkeros/core';\nimport type { SchemaRegistrySetup } from './types';\n\n/**\n * Register a schema with a Confluent-compatible Schema Registry.\n *\n * Idempotent:\n * - POST returns 2xx on first registration.\n * - POST returns 409 if a compatible version already exists; treated as\n *   success (idempotent re-runs).\n *\n * If `compatibility` is set, sets the per-subject compatibility level via\n * PUT /config/<subject>.\n */\nexport async function registerSchema(\n  options: SchemaRegistrySetup,\n  logger: Logger.Instance,\n): Promise<boolean> {\n  const { url, subject, schema, schemaType, compatibility, auth } = options;\n  const base = url.replace(/\\/$/, '');\n  const headers = buildHeaders(auth);\n\n  const postUrl = `${base}/subjects/${encodeURIComponent(subject)}/versions`;\n  const postRes = await fetch(postUrl, {\n    method: 'POST',\n    headers: {\n      ...headers,\n      'Content-Type': 'application/vnd.schemaregistry.v1+json',\n    },\n    body: JSON.stringify({ schema, schemaType }),\n  });\n\n  if (postRes.status === 409) {\n    logger.debug('setup: schema already registered (409)', { subject });\n  } else if (!postRes.ok) {\n    const text = await postRes.text();\n    throw new Error(\n      `Schema Registry POST failed: ${postRes.status} ${postRes.statusText} ${text}`,\n    );\n  } else {\n    logger.info('setup: schema registered', { subject });\n  }\n\n  if (compatibility) {\n    const putUrl = `${base}/config/${encodeURIComponent(subject)}`;\n    const putRes = await fetch(putUrl, {\n      method: 'PUT',\n      headers: {\n        ...headers,\n        'Content-Type': 'application/vnd.schemaregistry.v1+json',\n      },\n      body: JSON.stringify({ compatibility }),\n    });\n    if (!putRes.ok) {\n      const text = await putRes.text();\n      throw new Error(\n        `Schema Registry PUT /config failed: ${putRes.status} ${putRes.statusText} ${text}`,\n      );\n    }\n    logger.info('setup: compatibility set', { subject, compatibility });\n  }\n\n  return true;\n}\n\nfunction buildHeaders(\n  auth: SchemaRegistrySetup['auth'],\n): Record<string, string> {\n  if (!auth) return {};\n  const token = Buffer.from(`${auth.username}:${auth.password}`).toString(\n    'base64',\n  );\n  return { Authorization: `Basic ${token}` };\n}\n","// setup.ts\n//\n// Provision a Kafka topic idempotently. Triggered only by `walkeros setup\n// destination.<id>`. Never auto-runs.\n//\n// NO SAFE DEFAULTS for `numPartitions` or `replicationFactor`: these are\n// cluster-specific operational decisions and depend on broker count,\n// expected throughput, and consumer parallelism. The boolean form\n// (setup: true) is rejected at runtime; only the object form is valid.\nimport type { DestinationServer } from '@walkeros/server-core';\nimport type { LifecycleContext, Logger } from '@walkeros/core';\nimport type {\n  Env,\n  KafkaAdminMock,\n  KafkaClientConstructor,\n  Setup,\n  Types,\n} from './types';\nimport { isKafkaEnv } from './config';\nimport { registerSchema } from './schemaRegistry';\n\ntype WideConfig = DestinationServer.Config<Types>;\n\nexport interface SetupResult {\n  topicCreated: boolean;\n  schemaRegistered: boolean;\n}\n\nconst TOPIC_ALREADY_EXISTS_CODE = 36;\nconst TOPIC_ALREADY_EXISTS_TYPE = 'TopicAlreadyExistsError';\nconst CONFIG_RESOURCE_TYPE_TOPIC = 2;\n\n/**\n * Provision a Kafka topic idempotently.\n *\n * NO SAFE DEFAULTS for `numPartitions` or `replicationFactor`.\n * `setup: true` is rejected at runtime; only the object form is valid.\n */\nexport async function setup(\n  ctx: LifecycleContext<WideConfig, Env>,\n): Promise<SetupResult> {\n  const { config, env, logger } = ctx;\n\n  // The focal idiom of this package: NO SAFE DEFAULTS.\n  if (config.setup === true) {\n    throw new Error(\n      'kafka destination setup requires explicit options: ' +\n        '{ topic, numPartitions, replicationFactor }. ' +\n        'There is no safe default for partition count or replication factor, ' +\n        'these depend on your cluster topology. ' +\n        'See https://www.walkeros.io/docs/destinations/server/kafka#setup for guidance.',\n    );\n  }\n\n  if (!config.setup || typeof config.setup !== 'object') {\n    // setup is false or unset; the CLI should have skipped before reaching here.\n    // Defensive return so direct callers do not accidentally provision.\n    return { topicCreated: false, schemaRegistered: false };\n  }\n\n  const options: Setup = config.setup;\n\n  // Required field validation, with actionable messages.\n  if (typeof options.numPartitions !== 'number') {\n    throw new Error(\n      'kafka setup: `numPartitions` is required. No safe default. ' +\n        'Choose based on expected throughput and consumer parallelism.',\n    );\n  }\n  if (typeof options.replicationFactor !== 'number') {\n    const brokerList = config.settings?.kafka?.brokers?.join(',') ?? 'unknown';\n    throw new Error(\n      'kafka setup: `replicationFactor` is required. No safe default. ' +\n        'Must be <= broker count for cluster <' +\n        brokerList +\n        '>.',\n    );\n  }\n\n  const topic = options.topic || config.settings?.kafka?.topic;\n  if (!topic) {\n    throw new Error(\n      'kafka setup: topic is required (in `setup.topic` or `settings.kafka.topic`).',\n    );\n  }\n\n  const brokers = config.settings?.kafka?.brokers;\n  if (!brokers || brokers.length === 0) {\n    throw new Error(\n      'kafka setup: `settings.kafka.brokers` is required to reach the cluster.',\n    );\n  }\n\n  const numPartitions = options.numPartitions;\n  const replicationFactor = options.replicationFactor;\n\n  // Construct a kafkajs client (env-injected for tests; real SDK in production).\n  const Constructor = resolveKafkaConstructor(env, logger);\n  const client = new Constructor({\n    clientId: config.settings?.kafka?.clientId ?? 'walkeros-setup',\n    brokers,\n    ssl: config.settings?.kafka?.ssl,\n    sasl: config.settings?.kafka?.sasl,\n  });\n\n  const admin = client.admin();\n  await admin.connect();\n\n  let topicCreated = false;\n  try {\n    const validateOnly = options.validateOnly ?? false;\n    const configEntries = options.configEntries\n      ? Object.entries(options.configEntries).map(([name, value]) => ({\n          name,\n          value,\n        }))\n      : undefined;\n\n    try {\n      const created = await admin.createTopics({\n        topics: [\n          {\n            topic,\n            numPartitions,\n            replicationFactor,\n            ...(configEntries ? { configEntries } : {}),\n          },\n        ],\n        validateOnly,\n      });\n      topicCreated = created === true && !validateOnly;\n      if (validateOnly) {\n        logger.info('setup: validateOnly mode, no topic created', { topic });\n      } else if (topicCreated) {\n        logger.info('setup: topic created', {\n          topic,\n          numPartitions,\n          replicationFactor,\n        });\n      } else {\n        logger.debug(\n          'setup: topic already exists (createTopics returned false)',\n          { topic },\n        );\n      }\n    } catch (err) {\n      if (isAlreadyExists(err)) {\n        logger.debug('setup: topic already exists (race)', { topic });\n      } else {\n        throw err;\n      }\n    }\n\n    // Drift detection only when the topic is real (not validateOnly).\n    if (!validateOnly) {\n      await detectDrift(\n        admin,\n        topic,\n        {\n          numPartitions,\n          replicationFactor,\n          configEntries: options.configEntries,\n        },\n        logger,\n      );\n    }\n\n    // Schema registry (optional).\n    let schemaRegistered = false;\n    if (options.schemaRegistry) {\n      schemaRegistered = await registerSchema(options.schemaRegistry, logger);\n    }\n\n    return { topicCreated, schemaRegistered };\n  } finally {\n    await admin.disconnect();\n  }\n}\n\nfunction resolveKafkaConstructor(\n  env: Env,\n  logger: Logger.Instance,\n): KafkaClientConstructor {\n  if (isKafkaEnv(env) && env.Kafka?.Kafka) {\n    return env.Kafka.Kafka;\n  }\n  try {\n    const kafkajs: { Kafka: KafkaClientConstructor } = require('kafkajs');\n    return kafkajs.Kafka;\n  } catch (err) {\n    logger.throw(`Failed to load kafkajs: ${String(err)}`);\n    // logger.throw is `never`; this line is unreachable but satisfies TS.\n    throw err;\n  }\n}\n\nfunction isAlreadyExists(err: unknown): boolean {\n  if (typeof err !== 'object' || err === null) return false;\n  const obj: { code?: unknown; type?: unknown } = err;\n  if (obj.code === TOPIC_ALREADY_EXISTS_CODE) return true;\n  if (obj.type === TOPIC_ALREADY_EXISTS_TYPE) return true;\n  return false;\n}\n\ninterface DriftDeclared {\n  numPartitions: number;\n  replicationFactor: number;\n  configEntries?: Record<string, string>;\n}\n\nasync function detectDrift(\n  admin: KafkaAdminMock,\n  topic: string,\n  declared: DriftDeclared,\n  logger: Logger.Instance,\n): Promise<void> {\n  // Partition count + replication factor from fetchTopicMetadata.\n  try {\n    const meta = await admin.fetchTopicMetadata({ topics: [topic] });\n    const t = meta.topics[0];\n    if (t) {\n      const actualPartitions = t.partitions.length;\n      if (actualPartitions !== declared.numPartitions) {\n        logger.warn('setup.drift', {\n          field: 'numPartitions',\n          declared: declared.numPartitions,\n          actual: actualPartitions,\n        });\n      }\n      const actualReplication = t.partitions[0]?.replicas.length ?? 0;\n      if (actualReplication !== declared.replicationFactor) {\n        logger.warn('setup.drift', {\n          field: 'replicationFactor',\n          declared: declared.replicationFactor,\n          actual: actualReplication,\n        });\n      }\n    }\n  } catch (err) {\n    logger.debug('setup: drift check (metadata) failed (non-fatal)', {\n      error: err instanceof Error ? err.message : String(err),\n    });\n  }\n\n  // configEntries drift, granular per-key.\n  if (\n    declared.configEntries &&\n    Object.keys(declared.configEntries).length > 0\n  ) {\n    try {\n      const cfg = await admin.describeConfigs({\n        resources: [{ type: CONFIG_RESOURCE_TYPE_TOPIC, name: topic }],\n      });\n      const actualEntries = cfg.resources[0]?.configEntries ?? [];\n      const actualMap = new Map(\n        actualEntries.map((e) => [e.configName, e.configValue]),\n      );\n      for (const [key, declaredValue] of Object.entries(\n        declared.configEntries,\n      )) {\n        const actual = actualMap.get(key);\n        if (actual !== declaredValue) {\n          logger.warn('setup.drift', {\n            field: `configEntries.${key}`,\n            declared: declaredValue,\n            actual: actual ?? null,\n          });\n        }\n      }\n    } catch (err) {\n      logger.debug('setup: drift check (configs) failed (non-fatal)', {\n        error: err instanceof Error ? err.message : String(err),\n      });\n    }\n  }\n}\n","import type {\n  Destination as CoreDestination,\n  SetupFn as CoreSetupFn,\n} 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 Admin interface used by setup (subset of kafkajs.Admin).\n * Tests provide this via env.Kafka; production creates a real\n * kafkajs Admin client.\n */\nexport interface KafkaAdminMock {\n  connect: () => Promise<void>;\n  disconnect: () => Promise<void>;\n  createTopics: (args: {\n    topics: Array<{\n      topic: string;\n      numPartitions: number;\n      replicationFactor: number;\n      configEntries?: Array<{ name: string; value: string }>;\n    }>;\n    validateOnly?: boolean;\n    waitForLeaders?: boolean;\n    timeout?: number;\n  }) => Promise<boolean>;\n  fetchTopicMetadata: (args: { topics?: string[] }) => Promise<{\n    topics: Array<{\n      name: string;\n      partitions: Array<{\n        partitionId: number;\n        leader: number;\n        replicas: number[];\n        isr: number[];\n      }>;\n    }>;\n  }>;\n  describeConfigs: (args: {\n    resources: Array<{ type: number; name: string }>;\n    includeSynonyms?: boolean;\n  }) => Promise<{\n    resources: Array<{\n      resourceName: string;\n      configEntries: Array<{ configName: string; configValue: string }>;\n    }>;\n  }>;\n}\n\n/**\n * Mock-friendly Kafka client interface (subset of kafkajs.Kafka).\n */\nexport interface KafkaClientMock {\n  producer: (config?: ProducerConfig) => KafkaProducerMock;\n  admin: () => KafkaAdminMock;\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\n/**\n * Provisioning options for `walkeros setup destination.<id>`.\n *\n * Triggered only by the explicit CLI command. Idempotent. Never auto-run.\n *\n * NO SAFE DEFAULTS for `numPartitions` or `replicationFactor`: these are\n * cluster-specific operational decisions and depend on broker count,\n * expected throughput, and consumer parallelism. Both fields are optional\n * in the TypeScript shape (config often comes from JSON), but the runtime\n * REQUIRES both. Missing values throw with an actionable message. The\n * boolean form (setup: true) is rejected at runtime; only the object form\n * is valid.\n */\nexport interface Setup {\n  topic?: string;\n  numPartitions?: number;\n  replicationFactor?: number;\n  configEntries?: Record<string, string>;\n  schemaRegistry?: SchemaRegistrySetup;\n  validateOnly?: boolean;\n}\n\nexport interface SchemaRegistrySetup {\n  url: string;\n  subject: string;\n  schemaType: 'AVRO' | 'JSON' | 'PROTOBUF';\n  schema: string;\n  compatibility?:\n    | 'BACKWARD'\n    | 'FORWARD'\n    | 'FULL'\n    | 'NONE'\n    | 'BACKWARD_TRANSITIVE'\n    | 'FORWARD_TRANSITIVE'\n    | 'FULL_TRANSITIVE';\n  auth?: { username: string; password: string };\n}\n\nexport type Types = CoreDestination.Types<\n  Settings,\n  Mapping,\n  Env,\n  InitSettings,\n  Setup\n>;\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 SetupFn = CoreSetupFn<Config, Env>;\n\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\n\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';\nimport { setup } from './setup';\n\n// Types re-export\nexport * as DestinationKafka from './types';\n\nexport const destinationKafka: Destination = {\n  type: 'kafka',\n\n  config: {},\n\n  setup,\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"]}