@relaybus/kafka 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +126 -19
- package/dist/index.cjs +277 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +163 -2
- package/dist/index.d.ts +163 -2
- package/dist/index.js +274 -14
- package/dist/index.js.map +1 -1
- package/package.json +22 -9
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cloudevents-codec.ts","../src/kafka-transport.ts"],"names":["RelayBusError","NonRetryableError","assertEventType","ConfigurationError","toErrorInfo","toMilliseconds"],"mappings":"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","file":"index.cjs","sourcesContent":["import {\n NonRetryableError,\n RelayBusError,\n assertEventType,\n type EventEnvelope,\n} from '@relaybus/core';\nimport type { KafkaBytes, KafkaIncomingHeaders, KafkaOutgoingHeaders } from './kafka-client.js';\n\n/** A Kafka record that cannot be turned into an {@link EventEnvelope}. Never retried. */\nexport class InvalidKafkaMessageError extends RelayBusError {}\n\n/**\n * An event that cannot be written to Kafka: its payload is not representable as\n * JSON (`undefined`, a function, a symbol, a `BigInt`, a circular structure) or\n * its `occurredAt` is not an RFC 3339 instant (invalid date, year outside 0..9999).\n * Retrying cannot help, so it is a {@link NonRetryableError}.\n */\nexport class UnencodableEventError extends NonRetryableError {\n override name = 'UnencodableEventError';\n}\n\n/** The wire form of one event: a Kafka record in CloudEvents binary content mode. */\nexport interface EncodedMessage {\n readonly key: string | null;\n readonly value: string;\n readonly headers: Record<string, string>;\n}\n\n/** The parts of an incoming Kafka record the decoder reads. */\nexport interface DecodableMessage {\n readonly key: KafkaBytes | null;\n readonly value: KafkaBytes | null;\n readonly headers?: KafkaIncomingHeaders | undefined;\n /** Record timestamp in epoch milliseconds, used when `ce_time` is absent. */\n readonly timestamp?: string | undefined;\n}\n\nconst SPEC_VERSION = '1.0';\nconst CONTENT_TYPE = 'content-type';\nconst JSON_MEDIA_TYPE = 'application/json';\nconst CLOUDEVENTS_PREFIX = 'ce_';\nconst ESCAPE_PREFIX = 'x-relaybus-h-';\nconst RESERVED_PREFIXES = [CLOUDEVENTS_PREFIX, 'x-relaybus-'];\n\nconst HEADER = {\n specVersion: 'ce_specversion',\n id: 'ce_id',\n type: 'ce_type',\n source: 'ce_source',\n time: 'ce_time',\n subject: 'ce_subject',\n correlationId: 'ce_correlationid',\n causationId: 'ce_causationid',\n} as const;\n\nconst PROTOCOL_HEADERS: ReadonlySet<string> = new Set([...Object.values(HEADER), CONTENT_TYPE]);\n\nconst RFC3339_PATTERN = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$/i;\n\nconst strictUtf8 = new TextDecoder('utf-8', { fatal: true });\nconst lenientUtf8 = new TextDecoder('utf-8');\n\n/**\n * Encodes an envelope as a CloudEvents Kafka binary-mode record: the value is\n * the JSON payload, the event attributes travel as `ce_*` headers.\n *\n * User headers that would collide with protocol names (`ce_*`, `content-type`,\n * `x-relaybus-*`) are stored under an `x-relaybus-h-` prefix and restored on\n * decode, so every header survives a round trip unchanged.\n */\nexport function encodeEnvelope(envelope: EventEnvelope): EncodedMessage {\n const value = serializePayload(envelope);\n const entries: [string, string][] = Object.entries(envelope.headers).map(\n ([name, headerValue]) => [escapeUserHeaderName(name), headerValue],\n );\n entries.push(\n [HEADER.specVersion, SPEC_VERSION],\n [HEADER.id, envelope.id],\n [HEADER.type, envelope.type],\n [HEADER.source, envelope.source],\n [HEADER.time, formatTime(envelope)],\n [CONTENT_TYPE, JSON_MEDIA_TYPE],\n );\n if (envelope.key !== null) {\n entries.push([HEADER.subject, envelope.key]);\n }\n if (envelope.correlationId !== null) {\n entries.push([HEADER.correlationId, envelope.correlationId]);\n }\n if (envelope.causationId !== null) {\n entries.push([HEADER.causationId, envelope.causationId]);\n }\n // fromEntries defines own properties, so a header named `__proto__` is kept as data.\n return { key: envelope.key, value, headers: Object.fromEntries(entries) };\n}\n\nfunction serializePayload(envelope: EventEnvelope): string {\n let value: string | undefined;\n try {\n value = JSON.stringify(envelope.payload);\n } catch (error) {\n throw new UnencodableEventError(\n `Event ${envelope.id} has a payload that JSON cannot represent: ${(error as Error).message}`,\n );\n }\n if (value === undefined) {\n throw new UnencodableEventError(\n `Event ${envelope.id} has a payload that JSON cannot represent (undefined, a function or a symbol)`,\n );\n }\n return value;\n}\n\nfunction formatTime(envelope: EventEnvelope): string {\n const year = envelope.occurredAt.getUTCFullYear();\n if (Number.isNaN(year) || year < 0 || year > 9999) {\n throw new UnencodableEventError(\n `Event ${envelope.id} has an occurredAt that is not an RFC 3339 instant (invalid date or year outside 0..9999)`,\n );\n }\n return envelope.occurredAt.toISOString();\n}\n\n/**\n * Decodes a Kafka record strictly: the CloudEvents attributes `ce_specversion`\n * (`1.0`), `ce_id`, `ce_type`, `ce_source`, a JSON `content-type` and a JSON\n * value are required. `ce_time` is optional in CloudEvents: when absent, the\n * Kafka record timestamp is used; when present it must be RFC 3339.\n *\n * @throws InvalidKafkaMessageError for anything else. It is the only error\n * thrown for malformed input, so callers can tell poison messages from bugs.\n */\nexport function decodeEnvelope(message: DecodableMessage): EventEnvelope {\n const headers = readHeaders(message.headers);\n if (headers.get(HEADER.specVersion) !== SPEC_VERSION) {\n throw invalid(`${HEADER.specVersion} must be '${SPEC_VERSION}'`);\n }\n const type = requireHeader(headers, HEADER.type);\n try {\n assertEventType(type);\n } catch (error) {\n throw invalid(`${HEADER.type} is not a valid event type: ${(error as Error).message}`);\n }\n assertJsonContentType(headers.get(CONTENT_TYPE));\n return {\n id: requireHeader(headers, HEADER.id),\n type,\n source: requireHeader(headers, HEADER.source),\n key: resolveKey(headers.get(HEADER.subject), message.key),\n payload: parsePayload(message.value),\n headers: collectUserHeaders(headers),\n correlationId: headers.get(HEADER.correlationId) ?? null,\n causationId: headers.get(HEADER.causationId) ?? null,\n occurredAt: resolveTime(headers.get(HEADER.time), message.timestamp),\n };\n}\n\nfunction invalid(reason: string): InvalidKafkaMessageError {\n return new InvalidKafkaMessageError(reason);\n}\n\nfunction escapeUserHeaderName(name: string): string {\n const lowered = name.toLowerCase();\n const reserved = lowered === CONTENT_TYPE || RESERVED_PREFIXES.some((p) => lowered.startsWith(p));\n return reserved ? `${ESCAPE_PREFIX}${name}` : name;\n}\n\nfunction readHeaders(incoming: KafkaIncomingHeaders | undefined): Map<string, string> {\n const headers = new Map<string, string>();\n for (const [name, raw] of Object.entries(incoming ?? {})) {\n if (raw === undefined) {\n continue;\n }\n if (typeof raw !== 'string' && !(raw instanceof Uint8Array)) {\n throw invalid(`Header '${name}' is repeated`);\n }\n headers.set(name, decodeText(raw, PROTOCOL_HEADERS.has(name), `Header '${name}'`));\n }\n return headers;\n}\n\nfunction decodeText(raw: KafkaBytes | string, strict: boolean, label: string): string {\n if (typeof raw === 'string') {\n return raw;\n }\n try {\n return (strict ? strictUtf8 : lenientUtf8).decode(raw);\n } catch {\n throw invalid(`${label} is not valid UTF-8`);\n }\n}\n\nfunction requireHeader(headers: Map<string, string>, name: string): string {\n const value = headers.get(name);\n if (value === undefined || value.length === 0) {\n throw invalid(`Header '${name}' is missing or empty`);\n }\n return value;\n}\n\nfunction assertJsonContentType(contentType: string | undefined): void {\n const mediaType = contentType?.split(';')[0]?.trim().toLowerCase();\n if (mediaType !== JSON_MEDIA_TYPE) {\n throw invalid(`${CONTENT_TYPE} must be '${JSON_MEDIA_TYPE}', received '${contentType ?? ''}'`);\n }\n}\n\nfunction resolveTime(text: string | undefined, recordTimestamp: string | undefined): Date {\n if (text !== undefined && text.length > 0) {\n return parseTime(text);\n }\n const milliseconds = Number(recordTimestamp);\n const time = new Date(milliseconds);\n if (recordTimestamp === undefined || recordTimestamp === '' || Number.isNaN(time.getTime())) {\n throw invalid(`${HEADER.time} is missing and the record has no usable timestamp`);\n }\n return time;\n}\n\nfunction parseTime(text: string): Date {\n const time = new Date(text);\n if (!RFC3339_PATTERN.test(text) || Number.isNaN(time.getTime())) {\n throw invalid(`${HEADER.time} is not an RFC 3339 timestamp: '${text}'`);\n }\n return time;\n}\n\nfunction parsePayload(value: KafkaBytes | null): unknown {\n if (value === null) {\n throw invalid('Message has no value');\n }\n const text = decodeText(value, true, 'Message value');\n try {\n return JSON.parse(text) as unknown;\n } catch {\n throw invalid('Message value is not valid JSON');\n }\n}\n\nfunction resolveKey(subject: string | undefined, recordKey: KafkaBytes | null): string | null {\n const keyText = recordKey === null ? null : decodeText(recordKey, true, 'Message key');\n if (subject !== undefined && keyText !== null && subject !== keyText) {\n throw invalid(`${HEADER.subject} does not match the message key`);\n }\n return subject ?? keyText;\n}\n\nfunction collectUserHeaders(headers: Map<string, string>): Record<string, string> {\n const entries: [string, string][] = [];\n for (const [name, value] of headers) {\n if (!PROTOCOL_HEADERS.has(name)) {\n entries.push([\n name.startsWith(ESCAPE_PREFIX) ? name.slice(ESCAPE_PREFIX.length) : name,\n value,\n ]);\n }\n }\n return Object.fromEntries(entries);\n}\n\n/** Converts incoming headers to what a producer accepts, keeping every value byte-for-byte. */\nexport function toOutgoingHeaders(\n incoming: KafkaIncomingHeaders | undefined,\n): KafkaOutgoingHeaders {\n const entries: [string, Buffer | string | (Buffer | string)[]][] = [];\n for (const [name, raw] of Object.entries(incoming ?? {})) {\n if (raw !== undefined) {\n entries.push([\n name,\n Array.isArray(raw)\n ? (raw as (KafkaBytes | string)[]).map(toBufferOrString)\n : toBufferOrString(raw as KafkaBytes | string),\n ]);\n }\n }\n return Object.fromEntries(entries);\n}\n\nfunction toBufferOrString(value: KafkaBytes | string): Buffer | string {\n return typeof value === 'string' ? value : Buffer.from(value);\n}\n","import {\n ConfigurationError,\n NonRetryableError,\n RelayBusError,\n toErrorInfo,\n toMilliseconds,\n type Duration,\n type EventEnvelope,\n type RelayBusLogger,\n type Transport,\n type TransportMessageHandler,\n} from '@relaybus/core';\nimport {\n InvalidKafkaMessageError,\n decodeEnvelope,\n encodeEnvelope,\n toOutgoingHeaders,\n} from './cloudevents-codec.js';\nimport type {\n KafkaClientLike,\n KafkaConsumerEvent,\n KafkaConsumerLike,\n KafkaEachMessagePayload,\n KafkaProducerLike,\n KafkaProducerRecord,\n} from './kafka-client.js';\n\n/** A record the transport refused to hand to the bus because it is malformed. */\nexport interface InvalidKafkaMessage {\n readonly topic: string;\n readonly partition: number;\n readonly offset: string;\n /** Why the record was rejected. */\n readonly reason: string;\n readonly key: Uint8Array | null;\n readonly value: Uint8Array | null;\n}\n\n/**\n * What to do with a record that cannot be processed for good (it cannot be\n * decoded, or the bus rejected it with a `NonRetryableError`):\n * - `'dead-letter'` (default): the original record is produced to\n * `<source topic>.dead` with `relaybus-invalid-reason`, `relaybus-source-topic`,\n * `relaybus-source-partition` and `relaybus-source-offset` headers added to the\n * original ones; the offset advances only after the broker acked the copy.\n * - `{ deadLetterTopic }`: same, with a fixed topic name or a function of the\n * source topic.\n * - a function: called with the record; if it rejects, the record is retried\n * like any other failure, so nothing is dropped unless the function returns.\n * - `'skip'`: log an error and drop the record. Explicit opt-in only.\n *\n * The dead-letter topic must exist or the broker must auto-create topics;\n * otherwise the send fails and the record stays uncommitted (nothing is lost).\n */\nexport type InvalidMessagePolicy =\n | 'dead-letter'\n | 'skip'\n | ((message: InvalidKafkaMessage) => void | Promise<void>)\n | { readonly deadLetterTopic: string | ((sourceTopic: string) => string) };\n\n/** `publish` did not get a broker ack within `publishTimeout`. The outbox retries it. */\nexport class PublishTimeoutError extends RelayBusError {\n override name = 'PublishTimeoutError';\n}\n\n/** A handler failure re-thrown to the Kafka client, stripped of anything that could make it fatal. */\nexport class HandlerFailedError extends RelayBusError {\n override name = 'HandlerFailedError';\n}\n\n/** Bounded in-process retries around the inbound handler (the bus's `receive`). */\nexport interface KafkaProcessingOptions {\n /** Attempts per delivery of a record before the error is handed to the client. Default 5. */\n readonly maxAttempts?: number;\n /** Delay before the second attempt; doubles each attempt. Default `'200ms'`. */\n readonly initialBackoff?: Duration;\n /** Upper bound of the delay between attempts. Default `'5s'`. */\n readonly maxBackoff?: Duration;\n /** Interval of the heartbeats sent while sleeping between attempts. Default `'1s'`. */\n readonly heartbeatInterval?: Duration;\n}\n\n/** Backoff of the consumer restart loop that runs after an unrecoverable crash. */\nexport interface KafkaRestartOptions {\n /** Delay before the second restart attempt; doubles each failure. Default `'1s'`. */\n readonly initialBackoff?: Duration;\n /** Upper bound of the delay between restart attempts. Default `'30s'`. */\n readonly maxBackoff?: Duration;\n}\n\nexport interface KafkaTransportOptions {\n /** A `kafkajs` `Kafka` or `@confluentinc/kafka-javascript` `KafkaJS.Kafka` instance. */\n readonly kafka: KafkaClientLike;\n /** Name referenced by routes and subscriptions. Default `'kafka'`. */\n readonly name?: string;\n /** Consumer group id. Required as soon as `subscribe` is used. */\n readonly groupId?: string;\n /**\n * Where a group without committed offsets starts. Default `true` (earliest),\n * so events published before the first start are not skipped.\n */\n readonly fromBeginning?: boolean;\n /** Producer `maxInFlightRequests`, 1 to 5. Default 1, which keeps retries from reordering a key. */\n readonly maxInFlightRequests?: number;\n /** Extra producer settings; `idempotent` and `maxInFlightRequests` always win. */\n readonly producerConfig?: object;\n /** Extra consumer settings; `groupId` always wins. */\n readonly consumerConfig?: object;\n readonly processing?: KafkaProcessingOptions;\n /** How long `subscribe` waits for the consumer group join before failing. Default `'30s'`. */\n readonly startupTimeout?: Duration;\n /** How long `publish` waits for the broker ack before rejecting. Default `'30s'`. */\n readonly publishTimeout?: Duration;\n readonly restart?: KafkaRestartOptions;\n /** Handling of records that cannot be processed for good. Default `'dead-letter'`. */\n readonly onInvalidMessage?: InvalidMessagePolicy;\n /** Default `console`. */\n readonly logger?: RelayBusLogger;\n}\n\nconst DEFAULTS = {\n name: 'kafka',\n maxInFlightRequests: 1,\n maxAttempts: 5,\n initialBackoff: '200ms',\n maxBackoff: '5s',\n startupTimeout: '30s',\n publishTimeout: '30s',\n heartbeatInterval: '1s',\n restartInitialBackoff: '1s',\n restartMaxBackoff: '30s',\n} as const;\n\ntype TransportState = 'idle' | 'subscribed' | 'closed';\n\ninterface Settings {\n readonly maxAttempts: number;\n readonly initialBackoffMs: number;\n readonly maxBackoffMs: number;\n readonly startupTimeoutMs: number;\n readonly publishTimeoutMs: number;\n readonly heartbeatIntervalMs: number;\n readonly restartInitialBackoffMs: number;\n readonly restartMaxBackoffMs: number;\n}\n\n/**\n * Kafka {@link Transport}. Events travel as CloudEvents binary-mode records\n * (`ce_*` headers, JSON value), so any CloudEvents-aware consumer can read them.\n *\n * Publishing: idempotent producer, `acks=-1`, resolves after the broker ack and\n * rejects with {@link PublishTimeoutError} after `publishTimeout`. A timed-out\n * send may still complete later; the outbox then retries it and the duplicate is\n * absorbed by the consumer's inbox dedup. The record key is the envelope key, so events sharing a key land on one\n * partition and keep their order; events without a key have no ordering.\n *\n * Subscribing: one consumer, one group, one `subscribe` call. `eachMessage`\n * awaits the handler; the client commits the offset only after it resolved. A\n * failing handler is retried in-process (bounded, with backoff) and then the\n * error is rethrown (as a {@link HandlerFailedError}, so the client never treats\n * it as fatal) and the client does not commit the offset and redelivers the\n * record. A record is therefore never skipped because of a handler failure; the\n * partition simply waits. Records that can never succeed (undecodable, or\n * rejected with a `NonRetryableError`) are dead-lettered instead. If the client\n * reports an unrecoverable crash anyway, the consumer run loop is restarted with\n * bounded backoff until the transport is closed.\n */\nexport class KafkaTransport implements Transport {\n readonly name: string;\n readonly #kafka: KafkaClientLike;\n readonly #groupId: string | undefined;\n readonly #fromBeginning: boolean;\n readonly #maxInFlightRequests: number;\n readonly #producerConfig: object;\n readonly #consumerConfig: object;\n readonly #invalidPolicy: InvalidMessagePolicy;\n readonly #logger: RelayBusLogger;\n readonly #settings: Settings;\n readonly #sleepers = new Set<() => void>();\n #state: TransportState = 'idle';\n #producer: Promise<KafkaProducerLike> | undefined;\n #consumer: KafkaConsumerLike | undefined;\n #groupJoined = false;\n #consuming = false;\n #producerConnected = false;\n #restartLoop: Promise<void> | undefined;\n readonly #stalledPartitions = new Set<string>();\n #startConsuming: (() => Promise<void>) | undefined;\n #joinWaiter: { resolve(): void; reject(error: unknown): void } | undefined;\n\n constructor(options: KafkaTransportOptions) {\n this.name = options.name ?? DEFAULTS.name;\n this.#kafka = options.kafka;\n this.#groupId = options.groupId;\n this.#fromBeginning = options.fromBeginning ?? true;\n this.#maxInFlightRequests = options.maxInFlightRequests ?? DEFAULTS.maxInFlightRequests;\n if (\n !Number.isInteger(this.#maxInFlightRequests) ||\n this.#maxInFlightRequests < 1 ||\n this.#maxInFlightRequests > 5\n ) {\n throw new ConfigurationError(\n `maxInFlightRequests must be an integer from 1 to 5, received ${this.#maxInFlightRequests}`,\n );\n }\n this.#producerConfig = options.producerConfig ?? {};\n this.#consumerConfig = options.consumerConfig ?? {};\n this.#invalidPolicy = options.onInvalidMessage ?? 'dead-letter';\n this.#logger = options.logger ?? console;\n this.#settings = resolveSettings(options);\n }\n\n /**\n * True while the consumer is joined to its group, not between a crash or\n * rebalance and the next join, and no partition is stalled on a record whose\n * handler keeps failing. Use it for readiness so a consumer that silently\n * stopped is noticed.\n */\n isConsuming(): boolean {\n return this.#state === 'subscribed' && this.#groupJoined && this.#stalledPartitions.size === 0;\n }\n\n /**\n * True once the producer is connected and, if the transport subscribed, the\n * consumer is consuming. False before `connect`, after `close` and while a\n * dead consumer is being restarted.\n */\n isReady(): boolean {\n if (this.#state === 'closed' || !this.#producerConnected) {\n return false;\n }\n return this.#state === 'idle' || this.isConsuming();\n }\n\n /** Connects the producer. Called by the bus on start; `publish` also connects on demand. */\n async connect(): Promise<void> {\n await this.#connectedProducer();\n }\n\n async publish(envelope: EventEnvelope, destination: string): Promise<void> {\n const producer = await this.#connectedProducer();\n const { key, value, headers } = encodeEnvelope(envelope);\n await this.#send(producer, {\n topic: destination,\n acks: -1,\n messages: [{ key, value, headers }],\n });\n }\n\n /**\n * Starts the consumer and resolves once it joined its group, so a start-up\n * that cannot consume fails loudly instead of looking healthy.\n *\n * @throws ConfigurationError when `groupId` is missing, `destinations` is empty\n * or the transport already subscribed (create one transport per subscription).\n */\n async subscribe(\n destinations: readonly string[],\n onMessage: TransportMessageHandler,\n ): Promise<void> {\n this.#assertCanSubscribe(destinations);\n this.#state = 'subscribed';\n const consumer = this.#kafka.consumer({ ...this.#consumerConfig, groupId: this.#groupId! });\n this.#consumer = consumer;\n this.#observeConsumer(consumer);\n const start = (): Promise<void> => this.#startConsumer(consumer, [...destinations], onMessage);\n this.#startConsuming = start;\n try {\n await start();\n } catch (error) {\n // A consumer left half-started would keep running (or retrying) with nobody watching it.\n await consumer.disconnect().catch(() => undefined);\n this.#groupJoined = false;\n this.#consumer = undefined;\n this.#state = 'idle';\n throw error;\n }\n this.#consuming = true;\n this.#logger.log(\n `[KafkaTransport](subscribe) Consuming | transport=${this.name} group=${this.#groupId} topics=${destinations.join(',')}`,\n );\n }\n\n async #startConsumer(\n consumer: KafkaConsumerLike,\n destinations: string[],\n onMessage: TransportMessageHandler,\n ): Promise<void> {\n await consumer.connect();\n await consumer.subscribe({ topics: destinations, fromBeginning: this.#fromBeginning });\n const joined = this.#waitForGroupJoin(consumer);\n try {\n await consumer.run({ eachMessage: (payload) => this.#handleMessage(payload, onMessage) });\n await joined.promise;\n } finally {\n joined.dispose();\n }\n }\n\n /** Stops consuming and disconnects the consumer and the producer. Safe to call twice. */\n async close(): Promise<void> {\n if (this.#state === 'closed') {\n return;\n }\n this.#state = 'closed';\n const pendingProducer = this.#producer;\n this.#groupJoined = false;\n this.#producerConnected = false;\n for (const wake of this.#sleepers) {\n wake();\n }\n this.#joinWaiter?.reject(new RelayBusError(`Transport '${this.name}' is closed`));\n await this.#restartLoop;\n const producer = await pendingProducer?.catch(() => undefined);\n const results = await Promise.allSettled([\n this.#consumer?.disconnect(),\n producer?.disconnect(),\n ]);\n const failure = results.find((result) => result.status === 'rejected');\n if (failure !== undefined) {\n throw failure.reason;\n }\n }\n\n #assertCanSubscribe(destinations: readonly string[]): void {\n if (this.#state === 'closed') {\n throw new RelayBusError(`Transport '${this.name}' is closed`);\n }\n if (this.#state === 'subscribed') {\n throw new ConfigurationError(\n `Transport '${this.name}' already subscribed; list every topic in one subscription or use one KafkaTransport per consumer group`,\n );\n }\n if (this.#groupId === undefined || this.#groupId.length === 0) {\n throw new ConfigurationError(`Transport '${this.name}' needs a groupId to subscribe`);\n }\n if (destinations.length === 0) {\n throw new ConfigurationError(`Transport '${this.name}' subscribed to no topics`);\n }\n for (const topic of destinations) {\n const deadLetterTopic = this.#deadLetterTopicFor(topic);\n if (deadLetterTopic !== undefined && destinations.includes(deadLetterTopic)) {\n throw new ConfigurationError(\n `Dead letter topic '${deadLetterTopic}' is also consumed, which would loop`,\n );\n }\n }\n }\n\n /** The dead-letter topic for records of `sourceTopic`, or undefined when the policy does not use one. */\n #deadLetterTopicFor(sourceTopic: string): string | undefined {\n const policy = this.#invalidPolicy;\n if (policy === 'dead-letter') {\n return `${sourceTopic}.dead`;\n }\n if (typeof policy === 'object') {\n const { deadLetterTopic } = policy;\n return typeof deadLetterTopic === 'function' ? deadLetterTopic(sourceTopic) : deadLetterTopic;\n }\n return undefined;\n }\n\n /** Sends with the publish timeout; the late outcome of a timed-out send is ignored. */\n async #send(producer: KafkaProducerLike, record: KafkaProducerRecord): Promise<void> {\n let timer: NodeJS.Timeout | undefined;\n const timeout = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n reject(\n new PublishTimeoutError(\n `Transport '${this.name}' got no broker ack for topic '${record.topic}' within ${this.#settings.publishTimeoutMs}ms`,\n ),\n );\n }, this.#settings.publishTimeoutMs);\n });\n const sending = producer.send(record);\n sending.catch(() => undefined);\n try {\n await Promise.race([sending, timeout]);\n } finally {\n clearTimeout(timer);\n }\n }\n\n #connectedProducer(): Promise<KafkaProducerLike> {\n if (this.#state === 'closed') {\n return Promise.reject(new RelayBusError(`Transport '${this.name}' is closed`));\n }\n this.#producer ??= this.#openProducer();\n return this.#producer;\n }\n\n async #openProducer(): Promise<KafkaProducerLike> {\n const producer = this.#kafka.producer({\n ...this.#producerConfig,\n idempotent: true,\n maxInFlightRequests: this.#maxInFlightRequests,\n });\n try {\n await producer.connect();\n } catch (error) {\n this.#producer = undefined;\n throw error;\n }\n this.#producerConnected = this.#state !== 'closed';\n return producer;\n }\n\n async #handleMessage(\n payload: KafkaEachMessagePayload,\n onMessage: TransportMessageHandler,\n ): Promise<void> {\n let envelope: EventEnvelope;\n try {\n envelope = decodeEnvelope(payload.message);\n } catch (error) {\n if (!(error instanceof InvalidKafkaMessageError)) {\n throw toHandlerFailure(error);\n }\n await this.#withRetries(payload, 'handleInvalid', () =>\n this.#handleInvalid(payload, error.message),\n );\n return;\n }\n await this.#withRetries(payload, 'deliver', async () => {\n try {\n await onMessage(envelope);\n } catch (error) {\n // The bus rejected the event for good; redelivering it would block the partition forever.\n if (!(error instanceof NonRetryableError)) {\n throw error;\n }\n await this.#handleInvalid(payload, error.message);\n }\n });\n }\n\n async #handleInvalid(payload: KafkaEachMessagePayload, reason: string): Promise<void> {\n const { topic, partition, message } = payload;\n const location = `topic=${topic} partition=${partition} offset=${message.offset}`;\n const policy = this.#invalidPolicy;\n const deadLetterTopic = this.#deadLetterTopicFor(topic);\n if (policy === 'skip') {\n this.#logger.error(\n `[KafkaTransport](handleInvalid) Skipping malformed message | ${location} reason=${reason}`,\n );\n } else if (typeof policy === 'function') {\n await policy({\n topic,\n partition,\n offset: message.offset,\n reason,\n key: message.key,\n value: message.value,\n });\n } else {\n const producer = await this.#connectedProducer();\n await this.#send(producer, {\n topic: deadLetterTopic!,\n acks: -1,\n messages: [\n {\n key: message.key === null ? null : Buffer.from(message.key),\n value: message.value === null ? null : Buffer.from(message.value),\n headers: {\n ...toOutgoingHeaders(message.headers),\n 'relaybus-invalid-reason': reason,\n 'relaybus-source-topic': topic,\n 'relaybus-source-partition': String(partition),\n 'relaybus-source-offset': message.offset,\n },\n },\n ],\n });\n this.#logger.error(\n `[KafkaTransport](handleInvalid) Dead-lettered malformed message | ${location} deadLetterTopic=${deadLetterTopic} reason=${reason}`,\n );\n }\n }\n\n /**\n * Runs `operation` up to `maxAttempts` times with exponential backoff. The\n * last error is rethrown so the client leaves the offset uncommitted and\n * redelivers the record; heartbeats between attempts keep the session alive.\n */\n async #withRetries(\n payload: KafkaEachMessagePayload,\n method: string,\n operation: () => Promise<void>,\n ): Promise<void> {\n const { maxAttempts, initialBackoffMs, maxBackoffMs } = this.#settings;\n const location = `topic=${payload.topic} partition=${payload.partition} offset=${payload.message.offset}`;\n const partitionKey = `${payload.topic}:${payload.partition}`;\n for (let attempt = 1; ; attempt += 1) {\n try {\n await operation();\n this.#stalledPartitions.delete(partitionKey);\n return;\n } catch (error) {\n const reason = toErrorInfo(error).message;\n if (attempt >= maxAttempts || this.#state === 'closed') {\n this.#stalledPartitions.add(partitionKey);\n this.#logger.error(\n `[KafkaTransport](${method}) Giving up for now, the record stays uncommitted and will be redelivered | ${location} attempts=${attempt} error=${reason}`,\n );\n throw toHandlerFailure(error);\n }\n this.#logger.warn(\n `[KafkaTransport](${method}) Attempt failed, retrying | ${location} attempt=${attempt} error=${reason}`,\n );\n await this.#sleepWithHeartbeats(\n Math.min(initialBackoffMs * 2 ** (attempt - 1), maxBackoffMs),\n payload,\n );\n }\n }\n }\n\n /** Sleeps in slices and heartbeats after each, so a long backoff never outlives the session timeout. */\n async #sleepWithHeartbeats(\n milliseconds: number,\n payload: KafkaEachMessagePayload,\n ): Promise<void> {\n let remaining = milliseconds;\n do {\n const slice = Math.min(remaining, this.#settings.heartbeatIntervalMs);\n await this.#sleep(slice);\n await payload.heartbeat();\n remaining -= slice;\n } while (remaining > 0 && this.#state !== 'closed');\n }\n\n #sleep(milliseconds: number): Promise<void> {\n return new Promise((resolve) => {\n const wake = (): void => {\n clearTimeout(timer);\n this.#sleepers.delete(wake);\n resolve();\n };\n const timer = setTimeout(wake, milliseconds);\n this.#sleepers.add(wake);\n });\n }\n\n /** Whether the client exposes the instrumentation needed to follow the group membership. */\n #tracksMembership(consumer: KafkaConsumerLike): boolean {\n return consumer.on !== undefined && consumer.events?.GROUP_JOIN !== undefined;\n }\n\n #observeConsumer(consumer: KafkaConsumerLike): void {\n if (!this.#tracksMembership(consumer)) {\n this.#groupJoined = true;\n return;\n }\n const names = consumer.events!;\n const listen = (\n name: string | undefined,\n listener: (event: KafkaConsumerEvent) => void,\n ): void => {\n if (name !== undefined) {\n consumer.on!(name, listener);\n }\n };\n listen(names.GROUP_JOIN, () => {\n this.#groupJoined = true;\n this.#joinWaiter?.resolve();\n this.#logger.log(`[KafkaTransport](observeConsumer) Joined group | group=${this.#groupId}`);\n });\n listen(names.REBALANCING, () => {\n this.#groupJoined = false;\n // The partition assignment is about to change; a stall is re-detected if it persists.\n this.#stalledPartitions.clear();\n this.#logger.warn(`[KafkaTransport](observeConsumer) Rebalancing | group=${this.#groupId}`);\n });\n listen(names.CRASH, (event) => this.#handleCrash(event));\n listen(names.STOP, () => {\n this.#groupJoined = false;\n });\n listen(names.DISCONNECT, () => {\n this.#groupJoined = false;\n });\n }\n\n #handleCrash(event: KafkaConsumerEvent): void {\n const { error, restart } = (event.payload ?? {}) as { error?: unknown; restart?: unknown };\n this.#groupJoined = false;\n this.#logger.error(\n `[KafkaTransport](handleCrash) Consumer crashed | group=${this.#groupId} restart=${String(restart)} error=${toErrorInfo(error).message}`,\n );\n this.#joinWaiter?.reject(error);\n if (restart === false && this.#consuming && this.#restartLoop === undefined) {\n this.#restartLoop = this.#restartConsumer().finally(() => {\n this.#restartLoop = undefined;\n });\n }\n }\n\n /**\n * The client gave up on the consumer (`restart=false`): reconnect it and run\n * again, with bounded backoff, until it joined or the transport closed.\n */\n async #restartConsumer(): Promise<void> {\n const { restartInitialBackoffMs, restartMaxBackoffMs } = this.#settings;\n const consumer = this.#consumer!;\n for (let attempt = 1; this.#state === 'subscribed'; attempt += 1) {\n await this.#sleep(\n Math.min(restartInitialBackoffMs * 2 ** (attempt - 1), restartMaxBackoffMs),\n );\n if (this.#state !== 'subscribed') {\n return;\n }\n await consumer.disconnect().catch(() => undefined);\n try {\n await this.#startConsuming!();\n this.#logger.log(\n `[KafkaTransport](restartConsumer) Consumer restarted | group=${this.#groupId} attempt=${attempt}`,\n );\n return;\n } catch (error) {\n this.#logger.error(\n `[KafkaTransport](restartConsumer) Restart failed, will retry | group=${this.#groupId} attempt=${attempt} error=${toErrorInfo(error).message}`,\n );\n }\n }\n }\n\n #waitForGroupJoin(consumer: KafkaConsumerLike): { promise: Promise<void>; dispose(): void } {\n if (!this.#tracksMembership(consumer)) {\n return { promise: Promise.resolve(), dispose: () => undefined };\n }\n let timer: NodeJS.Timeout | undefined;\n const promise = new Promise<void>((resolve, reject) => {\n this.#joinWaiter = { resolve, reject };\n timer = setTimeout(() => {\n reject(\n new RelayBusError(\n `Consumer of transport '${this.name}' did not join group '${this.#groupId}' within ${this.#settings.startupTimeoutMs}ms`,\n ),\n );\n }, this.#settings.startupTimeoutMs);\n });\n // The rejection may land while `run` is still pending; the caller awaits it afterwards.\n promise.catch(() => undefined);\n return {\n promise,\n dispose: () => {\n clearTimeout(timer);\n this.#joinWaiter = undefined;\n },\n };\n }\n}\n\nfunction resolveSettings(options: KafkaTransportOptions): Settings {\n const maxAttempts = options.processing?.maxAttempts ?? DEFAULTS.maxAttempts;\n if (!Number.isInteger(maxAttempts) || maxAttempts < 1) {\n throw new ConfigurationError(\n `processing.maxAttempts must be a positive integer, received ${maxAttempts}`,\n );\n }\n return {\n maxAttempts,\n initialBackoffMs: toMilliseconds(\n options.processing?.initialBackoff ?? DEFAULTS.initialBackoff,\n 'processing.initialBackoff',\n ),\n maxBackoffMs: toMilliseconds(\n options.processing?.maxBackoff ?? DEFAULTS.maxBackoff,\n 'processing.maxBackoff',\n ),\n startupTimeoutMs: toMilliseconds(\n options.startupTimeout ?? DEFAULTS.startupTimeout,\n 'startupTimeout',\n ),\n publishTimeoutMs: toMilliseconds(\n options.publishTimeout ?? DEFAULTS.publishTimeout,\n 'publishTimeout',\n ),\n heartbeatIntervalMs: Math.max(\n 1,\n toMilliseconds(\n options.processing?.heartbeatInterval ?? DEFAULTS.heartbeatInterval,\n 'processing.heartbeatInterval',\n ),\n ),\n restartInitialBackoffMs: toMilliseconds(\n options.restart?.initialBackoff ?? DEFAULTS.restartInitialBackoff,\n 'restart.initialBackoff',\n ),\n restartMaxBackoffMs: toMilliseconds(\n options.restart?.maxBackoff ?? DEFAULTS.restartMaxBackoff,\n 'restart.maxBackoff',\n ),\n };\n}\n\n/**\n * Wraps a failure in a fresh error before it goes back to the Kafka client.\n * kafkajs classifies errors by type and cause chain: a handler that throws a\n * `TypeError` would be marked unrecoverable and kill the consumer for good.\n * The wrapper carries the original name and message but no `cause`.\n */\nfunction toHandlerFailure(error: unknown): Error {\n const { name, message } = toErrorInfo(error);\n return new HandlerFailedError(`${name}: ${message}`);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/cloudevents-codec.ts","../src/inbound-decoders.ts","../src/kafka-transport.ts","../src/field-extractors.ts"],"names":["RelayBusError","NonRetryableError","assertEventType","SPEC_VERSION","ConfigurationError","toErrorInfo","toMilliseconds"],"mappings":"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","file":"index.cjs","sourcesContent":["import {\n NonRetryableError,\n RelayBusError,\n assertEventType,\n type EventEnvelope,\n} from '@relaybus/core';\nimport type { KafkaBytes, KafkaIncomingHeaders, KafkaOutgoingHeaders } from './kafka-client.js';\n\n/** A Kafka record that cannot be turned into an {@link EventEnvelope}. Never retried. */\nexport class InvalidKafkaMessageError extends RelayBusError {}\n\n/**\n * An event that cannot be written to Kafka: its payload is not representable as\n * JSON (`undefined`, a function, a symbol, a `BigInt`, a circular structure) or\n * its `occurredAt` is not an RFC 3339 instant (invalid date, year outside 0..9999).\n * Retrying cannot help, so it is a {@link NonRetryableError}.\n */\nexport class UnencodableEventError extends NonRetryableError {\n override name = 'UnencodableEventError';\n}\n\n/** The wire form of one event: a Kafka record in CloudEvents binary content mode. */\nexport interface EncodedMessage {\n readonly key: string | null;\n readonly value: string;\n readonly headers: Record<string, string>;\n}\n\n/** The parts of an incoming Kafka record the decoder reads. */\nexport interface DecodableMessage {\n readonly key: KafkaBytes | null;\n readonly value: KafkaBytes | null;\n readonly headers?: KafkaIncomingHeaders | undefined;\n /** Record timestamp in epoch milliseconds, used when `ce_time` is absent. */\n readonly timestamp?: string | undefined;\n}\n\nconst SPEC_VERSION = '1.0';\n/** Name of the Kafka header that carries the media type of the record value. */\nexport const CONTENT_TYPE = 'content-type';\nconst JSON_MEDIA_TYPE = 'application/json';\nconst CLOUDEVENTS_PREFIX = 'ce_';\nconst ESCAPE_PREFIX = 'x-relaybus-h-';\nconst RESERVED_PREFIXES = [CLOUDEVENTS_PREFIX, 'x-relaybus-'];\n\nconst HEADER = {\n specVersion: 'ce_specversion',\n id: 'ce_id',\n type: 'ce_type',\n source: 'ce_source',\n time: 'ce_time',\n subject: 'ce_subject',\n correlationId: 'ce_correlationid',\n causationId: 'ce_causationid',\n} as const;\n\nconst PROTOCOL_HEADERS: ReadonlySet<string> = new Set([...Object.values(HEADER), CONTENT_TYPE]);\n\nconst RFC3339_PATTERN = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$/i;\n\nconst strictUtf8 = new TextDecoder('utf-8', { fatal: true });\nconst lenientUtf8 = new TextDecoder('utf-8');\n\n/**\n * Encodes an envelope as a CloudEvents Kafka binary-mode record: the value is\n * the JSON payload, the event attributes travel as `ce_*` headers.\n *\n * User headers that would collide with protocol names (`ce_*`, `content-type`,\n * `x-relaybus-*`) are stored under an `x-relaybus-h-` prefix and restored on\n * decode, so every header survives a round trip unchanged.\n */\nexport function encodeEnvelope(envelope: EventEnvelope): EncodedMessage {\n const value = serializePayload(envelope);\n const entries: [string, string][] = Object.entries(envelope.headers).map(\n ([name, headerValue]) => [escapeUserHeaderName(name), headerValue],\n );\n entries.push(\n [HEADER.specVersion, SPEC_VERSION],\n [HEADER.id, envelope.id],\n [HEADER.type, envelope.type],\n [HEADER.source, envelope.source],\n [HEADER.time, formatTime(envelope)],\n [CONTENT_TYPE, JSON_MEDIA_TYPE],\n );\n if (envelope.key !== null) {\n entries.push([HEADER.subject, envelope.key]);\n }\n if (envelope.correlationId !== null) {\n entries.push([HEADER.correlationId, envelope.correlationId]);\n }\n if (envelope.causationId !== null) {\n entries.push([HEADER.causationId, envelope.causationId]);\n }\n // fromEntries defines own properties, so a header named `__proto__` is kept as data.\n return { key: envelope.key, value, headers: Object.fromEntries(entries) };\n}\n\nfunction serializePayload(envelope: EventEnvelope): string {\n let value: string | undefined;\n try {\n value = JSON.stringify(envelope.payload);\n } catch (error) {\n throw new UnencodableEventError(\n `Event ${envelope.id} has a payload that JSON cannot represent: ${(error as Error).message}`,\n );\n }\n if (value === undefined) {\n throw new UnencodableEventError(\n `Event ${envelope.id} has a payload that JSON cannot represent (undefined, a function or a symbol)`,\n );\n }\n return value;\n}\n\nfunction formatTime(envelope: EventEnvelope): string {\n const year = envelope.occurredAt.getUTCFullYear();\n if (Number.isNaN(year) || year < 0 || year > 9999) {\n throw new UnencodableEventError(\n `Event ${envelope.id} has an occurredAt that is not an RFC 3339 instant (invalid date or year outside 0..9999)`,\n );\n }\n return envelope.occurredAt.toISOString();\n}\n\n/**\n * Decodes a Kafka record strictly: the CloudEvents attributes `ce_specversion`\n * (`1.0`), `ce_id`, `ce_type`, `ce_source`, a JSON `content-type` and a JSON\n * value are required. `ce_time` is optional in CloudEvents: when absent, the\n * Kafka record timestamp is used; when present it must be RFC 3339.\n *\n * @throws InvalidKafkaMessageError for anything else. It is the only error\n * thrown for malformed input, so callers can tell poison messages from bugs.\n */\nexport function decodeEnvelope(message: DecodableMessage): EventEnvelope {\n const headers = readHeaders(message.headers);\n if (headers.get(HEADER.specVersion) !== SPEC_VERSION) {\n throw invalid(`${HEADER.specVersion} must be '${SPEC_VERSION}'`);\n }\n const type = requireHeader(headers, HEADER.type);\n try {\n assertEventType(type);\n } catch (error) {\n throw invalid(`${HEADER.type} is not a valid event type: ${(error as Error).message}`);\n }\n assertJsonContentType(headers.get(CONTENT_TYPE));\n return {\n id: requireHeader(headers, HEADER.id),\n type,\n source: requireHeader(headers, HEADER.source),\n key: resolveKey(headers.get(HEADER.subject), message.key),\n payload: parsePayload(message.value),\n headers: collectUserHeaders(headers),\n correlationId: headers.get(HEADER.correlationId) ?? null,\n causationId: headers.get(HEADER.causationId) ?? null,\n occurredAt: resolveTime(headers.get(HEADER.time), message.timestamp),\n };\n}\n\n/** Creates the error thrown for every malformed record. */\nexport function invalid(reason: string): InvalidKafkaMessageError {\n return new InvalidKafkaMessageError(reason);\n}\n\nfunction escapeUserHeaderName(name: string): string {\n const lowered = name.toLowerCase();\n const reserved = lowered === CONTENT_TYPE || RESERVED_PREFIXES.some((p) => lowered.startsWith(p));\n return reserved ? `${ESCAPE_PREFIX}${name}` : name;\n}\n\n/** Reads headers strictly: a repeated header or a protocol header that is not UTF-8 is invalid. */\nexport function readHeaders(incoming: KafkaIncomingHeaders | undefined): Map<string, string> {\n const headers = new Map<string, string>();\n for (const [name, raw] of Object.entries(incoming ?? {})) {\n if (raw === undefined) {\n continue;\n }\n if (typeof raw !== 'string' && !(raw instanceof Uint8Array)) {\n throw invalid(`Header '${name}' is repeated`);\n }\n headers.set(name, decodeText(raw, PROTOCOL_HEADERS.has(name), `Header '${name}'`));\n }\n return headers;\n}\n\n/** Decodes header or value bytes as UTF-8; `strict` rejects invalid sequences. */\nexport function decodeText(raw: KafkaBytes | string, strict: boolean, label: string): string {\n if (typeof raw === 'string') {\n return raw;\n }\n try {\n return (strict ? strictUtf8 : lenientUtf8).decode(raw);\n } catch {\n throw invalid(`${label} is not valid UTF-8`);\n }\n}\n\nfunction requireHeader(headers: Map<string, string>, name: string): string {\n const value = headers.get(name);\n if (value === undefined || value.length === 0) {\n throw invalid(`Header '${name}' is missing or empty`);\n }\n return value;\n}\n\nfunction assertJsonContentType(contentType: string | undefined): void {\n const mediaType = contentType?.split(';')[0]?.trim().toLowerCase();\n if (mediaType !== JSON_MEDIA_TYPE) {\n throw invalid(`${CONTENT_TYPE} must be '${JSON_MEDIA_TYPE}', received '${contentType ?? ''}'`);\n }\n}\n\nfunction resolveTime(text: string | undefined, recordTimestamp: string | undefined): Date {\n if (text !== undefined && text.length > 0) {\n return parseTime(text);\n }\n const time = readRecordTimestamp(recordTimestamp);\n if (time === undefined) {\n throw invalid(`${HEADER.time} is missing and the record has no usable timestamp`);\n }\n return time;\n}\n\n/** The record timestamp (epoch milliseconds in a string) as a date, or undefined when unusable. */\nexport function readRecordTimestamp(recordTimestamp: string | undefined): Date | undefined {\n const time = new Date(Number(recordTimestamp));\n return recordTimestamp === undefined || recordTimestamp === '' || Number.isNaN(time.getTime())\n ? undefined\n : time;\n}\n\n/** Parses an RFC 3339 timestamp; anything else is invalid. `label` names the attribute in the error. */\nexport function parseTime(text: string, label: string = HEADER.time): Date {\n const time = new Date(text);\n if (!RFC3339_PATTERN.test(text) || Number.isNaN(time.getTime())) {\n throw invalid(`${label} is not an RFC 3339 timestamp: '${text}'`);\n }\n return time;\n}\n\n/** Parses the record value as UTF-8 JSON; a missing value or invalid JSON is invalid. */\nexport function parsePayload(value: KafkaBytes | null): unknown {\n if (value === null) {\n throw invalid('Message has no value');\n }\n const text = decodeText(value, true, 'Message value');\n try {\n return JSON.parse(text) as unknown;\n } catch {\n throw invalid('Message value is not valid JSON');\n }\n}\n\nfunction resolveKey(subject: string | undefined, recordKey: KafkaBytes | null): string | null {\n const keyText = readRecordKey(recordKey);\n if (subject !== undefined && keyText !== null && subject !== keyText) {\n throw invalid(`${HEADER.subject} does not match the message key`);\n }\n return subject ?? keyText;\n}\n\n/** The record key as UTF-8 text, or null when the record has none. Invalid UTF-8 is invalid. */\nexport function readRecordKey(recordKey: KafkaBytes | null): string | null {\n return recordKey === null ? null : decodeText(recordKey, true, 'Message key');\n}\n\n/** Headers that are not CloudEvents attributes, with escaped names restored. */\nexport function collectUserHeaders(headers: Map<string, string>): Record<string, string> {\n const entries: [string, string][] = [];\n for (const [name, value] of headers) {\n if (!PROTOCOL_HEADERS.has(name)) {\n entries.push([\n name.startsWith(ESCAPE_PREFIX) ? name.slice(ESCAPE_PREFIX.length) : name,\n value,\n ]);\n }\n }\n return Object.fromEntries(entries);\n}\n\n/** Converts incoming headers to what a producer accepts, keeping every value byte-for-byte. */\nexport function toOutgoingHeaders(\n incoming: KafkaIncomingHeaders | undefined,\n): KafkaOutgoingHeaders {\n const entries: [string, Buffer | string | (Buffer | string)[]][] = [];\n for (const [name, raw] of Object.entries(incoming ?? {})) {\n if (raw !== undefined) {\n entries.push([\n name,\n Array.isArray(raw)\n ? (raw as (KafkaBytes | string)[]).map(toBufferOrString)\n : toBufferOrString(raw as KafkaBytes | string),\n ]);\n }\n }\n return Object.fromEntries(entries);\n}\n\nfunction toBufferOrString(value: KafkaBytes | string): Buffer | string {\n return typeof value === 'string' ? value : Buffer.from(value);\n}\n","import { assertEventType, type EventEnvelope, type EventHeaders } from '@relaybus/core';\nimport {\n CONTENT_TYPE,\n collectUserHeaders,\n decodeEnvelope,\n invalid,\n parsePayload,\n parseTime,\n readHeaders,\n readRecordKey,\n readRecordTimestamp,\n type DecodableMessage,\n} from './cloudevents-codec.js';\nimport type { KafkaBytes, KafkaIncomingHeaders } from './kafka-client.js';\n\n/** A consumed record as handed to a {@link KafkaMessageDecoder}. */\nexport interface KafkaInboundRecord extends DecodableMessage {\n readonly topic: string;\n readonly partition: number;\n readonly offset: string;\n}\n\n/**\n * The event a decoder extracted from a record. `id`, `type` and `payload` are\n * required; every other field may be left out and is then filled by the\n * transport: `source` with the topic, `key` with the record key (UTF-8),\n * `headers` with none, `correlationId` and `causationId` with null, and\n * `occurredAt` with the record timestamp.\n */\nexport interface DecodedEvent {\n readonly id: string;\n readonly type: string;\n readonly payload: unknown;\n readonly source?: string;\n readonly key?: string | null;\n readonly headers?: EventHeaders;\n readonly correlationId?: string | null;\n readonly causationId?: string | null;\n readonly occurredAt?: Date;\n}\n\n/**\n * Turns a consumed record into an event, for topics written by producers that\n * do not use relaybus. Must be synchronous and free of side effects: it runs\n * again on every redelivery, so the same record must always give the same\n * event, above all the same `id`, which is what the inbox deduplicates on.\n *\n * Anything it throws marks the record as malformed: it goes to the transport's\n * `onInvalidMessage` policy (dead-letter by default) and the consumer moves on.\n * An event the bus then rejects (empty id, invalid type or time) is\n * dead-lettered the same way.\n */\nexport type KafkaMessageDecoder = (record: KafkaInboundRecord) => DecodedEvent;\n\n/** A plain JSON record, decoded for the extractor options of {@link plainJsonDecoder}. */\nexport interface PlainJsonRecord {\n readonly topic: string;\n readonly partition: number;\n readonly offset: string;\n /**\n * The record key as UTF-8 text, base64 when its bytes are not valid UTF-8\n * (for example a key written by Java's `LongSerializer`), null when absent.\n */\n readonly key: string | null;\n /**\n * Every record header as text: the last value of a repeated header; a value\n * that is not valid UTF-8 is left out.\n */\n readonly headers: EventHeaders;\n /** The record value parsed as JSON. */\n readonly payload: unknown;\n /** Record timestamp in epoch milliseconds. */\n readonly timestamp: string | undefined;\n}\n\n/** Options of {@link plainJsonDecoder}. Extractors returning undefined or `''` select the default. */\nexport interface PlainJsonDecoderOptions {\n /**\n * Event type handlers subscribe to: a fixed name for a topic that carries one\n * kind of event, or an extractor such as `fromHeader('event-type')` or\n * `fromPayloadField('type')`. Required; a record without a type is invalid.\n */\n readonly type: string | ((record: PlainJsonRecord) => string | undefined);\n /**\n * Event id the inbox deduplicates on, for example `fromHeader('message-id')`.\n * Default, and fallback when the extractor finds none:\n * `kafka:<topic>:<partition>:<offset>`, which is stable across redeliveries\n * of the record. Prefer an id set by the producer when it may send the same\n * event twice: two sends are two offsets, so only a producer id dedupes them.\n */\n readonly id?: (record: PlainJsonRecord) => string | undefined;\n /** Ordering key. Default: the record key. When given, its result is final (undefined means no key). */\n readonly key?: (record: PlainJsonRecord) => string | null | undefined;\n /** Logical name of the producer. Default: the topic. */\n readonly source?: string | ((record: PlainJsonRecord) => string | undefined);\n /** When the event happened. Default: the record timestamp. */\n readonly occurredAt?: (record: PlainJsonRecord) => Date | undefined;\n}\n\nconst STRUCTURED_MEDIA_TYPE = 'application/cloudevents+json';\n/** Refuses invalid UTF-8 and keeps a leading BOM, so different header bytes never decode equal. */\nconst exactUtf8 = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true });\nconst SPEC_VERSION = '1.0';\nconst SPEC_VERSION_HEADER = 'ce_specversion';\n/** Attributes of a structured event that map to envelope fields rather than headers. */\nconst STRUCTURED_ATTRIBUTES: ReadonlySet<string> = new Set([\n 'specversion',\n 'id',\n 'type',\n 'source',\n 'time',\n 'subject',\n 'datacontenttype',\n 'dataschema',\n 'data',\n 'data_base64',\n 'correlationid',\n 'causationid',\n]);\n\n/**\n * Decodes a CloudEvents 1.0 record in either content mode of the Kafka\n * protocol binding:\n * - structured (`content-type: application/cloudevents+json`): the value is\n * a JSON object with `specversion`, `id`, `type`, `source` and optionally\n * `time`, `subject` (the key, else the record key), `data` (the payload,\n * null when absent) and a JSON `datacontenttype`. `data_base64` is refused,\n * because relaybus payloads are JSON. Extension attributes with string\n * values (`traceparent`, ...) become event headers, as do the record\n * headers; `correlationid` and `causationid` fill their envelope fields.\n * - binary (anything else): exactly {@link decodeEnvelope}, the default decoder.\n *\n * @throws InvalidKafkaMessageError for a record that is neither.\n */\nexport function decodeCloudEvent(record: DecodableMessage): EventEnvelope {\n const headers = readHeaders(record.headers);\n if (mediaTypeOf(headers.get(CONTENT_TYPE)) !== STRUCTURED_MEDIA_TYPE) {\n return decodeEnvelope(record);\n }\n const body = parsePayload(record.value);\n if (!isJsonObject(body)) {\n throw invalid('A structured CloudEvent must be a JSON object');\n }\n if (body['specversion'] !== SPEC_VERSION) {\n throw invalid(`specversion must be '${SPEC_VERSION}'`);\n }\n const type = requiredAttribute(body, 'type');\n assertValidType(type, 'type');\n assertJsonDataContentType(optionalAttribute(body, 'datacontenttype'));\n if (Object.hasOwn(body, 'data_base64')) {\n throw invalid('data_base64 is not supported: relaybus payloads are JSON, send them as data');\n }\n const time = optionalAttribute(body, 'time');\n return {\n id: requiredAttribute(body, 'id'),\n type,\n source: requiredAttribute(body, 'source'),\n key: optionalAttribute(body, 'subject') ?? readRecordKey(record.key),\n payload: Object.hasOwn(body, 'data') ? body['data'] : null,\n headers: { ...collectUserHeaders(headers), ...extensionAttributes(body) },\n correlationId: optionalAttribute(body, 'correlationid') ?? null,\n causationId: optionalAttribute(body, 'causationid') ?? null,\n occurredAt: time === undefined ? requireRecordTimestamp(record) : parseTime(time, 'time'),\n };\n}\n\n/**\n * Creates a decoder for records whose value is plain JSON, as written by a\n * service that does not use relaybus (a plain kafkajs producer, Spring Kafka's\n * `JsonSerializer`, a Go service): the value becomes the payload, the record\n * headers become event headers, and the options say where the event type and\n * id come from.\n *\n * A record that is a CloudEvent anyway (a `ce_specversion` header, or a\n * structured `application/cloudevents+json` value) is decoded with\n * {@link decodeCloudEvent} instead, so relaybus and foreign producers can share\n * a topic. A missing or non-JSON value, a missing or invalid type, and an\n * extractor returning anything but a string are invalid.\n *\n * ```ts\n * new KafkaTransport({\n * kafka,\n * groupId: 'billing',\n * decode: plainJsonDecoder({ type: fromHeader('event-type'), id: fromHeader('message-id') }),\n * });\n * ```\n *\n * @throws ConfigurationError when a fixed `type` is not a valid event type.\n */\nexport function plainJsonDecoder(options: PlainJsonDecoderOptions): KafkaMessageDecoder {\n if (typeof options.type === 'string') {\n assertEventType(options.type);\n }\n return (record) => {\n const headers = readHeadersLeniently(record.headers);\n if (\n record.headers?.[SPEC_VERSION_HEADER] !== undefined ||\n mediaTypeOf(headers[CONTENT_TYPE]) === STRUCTURED_MEDIA_TYPE\n ) {\n return decodeCloudEvent(record);\n }\n const plain: PlainJsonRecord = {\n topic: record.topic,\n partition: record.partition,\n offset: record.offset,\n key: readKeyLeniently(record.key),\n headers,\n payload: parsePayload(record.value),\n timestamp: record.timestamp,\n };\n const type = resolveText(options.type, plain, 'type');\n if (type === undefined) {\n throw invalid('Record has no event type: the type option found none');\n }\n assertValidType(type, 'The event type');\n return {\n id:\n resolveText(options.id, plain, 'id') ??\n `kafka:${record.topic}:${record.partition}:${record.offset}`,\n type,\n source: resolveText(options.source, plain, 'source') ?? record.topic,\n key: options.key === undefined ? plain.key : (resolveText(options.key, plain, 'key') ?? null),\n payload: plain.payload,\n headers,\n correlationId: null,\n causationId: null,\n occurredAt: resolveOccurredAt(options.occurredAt, plain, record),\n };\n };\n}\n\n/**\n * Fills the fields a decoder left out (see {@link DecodedEvent}) and guards\n * against a decoder that returned no object, which would otherwise surface as\n * a retried `TypeError` instead of a malformed record.\n */\nexport function completeDecodedEvent(decoded: unknown, record: KafkaInboundRecord): EventEnvelope {\n if (typeof decoded !== 'object' || decoded === null) {\n throw invalid('The decoder must return an event object synchronously');\n }\n if ('then' in decoded) {\n observeRejection(decoded);\n throw invalid('The decoder must return an event object synchronously');\n }\n const event = decoded as DecodedEvent;\n return {\n id: event.id,\n type: event.type,\n source: event.source ?? record.topic,\n key: event.key === undefined ? readRecordKey(record.key) : event.key,\n payload: event.payload,\n headers: event.headers ?? {},\n correlationId: event.correlationId ?? null,\n causationId: event.causationId ?? null,\n occurredAt: event.occurredAt ?? requireRecordTimestamp(record),\n };\n}\n\nfunction mediaTypeOf(contentType: string | undefined): string | undefined {\n return contentType?.split(';')[0]?.trim().toLowerCase();\n}\n\nfunction isJsonObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction optionalAttribute(body: Record<string, unknown>, name: string): string | undefined {\n const value = body[name];\n if (value !== undefined && typeof value !== 'string') {\n throw invalid(`Attribute '${name}' must be a string`);\n }\n return value;\n}\n\nfunction requiredAttribute(body: Record<string, unknown>, name: string): string {\n const value = optionalAttribute(body, name);\n if (value === undefined || value.length === 0) {\n throw invalid(`Attribute '${name}' is missing or empty`);\n }\n return value;\n}\n\nfunction assertValidType(type: string, label: string): void {\n try {\n assertEventType(type);\n } catch (error) {\n throw invalid(`${label} is not a valid event type: ${(error as Error).message}`);\n }\n}\n\nfunction assertJsonDataContentType(dataContentType: string | undefined): void {\n const mediaType = mediaTypeOf(dataContentType);\n if (\n mediaType !== undefined &&\n mediaType !== 'application/json' &&\n mediaType !== 'text/json' &&\n !mediaType.endsWith('+json')\n ) {\n throw invalid(`datacontenttype must be JSON, received '${dataContentType}'`);\n }\n}\n\nfunction extensionAttributes(body: Record<string, unknown>): Record<string, string> {\n return Object.fromEntries(\n Object.entries(body).filter(\n (entry): entry is [string, string] =>\n !STRUCTURED_ATTRIBUTES.has(entry[0]) && typeof entry[1] === 'string',\n ),\n );\n}\n\nfunction requireRecordTimestamp(record: DecodableMessage): Date {\n const time = readRecordTimestamp(record.timestamp);\n if (time === undefined) {\n throw invalid('The event has no time and the record has no usable timestamp');\n }\n return time;\n}\n\n/**\n * Headers of a foreign record, never rejected: the last value of a repeated\n * header wins, and a value that is not valid UTF-8 is left out, because\n * replacing its bytes could make two different ids or types look equal.\n */\nfunction readHeadersLeniently(incoming: KafkaIncomingHeaders | undefined): EventHeaders {\n const entries: [string, string][] = [];\n for (const [name, raw] of Object.entries(incoming ?? {})) {\n const value = Array.isArray(raw)\n ? (raw as (KafkaBytes | string)[]).at(-1)\n : (raw as KafkaBytes | string | undefined);\n const text = value === undefined ? undefined : decodeUtf8OrUndefined(value);\n if (text !== undefined) {\n entries.push([name, text]);\n }\n }\n return Object.fromEntries(entries);\n}\n\nfunction decodeUtf8OrUndefined(value: KafkaBytes | string): string | undefined {\n if (typeof value === 'string') {\n return value;\n }\n try {\n return exactUtf8.decode(value);\n } catch {\n return undefined;\n }\n}\n\nfunction readKeyLeniently(key: KafkaBytes | null): string | null {\n if (key === null) {\n return null;\n }\n try {\n return readRecordKey(key);\n } catch {\n return Buffer.from(key).toString('base64');\n }\n}\n\nfunction resolveText<TValue extends string | null>(\n option: TValue | ((record: PlainJsonRecord) => TValue | undefined) | undefined,\n record: PlainJsonRecord,\n name: string,\n): string | undefined {\n const value: unknown = typeof option === 'function' ? option(record) : option;\n if (value === undefined || value === null) {\n return undefined;\n }\n if (typeof value !== 'string') {\n observeRejection(value);\n throw invalid(`The ${name} option returned ${typeof value}, expected a string`);\n }\n return value.length === 0 ? undefined : value;\n}\n\nfunction resolveOccurredAt(\n option: PlainJsonDecoderOptions['occurredAt'],\n plain: PlainJsonRecord,\n record: KafkaInboundRecord,\n): Date {\n const value: unknown = option?.(plain);\n if (value === undefined) {\n return requireRecordTimestamp(record);\n }\n if (!(value instanceof Date) || Number.isNaN(value.getTime())) {\n observeRejection(value);\n throw invalid('The occurredAt option returned no valid Date');\n }\n return value;\n}\n\n/**\n * Observes the rejection of a promise an async decoder or extractor returned by\n * mistake: the value is refused as malformed, and an unobserved rejection would\n * otherwise crash the process.\n */\nfunction observeRejection(value: unknown): void {\n if (typeof value === 'object' && value !== null && 'then' in value) {\n Promise.resolve(value).catch(() => undefined);\n }\n}\n","import {\n ConfigurationError,\n NonRetryableError,\n RelayBusError,\n toErrorInfo,\n toMilliseconds,\n type Duration,\n type EventEnvelope,\n type RelayBusLogger,\n type Transport,\n type TransportMessageHandler,\n} from '@relaybus/core';\nimport {\n InvalidKafkaMessageError,\n decodeEnvelope,\n encodeEnvelope,\n toOutgoingHeaders,\n} from './cloudevents-codec.js';\nimport { completeDecodedEvent, type KafkaMessageDecoder } from './inbound-decoders.js';\nimport type {\n KafkaClientLike,\n KafkaConsumerEvent,\n KafkaConsumerLike,\n KafkaEachMessagePayload,\n KafkaProducerLike,\n KafkaProducerRecord,\n} from './kafka-client.js';\n\n/** A record the transport refused to hand to the bus because it is malformed. */\nexport interface InvalidKafkaMessage {\n readonly topic: string;\n readonly partition: number;\n readonly offset: string;\n /** Why the record was rejected. */\n readonly reason: string;\n readonly key: Uint8Array | null;\n readonly value: Uint8Array | null;\n}\n\n/**\n * What to do with a record that cannot be processed for good (it cannot be\n * decoded, or the bus rejected it with a `NonRetryableError`):\n * - `'dead-letter'` (default): the original record is produced to\n * `<source topic>.dead` with `relaybus-invalid-reason`, `relaybus-source-topic`,\n * `relaybus-source-partition` and `relaybus-source-offset` headers added to the\n * original ones; the offset advances only after the broker acked the copy.\n * - `{ deadLetterTopic }`: same, with a fixed topic name or a function of the\n * source topic.\n * - a function: called with the record; if it rejects, the record is retried\n * like any other failure, so nothing is dropped unless the function returns.\n * - `'skip'`: log an error and drop the record. Explicit opt-in only.\n *\n * The dead-letter topic must exist or the broker must auto-create topics;\n * otherwise the send fails and the record stays uncommitted (nothing is lost).\n */\nexport type InvalidMessagePolicy =\n | 'dead-letter'\n | 'skip'\n | ((message: InvalidKafkaMessage) => void | Promise<void>)\n | { readonly deadLetterTopic: string | ((sourceTopic: string) => string) };\n\n/** `publish` did not get a broker ack within `publishTimeout`. The outbox retries it. */\nexport class PublishTimeoutError extends RelayBusError {\n override name = 'PublishTimeoutError';\n}\n\n/** A handler failure re-thrown to the Kafka client, stripped of anything that could make it fatal. */\nexport class HandlerFailedError extends RelayBusError {\n override name = 'HandlerFailedError';\n}\n\n/** Bounded in-process retries around the inbound handler (the bus's `receive`). */\nexport interface KafkaProcessingOptions {\n /** Attempts per delivery of a record before the error is handed to the client. Default 5. */\n readonly maxAttempts?: number;\n /** Delay before the second attempt; doubles each attempt. Default `'200ms'`. */\n readonly initialBackoff?: Duration;\n /** Upper bound of the delay between attempts. Default `'5s'`. */\n readonly maxBackoff?: Duration;\n /** Interval of the heartbeats sent while sleeping between attempts. Default `'1s'`. */\n readonly heartbeatInterval?: Duration;\n}\n\n/** Backoff of the consumer restart loop that runs after an unrecoverable crash. */\nexport interface KafkaRestartOptions {\n /** Delay before the second restart attempt; doubles each failure. Default `'1s'`. */\n readonly initialBackoff?: Duration;\n /** Upper bound of the delay between restart attempts. Default `'30s'`. */\n readonly maxBackoff?: Duration;\n}\n\nexport interface KafkaTransportOptions {\n /** A `kafkajs` `Kafka` or `@confluentinc/kafka-javascript` `KafkaJS.Kafka` instance. */\n readonly kafka: KafkaClientLike;\n /** Name referenced by routes and subscriptions. Default `'kafka'`. */\n readonly name?: string;\n /** Consumer group id. Required as soon as `subscribe` is used. */\n readonly groupId?: string;\n /**\n * Where a group without committed offsets starts. Default `true` (earliest),\n * so events published before the first start are not skipped.\n */\n readonly fromBeginning?: boolean;\n /** Producer `maxInFlightRequests`, 1 to 5. Default 1, which keeps retries from reordering a key. */\n readonly maxInFlightRequests?: number;\n /** Extra producer settings; `idempotent` and `maxInFlightRequests` always win. */\n readonly producerConfig?: object;\n /** Extra consumer settings; `groupId` always wins. */\n readonly consumerConfig?: object;\n readonly processing?: KafkaProcessingOptions;\n /** How long `subscribe` waits for the consumer group join before failing. Default `'30s'`. */\n readonly startupTimeout?: Duration;\n /** How long `publish` waits for the broker ack before rejecting. Default `'30s'`. */\n readonly publishTimeout?: Duration;\n readonly restart?: KafkaRestartOptions;\n /** Handling of records that cannot be processed for good. Default `'dead-letter'`. */\n readonly onInvalidMessage?: InvalidMessagePolicy;\n /**\n * How consumed records become events. Default: strict CloudEvents binary\n * mode ({@link decodeEnvelope}), which is what relaybus producers write; any\n * other record is malformed and goes to `onInvalidMessage`. Set it to read\n * topics written by services that do not use relaybus:\n * {@link decodeCloudEvent} also accepts structured mode, {@link plainJsonDecoder}\n * maps plain JSON records, and a function of your own can do anything else\n * (switch on `record.topic` to decode topics differently). Whatever a custom\n * decoder throws marks the record as malformed, never crashes the consumer.\n */\n readonly decode?: KafkaMessageDecoder;\n /** Default `console`. */\n readonly logger?: RelayBusLogger;\n}\n\nconst DEFAULTS = {\n name: 'kafka',\n maxInFlightRequests: 1,\n maxAttempts: 5,\n initialBackoff: '200ms',\n maxBackoff: '5s',\n startupTimeout: '30s',\n publishTimeout: '30s',\n heartbeatInterval: '1s',\n restartInitialBackoff: '1s',\n restartMaxBackoff: '30s',\n} as const;\n\ntype TransportState = 'idle' | 'subscribed' | 'closed';\n\ninterface Settings {\n readonly maxAttempts: number;\n readonly initialBackoffMs: number;\n readonly maxBackoffMs: number;\n readonly startupTimeoutMs: number;\n readonly publishTimeoutMs: number;\n readonly heartbeatIntervalMs: number;\n readonly restartInitialBackoffMs: number;\n readonly restartMaxBackoffMs: number;\n}\n\n/**\n * Kafka {@link Transport}. Events travel as CloudEvents binary-mode records\n * (`ce_*` headers, JSON value), so any CloudEvents-aware consumer can read them.\n * Records from producers that do not use relaybus are read through the\n * `decode` option.\n *\n * Publishing: idempotent producer, `acks=-1`, resolves after the broker ack and\n * rejects with {@link PublishTimeoutError} after `publishTimeout`. A timed-out\n * send may still complete later; the outbox then retries it and the duplicate is\n * absorbed by the consumer's inbox dedup. The record key is the envelope key, so events sharing a key land on one\n * partition and keep their order; events without a key have no ordering.\n *\n * Subscribing: one consumer, one group, one `subscribe` call. `eachMessage`\n * awaits the handler; the client commits the offset only after it resolved. A\n * failing handler is retried in-process (bounded, with backoff) and then the\n * error is rethrown (as a {@link HandlerFailedError}, so the client never treats\n * it as fatal) and the client does not commit the offset and redelivers the\n * record. A record is therefore never skipped because of a handler failure; the\n * partition simply waits. Records that can never succeed (undecodable, or\n * rejected with a `NonRetryableError`) are dead-lettered instead. If the client\n * reports an unrecoverable crash anyway, the consumer run loop is restarted with\n * bounded backoff until the transport is closed.\n */\nexport class KafkaTransport implements Transport {\n readonly name: string;\n readonly #kafka: KafkaClientLike;\n readonly #groupId: string | undefined;\n readonly #fromBeginning: boolean;\n readonly #maxInFlightRequests: number;\n readonly #producerConfig: object;\n readonly #consumerConfig: object;\n readonly #invalidPolicy: InvalidMessagePolicy;\n readonly #decode: KafkaMessageDecoder | undefined;\n readonly #logger: RelayBusLogger;\n readonly #settings: Settings;\n readonly #sleepers = new Set<() => void>();\n #state: TransportState = 'idle';\n #producer: Promise<KafkaProducerLike> | undefined;\n #consumer: KafkaConsumerLike | undefined;\n #groupJoined = false;\n #consuming = false;\n #producerConnected = false;\n #restartLoop: Promise<void> | undefined;\n readonly #stalledPartitions = new Set<string>();\n #startConsuming: (() => Promise<void>) | undefined;\n #joinWaiter: { resolve(): void; reject(error: unknown): void } | undefined;\n\n constructor(options: KafkaTransportOptions) {\n this.name = options.name ?? DEFAULTS.name;\n this.#kafka = options.kafka;\n this.#groupId = options.groupId;\n this.#fromBeginning = options.fromBeginning ?? true;\n this.#maxInFlightRequests = options.maxInFlightRequests ?? DEFAULTS.maxInFlightRequests;\n if (\n !Number.isInteger(this.#maxInFlightRequests) ||\n this.#maxInFlightRequests < 1 ||\n this.#maxInFlightRequests > 5\n ) {\n throw new ConfigurationError(\n `maxInFlightRequests must be an integer from 1 to 5, received ${this.#maxInFlightRequests}`,\n );\n }\n this.#producerConfig = options.producerConfig ?? {};\n this.#consumerConfig = options.consumerConfig ?? {};\n this.#invalidPolicy = options.onInvalidMessage ?? 'dead-letter';\n this.#decode = options.decode;\n this.#logger = options.logger ?? console;\n this.#settings = resolveSettings(options);\n }\n\n /**\n * True while the consumer is joined to its group, not between a crash or\n * rebalance and the next join, and no partition is stalled on a record whose\n * handler keeps failing. Use it for readiness so a consumer that silently\n * stopped is noticed.\n */\n isConsuming(): boolean {\n return this.#state === 'subscribed' && this.#groupJoined && this.#stalledPartitions.size === 0;\n }\n\n /**\n * True once the producer is connected and, if the transport subscribed, the\n * consumer is consuming. False before `connect`, after `close` and while a\n * dead consumer is being restarted.\n */\n isReady(): boolean {\n if (this.#state === 'closed' || !this.#producerConnected) {\n return false;\n }\n return this.#state === 'idle' || this.isConsuming();\n }\n\n /** Connects the producer. Called by the bus on start; `publish` also connects on demand. */\n async connect(): Promise<void> {\n await this.#connectedProducer();\n }\n\n async publish(envelope: EventEnvelope, destination: string): Promise<void> {\n const producer = await this.#connectedProducer();\n const { key, value, headers } = encodeEnvelope(envelope);\n await this.#send(producer, {\n topic: destination,\n acks: -1,\n messages: [{ key, value, headers }],\n });\n }\n\n /**\n * Starts the consumer and resolves once it joined its group, so a start-up\n * that cannot consume fails loudly instead of looking healthy.\n *\n * @throws ConfigurationError when `groupId` is missing, `destinations` is empty\n * or the transport already subscribed (create one transport per subscription).\n */\n async subscribe(\n destinations: readonly string[],\n onMessage: TransportMessageHandler,\n ): Promise<void> {\n this.#assertCanSubscribe(destinations);\n this.#state = 'subscribed';\n const consumer = this.#kafka.consumer({ ...this.#consumerConfig, groupId: this.#groupId! });\n this.#consumer = consumer;\n this.#observeConsumer(consumer);\n const start = (): Promise<void> => this.#startConsumer(consumer, [...destinations], onMessage);\n this.#startConsuming = start;\n try {\n await start();\n } catch (error) {\n // A consumer left half-started would keep running (or retrying) with nobody watching it.\n await consumer.disconnect().catch(() => undefined);\n this.#groupJoined = false;\n this.#consumer = undefined;\n this.#state = 'idle';\n throw error;\n }\n this.#consuming = true;\n this.#logger.log(\n `[KafkaTransport](subscribe) Consuming | transport=${this.name} group=${this.#groupId} topics=${destinations.join(',')}`,\n );\n }\n\n async #startConsumer(\n consumer: KafkaConsumerLike,\n destinations: string[],\n onMessage: TransportMessageHandler,\n ): Promise<void> {\n await consumer.connect();\n await consumer.subscribe({ topics: destinations, fromBeginning: this.#fromBeginning });\n const joined = this.#waitForGroupJoin(consumer);\n try {\n await consumer.run({ eachMessage: (payload) => this.#handleMessage(payload, onMessage) });\n await joined.promise;\n } finally {\n joined.dispose();\n }\n }\n\n /** Stops consuming and disconnects the consumer and the producer. Safe to call twice. */\n async close(): Promise<void> {\n if (this.#state === 'closed') {\n return;\n }\n this.#state = 'closed';\n const pendingProducer = this.#producer;\n this.#groupJoined = false;\n this.#producerConnected = false;\n for (const wake of this.#sleepers) {\n wake();\n }\n this.#joinWaiter?.reject(new RelayBusError(`Transport '${this.name}' is closed`));\n await this.#restartLoop;\n const producer = await pendingProducer?.catch(() => undefined);\n const results = await Promise.allSettled([\n this.#consumer?.disconnect(),\n producer?.disconnect(),\n ]);\n const failure = results.find((result) => result.status === 'rejected');\n if (failure !== undefined) {\n throw failure.reason;\n }\n }\n\n #assertCanSubscribe(destinations: readonly string[]): void {\n if (this.#state === 'closed') {\n throw new RelayBusError(`Transport '${this.name}' is closed`);\n }\n if (this.#state === 'subscribed') {\n throw new ConfigurationError(\n `Transport '${this.name}' already subscribed; list every topic in one subscription or use one KafkaTransport per consumer group`,\n );\n }\n if (this.#groupId === undefined || this.#groupId.length === 0) {\n throw new ConfigurationError(`Transport '${this.name}' needs a groupId to subscribe`);\n }\n if (destinations.length === 0) {\n throw new ConfigurationError(`Transport '${this.name}' subscribed to no topics`);\n }\n for (const topic of destinations) {\n const deadLetterTopic = this.#deadLetterTopicFor(topic);\n if (deadLetterTopic !== undefined && destinations.includes(deadLetterTopic)) {\n throw new ConfigurationError(\n `Dead letter topic '${deadLetterTopic}' is also consumed, which would loop`,\n );\n }\n }\n }\n\n /** The dead-letter topic for records of `sourceTopic`, or undefined when the policy does not use one. */\n #deadLetterTopicFor(sourceTopic: string): string | undefined {\n const policy = this.#invalidPolicy;\n if (policy === 'dead-letter') {\n return `${sourceTopic}.dead`;\n }\n if (typeof policy === 'object') {\n const { deadLetterTopic } = policy;\n return typeof deadLetterTopic === 'function' ? deadLetterTopic(sourceTopic) : deadLetterTopic;\n }\n return undefined;\n }\n\n /** Sends with the publish timeout; the late outcome of a timed-out send is ignored. */\n async #send(producer: KafkaProducerLike, record: KafkaProducerRecord): Promise<void> {\n let timer: NodeJS.Timeout | undefined;\n const timeout = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n reject(\n new PublishTimeoutError(\n `Transport '${this.name}' got no broker ack for topic '${record.topic}' within ${this.#settings.publishTimeoutMs}ms`,\n ),\n );\n }, this.#settings.publishTimeoutMs);\n });\n const sending = producer.send(record);\n sending.catch(() => undefined);\n try {\n await Promise.race([sending, timeout]);\n } finally {\n clearTimeout(timer);\n }\n }\n\n #connectedProducer(): Promise<KafkaProducerLike> {\n if (this.#state === 'closed') {\n return Promise.reject(new RelayBusError(`Transport '${this.name}' is closed`));\n }\n this.#producer ??= this.#openProducer();\n return this.#producer;\n }\n\n async #openProducer(): Promise<KafkaProducerLike> {\n const producer = this.#kafka.producer({\n ...this.#producerConfig,\n idempotent: true,\n maxInFlightRequests: this.#maxInFlightRequests,\n });\n try {\n await producer.connect();\n } catch (error) {\n this.#producer = undefined;\n throw error;\n }\n this.#producerConnected = this.#state !== 'closed';\n return producer;\n }\n\n async #handleMessage(\n payload: KafkaEachMessagePayload,\n onMessage: TransportMessageHandler,\n ): Promise<void> {\n let envelope: EventEnvelope;\n try {\n envelope = this.#decodeRecord(payload);\n } catch (error) {\n // The default decoder throws only InvalidKafkaMessageError for bad input; anything else is a bug.\n if (this.#decode === undefined && !(error instanceof InvalidKafkaMessageError)) {\n throw toHandlerFailure(error);\n }\n const reason = toErrorInfo(error).message;\n await this.#withRetries(payload, 'handleInvalid', () => this.#handleInvalid(payload, reason));\n return;\n }\n await this.#withRetries(payload, 'deliver', async () => {\n try {\n await onMessage(envelope);\n } catch (error) {\n // The bus rejected the event for good; redelivering it would block the partition forever.\n if (!(error instanceof NonRetryableError)) {\n throw error;\n }\n await this.#handleInvalid(payload, error.message);\n }\n });\n }\n\n #decodeRecord({ topic, partition, message }: KafkaEachMessagePayload): EventEnvelope {\n if (this.#decode === undefined) {\n return decodeEnvelope(message);\n }\n const record = {\n topic,\n partition,\n offset: message.offset,\n key: message.key,\n value: message.value,\n headers: message.headers,\n timestamp: message.timestamp,\n };\n return completeDecodedEvent(this.#decode(record), record);\n }\n\n async #handleInvalid(payload: KafkaEachMessagePayload, reason: string): Promise<void> {\n const { topic, partition, message } = payload;\n const location = `topic=${topic} partition=${partition} offset=${message.offset}`;\n const policy = this.#invalidPolicy;\n const deadLetterTopic = this.#deadLetterTopicFor(topic);\n if (policy === 'skip') {\n this.#logger.error(\n `[KafkaTransport](handleInvalid) Skipping malformed message | ${location} reason=${reason}`,\n );\n } else if (typeof policy === 'function') {\n await policy({\n topic,\n partition,\n offset: message.offset,\n reason,\n key: message.key,\n value: message.value,\n });\n } else {\n const producer = await this.#connectedProducer();\n await this.#send(producer, {\n topic: deadLetterTopic!,\n acks: -1,\n messages: [\n {\n key: message.key === null ? null : Buffer.from(message.key),\n value: message.value === null ? null : Buffer.from(message.value),\n headers: {\n ...toOutgoingHeaders(message.headers),\n 'relaybus-invalid-reason': reason,\n 'relaybus-source-topic': topic,\n 'relaybus-source-partition': String(partition),\n 'relaybus-source-offset': message.offset,\n },\n },\n ],\n });\n this.#logger.error(\n `[KafkaTransport](handleInvalid) Dead-lettered malformed message | ${location} deadLetterTopic=${deadLetterTopic} reason=${reason}`,\n );\n }\n }\n\n /**\n * Runs `operation` up to `maxAttempts` times with exponential backoff. The\n * last error is rethrown so the client leaves the offset uncommitted and\n * redelivers the record; heartbeats between attempts keep the session alive.\n */\n async #withRetries(\n payload: KafkaEachMessagePayload,\n method: string,\n operation: () => Promise<void>,\n ): Promise<void> {\n const { maxAttempts, initialBackoffMs, maxBackoffMs } = this.#settings;\n const location = `topic=${payload.topic} partition=${payload.partition} offset=${payload.message.offset}`;\n const partitionKey = `${payload.topic}:${payload.partition}`;\n for (let attempt = 1; ; attempt += 1) {\n try {\n await operation();\n this.#stalledPartitions.delete(partitionKey);\n return;\n } catch (error) {\n const reason = toErrorInfo(error).message;\n if (attempt >= maxAttempts || this.#state === 'closed') {\n this.#stalledPartitions.add(partitionKey);\n this.#logger.error(\n `[KafkaTransport](${method}) Giving up for now, the record stays uncommitted and will be redelivered | ${location} attempts=${attempt} error=${reason}`,\n );\n throw toHandlerFailure(error);\n }\n this.#logger.warn(\n `[KafkaTransport](${method}) Attempt failed, retrying | ${location} attempt=${attempt} error=${reason}`,\n );\n await this.#sleepWithHeartbeats(\n Math.min(initialBackoffMs * 2 ** (attempt - 1), maxBackoffMs),\n payload,\n );\n }\n }\n }\n\n /** Sleeps in slices and heartbeats after each, so a long backoff never outlives the session timeout. */\n async #sleepWithHeartbeats(\n milliseconds: number,\n payload: KafkaEachMessagePayload,\n ): Promise<void> {\n let remaining = milliseconds;\n do {\n const slice = Math.min(remaining, this.#settings.heartbeatIntervalMs);\n await this.#sleep(slice);\n await payload.heartbeat();\n remaining -= slice;\n } while (remaining > 0 && this.#state !== 'closed');\n }\n\n #sleep(milliseconds: number): Promise<void> {\n return new Promise((resolve) => {\n const wake = (): void => {\n clearTimeout(timer);\n this.#sleepers.delete(wake);\n resolve();\n };\n const timer = setTimeout(wake, milliseconds);\n this.#sleepers.add(wake);\n });\n }\n\n /** Whether the client exposes the instrumentation needed to follow the group membership. */\n #tracksMembership(consumer: KafkaConsumerLike): boolean {\n return consumer.on !== undefined && consumer.events?.GROUP_JOIN !== undefined;\n }\n\n #observeConsumer(consumer: KafkaConsumerLike): void {\n if (!this.#tracksMembership(consumer)) {\n this.#groupJoined = true;\n return;\n }\n const names = consumer.events!;\n const listen = (\n name: string | undefined,\n listener: (event: KafkaConsumerEvent) => void,\n ): void => {\n if (name !== undefined) {\n consumer.on!(name, listener);\n }\n };\n listen(names.GROUP_JOIN, () => {\n this.#groupJoined = true;\n this.#joinWaiter?.resolve();\n this.#logger.log(`[KafkaTransport](observeConsumer) Joined group | group=${this.#groupId}`);\n });\n listen(names.REBALANCING, () => {\n this.#groupJoined = false;\n // The partition assignment is about to change; a stall is re-detected if it persists.\n this.#stalledPartitions.clear();\n this.#logger.warn(`[KafkaTransport](observeConsumer) Rebalancing | group=${this.#groupId}`);\n });\n listen(names.CRASH, (event) => this.#handleCrash(event));\n listen(names.STOP, () => {\n this.#groupJoined = false;\n });\n listen(names.DISCONNECT, () => {\n this.#groupJoined = false;\n });\n }\n\n #handleCrash(event: KafkaConsumerEvent): void {\n const { error, restart } = (event.payload ?? {}) as { error?: unknown; restart?: unknown };\n this.#groupJoined = false;\n this.#logger.error(\n `[KafkaTransport](handleCrash) Consumer crashed | group=${this.#groupId} restart=${String(restart)} error=${toErrorInfo(error).message}`,\n );\n this.#joinWaiter?.reject(error);\n if (restart === false && this.#consuming && this.#restartLoop === undefined) {\n this.#restartLoop = this.#restartConsumer().finally(() => {\n this.#restartLoop = undefined;\n });\n }\n }\n\n /**\n * The client gave up on the consumer (`restart=false`): reconnect it and run\n * again, with bounded backoff, until it joined or the transport closed.\n */\n async #restartConsumer(): Promise<void> {\n const { restartInitialBackoffMs, restartMaxBackoffMs } = this.#settings;\n const consumer = this.#consumer!;\n for (let attempt = 1; this.#state === 'subscribed'; attempt += 1) {\n await this.#sleep(\n Math.min(restartInitialBackoffMs * 2 ** (attempt - 1), restartMaxBackoffMs),\n );\n if (this.#state !== 'subscribed') {\n return;\n }\n await consumer.disconnect().catch(() => undefined);\n try {\n await this.#startConsuming!();\n this.#logger.log(\n `[KafkaTransport](restartConsumer) Consumer restarted | group=${this.#groupId} attempt=${attempt}`,\n );\n return;\n } catch (error) {\n this.#logger.error(\n `[KafkaTransport](restartConsumer) Restart failed, will retry | group=${this.#groupId} attempt=${attempt} error=${toErrorInfo(error).message}`,\n );\n }\n }\n }\n\n #waitForGroupJoin(consumer: KafkaConsumerLike): { promise: Promise<void>; dispose(): void } {\n if (!this.#tracksMembership(consumer)) {\n return { promise: Promise.resolve(), dispose: () => undefined };\n }\n let timer: NodeJS.Timeout | undefined;\n const promise = new Promise<void>((resolve, reject) => {\n this.#joinWaiter = { resolve, reject };\n timer = setTimeout(() => {\n reject(\n new RelayBusError(\n `Consumer of transport '${this.name}' did not join group '${this.#groupId}' within ${this.#settings.startupTimeoutMs}ms`,\n ),\n );\n }, this.#settings.startupTimeoutMs);\n });\n // The rejection may land while `run` is still pending; the caller awaits it afterwards.\n promise.catch(() => undefined);\n return {\n promise,\n dispose: () => {\n clearTimeout(timer);\n this.#joinWaiter = undefined;\n },\n };\n }\n}\n\nfunction resolveSettings(options: KafkaTransportOptions): Settings {\n const maxAttempts = options.processing?.maxAttempts ?? DEFAULTS.maxAttempts;\n if (!Number.isInteger(maxAttempts) || maxAttempts < 1) {\n throw new ConfigurationError(\n `processing.maxAttempts must be a positive integer, received ${maxAttempts}`,\n );\n }\n return {\n maxAttempts,\n initialBackoffMs: toMilliseconds(\n options.processing?.initialBackoff ?? DEFAULTS.initialBackoff,\n 'processing.initialBackoff',\n ),\n maxBackoffMs: toMilliseconds(\n options.processing?.maxBackoff ?? DEFAULTS.maxBackoff,\n 'processing.maxBackoff',\n ),\n startupTimeoutMs: toMilliseconds(\n options.startupTimeout ?? DEFAULTS.startupTimeout,\n 'startupTimeout',\n ),\n publishTimeoutMs: toMilliseconds(\n options.publishTimeout ?? DEFAULTS.publishTimeout,\n 'publishTimeout',\n ),\n heartbeatIntervalMs: Math.max(\n 1,\n toMilliseconds(\n options.processing?.heartbeatInterval ?? DEFAULTS.heartbeatInterval,\n 'processing.heartbeatInterval',\n ),\n ),\n restartInitialBackoffMs: toMilliseconds(\n options.restart?.initialBackoff ?? DEFAULTS.restartInitialBackoff,\n 'restart.initialBackoff',\n ),\n restartMaxBackoffMs: toMilliseconds(\n options.restart?.maxBackoff ?? DEFAULTS.restartMaxBackoff,\n 'restart.maxBackoff',\n ),\n };\n}\n\n/**\n * Wraps a failure in a fresh error before it goes back to the Kafka client.\n * kafkajs classifies errors by type and cause chain: a handler that throws a\n * `TypeError` would be marked unrecoverable and kill the consumer for good.\n * The wrapper carries the original name and message but no `cause`.\n */\nfunction toHandlerFailure(error: unknown): Error {\n const { name, message } = toErrorInfo(error);\n return new HandlerFailedError(`${name}: ${message}`);\n}\n","import { ConfigurationError, type EventHeaders } from '@relaybus/core';\n\n/**\n * Reads one header of an incoming message, for the `type`, `id`, `key` or\n * `source` option of {@link plainJsonDecoder}. Header names are compared\n * exactly (Kafka header names are case-sensitive). Returns undefined when the\n * header is absent, so the decoder falls back to its default.\n *\n * ```ts\n * plainJsonDecoder({ type: fromHeader('event-type'), id: fromHeader('message-id') })\n * ```\n */\nexport function fromHeader(\n name: string,\n): (message: { readonly headers: EventHeaders }) => string | undefined {\n if (name.length === 0) {\n throw new ConfigurationError('fromHeader needs a header name');\n }\n return (message) => (Object.hasOwn(message.headers, name) ? message.headers[name] : undefined);\n}\n\n/**\n * Reads a field of the JSON payload by a dotted path (`'meta.eventType'`), for\n * the `type`, `id`, `key` or `source` option of {@link plainJsonDecoder}. A\n * string is returned as is and a safe integer as its decimal text (numeric ids\n * are common). Anything else returns undefined so the decoder falls back to its\n * default: a missing field, and also a fraction or an integer beyond 2^53, which\n * JSON parsing may already have rounded, so two different ids could collide.\n *\n * ```ts\n * plainJsonDecoder({ type: fromPayloadField('eventType'), key: fromPayloadField('order.id') })\n * ```\n */\nexport function fromPayloadField(\n path: string,\n): (message: { readonly payload: unknown }) => string | undefined {\n const segments = path.split('.');\n if (segments.some((segment) => segment.length === 0)) {\n throw new ConfigurationError(\n `fromPayloadField needs a dotted path of non-empty names, received '${path}'`,\n );\n }\n return (message) => {\n let value = message.payload;\n for (const segment of segments) {\n if (typeof value !== 'object' || value === null || !Object.hasOwn(value, segment)) {\n return undefined;\n }\n value = (value as Record<string, unknown>)[segment];\n }\n if (typeof value === 'string') {\n return value;\n }\n return Number.isSafeInteger(value) ? String(value) : undefined;\n };\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RelayBusError, NonRetryableError, EventEnvelope, Duration, Transport, RelayBusLogger, TransportMessageHandler } from '@relaybus/core';
|
|
1
|
+
import { RelayBusError, NonRetryableError, EventEnvelope, EventHeaders, Duration, Transport, RelayBusLogger, TransportMessageHandler } from '@relaybus/core';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Structural views of the Kafka client API used by this package.
|
|
@@ -143,6 +143,125 @@ declare function encodeEnvelope(envelope: EventEnvelope): EncodedMessage;
|
|
|
143
143
|
*/
|
|
144
144
|
declare function decodeEnvelope(message: DecodableMessage): EventEnvelope;
|
|
145
145
|
|
|
146
|
+
/** A consumed record as handed to a {@link KafkaMessageDecoder}. */
|
|
147
|
+
interface KafkaInboundRecord extends DecodableMessage {
|
|
148
|
+
readonly topic: string;
|
|
149
|
+
readonly partition: number;
|
|
150
|
+
readonly offset: string;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* The event a decoder extracted from a record. `id`, `type` and `payload` are
|
|
154
|
+
* required; every other field may be left out and is then filled by the
|
|
155
|
+
* transport: `source` with the topic, `key` with the record key (UTF-8),
|
|
156
|
+
* `headers` with none, `correlationId` and `causationId` with null, and
|
|
157
|
+
* `occurredAt` with the record timestamp.
|
|
158
|
+
*/
|
|
159
|
+
interface DecodedEvent {
|
|
160
|
+
readonly id: string;
|
|
161
|
+
readonly type: string;
|
|
162
|
+
readonly payload: unknown;
|
|
163
|
+
readonly source?: string;
|
|
164
|
+
readonly key?: string | null;
|
|
165
|
+
readonly headers?: EventHeaders;
|
|
166
|
+
readonly correlationId?: string | null;
|
|
167
|
+
readonly causationId?: string | null;
|
|
168
|
+
readonly occurredAt?: Date;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Turns a consumed record into an event, for topics written by producers that
|
|
172
|
+
* do not use relaybus. Must be synchronous and free of side effects: it runs
|
|
173
|
+
* again on every redelivery, so the same record must always give the same
|
|
174
|
+
* event, above all the same `id`, which is what the inbox deduplicates on.
|
|
175
|
+
*
|
|
176
|
+
* Anything it throws marks the record as malformed: it goes to the transport's
|
|
177
|
+
* `onInvalidMessage` policy (dead-letter by default) and the consumer moves on.
|
|
178
|
+
* An event the bus then rejects (empty id, invalid type or time) is
|
|
179
|
+
* dead-lettered the same way.
|
|
180
|
+
*/
|
|
181
|
+
type KafkaMessageDecoder = (record: KafkaInboundRecord) => DecodedEvent;
|
|
182
|
+
/** A plain JSON record, decoded for the extractor options of {@link plainJsonDecoder}. */
|
|
183
|
+
interface PlainJsonRecord {
|
|
184
|
+
readonly topic: string;
|
|
185
|
+
readonly partition: number;
|
|
186
|
+
readonly offset: string;
|
|
187
|
+
/**
|
|
188
|
+
* The record key as UTF-8 text, base64 when its bytes are not valid UTF-8
|
|
189
|
+
* (for example a key written by Java's `LongSerializer`), null when absent.
|
|
190
|
+
*/
|
|
191
|
+
readonly key: string | null;
|
|
192
|
+
/**
|
|
193
|
+
* Every record header as text: the last value of a repeated header; a value
|
|
194
|
+
* that is not valid UTF-8 is left out.
|
|
195
|
+
*/
|
|
196
|
+
readonly headers: EventHeaders;
|
|
197
|
+
/** The record value parsed as JSON. */
|
|
198
|
+
readonly payload: unknown;
|
|
199
|
+
/** Record timestamp in epoch milliseconds. */
|
|
200
|
+
readonly timestamp: string | undefined;
|
|
201
|
+
}
|
|
202
|
+
/** Options of {@link plainJsonDecoder}. Extractors returning undefined or `''` select the default. */
|
|
203
|
+
interface PlainJsonDecoderOptions {
|
|
204
|
+
/**
|
|
205
|
+
* Event type handlers subscribe to: a fixed name for a topic that carries one
|
|
206
|
+
* kind of event, or an extractor such as `fromHeader('event-type')` or
|
|
207
|
+
* `fromPayloadField('type')`. Required; a record without a type is invalid.
|
|
208
|
+
*/
|
|
209
|
+
readonly type: string | ((record: PlainJsonRecord) => string | undefined);
|
|
210
|
+
/**
|
|
211
|
+
* Event id the inbox deduplicates on, for example `fromHeader('message-id')`.
|
|
212
|
+
* Default, and fallback when the extractor finds none:
|
|
213
|
+
* `kafka:<topic>:<partition>:<offset>`, which is stable across redeliveries
|
|
214
|
+
* of the record. Prefer an id set by the producer when it may send the same
|
|
215
|
+
* event twice: two sends are two offsets, so only a producer id dedupes them.
|
|
216
|
+
*/
|
|
217
|
+
readonly id?: (record: PlainJsonRecord) => string | undefined;
|
|
218
|
+
/** Ordering key. Default: the record key. When given, its result is final (undefined means no key). */
|
|
219
|
+
readonly key?: (record: PlainJsonRecord) => string | null | undefined;
|
|
220
|
+
/** Logical name of the producer. Default: the topic. */
|
|
221
|
+
readonly source?: string | ((record: PlainJsonRecord) => string | undefined);
|
|
222
|
+
/** When the event happened. Default: the record timestamp. */
|
|
223
|
+
readonly occurredAt?: (record: PlainJsonRecord) => Date | undefined;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Decodes a CloudEvents 1.0 record in either content mode of the Kafka
|
|
227
|
+
* protocol binding:
|
|
228
|
+
* - structured (`content-type: application/cloudevents+json`): the value is
|
|
229
|
+
* a JSON object with `specversion`, `id`, `type`, `source` and optionally
|
|
230
|
+
* `time`, `subject` (the key, else the record key), `data` (the payload,
|
|
231
|
+
* null when absent) and a JSON `datacontenttype`. `data_base64` is refused,
|
|
232
|
+
* because relaybus payloads are JSON. Extension attributes with string
|
|
233
|
+
* values (`traceparent`, ...) become event headers, as do the record
|
|
234
|
+
* headers; `correlationid` and `causationid` fill their envelope fields.
|
|
235
|
+
* - binary (anything else): exactly {@link decodeEnvelope}, the default decoder.
|
|
236
|
+
*
|
|
237
|
+
* @throws InvalidKafkaMessageError for a record that is neither.
|
|
238
|
+
*/
|
|
239
|
+
declare function decodeCloudEvent(record: DecodableMessage): EventEnvelope;
|
|
240
|
+
/**
|
|
241
|
+
* Creates a decoder for records whose value is plain JSON, as written by a
|
|
242
|
+
* service that does not use relaybus (a plain kafkajs producer, Spring Kafka's
|
|
243
|
+
* `JsonSerializer`, a Go service): the value becomes the payload, the record
|
|
244
|
+
* headers become event headers, and the options say where the event type and
|
|
245
|
+
* id come from.
|
|
246
|
+
*
|
|
247
|
+
* A record that is a CloudEvent anyway (a `ce_specversion` header, or a
|
|
248
|
+
* structured `application/cloudevents+json` value) is decoded with
|
|
249
|
+
* {@link decodeCloudEvent} instead, so relaybus and foreign producers can share
|
|
250
|
+
* a topic. A missing or non-JSON value, a missing or invalid type, and an
|
|
251
|
+
* extractor returning anything but a string are invalid.
|
|
252
|
+
*
|
|
253
|
+
* ```ts
|
|
254
|
+
* new KafkaTransport({
|
|
255
|
+
* kafka,
|
|
256
|
+
* groupId: 'billing',
|
|
257
|
+
* decode: plainJsonDecoder({ type: fromHeader('event-type'), id: fromHeader('message-id') }),
|
|
258
|
+
* });
|
|
259
|
+
* ```
|
|
260
|
+
*
|
|
261
|
+
* @throws ConfigurationError when a fixed `type` is not a valid event type.
|
|
262
|
+
*/
|
|
263
|
+
declare function plainJsonDecoder(options: PlainJsonDecoderOptions): KafkaMessageDecoder;
|
|
264
|
+
|
|
146
265
|
/** A record the transport refused to hand to the bus because it is malformed. */
|
|
147
266
|
interface InvalidKafkaMessage {
|
|
148
267
|
readonly topic: string;
|
|
@@ -224,12 +343,25 @@ interface KafkaTransportOptions {
|
|
|
224
343
|
readonly restart?: KafkaRestartOptions;
|
|
225
344
|
/** Handling of records that cannot be processed for good. Default `'dead-letter'`. */
|
|
226
345
|
readonly onInvalidMessage?: InvalidMessagePolicy;
|
|
346
|
+
/**
|
|
347
|
+
* How consumed records become events. Default: strict CloudEvents binary
|
|
348
|
+
* mode ({@link decodeEnvelope}), which is what relaybus producers write; any
|
|
349
|
+
* other record is malformed and goes to `onInvalidMessage`. Set it to read
|
|
350
|
+
* topics written by services that do not use relaybus:
|
|
351
|
+
* {@link decodeCloudEvent} also accepts structured mode, {@link plainJsonDecoder}
|
|
352
|
+
* maps plain JSON records, and a function of your own can do anything else
|
|
353
|
+
* (switch on `record.topic` to decode topics differently). Whatever a custom
|
|
354
|
+
* decoder throws marks the record as malformed, never crashes the consumer.
|
|
355
|
+
*/
|
|
356
|
+
readonly decode?: KafkaMessageDecoder;
|
|
227
357
|
/** Default `console`. */
|
|
228
358
|
readonly logger?: RelayBusLogger;
|
|
229
359
|
}
|
|
230
360
|
/**
|
|
231
361
|
* Kafka {@link Transport}. Events travel as CloudEvents binary-mode records
|
|
232
362
|
* (`ce_*` headers, JSON value), so any CloudEvents-aware consumer can read them.
|
|
363
|
+
* Records from producers that do not use relaybus are read through the
|
|
364
|
+
* `decode` option.
|
|
233
365
|
*
|
|
234
366
|
* Publishing: idempotent producer, `acks=-1`, resolves after the broker ack and
|
|
235
367
|
* rejects with {@link PublishTimeoutError} after `publishTimeout`. A timed-out
|
|
@@ -280,4 +412,33 @@ declare class KafkaTransport implements Transport {
|
|
|
280
412
|
close(): Promise<void>;
|
|
281
413
|
}
|
|
282
414
|
|
|
283
|
-
|
|
415
|
+
/**
|
|
416
|
+
* Reads one header of an incoming message, for the `type`, `id`, `key` or
|
|
417
|
+
* `source` option of {@link plainJsonDecoder}. Header names are compared
|
|
418
|
+
* exactly (Kafka header names are case-sensitive). Returns undefined when the
|
|
419
|
+
* header is absent, so the decoder falls back to its default.
|
|
420
|
+
*
|
|
421
|
+
* ```ts
|
|
422
|
+
* plainJsonDecoder({ type: fromHeader('event-type'), id: fromHeader('message-id') })
|
|
423
|
+
* ```
|
|
424
|
+
*/
|
|
425
|
+
declare function fromHeader(name: string): (message: {
|
|
426
|
+
readonly headers: EventHeaders;
|
|
427
|
+
}) => string | undefined;
|
|
428
|
+
/**
|
|
429
|
+
* Reads a field of the JSON payload by a dotted path (`'meta.eventType'`), for
|
|
430
|
+
* the `type`, `id`, `key` or `source` option of {@link plainJsonDecoder}. A
|
|
431
|
+
* string is returned as is and a safe integer as its decimal text (numeric ids
|
|
432
|
+
* are common). Anything else returns undefined so the decoder falls back to its
|
|
433
|
+
* default: a missing field, and also a fraction or an integer beyond 2^53, which
|
|
434
|
+
* JSON parsing may already have rounded, so two different ids could collide.
|
|
435
|
+
*
|
|
436
|
+
* ```ts
|
|
437
|
+
* plainJsonDecoder({ type: fromPayloadField('eventType'), key: fromPayloadField('order.id') })
|
|
438
|
+
* ```
|
|
439
|
+
*/
|
|
440
|
+
declare function fromPayloadField(path: string): (message: {
|
|
441
|
+
readonly payload: unknown;
|
|
442
|
+
}) => string | undefined;
|
|
443
|
+
|
|
444
|
+
export { type DecodableMessage, type DecodedEvent, type EncodedMessage, HandlerFailedError, type InvalidKafkaMessage, InvalidKafkaMessageError, type InvalidMessagePolicy, type KafkaBytes, type KafkaClientLike, type KafkaConsumerConfig, type KafkaConsumerEvent, type KafkaConsumerEventNames, type KafkaConsumerLike, type KafkaEachMessagePayload, type KafkaInboundRecord, type KafkaIncomingHeaders, type KafkaIncomingMessage, type KafkaMessageDecoder, type KafkaOutgoingHeaders, type KafkaOutgoingMessage, type KafkaProcessingOptions, type KafkaProducerConfig, type KafkaProducerLike, type KafkaProducerRecord, type KafkaRestartOptions, type KafkaRunConfig, KafkaTransport, type KafkaTransportOptions, type PlainJsonDecoderOptions, type PlainJsonRecord, PublishTimeoutError, UnencodableEventError, decodeCloudEvent, decodeEnvelope, encodeEnvelope, fromHeader, fromPayloadField, plainJsonDecoder };
|