{"version":3,"sources":["../../../../../src/events/adapters/rabbitmq/index.ts"],"sourcesContent":["import { connect, type ChannelWrapper } from 'amqp-connection-manager'\nimport type { ConfirmChannel } from 'amqplib'\nimport { v } from 'valleyed'\n\nimport { Instance } from '../../../instance'\nimport type { Events } from '../../../types'\nimport { configurable, parseJSONValue, Random } from '../../../utilities'\nimport { EventBus, type Stream, type StreamOptions } from '../base'\n\nexport const rabbitmqConfigPipe = () =>\n\tv.meta(\n\t\tv.object({\n\t\t\turi: v.string(),\n\t\t\teventColumnName: v.string(),\n\t\t}),\n\t\t{ title: 'Rabbitmq Config', $refId: 'RabbitmqConfig' },\n\t)\n\nexport class RabbitMQEventBus extends configurable(rabbitmqConfigPipe, EventBus) {\n\t#client: ChannelWrapper\n\t#columnName: string\n\n\tprotected constructor(config: typeof RabbitMQEventBus.Config) {\n\t\tsuper(config)\n\n\t\tthis.#columnName = config.eventColumnName\n\t\tthis.#client = connect([config.uri]).createChannel({\n\t\t\tjson: false,\n\t\t\tsetup: async (channel: ConfirmChannel) => {\n\t\t\t\tawait channel.assertExchange(this.#columnName, 'direct', { durable: true })\n\t\t\t\tawait channel.prefetch(1)\n\t\t\t},\n\t\t})\n\t}\n\n\tstream<Event extends Events[keyof Events]>(topicName: Event['topic'], options: Partial<StreamOptions> = {}): Stream<Event['data']> {\n\t\tconst topic = options.skipScope ? topicName : Instance.get().getScopedName(topicName)\n\n\t\treturn {\n\t\t\tpublish: async (data) => await this.#client.publish(this.#columnName, topic, JSON.stringify(data), { persistent: true }),\n\t\t\tsubscribe: async (onMessage) => {\n\t\t\t\tconst subscribe = async () => {\n\t\t\t\t\tawait this.#client.addSetup(async (channel: ConfirmChannel) => {\n\t\t\t\t\t\tconst queueName = options.fanout\n\t\t\t\t\t\t\t? Instance.get().getScopedName(`${Instance.get().id}-fanout-${Random.string(10)}`)\n\t\t\t\t\t\t\t: topic\n\t\t\t\t\t\tconst { queue } = await channel.assertQueue(queueName, { durable: !options.fanout, exclusive: options.fanout })\n\t\t\t\t\t\tawait channel.bindQueue(queue, this.#columnName, topic)\n\t\t\t\t\t\tchannel.consume(\n\t\t\t\t\t\t\tqueue,\n\t\t\t\t\t\t\tasync (msg) => {\n\t\t\t\t\t\t\t\tawait Instance.resolveBeforeCrash(async () => {\n\t\t\t\t\t\t\t\t\tif (!msg) return\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tawait onMessage(parseJSONValue(msg.content.toString()))\n\t\t\t\t\t\t\t\t\t\tchannel.ack(msg)\n\t\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\t\tchannel.nack(msg)\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{ noAck: false },\n\t\t\t\t\t\t)\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tInstance.on('start', subscribe, { class: RabbitMQEventBus })\n\t\t\t},\n\t\t}\n\t}\n}\n\nif (import.meta.vitest) {\n\tconst { describe, test, expect, expectTypeOf } = import.meta.vitest\n\n\tdescribe('RabbitMQEventBus', () => {\n\t\ttest('create returns an instance with stream method', () => {\n\t\t\tconst bus = RabbitMQEventBus.create({ uri: 'amqp://localhost', eventColumnName: 'events' })\n\t\t\texpect(bus).toBeInstanceOf(RabbitMQEventBus)\n\t\t\texpect(bus.stream).toBeTypeOf('function')\n\t\t})\n\n\t\ttest('external new is a compile error', () => {\n\t\t\t// @ts-expect-error — external `new` on a class with protected constructor is a compile error\n\t\t\tvoid (() => new RabbitMQEventBus({ uri: 'amqp://localhost', eventColumnName: 'events' }))\n\t\t})\n\n\t\ttest('static Config resolves to the pipe output type', () => {\n\t\t\texpectTypeOf<typeof RabbitMQEventBus.Config>().toHaveProperty('uri')\n\t\t\texpectTypeOf<typeof RabbitMQEventBus.Config>().toHaveProperty('eventColumnName')\n\t\t})\n\n\t\ttest('create rejects invalid config', () => {\n\t\t\t// @ts-expect-error — missing required field\n\t\t\texpect(() => RabbitMQEventBus.create({ uri: 'amqp://localhost' })).toThrow()\n\t\t})\n\t})\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAAA,SAAS,eAAoC;AAE7C,SAAS,SAAS;AAOX,IAAM,qBAAqB,MACjC,EAAE;AAAA,EACD,EAAE,OAAO;AAAA,IACR,KAAK,EAAE,OAAO;AAAA,IACd,iBAAiB,EAAE,OAAO;AAAA,EAC3B,CAAC;AAAA,EACD,EAAE,OAAO,mBAAmB,QAAQ,iBAAiB;AACtD;AAEM,IAAM,mBAAN,MAAM,0BAAyB,aAAa,oBAAoB,QAAQ,EAAE;AAAA,EAChF;AAAA,EACA;AAAA,EAEU,YAAY,QAAwC;AAC7D,UAAM,MAAM;AAEZ,SAAK,cAAc,OAAO;AAC1B,SAAK,UAAU,QAAQ,CAAC,OAAO,GAAG,CAAC,EAAE,cAAc;AAAA,MAClD,MAAM;AAAA,MACN,OAAO,OAAO,YAA4B;AACzC,cAAM,QAAQ,eAAe,KAAK,aAAa,UAAU,EAAE,SAAS,KAAK,CAAC;AAC1E,cAAM,QAAQ,SAAS,CAAC;AAAA,MACzB;AAAA,IACD,CAAC;AAAA,EACF;AAAA,EAEA,OAA2C,WAA2B,UAAkC,CAAC,GAA0B;AAClI,UAAM,QAAQ,QAAQ,YAAY,YAAY,SAAS,IAAI,EAAE,cAAc,SAAS;AAEpF,WAAO;AAAA,MACN,SAAS,OAAO,SAAS,MAAM,KAAK,QAAQ,QAAQ,KAAK,aAAa,OAAO,KAAK,UAAU,IAAI,GAAG,EAAE,YAAY,KAAK,CAAC;AAAA,MACvH,WAAW,OAAO,cAAc;AAC/B,cAAM,YAAY,YAAY;AAC7B,gBAAM,KAAK,QAAQ,SAAS,OAAO,YAA4B;AAC9D,kBAAM,YAAY,QAAQ,SACvB,SAAS,IAAI,EAAE,cAAc,GAAG,SAAS,IAAI,EAAE,EAAE,WAAW,eAAO,OAAO,EAAE,CAAC,EAAE,IAC/E;AACH,kBAAM,EAAE,MAAM,IAAI,MAAM,QAAQ,YAAY,WAAW,EAAE,SAAS,CAAC,QAAQ,QAAQ,WAAW,QAAQ,OAAO,CAAC;AAC9G,kBAAM,QAAQ,UAAU,OAAO,KAAK,aAAa,KAAK;AACtD,oBAAQ;AAAA,cACP;AAAA,cACA,OAAO,QAAQ;AACd,sBAAM,SAAS,mBAAmB,YAAY;AAC7C,sBAAI,CAAC,IAAK;AACV,sBAAI;AACH,0BAAM,UAAU,eAAe,IAAI,QAAQ,SAAS,CAAC,CAAC;AACtD,4BAAQ,IAAI,GAAG;AAAA,kBAChB,QAAQ;AACP,4BAAQ,KAAK,GAAG;AAAA,kBACjB;AAAA,gBACD,CAAC;AAAA,cACF;AAAA,cACA,EAAE,OAAO,MAAM;AAAA,YAChB;AAAA,UACD,CAAC;AAAA,QACF;AAEA,iBAAS,GAAG,SAAS,WAAW,EAAE,OAAO,kBAAiB,CAAC;AAAA,MAC5D;AAAA,IACD;AAAA,EACD;AACD;AAEA,IAAI,QAAoB;AACvB,QAAM,EAAE,UAAU,MAAM,QAAQ,aAAa,IAAI;AAEjD,WAAS,oBAAoB,MAAM;AAClC,SAAK,iDAAiD,MAAM;AAC3D,YAAM,MAAM,iBAAiB,OAAO,EAAE,KAAK,oBAAoB,iBAAiB,SAAS,CAAC;AAC1F,aAAO,GAAG,EAAE,eAAe,gBAAgB;AAC3C,aAAO,IAAI,MAAM,EAAE,WAAW,UAAU;AAAA,IACzC,CAAC;AAED,SAAK,mCAAmC,MAAM;AAE7C,YAAM,MAAM,IAAI,iBAAiB,EAAE,KAAK,oBAAoB,iBAAiB,SAAS,CAAC;AAAA,IACxF,CAAC;AAED,SAAK,kDAAkD,MAAM;AAC5D,mBAA6C,EAAE,eAAe,KAAK;AACnE,mBAA6C,EAAE,eAAe,iBAAiB;AAAA,IAChF,CAAC;AAED,SAAK,iCAAiC,MAAM;AAE3C,aAAO,MAAM,iBAAiB,OAAO,EAAE,KAAK,mBAAmB,CAAC,CAAC,EAAE,QAAQ;AAAA,IAC5E,CAAC;AAAA,EACF,CAAC;AACF;","names":[]}