{"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":"+PAAA,OAAS,WAAAA,MAAoC,0BAE7C,OAAS,KAAAC,MAAS,WAOX,IAAMC,EAAqB,IACjCC,EAAE,KACDA,EAAE,OAAO,CACR,IAAKA,EAAE,OAAO,EACd,gBAAiBA,EAAE,OAAO,CAC3B,CAAC,EACD,CAAE,MAAO,kBAAmB,OAAQ,gBAAiB,CACtD,EAEYC,EAAN,MAAMC,UAAyBC,EAAaJ,EAAoBK,CAAQ,CAAE,CAChFC,GACAC,GAEU,YAAYC,EAAwC,CAC7D,MAAMA,CAAM,EAEZ,KAAKD,GAAcC,EAAO,gBAC1B,KAAKF,GAAUG,EAAQ,CAACD,EAAO,GAAG,CAAC,EAAE,cAAc,CAClD,KAAM,GACN,MAAO,MAAOE,GAA4B,CACzC,MAAMA,EAAQ,eAAe,KAAKH,GAAa,SAAU,CAAE,QAAS,EAAK,CAAC,EAC1E,MAAMG,EAAQ,SAAS,CAAC,CACzB,CACD,CAAC,CACF,CAEA,OAA2CC,EAA2BC,EAAkC,CAAC,EAA0B,CAClI,IAAMC,EAAQD,EAAQ,UAAYD,EAAYG,EAAS,IAAI,EAAE,cAAcH,CAAS,EAEpF,MAAO,CACN,QAAS,MAAOI,GAAS,MAAM,KAAKT,GAAQ,QAAQ,KAAKC,GAAaM,EAAO,KAAK,UAAUE,CAAI,EAAG,CAAE,WAAY,EAAK,CAAC,EACvH,UAAW,MAAOC,GAAc,CAC/B,IAAMC,EAAY,SAAY,CAC7B,MAAM,KAAKX,GAAQ,SAAS,MAAOI,GAA4B,CAC9D,IAAMQ,EAAYN,EAAQ,OACvBE,EAAS,IAAI,EAAE,cAAc,GAAGA,EAAS,IAAI,EAAE,EAAE,WAAWK,EAAO,OAAO,EAAE,CAAC,EAAE,EAC/EN,EACG,CAAE,MAAAO,CAAM,EAAI,MAAMV,EAAQ,YAAYQ,EAAW,CAAE,QAAS,CAACN,EAAQ,OAAQ,UAAWA,EAAQ,MAAO,CAAC,EAC9G,MAAMF,EAAQ,UAAUU,EAAO,KAAKb,GAAaM,CAAK,EACtDH,EAAQ,QACPU,EACA,MAAOC,GAAQ,CACd,MAAMP,EAAS,mBAAmB,SAAY,CAC7C,GAAKO,EACL,GAAI,CACH,MAAML,EAAUM,EAAeD,EAAI,QAAQ,SAAS,CAAC,CAAC,EACtDX,EAAQ,IAAIW,CAAG,CAChB,MAAQ,CACPX,EAAQ,KAAKW,CAAG,CACjB,CACD,CAAC,CACF,EACA,CAAE,MAAO,EAAM,CAChB,CACD,CAAC,CACF,EAEAP,EAAS,GAAG,QAASG,EAAW,CAAE,MAAOd,CAAiB,CAAC,CAC5D,CACD,CACD,CACD","names":["connect","v","rabbitmqConfigPipe","v","RabbitMQEventBus","_RabbitMQEventBus","configurable","EventBus","#client","#columnName","config","connect","channel","topicName","options","topic","Instance","data","onMessage","subscribe","queueName","random_exports","queue","msg","parseJSONValue"]}