@orion-js/echoes 4.3.2 → 4.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts","../src/requestsHandler/getEcho.ts","../src/publish/serialize.ts","../src/request/getSignature.ts","../src/request/getPassword.ts","../src/requestsHandler/checkSignature.ts","../src/requestsHandler/index.ts","../src/startService/KafkaManager.ts","../src/startService/index.ts","../src/publish/index.ts","../src/request/getURL.ts","../src/echo/deserialize.ts","../src/request/makeRequest.ts","../src/request/index.ts","../src/service/index.ts","../src/echo/index.ts"],"sourcesContent":["import {EchoesConfigHandler} from './types'\n\nconst config: EchoesConfigHandler = {}\n\nexport default config\n","import config from '../config'\n\nexport default function (method: string) {\n const echo = config.echoes[method]\n\n if (!echo) {\n throw new Error(`Echo named ${method} not found in this service`)\n }\n\n if (echo.type !== 'request') {\n throw new Error(`Echo named ${method} is not of type request`)\n }\n\n return echo\n}\n","import serialize from 'serialize-javascript'\nimport {clone} from '@orion-js/helpers'\n\nexport default function (data: any): string {\n const cloned = clone(data)\n const serialized = serialize(cloned, {ignoreFunction: true})\n return serialized\n}\n","import JSSHA from 'jssha'\nimport {getEchoesPassword} from './getPassword'\n\nexport default function (body: any): string {\n const password = getEchoesPassword()\n const shaObj = new JSSHA('SHA-1', 'TEXT')\n shaObj.setHMACKey(password, 'TEXT')\n shaObj.update(body)\n return shaObj.getHMAC('HEX')\n}\n","import {logger} from '@orion-js/logger'\nimport config from '../config'\nimport {internalGetEnv} from '@orion-js/env'\n\nexport function getEchoesPassword() {\n const secret = config?.requests?.key || internalGetEnv('echoes_password', 'ECHOES_PASSWORD')\n if (!secret) {\n logger.warn(\n 'Warning: no secret key found for echoes requests. Init echoes or set the env var \"echoes_password\" or process.env.ECHOES_PASSWORD',\n )\n }\n\n return secret\n}\n","import getSignature from '../request/getSignature'\n\nexport default function (body: any, signature: string) {\n const generatedSignature = getSignature(body)\n if (generatedSignature !== signature) {\n throw new Error('Echoes invalid signature')\n }\n}\n","import getEcho from './getEcho'\nimport serialize from '../publish/serialize'\nimport checkSignature from './checkSignature'\nimport {route} from '@orion-js/http'\nimport {EchoesOptions} from '../types'\n\nexport default (options: EchoesOptions) =>\n route({\n method: 'post',\n path: options.requests.handlerPath || '/echoes-services',\n bodyParser: 'json',\n bodyParserOptions: {\n limit: '10mb',\n },\n async resolve(req) {\n try {\n const {body, signature} = req.body\n\n checkSignature(body, signature)\n\n const {method, serializedParams} = body\n\n const echo = getEcho(method)\n const result = await echo.onRequest(serializedParams)\n\n return {\n body: {\n result: serialize(result),\n },\n }\n } catch (error) {\n if (!error.getInfo) {\n console.error('Error at echo requests handler:', error)\n }\n\n return {\n body: {\n error: error.message,\n errorInfo: error.getInfo ? error.getInfo() : null,\n isValidationError: !!error.isValidationError,\n isUserError: !!error.isUserError,\n },\n }\n }\n },\n })\n","import {Kafka, EachMessagePayload, Producer, Consumer} from 'kafkajs'\nimport {EchoesOptions, EchoType} from '../types'\nimport {logger} from '@orion-js/logger'\n\nconst HEARTBEAT_INTERVAL_SECONDS = 5 // This value must be less than the kafkajs session timeout\nconst CHECK_JOIN_CONSUMER_INTERVAL_SECONDS = 30\nconst DEFAULT_PARTITIONS_CONSUMED_CONCURRENTLY = 4 // How many partitions to consume concurrently, adjust this with the members to partitions ratio to avoid idle consumers.\nconst DEFAULT_MEMBERS_TO_PARTITIONS_RATIO = 1 // How many members are in comparison to partitions, this is used to determine if the consumer group has room for more members. Numbers over 1 leads to idle consumers. Numbers under 1 needs partitionsConsumedConcurrently to be more than 1.\n\n/**\n * Manages the Kafka connection and the consumers.\n */\nclass KafkaManager {\n kafka: Kafka\n options: EchoesOptions\n producer: Producer\n consumer: Consumer\n topics: string[]\n started: boolean\n interval: NodeJS.Timeout\n\n constructor(options: EchoesOptions) {\n this.kafka = new Kafka(options.client)\n this.options = options\n this.producer = this.kafka.producer(options.producer)\n this.consumer = this.kafka.consumer(options.consumer)\n this.topics = Object.keys(options.echoes).filter(key => options.echoes[key].type === 'event')\n }\n\n async checkJoinConsumerGroupConditions(): Promise<boolean> {\n const admin = this.kafka.admin()\n try {\n await admin.connect()\n const groupDescriptions = await admin.describeGroups([this.options.consumer.groupId])\n const group = groupDescriptions.groups[0]\n if (group.state === 'Empty') {\n logger.info(`Echoes: Consumer group ${this.options.consumer.groupId} is empty, joining`)\n return true\n }\n const topicsMetadata = await admin.fetchTopicMetadata({topics: this.topics})\n const totalPartitions = topicsMetadata.topics.reduce(\n (acc, topic) => acc + topic.partitions.length,\n 0,\n )\n logger.info(\n `Echoes: Consumer group ${this.options.consumer.groupId} has ${group.members.length} members and ${totalPartitions} partitions`,\n )\n const partitionsRatio =\n this.options.membersToPartitionsRatio || DEFAULT_MEMBERS_TO_PARTITIONS_RATIO\n const partitionsThreshold = Math.ceil(totalPartitions * partitionsRatio)\n if (partitionsThreshold > group.members.length) {\n logger.info(\n `Echoes: Consumer group ${this.options.consumer.groupId} has room for more members ${group.members.length}/${partitionsThreshold}, joining`,\n )\n return true\n }\n } catch (error) {\n logger.error('Echoes: Error checking consumer group conditions, join', {error})\n return true\n } finally {\n await admin.disconnect().catch(error => {\n logger.error('Echoes: Error disconnecting admin client', {error})\n })\n }\n }\n\n async joinConsumerGroup() {\n await this.consumer.connect()\n await this.consumer.subscribe({topics: this.topics})\n await this.consumer.run({\n partitionsConsumedConcurrently:\n this.options.partitionsConsumedConcurrently || DEFAULT_PARTITIONS_CONSUMED_CONCURRENTLY,\n eachMessage: params => this.handleMessage(params),\n })\n }\n\n async conditionalStart(): Promise<boolean> {\n if (await this.checkJoinConsumerGroupConditions()) {\n await this.joinConsumerGroup()\n return true\n }\n }\n\n async start() {\n if (this.started) return\n await this.producer.connect()\n this.started = await this.conditionalStart()\n if (this.started) return\n logger.info('Echoes: Delaying consumer group join, waiting for conditions to be met')\n this.interval = setInterval(async () => {\n this.started = await this.conditionalStart()\n if (this.started) clearInterval(this.interval)\n }, CHECK_JOIN_CONSUMER_INTERVAL_SECONDS * 1000)\n }\n\n async stop() {\n logger.warn('Echoes: Stopping echoes')\n if (this.interval) clearInterval(this.interval)\n if (this.consumer) await this.consumer.disconnect()\n if (this.producer) await this.producer.disconnect()\n }\n\n async handleMessage(params: EachMessagePayload) {\n const echo = this.options.echoes[params.topic]\n if (!echo || echo.type !== 'event') {\n logger.warn(`Echoes: Received a message for an unknown topic: ${params.topic}, ignoring it`)\n return\n }\n\n let intervalsCount = 0\n const heartbeatInterval = setInterval(async () => {\n await params.heartbeat().catch(error => {\n logger.warn(`Echoes: Error sending heartbeat: ${error.message}`)\n })\n intervalsCount++\n if ((intervalsCount * HEARTBEAT_INTERVAL_SECONDS) % 30 === 0) {\n logger.warn(\n `Echoes: Event is taking too long to process: ${params.topic} ${intervalsCount * HEARTBEAT_INTERVAL_SECONDS}s`,\n )\n }\n }, HEARTBEAT_INTERVAL_SECONDS * 1000)\n\n try {\n await echo.onMessage(params).catch(error => this.handleRetries(echo, params, error))\n } catch (error) {\n logger.error('Echoes: error processing a message', {error, topic: params.topic})\n throw error\n } finally {\n clearInterval(heartbeatInterval)\n }\n }\n\n async handleRetries(echo: EchoType, params: EachMessagePayload, error: Error) {\n const {message, topic} = params\n const retries = Number.parseInt(message?.headers?.retries?.toString() || '0', 10)\n if (echo.attemptsBeforeDeadLetter === undefined || echo.attemptsBeforeDeadLetter === null) {\n throw error\n }\n const maxRetries = echo.attemptsBeforeDeadLetter || 0\n const exceededMaxRetries = retries >= maxRetries\n const nextTopic = exceededMaxRetries ? `DLQ-${topic}` : topic\n await this.producer.send({\n topic: nextTopic,\n messages: [\n {\n value: message.value.toString(),\n headers: {\n retries: String(retries + 1),\n error: error.message,\n },\n },\n ],\n })\n\n if (exceededMaxRetries) {\n logger.error(\n 'Echoes: a message has reached the maximum number of retries, sending it to DLQ',\n {topic: nextTopic},\n )\n } else {\n logger.warn('Echoes: a retryable message failed', {error, topic: nextTopic})\n }\n }\n}\n\nexport default KafkaManager\n","import config from '../config'\nimport requestsHandler from '../requestsHandler'\nimport {EchoesOptions} from '../types'\nimport KafkaManager from './KafkaManager'\nimport {registerRoute} from '@orion-js/http'\n\nlet kafkaManager: KafkaManager = null\n\nexport default async function startService(options: EchoesOptions) {\n config.echoes = options.echoes\n\n if (options.requests) {\n config.requests = options.requests\n registerRoute(requestsHandler(options))\n }\n\n if (options.client) {\n kafkaManager = new KafkaManager(options)\n await kafkaManager.start()\n config.producer = kafkaManager.producer\n config.consumer = kafkaManager.consumer\n }\n}\n\nexport async function stopService() {\n if (kafkaManager) {\n console.info('Stoping echoes...')\n await kafkaManager.stop()\n console.info('Echoes stopped')\n }\n}\n","import config from '../config'\nimport {PublishOptions} from '../types'\nimport serialize from './serialize'\n\n/**\n * Publish\n */\nexport default async function publish<TParams = any>(options: PublishOptions<TParams>) {\n if (!config.producer) {\n throw new Error('You must initialize echoes configruation to use publish')\n }\n\n const payload = {\n params: options.params,\n }\n\n return await config.producer.send({\n acks: options.acks,\n timeout: options.timeout,\n topic: options.topic,\n messages: [\n {\n value: serialize(payload),\n },\n ],\n })\n}\n","import config from '../config'\n\nexport default function (serviceName: string): string {\n if (serviceName.startsWith('http')) return serviceName\n\n const url = config?.requests?.services[serviceName]\n\n if (!url) {\n throw new Error(`No URL found in echoes config for service ${serviceName}`)\n }\n\n return url\n}\n","export default function (serializedJavascript: string): any {\n try {\n return eval('(' + serializedJavascript + ')')\n } catch (error) {\n throw new Error('Error deserializing echo message')\n }\n}\n","import axios from 'axios'\nimport {RequestMaker} from '../types'\nimport {executeWithRetries} from '@orion-js/helpers'\n\nexport const makeRequest: RequestMaker = async options => {\n const result = await executeWithRetries(\n async () => {\n return await axios({\n method: 'post',\n url: options.url,\n timeout: options.timeout,\n headers: {\n 'User-Agent': 'Orionjs-Echoes/1.1',\n },\n data: options.data,\n })\n },\n options.retries,\n 200,\n )\n\n return {\n data: result.data as object,\n statusCode: result.status,\n }\n}\n","import getURL from './getURL'\nimport getSignature from './getSignature'\nimport serialize from '../publish/serialize'\nimport deserialize from '../echo/deserialize'\nimport type {\n MakeRequestParams,\n RequestHandlerResponse,\n RequestMaker,\n RequestOptions,\n} from '../types'\nimport config from '../config'\nimport {makeRequest} from './makeRequest'\nimport {ValidationError} from '@orion-js/schema'\nimport {UserError} from '@orion-js/helpers'\n\nexport default async function request<TData = any, TParams = any>(\n options: RequestOptions<TParams>,\n): Promise<TData> {\n const {method, service, params} = options\n const serializedParams = serialize(params)\n const date = new Date()\n const body = {method, service, serializedParams, date}\n const signature = getSignature(body)\n\n try {\n const requestMaker: RequestMaker = config?.requests?.makeRequest || makeRequest\n const requestOptions: MakeRequestParams = {\n url: getURL(service),\n retries: options.retries,\n timeout: options.timeout,\n data: {\n body,\n signature,\n },\n }\n const result = await requestMaker(requestOptions)\n\n if (result.statusCode !== 200) {\n throw new Error(`Wrong status code ${result.statusCode}`)\n }\n\n const data: RequestHandlerResponse = result.data\n\n if (data.error) {\n const info = data.errorInfo\n if (info) {\n if (data.isValidationError) {\n throw new ValidationError(info.validationErrors)\n }\n if (data.isUserError) {\n throw new UserError(info.error, info.message, info.extra)\n }\n }\n\n throw new Error(`${data.error}`)\n }\n\n const response = deserialize(data.result)\n return response\n } catch (error) {\n if (error.isOrionError) throw error\n\n throw new Error(`Echoes request network error calling ${service}/${method}: ${error.message}`)\n }\n}\n","import {runWithOrionAsyncContext} from '@orion-js/logger'\nimport {createEchoEvent, createEchoRequest} from '../echo'\nimport {EchoConfig, EchoesMap} from '../types'\nimport {getInstance, Service} from '@orion-js/services'\n\nexport interface EchoesPropertyDescriptor extends Omit<PropertyDecorator, 'value'> {\n value?: EchoConfig<any, any>['resolve']\n}\n// Define metadata storage using WeakMaps\nconst serviceMetadata = new WeakMap<any, {_serviceType: string}>()\nconst echoesMetadata = new WeakMap<any, Record<string, any>>()\nconst echoEntriesByClass = new Map<Function, Record<string, (instance: any) => any>>()\nlet pendingEchoEntries: Record<string, (instance: any) => any> = {}\n\nexport function Echoes() {\n return (target: any, context: ClassDecoratorContext<any>) => {\n Service()(target, context)\n serviceMetadata.set(target, {_serviceType: 'echoes'})\n\n if (Object.keys(pendingEchoEntries).length > 0) {\n echoEntriesByClass.set(target, pendingEchoEntries)\n pendingEchoEntries = {}\n }\n }\n}\n\nexport function EchoEvent(): (\n method: any,\n context: ClassFieldDecoratorContext | ClassMethodDecoratorContext,\n) => any\nexport function EchoEvent(\n options?: Omit<EchoConfig<any, any>, 'resolve' | 'type'>,\n): (method: any, context: ClassMethodDecoratorContext) => any\nexport function EchoEvent(options = {}) {\n return (method: any, context: ClassMethodDecoratorContext | ClassFieldDecoratorContext) => {\n const propertyKey = String(context.name)\n\n if (context.kind === 'method') {\n pendingEchoEntries[propertyKey] = (instance: any) => {\n const originalResolve = instance[propertyKey].bind(instance)\n return createEchoEvent({\n ...options,\n resolve: async (params, contextData) => {\n return await runWithOrionAsyncContext(\n {\n controllerType: 'echo',\n echoName: propertyKey,\n params,\n },\n async () => {\n return await originalResolve(params, contextData)\n },\n )\n },\n })\n }\n }\n\n if (context.kind === 'field') {\n pendingEchoEntries[propertyKey] = (instance: any) => instance[propertyKey]\n }\n\n return method\n }\n}\n\nexport function EchoRequest(): (\n method: any,\n context: ClassFieldDecoratorContext | ClassMethodDecoratorContext,\n) => any\nexport function EchoRequest(\n options?: Omit<EchoConfig<any, any>, 'resolve' | 'type'>,\n): (method: any, context: ClassMethodDecoratorContext) => any\nexport function EchoRequest(options = {}) {\n return (method: any, context: ClassMethodDecoratorContext | ClassFieldDecoratorContext) => {\n const propertyKey = String(context.name)\n\n if (context.kind === 'method') {\n pendingEchoEntries[propertyKey] = (instance: any) => {\n const originalResolve = instance[propertyKey].bind(instance)\n return createEchoRequest({\n ...options,\n resolve: async (params, contextData) => {\n return await runWithOrionAsyncContext(\n {\n controllerType: 'echo',\n echoName: propertyKey,\n params,\n },\n async () => {\n return await originalResolve(params, contextData)\n },\n )\n },\n })\n }\n }\n\n if (context.kind === 'field') {\n pendingEchoEntries[propertyKey] = (instance: any) => instance[propertyKey]\n }\n\n return method\n }\n}\n\nfunction initializeEchoesIfNeeded(instance: any) {\n if (echoesMetadata.has(instance)) return\n const entries = echoEntriesByClass.get(instance.constructor) || {}\n const echoes: Record<string, any> = {}\n for (const [key, setup] of Object.entries(entries)) {\n echoes[key] = setup(instance)\n }\n echoesMetadata.set(instance, echoes)\n}\n\nexport function getServiceEchoes(target: any): EchoesMap {\n const instance = getInstance(target)\n\n if (!serviceMetadata.has(instance.constructor)) {\n throw new Error('You must pass a class decorated with @Echoes to getServiceEchoes')\n }\n\n const instanceMetadata = serviceMetadata.get(instance.constructor)\n if (instanceMetadata._serviceType !== 'echoes') {\n throw new Error('You must pass a class decorated with @Echoes to getServiceEchoes')\n }\n\n initializeEchoesIfNeeded(instance)\n\n const echoesMap = echoesMetadata.get(instance) || {}\n\n return echoesMap\n}\n","import {EachMessagePayload} from 'kafkajs'\nimport {EchoType, EchoConfig, EchoRequestConfig, EchoEventConfig} from '../types'\nimport deserialize from './deserialize'\nimport {clean, cleanAndValidate, InferSchemaType} from '@orion-js/schema'\nimport {SchemaFieldType} from '@orion-js/schema'\n\n/**\n * @deprecated Use createEchoRequest and createEchoEvent instead\n */\nconst echo = function createNewEcho<\n TParamsSchema extends SchemaFieldType,\n TReturnsSchema extends SchemaFieldType,\n TEchoType extends 'event' | 'request',\n>(\n options: EchoConfig<TParamsSchema, TReturnsSchema, TEchoType>,\n): EchoType<TParamsSchema, TReturnsSchema, TEchoType> {\n const resolve = async (params: InferSchemaType<TParamsSchema>, context: any) => {\n const cleaned = options.params\n ? await cleanAndValidate(options.params, params)\n : (params ?? ({} as InferSchemaType<TParamsSchema>))\n\n const result = await options.resolve(cleaned, context)\n\n if (options.returns) {\n return await clean(options.returns, result)\n }\n\n return result\n }\n\n return {\n type: options.type,\n params: options.params,\n returns: options.returns,\n attemptsBeforeDeadLetter:\n options.type === 'event' ? options.attemptsBeforeDeadLetter : undefined,\n resolve,\n onMessage: async (messageData: EachMessagePayload) => {\n const {message} = messageData\n\n const data = deserialize(message.value.toString())\n\n const context = {\n ...messageData,\n data,\n }\n\n await resolve(data.params, context)\n },\n onRequest: async (serializedParams: string) => {\n const context = {}\n const params = deserialize(serializedParams)\n\n return await resolve(params, context)\n },\n }\n}\n\nexport function createEchoRequest<\n TParamsSchema extends SchemaFieldType,\n TReturnsSchema extends SchemaFieldType,\n>(\n options: EchoRequestConfig<TParamsSchema, TReturnsSchema>,\n): EchoType<TParamsSchema, TReturnsSchema, 'request'> {\n return echo({...options, type: 'request'})\n}\nexport function createEchoEvent<\n TParamsSchema extends SchemaFieldType,\n TReturnsSchema extends SchemaFieldType,\n>(\n options: EchoEventConfig<TParamsSchema, TReturnsSchema>,\n): EchoType<TParamsSchema, TReturnsSchema, 'event'> {\n return echo({...options, type: 'event' as any})\n}\n\nexport {echo}\n"],"mappings":"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","names":["echo","echo","logger","echo"]}
1
+ {"version":3,"sources":["../src/startService/index.ts","../src/config.ts","../src/startService/KafkaManager.ts","../src/echo/deserialize.ts","../src/publish/serialize.ts","../src/events/EventBus.ts","../src/events/PulseManager.ts","../src/events/createEventBus.ts","../src/requestsHandler/getEcho.ts","../src/request/getSignature.ts","../src/request/getPassword.ts","../src/requestsHandler/checkSignature.ts","../src/requestsHandler/index.ts","../src/publish/index.ts","../src/request/getURL.ts","../src/request/makeRequest.ts","../src/request/index.ts","../src/service/index.ts","../src/echo/index.ts"],"sourcesContent":["import {registerRoute} from '@orion-js/http'\nimport config from '../config'\nimport createEventBus from '../events/createEventBus'\nimport EventBus from '../events/EventBus'\nimport requestsHandler from '../requestsHandler'\nimport {EchoesOptions} from '../types'\n\nlet eventBus: EventBus = null\n\nexport default async function startService(options: EchoesOptions) {\n config.echoes = options.echoes\n\n if (options.requests) {\n config.requests = options.requests\n registerRoute(requestsHandler(options))\n }\n\n const nextEventBus = createEventBus(options)\n if (nextEventBus) {\n await nextEventBus.start()\n eventBus = nextEventBus\n config.eventBus = eventBus\n }\n}\n\nexport async function stopService() {\n if (eventBus) {\n console.info('Stoping echoes...')\n await eventBus.close()\n eventBus = null\n config.eventBus = undefined\n console.info('Echoes stopped')\n }\n}\n","import {EchoesConfigHandler} from './types'\n\nconst config: EchoesConfigHandler = {}\n\nexport default config\n","import {randomUUID} from 'node:crypto'\nimport {logger} from '@orion-js/logger'\nimport {Consumer, EachMessagePayload, Kafka, Producer} from 'kafkajs'\nimport deserialize from '../echo/deserialize'\nimport type {\n EventSubscriptionDefinition,\n EventTransport,\n EventTransportStartOptions,\n} from '../events/EventTransport'\nimport serialize from '../publish/serialize'\nimport type {EchoesKafkaEventsConfig, EchoesReceivedEvent, PublishOptions} from '../types'\n\nconst HEARTBEAT_INTERVAL_SECONDS = 5\nconst CHECK_JOIN_CONSUMER_INTERVAL_SECONDS = 30\nconst DEFAULT_PARTITIONS_CONSUMED_CONCURRENTLY = 4\nconst DEFAULT_MEMBERS_TO_PARTITIONS_RATIO = 1\n\n/**\n * Kafka event transport. It retains the existing consumer-group and retry behavior.\n */\nclass KafkaManager implements EventTransport {\n readonly name = 'kafka' as const\n\n private readonly kafka: Kafka\n private readonly options: EchoesKafkaEventsConfig\n private producer?: Producer\n private consumer?: Consumer\n private topics: string[] = []\n private subscriptions = new Map<string, EventSubscriptionDefinition>()\n private onEvent?: (event: EchoesReceivedEvent) => Promise<void>\n private consumerStarted = false\n private producerConnected = false\n private interval?: NodeJS.Timeout\n\n constructor(options: EchoesKafkaEventsConfig) {\n this.kafka = new Kafka(options.client)\n this.options = options\n }\n\n async start(options: EventTransportStartOptions) {\n this.onEvent = options.onEvent\n this.subscriptions = new Map(\n options.subscriptions.map(subscription => [subscription.topic, subscription]),\n )\n this.topics = options.subscriptions.map(subscription => subscription.topic)\n\n // Kafka retries and DLQ publishing use a producer even on consumer-only servers.\n if (options.publish || options.consume) {\n this.producer = this.kafka.producer(this.options.producer)\n await this.producer.connect()\n this.producerConnected = true\n }\n\n if (!options.consume || this.topics.length === 0) return\n if (!this.options.consumer?.groupId) {\n throw new Error('Echoes Kafka consumers require consumer.groupId')\n }\n\n this.consumer = this.kafka.consumer(this.options.consumer)\n this.consumerStarted = await this.conditionalStart()\n if (this.consumerStarted) return\n\n logger.info('Echoes: Delaying consumer group join, waiting for conditions to be met')\n this.interval = setInterval(async () => {\n this.consumerStarted = await this.conditionalStart()\n if (this.consumerStarted) clearInterval(this.interval)\n }, CHECK_JOIN_CONSUMER_INTERVAL_SECONDS * 1000)\n }\n\n async publish<TParams = any>(options: PublishOptions<TParams>) {\n if (!this.producer || !this.producerConnected) {\n throw new Error('Echoes Kafka producer is not connected')\n }\n\n return await this.producer.send({\n acks: options.acks,\n timeout: options.timeout,\n topic: options.topic,\n messages: [\n {\n value: serialize({params: options.params}),\n headers: {\n 'echoes-event-id': randomUUID(),\n },\n },\n ],\n })\n }\n\n async close() {\n logger.warn('Echoes: Stopping Kafka transport')\n if (this.interval) clearInterval(this.interval)\n await Promise.all([\n this.consumer?.disconnect(),\n this.producerConnected ? this.producer?.disconnect() : undefined,\n ])\n this.consumerStarted = false\n this.producerConnected = false\n }\n\n private async checkJoinConsumerGroupConditions(): Promise<boolean> {\n const admin = this.kafka.admin()\n try {\n await admin.connect()\n const groupId = this.options.consumer.groupId\n const groupDescriptions = await admin.describeGroups([groupId])\n const group = groupDescriptions.groups[0]\n if (group.state === 'Empty') {\n logger.info(`Echoes: Consumer group ${groupId} is empty, joining`)\n return true\n }\n const topicsMetadata = await admin.fetchTopicMetadata({topics: this.topics})\n const totalPartitions = topicsMetadata.topics.reduce(\n (acc, topic) => acc + topic.partitions.length,\n 0,\n )\n logger.info(\n `Echoes: Consumer group ${groupId} has ${group.members.length} members and ${totalPartitions} partitions`,\n )\n const partitionsRatio =\n this.options.membersToPartitionsRatio || DEFAULT_MEMBERS_TO_PARTITIONS_RATIO\n const partitionsThreshold = Math.ceil(totalPartitions * partitionsRatio)\n if (partitionsThreshold > group.members.length) {\n logger.info(\n `Echoes: Consumer group ${groupId} has room for more members ${group.members.length}/${partitionsThreshold}, joining`,\n )\n return true\n }\n return false\n } catch (error) {\n logger.error('Echoes: Error checking consumer group conditions, join', {error})\n return true\n } finally {\n await admin.disconnect().catch(error => {\n logger.error('Echoes: Error disconnecting admin client', {error})\n })\n }\n }\n\n private async joinConsumerGroup() {\n await this.consumer.connect()\n await this.consumer.subscribe({topics: this.topics})\n await this.consumer.run({\n partitionsConsumedConcurrently:\n this.options.partitionsConsumedConcurrently || DEFAULT_PARTITIONS_CONSUMED_CONCURRENTLY,\n eachMessage: params => this.handleMessage(params),\n })\n }\n\n private async conditionalStart(): Promise<boolean> {\n if (await this.checkJoinConsumerGroupConditions()) {\n await this.joinConsumerGroup()\n return true\n }\n return false\n }\n\n private async handleMessage(params: EachMessagePayload) {\n const subscription = this.subscriptions.get(params.topic)\n if (!subscription) {\n logger.warn(`Echoes: Received a message for an unknown topic: ${params.topic}, ignoring it`)\n return\n }\n\n let intervalsCount = 0\n const heartbeatInterval = setInterval(async () => {\n await params.heartbeat().catch(error => {\n logger.warn(`Echoes: Error sending heartbeat: ${error.message}`)\n })\n intervalsCount++\n if ((intervalsCount * HEARTBEAT_INTERVAL_SECONDS) % 30 === 0) {\n logger.warn(\n `Echoes: Event is taking too long to process: ${params.topic} ${intervalsCount * HEARTBEAT_INTERVAL_SECONDS}s`,\n )\n }\n }, HEARTBEAT_INTERVAL_SECONDS * 1000)\n\n try {\n const event = this.createReceivedEvent(params)\n await this.onEvent(event)\n } catch (error) {\n try {\n await this.handleRetries(subscription, params, error as Error)\n } catch (retryError) {\n logger.error('Echoes: error processing a message', {\n error: retryError,\n topic: params.topic,\n })\n throw retryError\n }\n } finally {\n clearInterval(heartbeatInterval)\n }\n }\n\n private createReceivedEvent(params: EachMessagePayload): EchoesReceivedEvent {\n const {message, topic, partition} = params\n const data = deserialize(message.value.toString())\n const retries = Number.parseInt(message.headers?.retries?.toString() || '0', 10)\n const timestamp = Number.parseInt(message.timestamp || '', 10)\n\n return {\n id:\n message.headers?.['echoes-event-id']?.toString() ||\n `kafka:${topic}:${partition}:${message.offset}`,\n topic,\n data,\n transport: 'kafka',\n headers: message.headers,\n createdAt: Number.isFinite(timestamp) ? new Date(timestamp) : new Date(),\n attempt: retries + 1,\n context: params,\n }\n }\n\n private async handleRetries(\n subscription: EventSubscriptionDefinition,\n params: EachMessagePayload,\n error: Error,\n ) {\n const {message, topic} = params\n const retries = Number.parseInt(message?.headers?.retries?.toString() || '0', 10)\n if (\n subscription.attemptsBeforeDeadLetter === undefined ||\n subscription.attemptsBeforeDeadLetter === null\n ) {\n throw error\n }\n const maxRetries = subscription.attemptsBeforeDeadLetter || 0\n const exceededMaxRetries = retries >= maxRetries\n const nextTopic = exceededMaxRetries ? `DLQ-${topic}` : topic\n await this.producer.send({\n topic: nextTopic,\n messages: [\n {\n value: message.value.toString(),\n headers: {\n ...message.headers,\n retries: String(retries + 1),\n error: error.message,\n },\n },\n ],\n })\n\n if (exceededMaxRetries) {\n logger.error(\n 'Echoes: a message has reached the maximum number of retries, sending it to DLQ',\n {topic: nextTopic},\n )\n } else {\n logger.warn('Echoes: a retryable message failed', {error, topic: nextTopic})\n }\n }\n}\n\nexport default KafkaManager\n","export default function (serializedJavascript: string): any {\n try {\n return eval('(' + serializedJavascript + ')')\n } catch (error) {\n throw new Error('Error deserializing echo message')\n }\n}\n","import serialize from 'serialize-javascript'\nimport {clone} from '@orion-js/helpers'\n\nexport default function (data: any): string {\n const cloned = clone(data)\n const serialized = serialize(cloned, {ignoreFunction: true})\n return serialized\n}\n","import {logger} from '@orion-js/logger'\nimport type {\n EchoesEventTransportName,\n EchoesMap,\n EchoesReceivedEvent,\n PublishOptions,\n} from '../types'\nimport type {EventSubscriptionDefinition, EventTransport} from './EventTransport'\n\nexport interface EventBusOptions {\n echoes: EchoesMap\n transports: Partial<Record<EchoesEventTransportName, EventTransport>>\n consumeFrom: EchoesEventTransportName[]\n publishTo?: EchoesEventTransportName\n}\n\nexport default class EventBus {\n private readonly echoes: EchoesMap\n private readonly transports: Partial<Record<EchoesEventTransportName, EventTransport>>\n private readonly consumeFrom: EchoesEventTransportName[]\n private readonly publishTo?: EchoesEventTransportName\n private readonly startedTransports: EventTransport[] = []\n private started = false\n private closed = false\n\n constructor(options: EventBusOptions) {\n this.echoes = options.echoes\n this.transports = options.transports\n this.consumeFrom = [...new Set(options.consumeFrom)]\n this.publishTo = options.publishTo\n }\n\n async start() {\n if (this.started) return\n\n const selected = new Set(this.consumeFrom)\n if (this.publishTo) selected.add(this.publishTo)\n\n for (const name of selected) {\n if (!this.transports[name]) {\n throw new Error(`Echoes event transport \"${name}\" is selected but not configured`)\n }\n }\n\n const subscriptions: EventSubscriptionDefinition[] = Object.entries(this.echoes)\n .filter(([, echo]) => echo.type === 'event')\n .map(([topic, echo]) => ({\n topic,\n attemptsBeforeDeadLetter: echo.attemptsBeforeDeadLetter,\n }))\n\n try {\n for (const name of selected) {\n const transport = this.transports[name]\n this.startedTransports.push(transport)\n await transport.start({\n consume: this.consumeFrom.includes(name),\n publish: this.publishTo === name,\n subscriptions,\n onEvent: event => this.handleEvent(event),\n })\n }\n this.started = true\n } catch (error) {\n await this.close().catch(() => undefined)\n throw error\n }\n }\n\n async publish<TParams = any>(options: PublishOptions<TParams>) {\n if (!this.started) {\n throw new Error('You must initialize echoes configuration to use publish')\n }\n if (!this.publishTo) {\n throw new Error('Echoes does not have a publish transport configured')\n }\n\n return await this.transports[this.publishTo].publish(options)\n }\n\n async close() {\n if (this.closed) return\n this.closed = true\n await Promise.all(this.startedTransports.map(transport => transport.close()))\n }\n\n private async handleEvent(event: EchoesReceivedEvent) {\n const echo = this.echoes[event.topic]\n if (!echo || echo.type !== 'event') {\n logger.warn(`Echoes: Received a message for an unknown topic: ${event.topic}, ignoring it`)\n return\n }\n\n // Preserve the exact legacy Kafka entrypoint for custom EchoType implementations.\n if (event.transport === 'kafka' && event.context) {\n await echo.onMessage(event.context as any)\n return\n }\n\n if (echo.onEvent) {\n await echo.onEvent(event)\n return\n }\n\n await echo.resolve(event.data.params, {\n ...(event.context || {}),\n transport: event.transport,\n eventId: event.id,\n topic: event.topic,\n headers: event.headers,\n createdAt: event.createdAt,\n attempt: event.attempt,\n data: event.data,\n })\n }\n}\n","import type {\n Pulse,\n PulseReceivedEvent,\n PulseSubscribeOptions,\n PulseSubscription,\n} from '@orion-js/pulse'\nimport type {\n EchoesEventPayload,\n EchoesPulseEventsConfig,\n EchoesReceivedEvent,\n PublishOptions,\n} from '../types'\nimport type {EventTransport, EventTransportStartOptions} from './EventTransport'\n\ntype EchoesPulseEventMap = Record<string, EchoesEventPayload>\n\nexport default class PulseManager implements EventTransport {\n readonly name = 'pulse' as const\n\n private readonly options: EchoesPulseEventsConfig\n private pulse?: Pulse<EchoesPulseEventMap>\n private subscriptions: PulseSubscription[] = []\n\n constructor(options: EchoesPulseEventsConfig) {\n this.options = options\n }\n\n async start(options: EventTransportStartOptions) {\n let pulseModule: typeof import('@orion-js/pulse')\n try {\n pulseModule = await import('@orion-js/pulse')\n } catch (error) {\n const wrapped = new Error(\n 'Echoes Pulse transport requires @orion-js/pulse to be installed in the application',\n )\n ;(wrapped as any).cause = error\n throw wrapped\n }\n\n const {subscription, ...connectOptions} = this.options\n this.pulse = pulseModule.connect<EchoesPulseEventMap>(connectOptions)\n await this.pulse.awaitConnection()\n\n if (!options.consume) return\n\n this.subscriptions = await Promise.all(\n options.subscriptions.map(definition =>\n this.pulse.subscribe(\n definition.topic,\n event => options.onEvent(this.createReceivedEvent(event)),\n this.getSubscribeOptions(subscription, definition.attemptsBeforeDeadLetter),\n ),\n ),\n )\n }\n\n async publish<TParams = any>(options: PublishOptions<TParams>) {\n if (!this.pulse) {\n throw new Error('Echoes Pulse client is not connected')\n }\n\n return await this.pulse.publish({\n topic: options.topic,\n data: {params: options.params},\n })\n }\n\n async close() {\n await this.pulse?.close()\n this.subscriptions = []\n }\n\n private getSubscribeOptions(\n defaults: PulseSubscribeOptions = {},\n attemptsBeforeDeadLetter?: number,\n ): PulseSubscribeOptions {\n return {\n ...defaults,\n ...(attemptsBeforeDeadLetter === undefined ? {} : {maxRetries: attemptsBeforeDeadLetter}),\n }\n }\n\n private createReceivedEvent(\n event: PulseReceivedEvent<string, EchoesEventPayload>,\n ): EchoesReceivedEvent {\n return {\n id: event.id,\n topic: event.topic,\n data: event.data,\n transport: 'pulse',\n headers: event.headers,\n createdAt: event.createdAt,\n attempt: event.attempt,\n context: event,\n }\n }\n}\n","import KafkaManager from '../startService/KafkaManager'\nimport type {\n EchoesEventTransportName,\n EchoesKafkaEventsConfig,\n EchoesOptions,\n EchoesPulseEventsConfig,\n} from '../types'\nimport EventBus from './EventBus'\nimport type {EventTransport} from './EventTransport'\nimport PulseManager from './PulseManager'\n\nexport interface ResolvedEventsConfig {\n kafka?: EchoesKafkaEventsConfig\n pulse?: EchoesPulseEventsConfig\n consumeFrom: EchoesEventTransportName[]\n publishTo?: EchoesEventTransportName\n}\n\nexport function resolveEventsConfig(options: EchoesOptions): ResolvedEventsConfig | undefined {\n const legacyKafka = options.client\n ? {\n client: options.client,\n producer: options.producer,\n consumer: options.consumer,\n readTopicsFromBeginning: options.readTopicsFromBeginning,\n partitionsConsumedConcurrently: options.partitionsConsumedConcurrently,\n membersToPartitionsRatio: options.membersToPartitionsRatio,\n }\n : undefined\n\n const kafka = options.events?.kafka || legacyKafka\n const pulse = options.events?.pulse\n\n if (!kafka && !pulse && !options.events) return undefined\n\n const defaultTransport: EchoesEventTransportName | undefined = kafka\n ? 'kafka'\n : pulse\n ? 'pulse'\n : undefined\n\n return {\n kafka,\n pulse,\n consumeFrom: options.events?.consumeFrom || (defaultTransport ? [defaultTransport] : []),\n publishTo: options.events?.publishTo || defaultTransport,\n }\n}\n\nexport default function createEventBus(options: EchoesOptions) {\n const resolved = resolveEventsConfig(options)\n if (!resolved) return undefined\n\n const transports: Partial<Record<EchoesEventTransportName, EventTransport>> = {}\n if (resolved.kafka) transports.kafka = new KafkaManager(resolved.kafka)\n if (resolved.pulse) transports.pulse = new PulseManager(resolved.pulse)\n\n return new EventBus({\n echoes: options.echoes,\n transports,\n consumeFrom: resolved.consumeFrom,\n publishTo: resolved.publishTo,\n })\n}\n","import config from '../config'\n\nexport default function (method: string) {\n const echo = config.echoes[method]\n\n if (!echo) {\n throw new Error(`Echo named ${method} not found in this service`)\n }\n\n if (echo.type !== 'request') {\n throw new Error(`Echo named ${method} is not of type request`)\n }\n\n return echo\n}\n","import JSSHA from 'jssha'\nimport {getEchoesPassword} from './getPassword'\n\nexport default function (body: any): string {\n const password = getEchoesPassword()\n const shaObj = new JSSHA('SHA-1', 'TEXT')\n shaObj.setHMACKey(password, 'TEXT')\n shaObj.update(body)\n return shaObj.getHMAC('HEX')\n}\n","import {logger} from '@orion-js/logger'\nimport config from '../config'\nimport {internalGetEnv} from '@orion-js/env'\n\nexport function getEchoesPassword() {\n const secret = config?.requests?.key || internalGetEnv('echoes_password', 'ECHOES_PASSWORD')\n if (!secret) {\n logger.warn(\n 'Warning: no secret key found for echoes requests. Init echoes or set the env var \"echoes_password\" or process.env.ECHOES_PASSWORD',\n )\n }\n\n return secret\n}\n","import getSignature from '../request/getSignature'\n\nexport default function (body: any, signature: string) {\n const generatedSignature = getSignature(body)\n if (generatedSignature !== signature) {\n throw new Error('Echoes invalid signature')\n }\n}\n","import getEcho from './getEcho'\nimport serialize from '../publish/serialize'\nimport checkSignature from './checkSignature'\nimport {route} from '@orion-js/http'\nimport {EchoesOptions} from '../types'\n\nexport default (options: EchoesOptions) =>\n route({\n method: 'post',\n path: options.requests.handlerPath || '/echoes-services',\n bodyParser: 'json',\n bodyParserOptions: {\n limit: '10mb',\n },\n async resolve(req) {\n try {\n const {body, signature} = req.body\n\n checkSignature(body, signature)\n\n const {method, serializedParams} = body\n\n const echo = getEcho(method)\n const result = await echo.onRequest(serializedParams)\n\n return {\n body: {\n result: serialize(result),\n },\n }\n } catch (error) {\n if (!error.getInfo) {\n console.error('Error at echo requests handler:', error)\n }\n\n return {\n body: {\n error: error.message,\n errorInfo: error.getInfo ? error.getInfo() : null,\n isValidationError: !!error.isValidationError,\n isUserError: !!error.isUserError,\n },\n }\n }\n },\n })\n","import config from '../config'\nimport {PublishOptions} from '../types'\n\n/**\n * Publish\n */\nexport default async function publish<TParams = any>(options: PublishOptions<TParams>) {\n if (!config.eventBus) {\n throw new Error('You must initialize echoes configuration to use publish')\n }\n\n return await config.eventBus.publish(options)\n}\n","import config from '../config'\n\nexport default function (serviceName: string): string {\n if (serviceName.startsWith('http')) return serviceName\n\n const url = config?.requests?.services[serviceName]\n\n if (!url) {\n throw new Error(`No URL found in echoes config for service ${serviceName}`)\n }\n\n return url\n}\n","import axios from 'axios'\nimport {RequestMaker} from '../types'\nimport {executeWithRetries} from '@orion-js/helpers'\n\nexport const makeRequest: RequestMaker = async options => {\n const result = await executeWithRetries(\n async () => {\n return await axios({\n method: 'post',\n url: options.url,\n timeout: options.timeout,\n headers: {\n 'User-Agent': 'Orionjs-Echoes/1.1',\n },\n data: options.data,\n })\n },\n options.retries,\n 200,\n )\n\n return {\n data: result.data as object,\n statusCode: result.status,\n }\n}\n","import getURL from './getURL'\nimport getSignature from './getSignature'\nimport serialize from '../publish/serialize'\nimport deserialize from '../echo/deserialize'\nimport type {\n MakeRequestParams,\n RequestHandlerResponse,\n RequestMaker,\n RequestOptions,\n} from '../types'\nimport config from '../config'\nimport {makeRequest} from './makeRequest'\nimport {ValidationError} from '@orion-js/schema'\nimport {UserError} from '@orion-js/helpers'\n\nexport default async function request<TData = any, TParams = any>(\n options: RequestOptions<TParams>,\n): Promise<TData> {\n const {method, service, params} = options\n const serializedParams = serialize(params)\n const date = new Date()\n const body = {method, service, serializedParams, date}\n const signature = getSignature(body)\n\n try {\n const requestMaker: RequestMaker = config?.requests?.makeRequest || makeRequest\n const requestOptions: MakeRequestParams = {\n url: getURL(service),\n retries: options.retries,\n timeout: options.timeout,\n data: {\n body,\n signature,\n },\n }\n const result = await requestMaker(requestOptions)\n\n if (result.statusCode !== 200) {\n throw new Error(`Wrong status code ${result.statusCode}`)\n }\n\n const data: RequestHandlerResponse = result.data\n\n if (data.error) {\n const info = data.errorInfo\n if (info) {\n if (data.isValidationError) {\n throw new ValidationError(info.validationErrors)\n }\n if (data.isUserError) {\n throw new UserError(info.error, info.message, info.extra)\n }\n }\n\n throw new Error(`${data.error}`)\n }\n\n const response = deserialize(data.result)\n return response\n } catch (error) {\n if (error.isOrionError) throw error\n\n throw new Error(`Echoes request network error calling ${service}/${method}: ${error.message}`)\n }\n}\n","import {runWithOrionAsyncContext} from '@orion-js/logger'\nimport {createEchoEvent, createEchoRequest} from '../echo'\nimport {EchoConfig, EchoesMap} from '../types'\nimport {getInstance, Service} from '@orion-js/services'\n\nexport interface EchoesPropertyDescriptor extends Omit<PropertyDecorator, 'value'> {\n value?: EchoConfig<any, any>['resolve']\n}\n// Define metadata storage using WeakMaps\nconst serviceMetadata = new WeakMap<any, {_serviceType: string}>()\nconst echoesMetadata = new WeakMap<any, Record<string, any>>()\nconst echoEntriesByClass = new Map<Function, Record<string, (instance: any) => any>>()\nlet pendingEchoEntries: Record<string, (instance: any) => any> = {}\n\nexport function Echoes() {\n return (target: any, context: ClassDecoratorContext<any>) => {\n Service()(target, context)\n serviceMetadata.set(target, {_serviceType: 'echoes'})\n\n if (Object.keys(pendingEchoEntries).length > 0) {\n echoEntriesByClass.set(target, pendingEchoEntries)\n pendingEchoEntries = {}\n }\n }\n}\n\nexport function EchoEvent(): (\n method: any,\n context: ClassFieldDecoratorContext | ClassMethodDecoratorContext,\n) => any\nexport function EchoEvent(\n options?: Omit<EchoConfig<any, any>, 'resolve' | 'type'>,\n): (method: any, context: ClassMethodDecoratorContext) => any\nexport function EchoEvent(options = {}) {\n return (method: any, context: ClassMethodDecoratorContext | ClassFieldDecoratorContext) => {\n const propertyKey = String(context.name)\n\n if (context.kind === 'method') {\n pendingEchoEntries[propertyKey] = (instance: any) => {\n const originalResolve = instance[propertyKey].bind(instance)\n return createEchoEvent({\n ...options,\n resolve: async (params, contextData) => {\n return await runWithOrionAsyncContext(\n {\n controllerType: 'echo',\n echoName: propertyKey,\n params,\n },\n async () => {\n return await originalResolve(params, contextData)\n },\n )\n },\n })\n }\n }\n\n if (context.kind === 'field') {\n pendingEchoEntries[propertyKey] = (instance: any) => instance[propertyKey]\n }\n\n return method\n }\n}\n\nexport function EchoRequest(): (\n method: any,\n context: ClassFieldDecoratorContext | ClassMethodDecoratorContext,\n) => any\nexport function EchoRequest(\n options?: Omit<EchoConfig<any, any>, 'resolve' | 'type'>,\n): (method: any, context: ClassMethodDecoratorContext) => any\nexport function EchoRequest(options = {}) {\n return (method: any, context: ClassMethodDecoratorContext | ClassFieldDecoratorContext) => {\n const propertyKey = String(context.name)\n\n if (context.kind === 'method') {\n pendingEchoEntries[propertyKey] = (instance: any) => {\n const originalResolve = instance[propertyKey].bind(instance)\n return createEchoRequest({\n ...options,\n resolve: async (params, contextData) => {\n return await runWithOrionAsyncContext(\n {\n controllerType: 'echo',\n echoName: propertyKey,\n params,\n },\n async () => {\n return await originalResolve(params, contextData)\n },\n )\n },\n })\n }\n }\n\n if (context.kind === 'field') {\n pendingEchoEntries[propertyKey] = (instance: any) => instance[propertyKey]\n }\n\n return method\n }\n}\n\nfunction initializeEchoesIfNeeded(instance: any) {\n if (echoesMetadata.has(instance)) return\n const entries = echoEntriesByClass.get(instance.constructor) || {}\n const echoes: Record<string, any> = {}\n for (const [key, setup] of Object.entries(entries)) {\n echoes[key] = setup(instance)\n }\n echoesMetadata.set(instance, echoes)\n}\n\nexport function getServiceEchoes(target: any): EchoesMap {\n const instance = getInstance(target)\n\n if (!serviceMetadata.has(instance.constructor)) {\n throw new Error('You must pass a class decorated with @Echoes to getServiceEchoes')\n }\n\n const instanceMetadata = serviceMetadata.get(instance.constructor)\n if (instanceMetadata._serviceType !== 'echoes') {\n throw new Error('You must pass a class decorated with @Echoes to getServiceEchoes')\n }\n\n initializeEchoesIfNeeded(instance)\n\n const echoesMap = echoesMetadata.get(instance) || {}\n\n return echoesMap\n}\n","import {clean, cleanAndValidate, InferSchemaType, SchemaFieldType} from '@orion-js/schema'\nimport {EachMessagePayload} from 'kafkajs'\nimport {\n EchoConfig,\n EchoEventConfig,\n EchoesReceivedEvent,\n EchoRequestConfig,\n EchoType,\n} from '../types'\nimport deserialize from './deserialize'\n\n/**\n * @deprecated Use createEchoRequest and createEchoEvent instead\n */\nconst echo = function createNewEcho<\n TParamsSchema extends SchemaFieldType,\n TReturnsSchema extends SchemaFieldType,\n TEchoType extends 'event' | 'request',\n>(\n options: EchoConfig<TParamsSchema, TReturnsSchema, TEchoType>,\n): EchoType<TParamsSchema, TReturnsSchema, TEchoType> {\n const resolve = async (params: InferSchemaType<TParamsSchema>, context: any) => {\n const cleaned = options.params\n ? await cleanAndValidate(options.params, params)\n : (params ?? ({} as InferSchemaType<TParamsSchema>))\n\n const result = await options.resolve(cleaned, context)\n\n if (options.returns) {\n return await clean(options.returns, result)\n }\n\n return result\n }\n\n const onEvent = async (event: EchoesReceivedEvent) => {\n const context = {\n ...(event.context || {}),\n transport: event.transport,\n eventId: event.id,\n topic: event.topic,\n headers: event.headers,\n createdAt: event.createdAt,\n attempt: event.attempt,\n data: event.data,\n }\n\n await resolve(event.data.params, context)\n }\n\n return {\n type: options.type,\n params: options.params,\n returns: options.returns,\n attemptsBeforeDeadLetter:\n options.type === 'event' ? options.attemptsBeforeDeadLetter : undefined,\n resolve,\n onEvent,\n onMessage: async (messageData: EachMessagePayload) => {\n const {message} = messageData\n\n const data = deserialize(message.value.toString())\n const retries = Number.parseInt(message.headers?.retries?.toString() || '0', 10)\n const timestamp = Number(message.timestamp)\n const createdAt = Number.isFinite(timestamp) ? new Date(timestamp) : new Date()\n const eventId =\n message.headers?.['echoes-event-id']?.toString() ||\n `kafka:${messageData.topic}:${messageData.partition}:${message.offset}`\n\n await onEvent({\n id: eventId,\n topic: messageData.topic,\n data,\n transport: 'kafka',\n headers: message.headers,\n createdAt,\n attempt: retries + 1,\n context: messageData,\n })\n },\n onRequest: async (serializedParams: string) => {\n const context = {}\n const params = deserialize(serializedParams)\n\n return await resolve(params, context)\n },\n }\n}\n\nexport function createEchoRequest<\n TParamsSchema extends SchemaFieldType,\n TReturnsSchema extends SchemaFieldType,\n>(\n options: EchoRequestConfig<TParamsSchema, TReturnsSchema>,\n): EchoType<TParamsSchema, TReturnsSchema, 'request'> {\n return echo({...options, type: 'request'})\n}\nexport function createEchoEvent<\n TParamsSchema extends SchemaFieldType,\n TReturnsSchema extends SchemaFieldType,\n>(\n options: EchoEventConfig<TParamsSchema, TReturnsSchema>,\n): EchoType<TParamsSchema, TReturnsSchema, 'event'> {\n return echo({...options, type: 'event' as any})\n}\n\nexport {echo}\n"],"mappings":"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","names":["logger","echo","echo","logger","logger","echo"]}
@@ -0,0 +1,5 @@
1
+ import { PublishOptions } from '../types';
2
+ /**
3
+ * Publish
4
+ */
5
+ export default function publish<TParams = any>(options: PublishOptions<TParams>): Promise<any>;
@@ -0,0 +1 @@
1
+ export default function (data: any): string;
@@ -0,0 +1 @@
1
+ export declare function getEchoesPassword(): string;
@@ -0,0 +1 @@
1
+ export default function (body: any): string;
@@ -0,0 +1 @@
1
+ export default function (serviceName: string): string;
@@ -0,0 +1,2 @@
1
+ import type { RequestOptions } from '../types';
2
+ export default function request<TData = any, TParams = any>(options: RequestOptions<TParams>): Promise<TData>;
@@ -0,0 +1,2 @@
1
+ import { RequestMaker } from '../types';
2
+ export declare const makeRequest: RequestMaker;
@@ -0,0 +1 @@
1
+ export default function (body: any, signature: string): void;
@@ -0,0 +1 @@
1
+ export default function (method: string): import("..").EchoType<any, any, "event" | "request">;
@@ -0,0 +1,3 @@
1
+ import { EchoesOptions } from '../types';
2
+ export default _default;
3
+ declare function _default(options: EchoesOptions): import("@orion-js/http").RouteType<string, import("@orion-js/schema").Schema, import("@orion-js/schema").Schema, import("@orion-js/schema").SchemaFieldType>;
@@ -0,0 +1,10 @@
1
+ import { EchoConfig, EchoesMap } from '../types';
2
+ export interface EchoesPropertyDescriptor extends Omit<PropertyDecorator, 'value'> {
3
+ value?: EchoConfig<any, any>['resolve'];
4
+ }
5
+ export declare function Echoes(): (target: any, context: ClassDecoratorContext<any>) => void;
6
+ export declare function EchoEvent(): (method: any, context: ClassFieldDecoratorContext | ClassMethodDecoratorContext) => any;
7
+ export declare function EchoEvent(options?: Omit<EchoConfig<any, any>, 'resolve' | 'type'>): (method: any, context: ClassMethodDecoratorContext) => any;
8
+ export declare function EchoRequest(): (method: any, context: ClassFieldDecoratorContext | ClassMethodDecoratorContext) => any;
9
+ export declare function EchoRequest(options?: Omit<EchoConfig<any, any>, 'resolve' | 'type'>): (method: any, context: ClassMethodDecoratorContext) => any;
10
+ export declare function getServiceEchoes(target: any): EchoesMap;
@@ -0,0 +1,29 @@
1
+ import type { EventTransport, EventTransportStartOptions } from '../events/EventTransport';
2
+ import type { EchoesKafkaEventsConfig, PublishOptions } from '../types';
3
+ /**
4
+ * Kafka event transport. It retains the existing consumer-group and retry behavior.
5
+ */
6
+ declare class KafkaManager implements EventTransport {
7
+ readonly name: 'kafka';
8
+ private readonly kafka;
9
+ private readonly options;
10
+ private producer?;
11
+ private consumer?;
12
+ private topics;
13
+ private subscriptions;
14
+ private onEvent?;
15
+ private consumerStarted;
16
+ private producerConnected;
17
+ private interval?;
18
+ constructor(options: EchoesKafkaEventsConfig);
19
+ start(options: EventTransportStartOptions): Promise<void>;
20
+ publish<TParams = any>(options: PublishOptions<TParams>): Promise<import("kafkajs").RecordMetadata[]>;
21
+ close(): Promise<void>;
22
+ private checkJoinConsumerGroupConditions;
23
+ private joinConsumerGroup;
24
+ private conditionalStart;
25
+ private handleMessage;
26
+ private createReceivedEvent;
27
+ private handleRetries;
28
+ }
29
+ export default KafkaManager;
@@ -0,0 +1,3 @@
1
+ import { EchoesOptions } from '../types';
2
+ export default function startService(options: EchoesOptions): Promise<void>;
3
+ export declare function stopService(): Promise<void>;
@@ -0,0 +1,198 @@
1
+ import { InferSchemaType, SchemaFieldType } from '@orion-js/schema';
2
+ import { Consumer, ConsumerConfig, EachMessagePayload, KafkaConfig, Producer, ProducerConfig } from 'kafkajs';
3
+ export interface EchoRequestConfig<TParamsSchema extends SchemaFieldType, TReturnsSchema extends SchemaFieldType> {
4
+ params?: TParamsSchema;
5
+ returns?: TReturnsSchema;
6
+ resolve(params?: InferSchemaType<TParamsSchema>, context?: any): Promise<InferSchemaType<TReturnsSchema>>;
7
+ attemptsBeforeDeadLetter?: number;
8
+ }
9
+ export interface EchoEventConfig<TParamsSchema extends SchemaFieldType, TReturnsSchema extends SchemaFieldType> {
10
+ params?: TParamsSchema;
11
+ returns?: TReturnsSchema;
12
+ resolve(params?: InferSchemaType<TParamsSchema>, context?: any): Promise<InferSchemaType<TReturnsSchema>>;
13
+ attemptsBeforeDeadLetter?: number;
14
+ }
15
+ export type EchoConfig<TParamsSchema extends SchemaFieldType, TReturnsSchema extends SchemaFieldType, TEchoType extends 'event' | 'request' = 'event' | 'request'> = (TEchoType extends 'event' ? EchoEventConfig<TParamsSchema, TReturnsSchema> : EchoRequestConfig<TParamsSchema, TReturnsSchema>) & {
16
+ type: TEchoType;
17
+ };
18
+ export type EchoType<TParamsSchema extends SchemaFieldType = any, TReturnsSchema extends SchemaFieldType = any, TEchoType extends 'event' | 'request' = 'event' | 'request'> = {
19
+ params?: TParamsSchema;
20
+ returns?: TReturnsSchema;
21
+ attemptsBeforeDeadLetter?: number;
22
+ type: TEchoType;
23
+ resolve(params?: InferSchemaType<TParamsSchema>, context?: any): Promise<InferSchemaType<TReturnsSchema>>;
24
+ onEvent?(event: EchoesReceivedEvent): Promise<void>;
25
+ /**
26
+ * @deprecated Kafka compatibility entrypoint. Event transports use onEvent.
27
+ */
28
+ onMessage(messageData: EachMessagePayload): Promise<void>;
29
+ onRequest(serializedParams: string): any;
30
+ };
31
+ export type EchoesEventTransportName = 'kafka' | 'pulse';
32
+ export interface EchoesEventPayload<TParams = any> {
33
+ params: TParams;
34
+ }
35
+ export interface EchoesReceivedEvent<TParams = any> {
36
+ id: string;
37
+ topic: string;
38
+ data: EchoesEventPayload<TParams>;
39
+ transport: EchoesEventTransportName;
40
+ headers?: Record<string, unknown>;
41
+ createdAt: Date;
42
+ attempt: number;
43
+ context?: Record<string, any>;
44
+ }
45
+ export interface PublishOptions<TParams = any> {
46
+ topic: string;
47
+ params: TParams;
48
+ acks?: number;
49
+ timeout?: number;
50
+ }
51
+ export interface RequestOptions<TParams> {
52
+ method: string;
53
+ service: string;
54
+ params: TParams;
55
+ retries?: number;
56
+ timeout?: number;
57
+ }
58
+ export interface RequestHandlerResponse {
59
+ result?: any;
60
+ error?: any;
61
+ isUserError?: boolean;
62
+ isValidationError?: boolean;
63
+ errorInfo?: {
64
+ error: string;
65
+ message: string;
66
+ extra?: any;
67
+ validationErrors?: any;
68
+ };
69
+ }
70
+ export interface MakeRequestParams {
71
+ url: string;
72
+ retries?: number;
73
+ timeout?: number;
74
+ data: {
75
+ body: object;
76
+ signature: string;
77
+ };
78
+ }
79
+ export interface RequestMakerResult {
80
+ statusCode: number;
81
+ data: object;
82
+ }
83
+ export type RequestMaker = (options: MakeRequestParams) => Promise<RequestMakerResult>;
84
+ export interface RequestsConfig {
85
+ /**
86
+ * The secret key used to sign all requests. Shared between all your services.
87
+ * You can also set the env var echoes_password or process.env.ECHOES_PASSWORD
88
+ */
89
+ key?: string;
90
+ /**
91
+ * The path of the echoes http receiver. Defaults to /echoes-services
92
+ */
93
+ handlerPath?: string;
94
+ /**
95
+ * Map of all the services that have echoes requests handlers
96
+ */
97
+ services?: {
98
+ [key: string]: string;
99
+ };
100
+ /**
101
+ * A custom function that make the requests to the services. Uses axios by default
102
+ */
103
+ makeRequest?: RequestMaker;
104
+ }
105
+ export interface EchoesMap {
106
+ [key: string]: EchoType<any, any>;
107
+ }
108
+ export interface EchoesKafkaEventsConfig {
109
+ client: KafkaConfig;
110
+ producer?: ProducerConfig;
111
+ consumer?: ConsumerConfig;
112
+ /**
113
+ * Defaults to true. When true, allows a reconnecting service to read missed messages.
114
+ */
115
+ readTopicsFromBeginning?: boolean;
116
+ /**
117
+ * Defaults to 4.
118
+ */
119
+ partitionsConsumedConcurrently?: number;
120
+ /**
121
+ * Defaults to 1.
122
+ */
123
+ membersToPartitionsRatio?: number;
124
+ }
125
+ export interface EchoesPulseEventsConfig {
126
+ connectionString: string;
127
+ consumerGroup: string;
128
+ databaseName?: string;
129
+ collectionPrefix?: string;
130
+ changeStreams?: 'auto' | 'required' | 'disabled';
131
+ eventRetentionMs?: number | null;
132
+ historyRetentionMs?: number | null;
133
+ pollIntervalMs?: number;
134
+ workerCount?: number;
135
+ maxPoolSize?: number;
136
+ lockTimeoutMs?: number;
137
+ onError?: (error: Error) => void;
138
+ /**
139
+ * Subscription defaults used by every Echoes event handled through Pulse.
140
+ * attemptsBeforeDeadLetter overrides maxRetries per event when configured.
141
+ */
142
+ subscription?: {
143
+ ordered?: boolean;
144
+ offsetReset?: 'latest' | 'earliest';
145
+ delivery?: 'at-least-once' | 'at-most-once';
146
+ maxRetries?: number;
147
+ retryDelayMs?: number;
148
+ retryBackoffMultiplier?: number;
149
+ maxConcurrency?: number;
150
+ };
151
+ }
152
+ export interface EchoesEventsConfig {
153
+ kafka?: EchoesKafkaEventsConfig;
154
+ pulse?: EchoesPulseEventsConfig;
155
+ /**
156
+ * Event transports that execute listeners. Defaults to Kafka when configured,
157
+ * otherwise Pulse.
158
+ */
159
+ consumeFrom?: EchoesEventTransportName[];
160
+ /**
161
+ * The only transport used by publish(). Defaults to Kafka when configured,
162
+ * otherwise Pulse.
163
+ */
164
+ publishTo?: EchoesEventTransportName;
165
+ }
166
+ export interface EchoesOptions {
167
+ client?: KafkaConfig;
168
+ producer?: ProducerConfig;
169
+ consumer?: ConsumerConfig;
170
+ requests?: RequestsConfig;
171
+ echoes: EchoesMap;
172
+ /**
173
+ * Multi-transport event configuration. The legacy Kafka fields above remain supported.
174
+ */
175
+ events?: EchoesEventsConfig;
176
+ /**
177
+ * Defaults to true. When true, allows a reconnecting service to read missed messages.
178
+ */
179
+ readTopicsFromBeginning?: boolean;
180
+ /**
181
+ * Defaults to 4. How many partitions to consume concurrently, adjust this with the members to partitions ratio to avoid idle consumers.
182
+ */
183
+ partitionsConsumedConcurrently?: number;
184
+ /**
185
+ * Defaults to 1. How many members are in comparison to partitions, this is used to determine if the consumer group has room for more members. Numbers over 1 leads to idle consumers. Numbers under 1 needs partitionsConsumedConcurrently to be more than 1.
186
+ */
187
+ membersToPartitionsRatio?: number;
188
+ }
189
+ export interface EchoesConfigHandler {
190
+ producer?: Producer;
191
+ consumer?: Consumer;
192
+ requests?: RequestsConfig;
193
+ echoes?: EchoesMap;
194
+ eventBus?: {
195
+ publish<TParams = any>(options: PublishOptions<TParams>): Promise<any>;
196
+ close(): Promise<void>;
197
+ };
198
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orion-js/echoes",
3
- "version": "4.3.2",
3
+ "version": "4.4.1",
4
4
  "main": "./dist/index.cjs",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [
@@ -8,33 +8,35 @@
8
8
  ],
9
9
  "author": "nicolaslopezj",
10
10
  "license": "MIT",
11
- "scripts": {
12
- "test": "bun test",
13
- "prepare": "bun run build",
14
- "clean": "rm -rf ./dist",
15
- "build": "tsup",
16
- "dev": "tsup --watch"
17
- },
18
11
  "dependencies": {
19
- "@orion-js/env": "4.3.1",
20
- "@orion-js/helpers": "4.3.1",
21
- "@orion-js/http": "4.3.2",
22
- "@orion-js/schema": "4.3.1",
23
- "@orion-js/services": "4.3.1",
12
+ "@orion-js/env": "4.4.0",
13
+ "@orion-js/helpers": "4.4.0",
14
+ "@orion-js/http": "4.4.0",
15
+ "@orion-js/schema": "4.4.0",
16
+ "@orion-js/services": "4.4.0",
24
17
  "axios": "^0.24.0",
25
18
  "jssha": "^3.2.0",
26
19
  "kafkajs": "^2.2.4",
27
20
  "serialize-javascript": "^6.0.0"
28
21
  },
29
22
  "peerDependencies": {
30
- "@orion-js/logger": "4.3.1"
23
+ "@orion-js/logger": "4.4.0",
24
+ "@orion-js/pulse": "^4.4.2"
25
+ },
26
+ "peerDependenciesMeta": {
27
+ "@orion-js/pulse": {
28
+ "optional": true
29
+ }
31
30
  },
32
31
  "devDependencies": {
32
+ "@orion-js/pulse": "4.4.2",
33
33
  "@types/node": "^18.0.0",
34
34
  "@types/supertest": "2.0.11",
35
+ "mongodb": "^6.15.0",
36
+ "mongodb-memory-server": "^10.1.4",
35
37
  "supertest": "^6.1.6",
36
38
  "tsup": "^8.0.1",
37
- "typescript": "^5.4.5"
39
+ "typescript": "^7.0.2"
38
40
  },
39
41
  "publishConfig": {
40
42
  "access": "public"
@@ -46,5 +48,11 @@
46
48
  "types": "./dist/index.d.ts",
47
49
  "import": "./dist/index.js",
48
50
  "require": "./dist/index.cjs"
51
+ },
52
+ "scripts": {
53
+ "test": "bun test",
54
+ "clean": "rm -rf ./dist",
55
+ "build": "tsup && bun run ../../scripts/emit-declarations.ts",
56
+ "dev": "tsup --watch"
49
57
  }
50
- }
58
+ }