diff --git a/packages/kafka/lib/AbstractKafkaConsumer.ts b/packages/kafka/lib/AbstractKafkaConsumer.ts index c632669a..fa1948ef 100644 --- a/packages/kafka/lib/AbstractKafkaConsumer.ts +++ b/packages/kafka/lib/AbstractKafkaConsumer.ts @@ -1,4 +1,5 @@ import { randomUUID } from 'node:crypto' +import { pipeline } from 'node:stream/promises' import { setTimeout } from 'node:timers/promises' import { InternalError, @@ -190,19 +191,23 @@ export abstract class AbstractKafkaConsumer< }) this.consumerStream = await this.consumer.consume({ ...consumeOptions, topics }) - this.consumerStream.on('error', (error) => this.handlerError(error)) if (this.options.batchProcessingEnabled && this.options.batchProcessingOptions) { this.messageBatchStream = new KafkaMessageBatchStream< DeserializedMessage> - >( - (batch) => - this.consume(batch.topic, batch.messages).catch((error) => this.handlerError(error)), - this.options.batchProcessingOptions, + >({ + batchSize: this.options.batchProcessingOptions.batchSize, + timeoutMilliseconds: this.options.batchProcessingOptions.timeoutMilliseconds, + readableHighWaterMark: this.options.batchProcessingOptions.readableHighWaterMark, + }) + + // Use pipeline for better error handling and backpressure management. + // pipeline() internally listens for errors on all streams + pipeline(this.consumerStream, this.messageBatchStream).catch((error) => + this.handlerError(error), ) - this.consumerStream.pipe(this.messageBatchStream) } else { - this.handleSyncStream(this.consumerStream).catch((error) => this.handlerError(error)) + this.consumerStream.on('error', (error) => this.handlerError(error)) } } catch (error) { throw new InternalError({ @@ -211,6 +216,12 @@ export abstract class AbstractKafkaConsumer< cause: error, }) } + + if (this.messageBatchStream) { + this.handleSyncStreamBatch(this.messageBatchStream).catch((error) => this.handlerError(error)) + } else { + this.handleSyncStream(this.consumerStream).catch((error) => this.handlerError(error)) + } } private async handleSyncStream( @@ -223,6 +234,13 @@ export abstract class AbstractKafkaConsumer< ) } } + private async handleSyncStreamBatch( + stream: KafkaMessageBatchStream>>, + ): Promise { + for await (const messageBatch of stream) { + await this.consume(messageBatch[0].topic, messageBatch) + } + } async close(): Promise { if (!this.consumerStream && !this.messageBatchStream) { @@ -371,6 +389,7 @@ export abstract class AbstractKafkaConsumer< ): Promise { try { const isBatch = Array.isArray(messageOrBatch) + /* v8 ignore start */ if (this.options.batchProcessingEnabled && !isBatch) { throw new Error( 'Batch processing is enabled, but a single message was passed to the handler', @@ -381,6 +400,7 @@ export abstract class AbstractKafkaConsumer< 'Batch processing is disabled, but a batch of messages was passed to the handler', ) } + /* v8 ignore stop */ await handler( // We need casting to match message type with handler type - it is safe as we verify the type above @@ -395,10 +415,7 @@ export abstract class AbstractKafkaConsumer< const errorContext = Array.isArray(messageOrBatch) ? { batchSize: messageOrBatch.length } : { message: stringValueSerializer(messageOrBatch.value) } - this.handlerError(error, { - topic, - ...errorContext, - }) + this.handlerError(error, { topic, ...errorContext }) } return { status: 'error', errorReason: 'handlerError' } @@ -443,7 +460,7 @@ export abstract class AbstractKafkaConsumer< } catch (error) { this.logger.debug(logDetails, 'Message commit failed') if (error instanceof ResponseError) return this.handleResponseErrorOnCommit(error) - throw error + this.handlerError(error) } } @@ -455,7 +472,7 @@ export abstract class AbstractKafkaConsumer< error.apiCode && commitErrorCodesToIgnore.has(error.apiCode) ) { - this.logger.error( + this.logger.warn( { apiCode: error.apiCode, apiId: error.apiId, @@ -466,8 +483,7 @@ export abstract class AbstractKafkaConsumer< `Failed to commit message: ${error.message}`, ) } else { - // If error is not recognized, rethrow it - throw responseError + this.handlerError(error) } } } diff --git a/packages/kafka/lib/AbstractKafkaService.ts b/packages/kafka/lib/AbstractKafkaService.ts index 1528ee90..aa0d9275 100644 --- a/packages/kafka/lib/AbstractKafkaService.ts +++ b/packages/kafka/lib/AbstractKafkaService.ts @@ -127,6 +127,10 @@ export abstract class AbstractKafkaService< protected handlerError(error: unknown, context: Record = {}): void { this.logger.error({ ...resolveGlobalErrorLogObject(error), ...context }) - if (isError(error)) this.errorReporter.report({ error, context }) + if (isError(error)) + this.errorReporter.report({ + error, + context: context, + }) } } diff --git a/packages/kafka/lib/utils/KafkaMessageBatchStream.spec.ts b/packages/kafka/lib/utils/KafkaMessageBatchStream.spec.ts index ccc88e03..f5dc220e 100644 --- a/packages/kafka/lib/utils/KafkaMessageBatchStream.spec.ts +++ b/packages/kafka/lib/utils/KafkaMessageBatchStream.spec.ts @@ -1,6 +1,5 @@ import { setTimeout } from 'node:timers/promises' -import { waitAndRetry } from '@lokalise/universal-ts-utils/node' -import { KafkaMessageBatchStream, type MessageBatch } from './KafkaMessageBatchStream.ts' +import { KafkaMessageBatchStream } from './KafkaMessageBatchStream.ts' describe('KafkaMessageBatchStream', () => { it('should batch messages based on batch size', async () => { @@ -14,27 +13,25 @@ describe('KafkaMessageBatchStream', () => { })) // When - const receivedBatches: MessageBatch[] = [] + const receivedBatches: any[][] = [] let resolvePromise: () => void const dataFetchingPromise = new Promise((resolve) => { resolvePromise = resolve }) - const batchStream = new KafkaMessageBatchStream( - (batch) => { - receivedBatches.push(batch) - // We expect 3 batches and the last message waiting in the stream - if (receivedBatches.length >= 3) { - resolvePromise() - } - return Promise.resolve() - }, - { - batchSize: 3, - timeoutMilliseconds: 10000, - }, - ) // Setting big timeout to check batch size only + const batchStream = new KafkaMessageBatchStream({ + batchSize: 3, + timeoutMilliseconds: 10000, + }) // Setting big timeout to check batch size only + + batchStream.on('data', (batch) => { + receivedBatches.push(batch) + // We expect 3 batches and the last message waiting in the stream + if (receivedBatches.length >= 3) { + resolvePromise() + } + }) for (const message of messages) { batchStream.write(message) @@ -44,9 +41,9 @@ describe('KafkaMessageBatchStream', () => { // Then expect(receivedBatches).toEqual([ - { topic, partition: 0, messages: [messages[0], messages[1], messages[2]] }, - { topic, partition: 0, messages: [messages[3], messages[4], messages[5]] }, - { topic, partition: 0, messages: [messages[6], messages[7], messages[8]] }, + [messages[0], messages[1], messages[2]], + [messages[3], messages[4], messages[5]], + [messages[6], messages[7], messages[8]], ]) }) @@ -61,18 +58,16 @@ describe('KafkaMessageBatchStream', () => { })) // When - const receivedBatches: MessageBatch[] = [] + const receivedBatches: any[][] = [] - const batchStream = new KafkaMessageBatchStream( - (batch) => { - receivedBatches.push(batch) - return Promise.resolve() - }, - { - batchSize: 1000, - timeoutMilliseconds: 100, - }, - ) // Setting big batch size to check timeout only + const batchStream = new KafkaMessageBatchStream({ + batchSize: 1000, + timeoutMilliseconds: 100, + }) // Setting big batch size to check timeout only + + batchStream.on('data', (batch) => { + receivedBatches.push(batch) + }) for (const message of messages) { batchStream.write(message) @@ -82,7 +77,7 @@ describe('KafkaMessageBatchStream', () => { await setTimeout(150) // Then - expect(receivedBatches).toEqual([{ topic, partition: 0, messages }]) + expect(receivedBatches).toEqual([messages]) }) it('should support multiple topics and partitions', async () => { @@ -120,27 +115,24 @@ describe('KafkaMessageBatchStream', () => { resolvePromise = resolve }) - const batchStream = new KafkaMessageBatchStream<{ topic: string; partition: number }>( - (batch) => { - const key = `${batch.topic}:${batch.partition}` - if (!receivedBatchesByTopicPartition[key]) { - receivedBatchesByTopicPartition[key] = [] - } - receivedBatchesByTopicPartition[key]!.push(batch.messages) - - // We expect 5 batches and last message waiting in the stream - receivedMessagesCounter++ - if (receivedMessagesCounter >= 5) { - resolvePromise() - } - - return Promise.resolve() - }, - { - batchSize: 2, - timeoutMilliseconds: 10000, - }, - ) // Setting big timeout to check batch size only + const batchStream = new KafkaMessageBatchStream<{ topic: string; partition: number }>({ + batchSize: 2, + timeoutMilliseconds: 10000, + }) // Setting big timeout to check batch size only + + batchStream.on('data', (batch) => { + const key = `${batch[0]!.topic}:${batch[0]!.partition}` + if (!receivedBatchesByTopicPartition[key]) { + receivedBatchesByTopicPartition[key] = [] + } + receivedBatchesByTopicPartition[key]!.push(batch) + + // We expect 5 batches and last message waiting in the stream + receivedMessagesCounter++ + if (receivedMessagesCounter >= 5) { + resolvePromise() + } + }) for (const message of messages) { batchStream.write(message) @@ -199,23 +191,20 @@ describe('KafkaMessageBatchStream', () => { resolvePromise = resolve }) - const batchStream = new KafkaMessageBatchStream<{ topic: string; partition: number }>( - (batch) => { - receivedBatches.push(batch) + const batchStream = new KafkaMessageBatchStream<{ topic: string; partition: number }>({ + batchSize: 2, + timeoutMilliseconds: 10000, + }) // Setting big timeout to check batch size only - // We expect 4 batches (2 per partition) - receivedBatchesCounter++ - if (receivedBatchesCounter >= 4) { - resolvePromise() - } + batchStream.on('data', (batch) => { + receivedBatches.push(batch) - return Promise.resolve() - }, - { - batchSize: 2, - timeoutMilliseconds: 10000, - }, - ) // Setting big timeout to check batch size only + // We expect 6 batches due to cross-partition accumulation with batchSize=2 + receivedBatchesCounter++ + if (receivedBatchesCounter >= 6) { + resolvePromise() + } + }) for (const message of messages) { batchStream.write(message) @@ -224,76 +213,192 @@ describe('KafkaMessageBatchStream', () => { await dataFetchingPromise // Then + // With batchSize=2, messages accumulate across all partitions: + // - write(msg[0], msg[1]) → flush → [msg[0], msg[1]] (partition 0) + // - write(msg[2], msg[3]) → flush → [msg[2]] (partition 0) and [msg[3]] (partition 1) + // - write(msg[4], msg[5]) → flush → [msg[4], msg[5]] (partition 1) + // - write(msg[6], msg[7]) → flush → [msg[6]] (partition 0) and [msg[7]] (partition 1) expect(receivedBatches).toEqual([ - { topic, partition: 0, messages: [messages[0], messages[1]] }, - { topic, partition: 1, messages: [messages[3], messages[4]] }, - { topic, partition: 0, messages: [messages[2], messages[6]] }, - { topic, partition: 1, messages: [messages[5], messages[7]] }, + [messages[0], messages[1]], // partition 0 + [messages[2]], // partition 0 + [messages[3]], // partition 1 + [messages[4], messages[5]], // partition 1 + [messages[6]], // partition 0 + [messages[7]], // partition 1 ]) + + expect(messages[0]!.partition).toBe(0) + expect(messages[1]!.partition).toBe(0) + expect(messages[2]!.partition).toBe(0) + expect(messages[3]!.partition).toBe(1) + expect(messages[4]!.partition).toBe(1) + expect(messages[5]!.partition).toBe(1) + expect(messages[6]!.partition).toBe(0) + expect(messages[7]!.partition).toBe(1) }) - it('should handle backpressure correctly when timeout flush is slow', async () => { - // Given - const topic = 'test-topic' - const messages = Array.from({ length: 6 }, (_, i) => ({ - id: i + 1, - content: `Message ${i + 1}`, - topic, - partition: 0, - })) + describe('backpressure', () => { + it('should pause writes when the readable buffer is full', async () => { + // With batchSize=1, each message is immediately flushed to the readable buffer. + // The objectMode readableHighWaterMark defaults to 16: + // push() returns false on the 16th flush, causing the _write callback to be held + // until _read() signals the downstream is ready again. + const batchStream = new KafkaMessageBatchStream({ + batchSize: 1, + timeoutMilliseconds: 10000, + }) + + const processedmessages = new Set() + // Write 15 messages: push() returns true for each (buffer 1→15, below HWM of 16) + for (let i = 0; i < 15; i++) { + await new Promise((resolve) => + batchStream.write({ id: i, topic: 'test', partition: 0 }, () => { + processedmessages.add(i) + resolve() + }), + ) + } + + // 16th write fills the buffer to HWM: push() returns false, callback is held + let sixteenthWriteCompleted = false + batchStream.write({ id: 15, topic: 'test', partition: 0 }, () => { + processedmessages.add(15) + sixteenthWriteCompleted = true + }) + + await setTimeout(10) + expect(processedmessages.size).toEqual(15) + expect(sixteenthWriteCompleted).toBe(false) // write is paused by backpressure + + // Consuming one item triggers _read(), releasing the held callback + batchStream.read() + + await setTimeout(10) + expect(processedmessages.size).toEqual(16) + expect(sixteenthWriteCompleted).toBe(true) // write resumes + }) - const batchStartTimes: number[] = [] // Track start times of batch processing - const batchEndTimes: number[] = [] // Track end times of batch processing - const batchMessageCounts: number[] = [] // Track number of messages per batch - let maxConcurrentBatches = 0 // Track max concurrent batches + it('should deliver all messages without loss when the consumer is slow', async () => { + // 20 messages with batchSize=1 generates 20 batches. + // HWM is 16, so batches 17-20 are held until the consumer drains the buffer, + // verifying that backpressure does not cause message loss. + const topic = 'test-topic' + const totalMessages = 20 + const messages = Array.from({ length: totalMessages }, (_, i) => ({ + id: i, + topic, + partition: 0, + })) - let batchesProcessing = 0 - const batchStream = new KafkaMessageBatchStream( - async (batch) => { - batchStartTimes.push(Date.now()) - batchMessageCounts.push(batch.messages.length) + const batchStream = new KafkaMessageBatchStream({ + batchSize: 1, + timeoutMilliseconds: 10000, + }) + + const receivedIds: number[] = [] + let resolveAll!: () => void + const allReceived = new Promise((resolve) => { + resolveAll = resolve + }) + + // Slow consumer: each batch takes longer than writes are produced + const consume = async () => { + for await (const batch of batchStream) { + await setTimeout(10) + for (const msg of batch) receivedIds.push(msg.id) + if (receivedIds.length >= totalMessages) { + resolveAll() + break + } + } + } + void consume() - batchesProcessing++ - maxConcurrentBatches = Math.max(maxConcurrentBatches, batchesProcessing) + for (const msg of messages) batchStream.write(msg) - // Simulate batch processing (50ms per batch) - await setTimeout(50) + await allReceived + expect(receivedIds).toHaveLength(totalMessages) + expect(receivedIds).toEqual(messages.map((m) => m.id)) + }) - batchEndTimes.push(Date.now()) - batchesProcessing-- - }, - { - batchSize: 1000, // Large batch size to never trigger size-based flushing - timeoutMilliseconds: 10, // Short timeout to trigger flush after each message - }, - ) + it('should respect a custom readableHighWaterMark', async () => { + // With readableHighWaterMark=1 and batchSize=1, push() returns false after the + // very first item in the readable buffer, triggering backpressure immediately. + const batchStream = new KafkaMessageBatchStream({ + batchSize: 1, + timeoutMilliseconds: 10000, + readableHighWaterMark: 1, + }) - // When: Write messages with 20ms delay between them - // Since processing (50ms) is slower than message arrival + timeout, backpressure causes accumulation - for (const message of messages) { - batchStream.write(message) - await setTimeout(20) - } + // First write: flushed immediately, buffer reaches HWM=1, push() returns false + // → _write callback is held by backpressure + let firstWriteCompleted = false + batchStream.write({ id: 0, topic: 'test', partition: 0 }, () => { + firstWriteCompleted = true + }) - // Then - // Wait until all 3 batches have been processed - await waitAndRetry(() => batchMessageCounts.length >= 3, 500, 20) - - // Backpressure causes messages to accumulate while previous batch processes: - // - Batch 1: Message 1 (flushed at 10ms timeout) - // - Batch 2: Messages 2-4 (accumulated during Batch 1 processing, including Message 4 arriving at ~60ms) - // - Batch 3: Messages 5-6 (accumulated during Batch 2 processing) - expect(batchMessageCounts).toEqual([1, 3, 2]) - - // Verify that batches never processed in parallel (backpressure working) - expect(maxConcurrentBatches).toBe(1) // Should never process more than 1 batch at a time - - // Verify that batches were processed sequentially (each starts after previous ends) - for (let i = 1; i < batchStartTimes.length; i++) { - const previousEndTime = batchEndTimes[i - 1] - const currentStartTime = batchStartTimes[i] - // The current batch must start after the previous batch finished - expect(currentStartTime).toBeGreaterThanOrEqual(previousEndTime ?? 0) - } + await setTimeout(10) + expect(firstWriteCompleted).toBe(false) // held by backpressure + + // Consuming one item triggers _read(), releasing the held callback + batchStream.read() + + await setTimeout(10) + expect(firstWriteCompleted).toBe(true) // write resumes + }) + + it('should defer timeout flush when backpressured and flush once consumer reads', () => { + vi.useFakeTimers() + + const topic = 'test-topic' + const batchStream = new KafkaMessageBatchStream({ + batchSize: 1000, // large: only timeout-based flushes + timeoutMilliseconds: 100, + }) + + // Mock push() to simulate a full readable buffer on the first flush + let simulateBackpressure = true + const originalPush = batchStream.push.bind(batchStream) + vi.spyOn(batchStream, 'push').mockImplementation((chunk) => { + originalPush(chunk) // still push the data to the buffer + return !simulateBackpressure // return false to signal backpressure + }) + + // No 'data' listener: stream stays in paused mode so _read() is only + // triggered when batchStream.read() is called explicitly + + // Write 5 messages: they accumulate in this.messages, a timeout is scheduled + for (let i = 0; i < 5; i++) { + batchStream.write({ id: i, topic, partition: 0 }) + } + + // First timeout fires: flushMessages() → push() returns false → isBackPreassured = true + vi.advanceTimersByTime(100) + expect(batchStream.readableLength).toBe(1) // 1 batch buffered (the 5 messages) + + // Write 3 more messages: they accumulate in this.messages while backpressured + for (let i = 5; i < 8; i++) { + batchStream.write({ id: i, topic, partition: 0 }) + } + + // Second timeout fires: isBackPreassured is true → reschedules several times without flushing + vi.advanceTimersByTime(300) + expect(batchStream.readableLength).toBe(1) // unchanged: no new flush happened + + // Consumer reads one item → triggers _read() → isBackPreassured = false + simulateBackpressure = false + const firstBatch = batchStream.read() + expect(firstBatch).toHaveLength(5) + expect(batchStream.readableLength).toBe(0) + + // Third timeout fires: isBackPreassured is false → flushes the 3 accumulated messages + vi.advanceTimersByTime(100) + expect(batchStream.readableLength).toBe(1) // new batch pushed + + const secondBatch = batchStream.read() + expect(secondBatch).toHaveLength(3) // messages 5–7 + + vi.useRealTimers() + }) }) }) diff --git a/packages/kafka/lib/utils/KafkaMessageBatchStream.ts b/packages/kafka/lib/utils/KafkaMessageBatchStream.ts index a6c43d0a..edde1ffa 100644 --- a/packages/kafka/lib/utils/KafkaMessageBatchStream.ts +++ b/packages/kafka/lib/utils/KafkaMessageBatchStream.ts @@ -1,122 +1,158 @@ -import { Transform } from 'node:stream' +import { Duplex } from 'node:stream' -// Topic and partition are required for the stream to work properly +type CallbackFunction = (error?: Error | null) => void type MessageWithTopicAndPartition = { topic: string; partition: number } +/** + * Options for configuring the KafkaMessageBatchStream behavior. + */ export type KafkaMessageBatchOptions = { + /** Maximum number of messages to accumulate across all partitions before flushing */ batchSize: number + /** Time in milliseconds to wait before flushing incomplete batches */ timeoutMilliseconds: number + /** + * Maximum number of topic-partition batches to buffer on the readable side before signaling backpressure. + * Each unit represents one array of messages belonging to the same topic-partition, produced per flush. + * A single flush may push multiple such arrays (one per distinct topic-partition in the accumulated batch). + * Defaults to Node.js object-mode default (16). Lower values trigger backpressure sooner, + * reducing downstream memory pressure at the cost of more frequent flow-control cycles. + */ + readableHighWaterMark?: number } -export type MessageBatch = { topic: string; partition: number; messages: TMessage[] } -export type OnMessageBatchCallback = (batch: MessageBatch) => Promise +/** + * Interface extending Duplex to provide strong typing for the 'data' event. + * The stream emits arrays of messages grouped by topic-partition. + */ +export interface KafkaMessageBatchStream + extends Duplex { + // biome-ignore lint/suspicious/noExplicitAny: compatible with Duplex definition + on(event: string | symbol, listener: (...args: any[]) => void): this + /** Listen for batches of messages from the same topic-partition */ + on(event: 'data', listener: (chunk: TMessage[]) => void): this + push(chunk: TMessage[] | null): boolean +} /** - * Collects messages in batches based on provided batchSize and flushes them when messages amount or timeout is reached. + * A Duplex stream that batches Kafka messages based on size and timeout constraints. * - * This implementation uses Transform stream which properly handles backpressure by design. - * When the downstream consumer is slow, the stream will automatically pause accepting new messages - * until the consumer catches up, preventing memory leaks and OOM errors. + * Key features: + * - Accumulates messages across all partitions up to `batchSize` for true memory control + * - Groups messages by topic-partition when flushing + * - Implements backpressure: pauses input when downstream consumers are overwhelmed + * - Auto-flushes on timeout to prevent messages from waiting indefinitely + * + * @example + * ```typescript + * const batchStream = new KafkaMessageBatchStream({ batchSize: 100, timeoutMilliseconds: 1000 }) + * batchStream.on('data', (batch) => { + * console.log(`Received ${batch.length} messages from ${batch[0].topic}:${batch[0].partition}`) + * }) + * ``` */ -export class KafkaMessageBatchStream< - TMessage extends MessageWithTopicAndPartition, -> extends Transform { - private readonly onBatch: OnMessageBatchCallback +// biome-ignore lint/suspicious/noUnsafeDeclarationMerging: merging interface with class to add strong typing for 'data' event +export class KafkaMessageBatchStream extends Duplex { private readonly batchSize: number private readonly timeout: number - private readonly currentBatchPerTopicPartition: Record - private readonly batchTimeoutPerTopicPartition: Record - - private readonly timeoutProcessingPromises: Map> = new Map() + private messages: TMessage[] + private existingTimeout: NodeJS.Timeout | undefined + private pendingCallback: CallbackFunction | undefined + private isBackPressured: boolean - constructor( - onBatch: OnMessageBatchCallback, - options: { batchSize: number; timeoutMilliseconds: number }, - ) { - super({ objectMode: true }) - this.onBatch = onBatch + constructor(options: KafkaMessageBatchOptions) { + super({ objectMode: true, readableHighWaterMark: options.readableHighWaterMark }) this.batchSize = options.batchSize this.timeout = options.timeoutMilliseconds - this.currentBatchPerTopicPartition = {} - this.batchTimeoutPerTopicPartition = {} + this.messages = [] + this.isBackPressured = false } - override async _transform(message: TMessage, _encoding: BufferEncoding, callback: () => void) { - const key = getTopicPartitionKey(message.topic, message.partition) - - // Wait for all pending timeout flushes to complete to maintain backpressure - if (this.timeoutProcessingPromises.size > 0) { - // Capture a snapshot of current promises to avoid race conditions with new timeouts - const promiseEntries = Array.from(this.timeoutProcessingPromises.entries()) - // Wait for all to complete and then clean up from the map - await Promise.all( - promiseEntries.map(([k, p]) => p.finally(() => this.timeoutProcessingPromises.delete(k))), - ) - } - - // Accumulate the message - if (!this.currentBatchPerTopicPartition[key]) this.currentBatchPerTopicPartition[key] = [] - this.currentBatchPerTopicPartition[key].push(message) - - // Check if the batch is complete by size - if (this.currentBatchPerTopicPartition[key].length >= this.batchSize) { - await this.flushCurrentBatchMessages(message.topic, message.partition) - callback() - return - } + /** + * Called when the downstream consumer is ready to receive more data. + * This is the backpressure release mechanism: we resume the writable side + * by calling the pending callback that was held during backpressure. + */ + override _read() { + this.isBackPressured = false + if (!this.pendingCallback) return + + const cb = this.pendingCallback + this.pendingCallback = undefined + cb() // Resume the writable side + } - // Start timeout for this partition if not already started - if (!this.batchTimeoutPerTopicPartition[key]) { - this.batchTimeoutPerTopicPartition[key] = setTimeout( - () => - this.timeoutProcessingPromises.set( - key, - this.flushCurrentBatchMessages(message.topic, message.partition), - ), - this.timeout, - ) + /** + * Writes a message to the stream. + * Messages accumulate until batchSize is reached or timeout expires. + * Implements backpressure by holding the callback when downstream cannot consume. + */ + override _write(message: TMessage, _encoding: BufferEncoding, callback: CallbackFunction) { + let canContinue = true + + try { + this.messages.push(message) + + if (this.messages.length >= this.batchSize) { + // Batch is full, flush immediately + canContinue = this.flushMessages() + } else { + // Start/continue the timeout for partial batches + // Using ??= ensures we only set one timeout at a time + this.existingTimeout ??= setTimeout(() => this.flushMessages(), this.timeout) + } + } finally { + // Backpressure handling: hold the callback if push() returned false + if (!canContinue) this.pendingCallback = callback + else callback() } - - callback() } - // Flush all remaining batches when stream is closing - override async _flush(callback: () => void) { - await this.flushAllBatches() + override _final(callback: CallbackFunction) { + // Clean timeout + clearTimeout(this.existingTimeout) + this.existingTimeout = undefined + // If there are remaining messages -> skip them + // As they are not committed, the next consumer will process them + this.messages = [] + this.push(null) callback() } - private async flushAllBatches() { - for (const key of Object.keys(this.currentBatchPerTopicPartition)) { - const { topic, partition } = splitTopicPartitionKey(key) - await this.flushCurrentBatchMessages(topic, partition) + private flushMessages(): boolean { + clearTimeout(this.existingTimeout) + this.existingTimeout = undefined + + if (this.isBackPressured) { + this.existingTimeout = setTimeout(() => this.flushMessages(), this.timeout) + return false } - } - private async flushCurrentBatchMessages(topic: string, partition: number) { - const key = getTopicPartitionKey(topic, partition) + // Extract all accumulated messages and clear the array + const messageBatch = this.messages.splice(0, this.messages.length) + + // Group by topic-partition to maintain commit guarantees + const messagesByTopicPartition: Record = {} + for (const message of messageBatch) { + const key = getTopicPartitionKey(message.topic, message.partition) + if (!messagesByTopicPartition[key]) messagesByTopicPartition[key] = [] + messagesByTopicPartition[key].push(message) + } - // Clear timeout - if (this.batchTimeoutPerTopicPartition[key]) { - clearTimeout(this.batchTimeoutPerTopicPartition[key]) - this.batchTimeoutPerTopicPartition[key] = undefined + // Push each topic-partition batch and track backpressure. + // All batches must be pushed regardless: messages were already splice'd from the buffer, + // so breaking early would lose them. Once push() returns false, subsequent calls in the + // same tick also return false, so the last value correctly reflects backpressure. + let canContinue = true + for (const messagesForKey of Object.values(messagesByTopicPartition)) { + canContinue = this.push(messagesForKey) } - const messages = this.currentBatchPerTopicPartition[key] ?? [] + if (!canContinue) this.isBackPressured = true - // Push the batch downstream - await this.onBatch({ topic, partition, messages }) - this.currentBatchPerTopicPartition[key] = [] + return canContinue } } const getTopicPartitionKey = (topic: string, partition: number): string => `${topic}:${partition}` -const splitTopicPartitionKey = (key: string): { topic: string; partition: number } => { - const [topic, partition] = key.split(':') - /* v8 ignore start */ - if (!topic || !partition) throw new Error('Invalid topic-partition key format') - /* v8 ignore stop */ - - return { topic, partition: Number.parseInt(partition, 10) } -} diff --git a/packages/kafka/load-tests/package-lock.json b/packages/kafka/load-tests/package-lock.json index 0b713db7..76f67b51 100644 --- a/packages/kafka/load-tests/package-lock.json +++ b/packages/kafka/load-tests/package-lock.json @@ -1,1207 +1,1211 @@ { - "name": "@message-queue-toolkit/kafka-load-tests", - "version": "0.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@message-queue-toolkit/kafka-load-tests", - "version": "0.0.0", - "dependencies": { - "@lokalise/node-core": "^14.2.0", - "@message-queue-toolkit/core": "file:../../core", - "@message-queue-toolkit/kafka": "file:../../kafka", - "@message-queue-toolkit/schemas": "file:../../schemas", - "@platformatic/kafka": "1.28.0", - "pg": "^8.19.0", - "zod": "^4.0.17" - }, - "devDependencies": { - "@types/pg": "^8.16.0", - "typescript": "^5.9.3" - } - }, - "..": { - "name": "@message-queue-toolkit/kafka", - "version": "0.9.1", - "license": "MIT", - "dependencies": { - "@lokalise/node-core": "^14.2.0", - "@lokalise/universal-ts-utils": "^4.5.1", - "@platformatic/kafka": "^1.26.0" - }, - "devDependencies": { - "@biomejs/biome": "^2.3.2", - "@lokalise/biome-config": "^3.1.0", - "@lokalise/tsconfig": "^3.0.0", - "@message-queue-toolkit/core": ">=23.0.0", - "@message-queue-toolkit/schemas": ">=7.0.0", - "@types/node": "^25.0.2", - "@vitest/coverage-v8": "^4.0.15", - "awilix": "^12.0.1", - "awilix-manager": "^6.0.0", - "rimraf": "^6.0.1", - "typescript": "^5.9.2", - "vitest": "^4.0.15", - "zod": "^4.0.17" - }, - "engines": { - "node": ">= 22.14.0" - }, - "peerDependencies": { - "@message-queue-toolkit/core": ">=23.0.0", - "@message-queue-toolkit/schemas": ">=7.0.0", - "zod": ">=3.25.76 <5.0.0" - } - }, - "../../core": { - "name": "@message-queue-toolkit/core", - "version": "25.3.0", - "license": "MIT", - "dependencies": { - "@lokalise/node-core": "^14.2.0", - "@lokalise/universal-ts-utils": "^4.5.1", - "@message-queue-toolkit/schemas": "^7.0.0", - "dot-prop": "^10.1.0", - "fast-equals": "^6.0.0", - "json-stream-stringify": "^3.1.6", - "tmp": "^0.2.3", - "toad-cache": "^3.7.0" - }, - "devDependencies": { - "@biomejs/biome": "^2.3.8", - "@lokalise/biome-config": "^3.1.0", - "@lokalise/tsconfig": "^3.0.0", - "@types/node": "^25.0.2", - "@types/tmp": "^0.2.6", - "@vitest/coverage-v8": "^4.0.15", - "awilix": "^12.0.5", - "awilix-manager": "^6.1.0", - "rimraf": "^6.0.1", - "typescript": "^5.9.2", - "vitest": "^4.0.15", - "zod": "^4.1.13" - }, - "peerDependencies": { - "zod": ">=3.25.76 <5.0.0" - } - }, - "../../schemas": { - "name": "@message-queue-toolkit/schemas", - "version": "7.1.0", - "license": "MIT", - "devDependencies": { - "@biomejs/biome": "^2.3.2", - "@lokalise/biome-config": "^3.1.0", - "@lokalise/tsconfig": "^3.0.0", - "@types/node": "^25.0.2", - "@vitest/coverage-v8": "^4.0.15", - "rimraf": "^6.0.1", - "typescript": "^5.9.2", - "vitest": "^4.0.15", - "zod": "^4.0.17" - }, - "peerDependencies": { - "zod": ">=3.25.67" - } - }, - "node_modules/@emnapi/core": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", - "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.1.0", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", - "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", - "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@lokalise/node-core": { - "version": "14.7.4", - "resolved": "https://registry.npmjs.org/@lokalise/node-core/-/node-core-14.7.4.tgz", - "integrity": "sha512-ZBlqh25P4YHgHGTc8iON6FtrLwTyy0MbIu7BmiN4ClZI2M92ssvnIUf2PHHZALLHN9w3yrs67JyHw0X+yiam2Q==", - "license": "Apache-2.0", - "dependencies": { - "dot-prop": "6.0.1", - "pino": "^10.0.0", - "pino-pretty": "^13.1.1", - "tslib": "^2.8.1" - }, - "peerDependencies": { - "zod": ">=3.25.76 <5.0.0" - } - }, - "node_modules/@message-queue-toolkit/core": { - "resolved": "../../core", - "link": true - }, - "node_modules/@message-queue-toolkit/kafka": { - "resolved": "..", - "link": true - }, - "node_modules/@message-queue-toolkit/schemas": { - "resolved": "../../schemas", - "link": true - }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", - "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.10.0" - } - }, - "node_modules/@node-rs/crc32": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32/-/crc32-1.10.6.tgz", - "integrity": "sha512-+llXfqt+UzgoDzT9of5vPQPGqTAVCohU74I9zIBkNo5TH6s2P31DFJOGsJQKN207f0GHnYv5pV3wh3BCY/un/A==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "optionalDependencies": { - "@node-rs/crc32-android-arm-eabi": "1.10.6", - "@node-rs/crc32-android-arm64": "1.10.6", - "@node-rs/crc32-darwin-arm64": "1.10.6", - "@node-rs/crc32-darwin-x64": "1.10.6", - "@node-rs/crc32-freebsd-x64": "1.10.6", - "@node-rs/crc32-linux-arm-gnueabihf": "1.10.6", - "@node-rs/crc32-linux-arm64-gnu": "1.10.6", - "@node-rs/crc32-linux-arm64-musl": "1.10.6", - "@node-rs/crc32-linux-x64-gnu": "1.10.6", - "@node-rs/crc32-linux-x64-musl": "1.10.6", - "@node-rs/crc32-wasm32-wasi": "1.10.6", - "@node-rs/crc32-win32-arm64-msvc": "1.10.6", - "@node-rs/crc32-win32-ia32-msvc": "1.10.6", - "@node-rs/crc32-win32-x64-msvc": "1.10.6" - } - }, - "node_modules/@node-rs/crc32-android-arm-eabi": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-android-arm-eabi/-/crc32-android-arm-eabi-1.10.6.tgz", - "integrity": "sha512-vZAMuJXm3TpWPOkkhxdrofWDv+Q+I2oO7ucLRbXyAPmXFNDhHtBxbO1rk9Qzz+M3eep8ieS4/+jCL1Q0zacNMQ==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-android-arm64": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-android-arm64/-/crc32-android-arm64-1.10.6.tgz", - "integrity": "sha512-Vl/JbjCinCw/H9gEpZveWCMjxjcEChDcDBM8S4hKay5yyoRCUHJPuKr4sjVDBeOm+1nwU3oOm6Ca8dyblwp4/w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-darwin-arm64": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-darwin-arm64/-/crc32-darwin-arm64-1.10.6.tgz", - "integrity": "sha512-kARYANp5GnmsQiViA5Qu74weYQ3phOHSYQf0G+U5wB3NB5JmBHnZcOc46Ig21tTypWtdv7u63TaltJQE41noyg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-darwin-x64": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-darwin-x64/-/crc32-darwin-x64-1.10.6.tgz", - "integrity": "sha512-Q99bevJVMfLTISpkpKBlXgtPUItrvTWKFyiqoKH5IvscZmLV++NH4V13Pa17GTBmv9n18OwzgQY4/SRq6PQNVA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-freebsd-x64": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-freebsd-x64/-/crc32-freebsd-x64-1.10.6.tgz", - "integrity": "sha512-66hpawbNjrgnS9EDMErta/lpaqOMrL6a6ee+nlI2viduVOmRZWm9Rg9XdGTK/+c4bQLdtC6jOd+Kp4EyGRYkAg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-linux-arm-gnueabihf": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm-gnueabihf/-/crc32-linux-arm-gnueabihf-1.10.6.tgz", - "integrity": "sha512-E8Z0WChH7X6ankbVm8J/Yym19Cq3otx6l4NFPS6JW/cWdjv7iw+Sps2huSug+TBprjbcEA+s4TvEwfDI1KScjg==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-linux-arm64-gnu": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm64-gnu/-/crc32-linux-arm64-gnu-1.10.6.tgz", - "integrity": "sha512-LmWcfDbqAvypX0bQjQVPmQGazh4dLiVklkgHxpV4P0TcQ1DT86H/SWpMBMs/ncF8DGuCQ05cNyMv1iddUDugoQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-linux-arm64-musl": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm64-musl/-/crc32-linux-arm64-musl-1.10.6.tgz", - "integrity": "sha512-k8ra/bmg0hwRrIEE8JL1p32WfaN9gDlUUpQRWsbxd1WhjqvXea7kKO6K4DwVxyxlPhBS9Gkb5Urq7Y4mXANzaw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-linux-x64-gnu": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-x64-gnu/-/crc32-linux-x64-gnu-1.10.6.tgz", - "integrity": "sha512-IfjtqcuFK7JrSZ9mlAFhb83xgium30PguvRjIMI45C3FJwu18bnLk1oR619IYb/zetQT82MObgmqfKOtgemEKw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-linux-x64-musl": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-x64-musl/-/crc32-linux-x64-musl-1.10.6.tgz", - "integrity": "sha512-LbFYsA5M9pNunOweSt6uhxenYQF94v3bHDAQRPTQ3rnjn+mK6IC7YTAYoBjvoJP8lVzcvk9hRj8wp4Jyh6Y80g==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-wasm32-wasi": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-wasm32-wasi/-/crc32-wasm32-wasi-1.10.6.tgz", - "integrity": "sha512-KaejdLgHMPsRaxnM+OG9L9XdWL2TabNx80HLdsCOoX9BVhEkfh39OeahBo8lBmidylKbLGMQoGfIKDjq0YMStw==", - "cpu": [ - "wasm32" - ], - "license": "MIT", - "optional": true, - "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.5" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@node-rs/crc32-win32-arm64-msvc": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-arm64-msvc/-/crc32-win32-arm64-msvc-1.10.6.tgz", - "integrity": "sha512-x50AXiSxn5Ccn+dCjLf1T7ZpdBiV1Sp5aC+H2ijhJO4alwznvXgWbopPRVhbp2nj0i+Gb6kkDUEyU+508KAdGQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-win32-ia32-msvc": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-ia32-msvc/-/crc32-win32-ia32-msvc-1.10.6.tgz", - "integrity": "sha512-DpDxQLaErJF9l36aghe1Mx+cOnYLKYo6qVPqPL9ukJ5rAGLtCdU0C+Zoi3gs9ySm8zmbFgazq/LvmsZYU42aBw==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-win32-x64-msvc": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-x64-msvc/-/crc32-win32-x64-msvc-1.10.6.tgz", - "integrity": "sha512-5B1vXosIIBw1m2Rcnw62IIfH7W9s9f7H7Ma0rRuhT8HR4Xh8QCgw6NJSI2S2MCngsGktYnAhyUvs81b7efTyQw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@pinojs/redact": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", - "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", - "license": "MIT" - }, - "node_modules/@platformatic/dynamic-buffer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@platformatic/dynamic-buffer/-/dynamic-buffer-0.3.0.tgz", - "integrity": "sha512-x/SN9lEK9qYqRXAQKXC61bD2LPCd3uUYfzAIX7+tpgaCLky7voJ/xcSh9cC+jmNbbzNH8cxDzYUJD4Lua5VmlQ==", - "license": "Apache-2.0", - "engines": { - "node": ">= 22.19.0" - } - }, - "node_modules/@platformatic/kafka": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/@platformatic/kafka/-/kafka-1.28.0.tgz", - "integrity": "sha512-JwG9FG36gwXpu4j3+61sLbHGSXkxTDc0eGowGsbcimiL+AnnI4rUWSqkCurBmAuBRbH6fa/BX54YfYFMHAr1fg==", - "license": "Apache-2.0", - "dependencies": { - "@platformatic/dynamic-buffer": "^0.3.0", - "@platformatic/wasm-utils": "^0.1.0", - "ajv": "^8.17.1", - "avsc": "^5.7.9", - "debug": "^4.4.3", - "fastq": "^1.19.1", - "mnemonist": "^0.40.3", - "scule": "^1.3.0" - }, - "engines": { - "node": ">= 20.19.4 || >= 22.18.0 || >= 24.6.0" - }, - "optionalDependencies": { - "@node-rs/crc32": "^1.10.6", - "protobufjs": "^8.0.0" - } - }, - "node_modules/@platformatic/wasm-utils": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@platformatic/wasm-utils/-/wasm-utils-0.1.0.tgz", - "integrity": "sha512-1fMkKsdud0pNlBh0JRELpWi3NE3/Kb0SCKR+5g2vH3ANDNlWDPJVDjNIJZYNdXA73yBfTVVve7xxBV22PUqZeg==", - "license": "Apache-2.0", - "dependencies": { - "@platformatic/dynamic-buffer": "^0.3.0" - }, - "engines": { - "node": ">= 22.19.0" - } - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "license": "BSD-3-Clause", - "optional": true - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "license": "BSD-3-Clause", - "optional": true - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "license": "BSD-3-Clause", - "optional": true - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", - "license": "BSD-3-Clause", - "optional": true - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "license": "BSD-3-Clause", - "optional": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", - "license": "BSD-3-Clause", - "optional": true - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", - "license": "BSD-3-Clause", - "optional": true - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", - "license": "BSD-3-Clause", - "optional": true - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "license": "BSD-3-Clause", - "optional": true - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", - "license": "BSD-3-Clause", - "optional": true - }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@types/node": { - "version": "25.3.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.2.tgz", - "integrity": "sha512-RpV6r/ij22zRRdyBPcxDeKAzH43phWVKEjL2iksqo1Vz3CuBUrgmPpPhALKiRfU7OMCmeeO9vECBMsV0hMTG8Q==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.18.0" - } - }, - "node_modules/@types/pg": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.16.0.tgz", - "integrity": "sha512-RmhMd/wD+CF8Dfo+cVIy3RR5cl8CyfXQ0tGgW6XBL8L4LM/UTEbNXYRbLwU6w+CgrKBNbrQWt4FUtTfaU5jSYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "pg-protocol": "*", - "pg-types": "^2.2.0" - } - }, - "node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/atomic-sleep": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", - "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/avsc": { - "version": "5.7.9", - "resolved": "https://registry.npmjs.org/avsc/-/avsc-5.7.9.tgz", - "integrity": "sha512-yOA4wFeI7ET3v32Di/sUybQ+ttP20JHSW3mxLuNGeO0uD6PPcvLrIQXSvy/rhJOWU5JrYh7U4OHplWMmtAtjMg==", - "license": "MIT", - "engines": { - "node": ">=0.11" - } - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "license": "MIT" - }, - "node_modules/dateformat": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", - "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/dot-prop": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", - "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", - "license": "MIT", - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/fast-copy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-4.0.2.tgz", - "integrity": "sha512-ybA6PDXIXOXivLJK/z9e+Otk7ve13I4ckBvGO5I2RRmBU1gMHLVDJYEuJYhGwez7YNlYji2M2DvVU+a9mSFDlw==", - "license": "MIT" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/help-me": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", - "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", - "license": "MIT" - }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/joycon": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", - "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/long": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", - "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", - "license": "Apache-2.0", - "optional": true - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mnemonist": { - "version": "0.40.3", - "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.40.3.tgz", - "integrity": "sha512-Vjyr90sJ23CKKH/qPAgUKicw/v6pRoamxIEDFOF8uSgFME7DqPRpHgRTejWVjkdGg5dXj0/NyxZHZ9bcjH+2uQ==", - "license": "MIT", - "dependencies": { - "obliterator": "^2.0.4" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/obliterator": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.5.tgz", - "integrity": "sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==", - "license": "MIT" - }, - "node_modules/on-exit-leak-free": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", - "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/pg": { - "version": "8.19.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.19.0.tgz", - "integrity": "sha512-QIcLGi508BAHkQ3pJNptsFz5WQMlpGbuBGBaIaXsWK8mel2kQ/rThYI+DbgjUvZrIr7MiuEuc9LcChJoEZK1xQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "pg-connection-string": "^2.11.0", - "pg-pool": "^3.12.0", - "pg-protocol": "^1.12.0", - "pg-types": "2.2.0", - "pgpass": "1.0.5" - }, - "engines": { - "node": ">= 16.0.0" - }, - "optionalDependencies": { - "pg-cloudflare": "^1.3.0" - }, - "peerDependencies": { - "pg-native": ">=3.0.1" - }, - "peerDependenciesMeta": { - "pg-native": { - "optional": true - } - } - }, - "node_modules/pg-cloudflare": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz", - "integrity": "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==", - "license": "MIT", - "optional": true - }, - "node_modules/pg-connection-string": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.11.0.tgz", - "integrity": "sha512-kecgoJwhOpxYU21rZjULrmrBJ698U2RxXofKVzOn5UDj61BPj/qMb7diYUR1nLScCDbrztQFl1TaQZT0t1EtzQ==", - "license": "MIT" - }, - "node_modules/pg-int8": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", - "license": "ISC", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/pg-pool": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.12.0.tgz", - "integrity": "sha512-eIJ0DES8BLaziFHW7VgJEBPi5hg3Nyng5iKpYtj3wbcAUV9A1wLgWiY7ajf/f/oO1wfxt83phXPY8Emztg7ITg==", - "license": "MIT", - "peerDependencies": { - "pg": ">=8.0" - } - }, - "node_modules/pg-protocol": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.12.0.tgz", - "integrity": "sha512-uOANXNRACNdElMXJ0tPz6RBM0XQ61nONGAwlt8da5zs/iUOOCLBQOHSXnrC6fMsvtjxbOJrZZl5IScGv+7mpbg==", - "license": "MIT" - }, - "node_modules/pg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", - "license": "MIT", - "dependencies": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pgpass": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", - "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", - "license": "MIT", - "dependencies": { - "split2": "^4.1.0" - } - }, - "node_modules/pino": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", - "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", - "license": "MIT", - "dependencies": { - "@pinojs/redact": "^0.4.0", - "atomic-sleep": "^1.0.0", - "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^3.0.0", - "pino-std-serializers": "^7.0.0", - "process-warning": "^5.0.0", - "quick-format-unescaped": "^4.0.3", - "real-require": "^0.2.0", - "safe-stable-stringify": "^2.3.1", - "sonic-boom": "^4.0.1", - "thread-stream": "^4.0.0" - }, - "bin": { - "pino": "bin.js" - } - }, - "node_modules/pino-abstract-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", - "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", - "license": "MIT", - "dependencies": { - "split2": "^4.0.0" - } - }, - "node_modules/pino-pretty": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.3.tgz", - "integrity": "sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==", - "license": "MIT", - "dependencies": { - "colorette": "^2.0.7", - "dateformat": "^4.6.3", - "fast-copy": "^4.0.0", - "fast-safe-stringify": "^2.1.1", - "help-me": "^5.0.0", - "joycon": "^3.1.1", - "minimist": "^1.2.6", - "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^3.0.0", - "pump": "^3.0.0", - "secure-json-parse": "^4.0.0", - "sonic-boom": "^4.0.1", - "strip-json-comments": "^5.0.2" - }, - "bin": { - "pino-pretty": "bin.js" - } - }, - "node_modules/pino-std-serializers": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", - "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", - "license": "MIT" - }, - "node_modules/postgres-array": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/postgres-bytea": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", - "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-date": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-interval": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "license": "MIT", - "dependencies": { - "xtend": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/process-warning": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", - "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT" - }, - "node_modules/protobufjs": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-8.0.0.tgz", - "integrity": "sha512-jx6+sE9h/UryaCZhsJWbJtTEy47yXoGNYI4z8ZaRncM0zBKeRqjO2JEcOUYwrYGb1WLhXM1FfMzW3annvFv0rw==", - "hasInstallScript": true, - "license": "BSD-3-Clause", - "optional": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/quick-format-unescaped": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", - "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", - "license": "MIT" - }, - "node_modules/real-require": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", - "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", - "license": "MIT", - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/safe-stable-stringify": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", - "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/scule": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz", - "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", - "license": "MIT" - }, - "node_modules/secure-json-parse": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.1.0.tgz", - "integrity": "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" + "name": "@message-queue-toolkit/kafka-load-tests", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@message-queue-toolkit/kafka-load-tests", + "version": "0.0.0", + "dependencies": { + "@lokalise/node-core": "^14.2.0", + "@message-queue-toolkit/core": "file:../../core", + "@message-queue-toolkit/kafka": "file:../../kafka", + "@message-queue-toolkit/schemas": "file:../../schemas", + "@platformatic/dynamic-buffer": "^0.3.1", + "@platformatic/kafka": "1.28.0", + "pg": "^8.19.0", + "zod": "^4.0.17" + }, + "devDependencies": { + "@types/pg": "^8.16.0", + "typescript": "^5.9.3" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "..": { + "name": "@message-queue-toolkit/kafka", + "version": "0.9.1", + "license": "MIT", + "dependencies": { + "@lokalise/node-core": "^14.2.0", + "@lokalise/universal-ts-utils": "^4.5.1", + "@platformatic/kafka": "^1.28.0" + }, + "devDependencies": { + "@biomejs/biome": "^2.3.2", + "@lokalise/biome-config": "^3.1.0", + "@lokalise/tsconfig": "^3.0.0", + "@message-queue-toolkit/core": ">=23.0.0", + "@message-queue-toolkit/schemas": ">=7.0.0", + "@types/node": "^25.0.2", + "@vitest/coverage-v8": "^4.0.15", + "awilix": "^12.0.1", + "awilix-manager": "^6.0.0", + "rimraf": "^6.0.1", + "typescript": "^5.9.2", + "vitest": "^4.0.15", + "zod": "^4.0.17" + }, + "engines": { + "node": ">= 22.14.0" + }, + "peerDependencies": { + "@message-queue-toolkit/core": ">=23.0.0", + "@message-queue-toolkit/schemas": ">=7.0.0", + "zod": ">=3.25.76 <5.0.0" + } + }, + "../../core": { + "name": "@message-queue-toolkit/core", + "version": "25.3.0", + "license": "MIT", + "dependencies": { + "@lokalise/node-core": "^14.2.0", + "@lokalise/universal-ts-utils": "^4.5.1", + "@message-queue-toolkit/schemas": "^7.0.0", + "dot-prop": "^10.1.0", + "fast-equals": "^6.0.0", + "json-stream-stringify": "^3.1.6", + "tmp": "^0.2.3", + "toad-cache": "^3.7.0" + }, + "devDependencies": { + "@biomejs/biome": "^2.3.8", + "@lokalise/biome-config": "^3.1.0", + "@lokalise/tsconfig": "^3.0.0", + "@types/node": "^25.0.2", + "@types/tmp": "^0.2.6", + "@vitest/coverage-v8": "^4.0.15", + "awilix": "^12.0.5", + "awilix-manager": "^6.1.0", + "rimraf": "^6.0.1", + "typescript": "^5.9.2", + "vitest": "^4.0.15", + "zod": "^4.1.13" + }, + "peerDependencies": { + "zod": ">=3.25.76 <5.0.0" + } + }, + "../../schemas": { + "name": "@message-queue-toolkit/schemas", + "version": "7.1.0", + "license": "MIT", + "devDependencies": { + "@biomejs/biome": "^2.3.2", + "@lokalise/biome-config": "^3.1.0", + "@lokalise/tsconfig": "^3.0.0", + "@types/node": "^25.0.2", + "@vitest/coverage-v8": "^4.0.15", + "rimraf": "^6.0.1", + "typescript": "^5.9.2", + "vitest": "^4.0.15", + "zod": "^4.0.17" + }, + "peerDependencies": { + "zod": ">=3.25.67" + } + }, + "node_modules/@emnapi/core": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", + "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@lokalise/node-core": { + "version": "14.7.4", + "resolved": "https://registry.npmjs.org/@lokalise/node-core/-/node-core-14.7.4.tgz", + "integrity": "sha512-ZBlqh25P4YHgHGTc8iON6FtrLwTyy0MbIu7BmiN4ClZI2M92ssvnIUf2PHHZALLHN9w3yrs67JyHw0X+yiam2Q==", + "license": "Apache-2.0", + "dependencies": { + "dot-prop": "6.0.1", + "pino": "^10.0.0", + "pino-pretty": "^13.1.1", + "tslib": "^2.8.1" + }, + "peerDependencies": { + "zod": ">=3.25.76 <5.0.0" + } + }, + "node_modules/@message-queue-toolkit/core": { + "resolved": "../../core", + "link": true + }, + "node_modules/@message-queue-toolkit/kafka": { + "resolved": "..", + "link": true + }, + "node_modules/@message-queue-toolkit/schemas": { + "resolved": "../../schemas", + "link": true + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@node-rs/crc32": { + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/@node-rs/crc32/-/crc32-1.10.6.tgz", + "integrity": "sha512-+llXfqt+UzgoDzT9of5vPQPGqTAVCohU74I9zIBkNo5TH6s2P31DFJOGsJQKN207f0GHnYv5pV3wh3BCY/un/A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@node-rs/crc32-android-arm-eabi": "1.10.6", + "@node-rs/crc32-android-arm64": "1.10.6", + "@node-rs/crc32-darwin-arm64": "1.10.6", + "@node-rs/crc32-darwin-x64": "1.10.6", + "@node-rs/crc32-freebsd-x64": "1.10.6", + "@node-rs/crc32-linux-arm-gnueabihf": "1.10.6", + "@node-rs/crc32-linux-arm64-gnu": "1.10.6", + "@node-rs/crc32-linux-arm64-musl": "1.10.6", + "@node-rs/crc32-linux-x64-gnu": "1.10.6", + "@node-rs/crc32-linux-x64-musl": "1.10.6", + "@node-rs/crc32-wasm32-wasi": "1.10.6", + "@node-rs/crc32-win32-arm64-msvc": "1.10.6", + "@node-rs/crc32-win32-ia32-msvc": "1.10.6", + "@node-rs/crc32-win32-x64-msvc": "1.10.6" + } + }, + "node_modules/@node-rs/crc32-android-arm-eabi": { + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-android-arm-eabi/-/crc32-android-arm-eabi-1.10.6.tgz", + "integrity": "sha512-vZAMuJXm3TpWPOkkhxdrofWDv+Q+I2oO7ucLRbXyAPmXFNDhHtBxbO1rk9Qzz+M3eep8ieS4/+jCL1Q0zacNMQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/crc32-android-arm64": { + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-android-arm64/-/crc32-android-arm64-1.10.6.tgz", + "integrity": "sha512-Vl/JbjCinCw/H9gEpZveWCMjxjcEChDcDBM8S4hKay5yyoRCUHJPuKr4sjVDBeOm+1nwU3oOm6Ca8dyblwp4/w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/crc32-darwin-arm64": { + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-darwin-arm64/-/crc32-darwin-arm64-1.10.6.tgz", + "integrity": "sha512-kARYANp5GnmsQiViA5Qu74weYQ3phOHSYQf0G+U5wB3NB5JmBHnZcOc46Ig21tTypWtdv7u63TaltJQE41noyg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/crc32-darwin-x64": { + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-darwin-x64/-/crc32-darwin-x64-1.10.6.tgz", + "integrity": "sha512-Q99bevJVMfLTISpkpKBlXgtPUItrvTWKFyiqoKH5IvscZmLV++NH4V13Pa17GTBmv9n18OwzgQY4/SRq6PQNVA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/crc32-freebsd-x64": { + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-freebsd-x64/-/crc32-freebsd-x64-1.10.6.tgz", + "integrity": "sha512-66hpawbNjrgnS9EDMErta/lpaqOMrL6a6ee+nlI2viduVOmRZWm9Rg9XdGTK/+c4bQLdtC6jOd+Kp4EyGRYkAg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/crc32-linux-arm-gnueabihf": { + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm-gnueabihf/-/crc32-linux-arm-gnueabihf-1.10.6.tgz", + "integrity": "sha512-E8Z0WChH7X6ankbVm8J/Yym19Cq3otx6l4NFPS6JW/cWdjv7iw+Sps2huSug+TBprjbcEA+s4TvEwfDI1KScjg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/crc32-linux-arm64-gnu": { + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm64-gnu/-/crc32-linux-arm64-gnu-1.10.6.tgz", + "integrity": "sha512-LmWcfDbqAvypX0bQjQVPmQGazh4dLiVklkgHxpV4P0TcQ1DT86H/SWpMBMs/ncF8DGuCQ05cNyMv1iddUDugoQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/crc32-linux-arm64-musl": { + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm64-musl/-/crc32-linux-arm64-musl-1.10.6.tgz", + "integrity": "sha512-k8ra/bmg0hwRrIEE8JL1p32WfaN9gDlUUpQRWsbxd1WhjqvXea7kKO6K4DwVxyxlPhBS9Gkb5Urq7Y4mXANzaw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/crc32-linux-x64-gnu": { + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-x64-gnu/-/crc32-linux-x64-gnu-1.10.6.tgz", + "integrity": "sha512-IfjtqcuFK7JrSZ9mlAFhb83xgium30PguvRjIMI45C3FJwu18bnLk1oR619IYb/zetQT82MObgmqfKOtgemEKw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/crc32-linux-x64-musl": { + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-x64-musl/-/crc32-linux-x64-musl-1.10.6.tgz", + "integrity": "sha512-LbFYsA5M9pNunOweSt6uhxenYQF94v3bHDAQRPTQ3rnjn+mK6IC7YTAYoBjvoJP8lVzcvk9hRj8wp4Jyh6Y80g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/crc32-wasm32-wasi": { + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-wasm32-wasi/-/crc32-wasm32-wasi-1.10.6.tgz", + "integrity": "sha512-KaejdLgHMPsRaxnM+OG9L9XdWL2TabNx80HLdsCOoX9BVhEkfh39OeahBo8lBmidylKbLGMQoGfIKDjq0YMStw==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.5" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@node-rs/crc32-win32-arm64-msvc": { + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-arm64-msvc/-/crc32-win32-arm64-msvc-1.10.6.tgz", + "integrity": "sha512-x50AXiSxn5Ccn+dCjLf1T7ZpdBiV1Sp5aC+H2ijhJO4alwznvXgWbopPRVhbp2nj0i+Gb6kkDUEyU+508KAdGQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/crc32-win32-ia32-msvc": { + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-ia32-msvc/-/crc32-win32-ia32-msvc-1.10.6.tgz", + "integrity": "sha512-DpDxQLaErJF9l36aghe1Mx+cOnYLKYo6qVPqPL9ukJ5rAGLtCdU0C+Zoi3gs9ySm8zmbFgazq/LvmsZYU42aBw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/crc32-win32-x64-msvc": { + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-x64-msvc/-/crc32-win32-x64-msvc-1.10.6.tgz", + "integrity": "sha512-5B1vXosIIBw1m2Rcnw62IIfH7W9s9f7H7Ma0rRuhT8HR4Xh8QCgw6NJSI2S2MCngsGktYnAhyUvs81b7efTyQw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@pinojs/redact": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", + "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", + "license": "MIT" + }, + "node_modules/@platformatic/dynamic-buffer": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@platformatic/dynamic-buffer/-/dynamic-buffer-0.3.1.tgz", + "integrity": "sha512-xQD5JSkQc4D15suOk7FezGDmh6Vb5e4phDoFZ/ASpa3Ft+3fOVwFOENmHtC1561zm/xHnKwI91NbMF8inpbk0Q==", + "license": "Apache-2.0", + "engines": { + "node": ">= 22.19.0" + } + }, + "node_modules/@platformatic/kafka": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@platformatic/kafka/-/kafka-1.28.0.tgz", + "integrity": "sha512-JwG9FG36gwXpu4j3+61sLbHGSXkxTDc0eGowGsbcimiL+AnnI4rUWSqkCurBmAuBRbH6fa/BX54YfYFMHAr1fg==", + "license": "Apache-2.0", + "dependencies": { + "@platformatic/dynamic-buffer": "^0.3.0", + "@platformatic/wasm-utils": "^0.1.0", + "ajv": "^8.17.1", + "avsc": "^5.7.9", + "debug": "^4.4.3", + "fastq": "^1.19.1", + "mnemonist": "^0.40.3", + "scule": "^1.3.0" + }, + "engines": { + "node": ">= 20.19.4 || >= 22.18.0 || >= 24.6.0" + }, + "optionalDependencies": { + "@node-rs/crc32": "^1.10.6", + "protobufjs": "^8.0.0" + } + }, + "node_modules/@platformatic/wasm-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@platformatic/wasm-utils/-/wasm-utils-0.1.0.tgz", + "integrity": "sha512-1fMkKsdud0pNlBh0JRELpWi3NE3/Kb0SCKR+5g2vH3ANDNlWDPJVDjNIJZYNdXA73yBfTVVve7xxBV22PUqZeg==", + "license": "Apache-2.0", + "dependencies": { + "@platformatic/dynamic-buffer": "^0.3.0" + }, + "engines": { + "node": ">= 22.19.0" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/node": { + "version": "25.3.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.2.tgz", + "integrity": "sha512-RpV6r/ij22zRRdyBPcxDeKAzH43phWVKEjL2iksqo1Vz3CuBUrgmPpPhALKiRfU7OMCmeeO9vECBMsV0hMTG8Q==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/pg": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.16.0.tgz", + "integrity": "sha512-RmhMd/wD+CF8Dfo+cVIy3RR5cl8CyfXQ0tGgW6XBL8L4LM/UTEbNXYRbLwU6w+CgrKBNbrQWt4FUtTfaU5jSYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/avsc": { + "version": "5.7.9", + "resolved": "https://registry.npmjs.org/avsc/-/avsc-5.7.9.tgz", + "integrity": "sha512-yOA4wFeI7ET3v32Di/sUybQ+ttP20JHSW3mxLuNGeO0uD6PPcvLrIQXSvy/rhJOWU5JrYh7U4OHplWMmtAtjMg==", + "license": "MIT", + "engines": { + "node": ">=0.11" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT" + }, + "node_modules/dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/fast-copy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-4.0.2.tgz", + "integrity": "sha512-ybA6PDXIXOXivLJK/z9e+Otk7ve13I4ckBvGO5I2RRmBU1gMHLVDJYEuJYhGwez7YNlYji2M2DvVU+a9mSFDlw==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "license": "MIT" + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0", + "optional": true + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mnemonist": { + "version": "0.40.3", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.40.3.tgz", + "integrity": "sha512-Vjyr90sJ23CKKH/qPAgUKicw/v6pRoamxIEDFOF8uSgFME7DqPRpHgRTejWVjkdGg5dXj0/NyxZHZ9bcjH+2uQ==", + "license": "MIT", + "dependencies": { + "obliterator": "^2.0.4" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/obliterator": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.5.tgz", + "integrity": "sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==", + "license": "MIT" + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/pg": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.19.0.tgz", + "integrity": "sha512-QIcLGi508BAHkQ3pJNptsFz5WQMlpGbuBGBaIaXsWK8mel2kQ/rThYI+DbgjUvZrIr7MiuEuc9LcChJoEZK1xQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "pg-connection-string": "^2.11.0", + "pg-pool": "^3.12.0", + "pg-protocol": "^1.12.0", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.3.0" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz", + "integrity": "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.11.0.tgz", + "integrity": "sha512-kecgoJwhOpxYU21rZjULrmrBJ698U2RxXofKVzOn5UDj61BPj/qMb7diYUR1nLScCDbrztQFl1TaQZT0t1EtzQ==", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.12.0.tgz", + "integrity": "sha512-eIJ0DES8BLaziFHW7VgJEBPi5hg3Nyng5iKpYtj3wbcAUV9A1wLgWiY7ajf/f/oO1wfxt83phXPY8Emztg7ITg==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.12.0.tgz", + "integrity": "sha512-uOANXNRACNdElMXJ0tPz6RBM0XQ61nONGAwlt8da5zs/iUOOCLBQOHSXnrC6fMsvtjxbOJrZZl5IScGv+7mpbg==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/pino": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", + "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", + "license": "MIT", + "dependencies": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^4.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", + "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-pretty": { + "version": "13.1.3", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.3.tgz", + "integrity": "sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==", + "license": "MIT", + "dependencies": { + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^4.0.0", + "fast-safe-stringify": "^2.1.1", + "help-me": "^5.0.0", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pump": "^3.0.0", + "secure-json-parse": "^4.0.0", + "sonic-boom": "^4.0.1", + "strip-json-comments": "^5.0.2" + }, + "bin": { + "pino-pretty": "bin.js" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", + "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", + "license": "MIT" + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/process-warning": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", + "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/protobufjs": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-8.0.0.tgz", + "integrity": "sha512-jx6+sE9h/UryaCZhsJWbJtTEy47yXoGNYI4z8ZaRncM0zBKeRqjO2JEcOUYwrYGb1WLhXM1FfMzW3annvFv0rw==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/scule": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz", + "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", + "license": "MIT" + }, + "node_modules/secure-json-parse": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.1.0.tgz", + "integrity": "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/sonic-boom": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", + "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/strip-json-comments": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", + "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/thread-stream": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.0.0.tgz", + "integrity": "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } - ], - "license": "BSD-3-Clause" - }, - "node_modules/sonic-boom": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", - "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", - "license": "MIT", - "dependencies": { - "atomic-sleep": "^1.0.0" - } - }, - "node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "license": "ISC", - "engines": { - "node": ">= 10.x" - } - }, - "node_modules/strip-json-comments": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", - "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==", - "license": "MIT", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/thread-stream": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.0.0.tgz", - "integrity": "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==", - "license": "MIT", - "dependencies": { - "real-require": "^0.2.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/zod": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", - "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", - "license": "MIT", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } } - } } diff --git a/packages/kafka/load-tests/package.json b/packages/kafka/load-tests/package.json index 8efcfdfe..80d2a323 100644 --- a/packages/kafka/load-tests/package.json +++ b/packages/kafka/load-tests/package.json @@ -32,6 +32,7 @@ "@message-queue-toolkit/core": "file:../../core", "@message-queue-toolkit/schemas": "file:../../schemas", "@lokalise/node-core": "^14.2.0", + "@platformatic/dynamic-buffer": "^0.3.1", "@platformatic/kafka": "1.28.0", "pg": "^8.19.0", "zod": "^4.0.17" diff --git a/packages/kafka/package.json b/packages/kafka/package.json index eda1bc71..45ddca1b 100644 --- a/packages/kafka/package.json +++ b/packages/kafka/package.json @@ -53,7 +53,8 @@ "dependencies": { "@lokalise/node-core": "^14.2.0", "@lokalise/universal-ts-utils": "^4.5.1", - "@platformatic/kafka": "^1.26.0" + "@platformatic/kafka": "^1.28.0", + "@platformatic/dynamic-buffer": "^0.3.1" }, "peerDependencies": { "@message-queue-toolkit/core": ">=23.0.0", diff --git a/packages/kafka/vitest.config.ts b/packages/kafka/vitest.config.ts index 00c6ebbb..16786673 100644 --- a/packages/kafka/vitest.config.ts +++ b/packages/kafka/vitest.config.ts @@ -14,7 +14,7 @@ export default defineConfig({ exclude: ['vitest.config.ts', 'lib/**/index.ts'], thresholds: { lines: 93, - functions: 91, + functions: 88, branches: 85, statements: 92, },