{"_id":"@a_jackie_z/event-bus","_rev":"11-587cc52eb0f6b34db508cbae62da5747","name":"@a_jackie_z/event-bus","dist-tags":{"latest":"1.0.8"},"versions":{"1.0.1":{"name":"@a_jackie_z/event-bus","version":"1.0.1","author":{"name":"Sang Lu","email":"connect.with.sang@gmail.com"},"license":"MIT","_id":"@a_jackie_z/event-bus@1.0.1","maintainers":[{"name":"sanglu","email":"connect.with.sang@gmail.com"}],"dist":{"shasum":"63b2136aee32b871d4901c052a3926de5ae812ee","tarball":"https://registry.npmjs.org/@a_jackie_z/event-bus/-/event-bus-1.0.1.tgz","fileCount":30,"integrity":"sha512-ZSQv6SpPU/lxb7GyIt3X1Kpq8LlO3v05qs2JC0aj1ece/S5By3IupYSdVlLMMkVEwqfr7inK9u+fLU9nM/VhaA==","signatures":[{"sig":"MEUCIQCbzXzFSiYvzltvGAz/ibZWmgTisYaBcBKETEJEWzo50wIgUwjBss54oRrf/tAcvFZ+R9g2tg12Qabg9DBKXn4QOAc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":118504},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"cc48eb9342eef2b94a1cc00ed40537f85c945841","scripts":{"build":"tsup","test:consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/consumer.js","test:producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/producer.js","test:mixed-consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/mixed-consumer.js","test:mixed-producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/mixed-producer.js","test:broadcast-consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/broadcast-consumer.js","test:broadcast-producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/broadcast-producer.js"},"_npmUser":{"name":"sanglu","email":"connect.with.sang@gmail.com"},"_npmVersion":"11.6.2","description":"An event bus using RabbitMQ","directories":{},"_nodeVersion":"24.13.0","dependencies":{"amqplib":"^0.10.9","@a_jackie_z/logger":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","ts-node":"^10.9.2","typescript":"^5.9.3","@types/node":"^25.0.9","@types/amqplib":"^0.10.8"},"_npmOperationalInternal":{"tmp":"tmp/event-bus_1.0.1_1768845309235_0.12330953075823792","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@a_jackie_z/event-bus","version":"1.0.2","author":{"name":"Sang Lu","email":"connect.with.sang@gmail.com"},"license":"MIT","_id":"@a_jackie_z/event-bus@1.0.2","maintainers":[{"name":"sanglu","email":"connect.with.sang@gmail.com"}],"homepage":"https://github.com/a-jackie-z/event-bus#readme","bugs":{"url":"https://github.com/a-jackie-z/event-bus/issues"},"dist":{"shasum":"c8bdb90f63d55f6cba0c1e52b367202a05cf2a01","tarball":"https://registry.npmjs.org/@a_jackie_z/event-bus/-/event-bus-1.0.2.tgz","fileCount":30,"integrity":"sha512-JQXzGg4YojjFfitG2vJaseVRFUdp3T20Qx9zedtR6DNzYUsSxqY3tKRC9B1HEQRyzt4U6Out13gKtiH62WpGaQ==","signatures":[{"sig":"MEUCIQDNoOucYAUBRa6VxwUQGNXKIfaHN7yevTb8bCtV94p4VAIgHtQFbadAooMSyX+hP4E5Q07FqO67XdR+WijMQxXN1WU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":118580},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"ea5b131a1e1ef75492239703ea996f2e99da11bb","scripts":{"build":"tsup","test:consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/consumer.js","test:producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/producer.js","test:mixed-consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/mixed-consumer.js","test:mixed-producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/mixed-producer.js","test:broadcast-consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/broadcast-consumer.js","test:broadcast-producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/broadcast-producer.js"},"_npmUser":{"name":"sanglu","email":"connect.with.sang@gmail.com"},"repository":{"url":"git+https://github.com/a-jackie-z/event-bus.git"},"_npmVersion":"11.6.2","description":"An event bus using RabbitMQ","directories":{},"_nodeVersion":"24.13.0","dependencies":{"amqplib":"^0.10.9","@a_jackie_z/logger":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","ts-node":"^10.9.2","typescript":"^5.9.3","@types/node":"^25.0.9","@types/amqplib":"^0.10.8"},"_npmOperationalInternal":{"tmp":"tmp/event-bus_1.0.2_1770011768991_0.7432679141595595","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@a_jackie_z/event-bus","version":"1.0.3","author":{"name":"Sang Lu","email":"connect.with.sang@gmail.com"},"license":"MIT","_id":"@a_jackie_z/event-bus@1.0.3","maintainers":[{"name":"sanglu","email":"connect.with.sang@gmail.com"}],"homepage":"https://github.com/a-jackie-z/event-bus#readme","bugs":{"url":"https://github.com/a-jackie-z/event-bus/issues"},"dist":{"shasum":"8136adcea328b836a4a8d520bf549c1b67af6be7","tarball":"https://registry.npmjs.org/@a_jackie_z/event-bus/-/event-bus-1.0.3.tgz","fileCount":30,"integrity":"sha512-LlMtQ4+Ov+yD8G9HkO7Ipy28YMCWviDtw16+sKFIKzKL0jxAVol8pngPwQw0m8g/wLbNZhVyZlOk96sUQsdfXQ==","signatures":[{"sig":"MEUCIEGSYFiudVPYeGmKtQ9KbOEW9RvGnFlOymbstF0lhnu+AiEAlWLyJo3NNptWtM4WftNyFN5eEuNvZIz0TQnfp71HBhg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":118580},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"ea5b131a1e1ef75492239703ea996f2e99da11bb","scripts":{"build":"tsup","test:consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/consumer.js","test:producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/producer.js","test:mixed-consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/mixed-consumer.js","test:mixed-producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/mixed-producer.js","test:broadcast-consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/broadcast-consumer.js","test:broadcast-producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/broadcast-producer.js"},"_npmUser":{"name":"sanglu","email":"connect.with.sang@gmail.com"},"repository":{"url":"git+https://github.com/a-jackie-z/event-bus.git"},"_npmVersion":"11.6.2","description":"An event bus using RabbitMQ","directories":{},"_nodeVersion":"24.13.0","dependencies":{"amqplib":"^0.10.9","@a_jackie_z/logger":"^1.0.1"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","ts-node":"^10.9.2","typescript":"^5.9.3","@types/node":"^25.2.0","@types/amqplib":"^0.10.8"},"_npmOperationalInternal":{"tmp":"tmp/event-bus_1.0.3_1770142693129_0.291914631061176","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@a_jackie_z/event-bus","version":"1.0.4","author":{"name":"Sang Lu","email":"connect.with.sang@gmail.com"},"license":"MIT","_id":"@a_jackie_z/event-bus@1.0.4","maintainers":[{"name":"sanglu","email":"connect.with.sang@gmail.com"}],"homepage":"https://github.com/a-jackie-z/event-bus#readme","bugs":{"url":"https://github.com/a-jackie-z/event-bus/issues"},"dist":{"shasum":"008f60bf558e38d14839815e9fe00e1d778bd643","tarball":"https://registry.npmjs.org/@a_jackie_z/event-bus/-/event-bus-1.0.4.tgz","fileCount":30,"integrity":"sha512-3s0pJy6jom3okX4PgtunM7pPOIjSceeuzmk00iUPjCXjY/TcUlMg799TxkPpyY2LmI+AEOnFtocxfcZ2hMKEsQ==","signatures":[{"sig":"MEYCIQCYrqFck44aiGLDGHPvsvlaKH2fkAGlWZhdkNkBe37YIQIhAN1LKQOG9ZiC1WTL/ojap+V9RlcxtUUt9JvT7pQE6R9x","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":118580},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"2710c04b189a5efe18554a343a1cca2abd108805","scripts":{"build":"tsup","test:consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/consumer.js","test:producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/producer.js","test:mixed-consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/mixed-consumer.js","test:mixed-producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/mixed-producer.js","test:broadcast-consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/broadcast-consumer.js","test:broadcast-producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/broadcast-producer.js"},"_npmUser":{"name":"sanglu","email":"connect.with.sang@gmail.com"},"repository":{"url":"git+https://github.com/a-jackie-z/event-bus.git"},"_npmVersion":"11.6.2","description":"An event bus using RabbitMQ","directories":{},"_nodeVersion":"24.13.0","dependencies":{"amqplib":"^0.10.9","@a_jackie_z/logger":"^1.0.2"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","ts-node":"^10.9.2","typescript":"^5.9.3","@types/node":"^25.2.0","@types/amqplib":"^0.10.8"},"_npmOperationalInternal":{"tmp":"tmp/event-bus_1.0.4_1770192527582_0.3357401279460106","host":"s3://npm-registry-packages-npm-production"}},"1.0.5":{"name":"@a_jackie_z/event-bus","version":"1.0.5","author":{"name":"Sang Lu","email":"connect.with.sang@gmail.com"},"license":"MIT","_id":"@a_jackie_z/event-bus@1.0.5","maintainers":[{"name":"sanglu","email":"connect.with.sang@gmail.com"}],"homepage":"https://github.com/a-jackie-z/event-bus#readme","bugs":{"url":"https://github.com/a-jackie-z/event-bus/issues"},"dist":{"shasum":"97110f2e76390510d66e6bbe4e60f999130ea01f","tarball":"https://registry.npmjs.org/@a_jackie_z/event-bus/-/event-bus-1.0.5.tgz","fileCount":30,"integrity":"sha512-qRIhgx9OXVAk7DZ2v5Dp5KyuL9nv8Ml9JtwiHKg5HTVCxC7KFpfSGssdft6PFD+iFlZVMUzkeEIwKvn1T49JpQ==","signatures":[{"sig":"MEUCIAvHthZuv4O1q2yUzgXV9uAsK4DJuxfxctloJ/y11V00AiEA4a2BT3TEX45k3RMDJ/ji/5tVoKxc/y7CEYkKl6uR5nw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":118588},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"e6db9c6a339a436cc5e74392023670bcc7312a82","scripts":{"build":"tsup","test:consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/consumer.js","test:producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/producer.js","test:mixed-consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/mixed-consumer.js","test:mixed-producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/mixed-producer.js","test:broadcast-consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/broadcast-consumer.js","test:broadcast-producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/broadcast-producer.js"},"_npmUser":{"name":"sanglu","email":"connect.with.sang@gmail.com"},"repository":{"url":"git+https://github.com/a-jackie-z/event-bus.git"},"_npmVersion":"11.8.0","description":"An event bus using RabbitMQ","directories":{},"_nodeVersion":"24.13.1","dependencies":{"amqplib":"^0.10.9","@a_jackie_z/logger":"^1.0.2"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","ts-node":"^10.9.2","typescript":"^5.9.3","@types/node":"^25.3.0","@types/amqplib":"^0.10.8"},"_npmOperationalInternal":{"tmp":"tmp/event-bus_1.0.5_1772032208335_0.8401918379928999","host":"s3://npm-registry-packages-npm-production"}},"1.0.6":{"name":"@a_jackie_z/event-bus","version":"1.0.6","author":{"name":"Sang Lu","email":"connect.with.sang@gmail.com"},"license":"MIT","_id":"@a_jackie_z/event-bus@1.0.6","maintainers":[{"name":"sanglu","email":"connect.with.sang@gmail.com"}],"homepage":"https://github.com/a-jackie-z/event-bus#readme","bugs":{"url":"https://github.com/a-jackie-z/event-bus/issues"},"dist":{"shasum":"26d3b6f26d10977951a125f247971070978efcf7","tarball":"https://registry.npmjs.org/@a_jackie_z/event-bus/-/event-bus-1.0.6.tgz","fileCount":30,"integrity":"sha512-wy7Ws59Whiwy1kCGAKmyxsIXfQT1Cno+6QOJl/m+btZrY5lbIChgesfcEoViLwv0X01S1kev+1vDi7vtXYPphA==","signatures":[{"sig":"MEYCIQC3sfmfkrRAOMLTQcq+uo5h+o1Dbl8F+rwP3hHKEcJS7gIhANhFq3N2B0U7T4xyATs7rkjItJE2Ka+eOntYUuB6CoKG","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":118588},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"e6db9c6a339a436cc5e74392023670bcc7312a82","scripts":{"build":"tsup","test:consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/consumer.js","test:producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/producer.js","test:mixed-consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/mixed-consumer.js","test:mixed-producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/mixed-producer.js","test:broadcast-consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/broadcast-consumer.js","test:broadcast-producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/broadcast-producer.js"},"_npmUser":{"name":"sanglu","email":"connect.with.sang@gmail.com"},"repository":{"url":"git+https://github.com/a-jackie-z/event-bus.git"},"_npmVersion":"11.8.0","description":"An event bus using RabbitMQ","directories":{},"_nodeVersion":"24.13.1","dependencies":{"amqplib":"^0.10.9","@a_jackie_z/logger":"^1.0.3"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","ts-node":"^10.9.2","typescript":"^5.9.3","@types/node":"^25.3.0","@types/amqplib":"^0.10.8"},"_npmOperationalInternal":{"tmp":"tmp/event-bus_1.0.6_1772032267025_0.8841515723823643","host":"s3://npm-registry-packages-npm-production"}},"1.0.7":{"name":"@a_jackie_z/event-bus","version":"1.0.7","author":{"name":"Sang Lu","email":"connect.with.sang@gmail.com"},"license":"MIT","_id":"@a_jackie_z/event-bus@1.0.7","maintainers":[{"name":"sanglu","email":"connect.with.sang@gmail.com"}],"homepage":"https://github.com/a-jackie-z/event-bus#readme","bugs":{"url":"https://github.com/a-jackie-z/event-bus/issues"},"dist":{"shasum":"69835de31ff605d4af0b43005196149fa62585e3","tarball":"https://registry.npmjs.org/@a_jackie_z/event-bus/-/event-bus-1.0.7.tgz","fileCount":30,"integrity":"sha512-q4dRgCCFwQ5/5rLwfTfjTRSCufFWR4Hn9ybk76BkkiDZ+q5LaS3tArF+3sl4tFGDrA5KG3nfSdEYABTTAdaS5w==","signatures":[{"sig":"MEUCIDsJK3deIhKEPZ2i/JPIt8ruxnKO/WO8YdyCYZu0isFVAiEAvPgJG6yjNa40c7amEAVl9h1NPs/OEL7BzyYNr7xTXQ8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":118588},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"2f60fbd9db5ae363ee5f5c4cae2b04341b00b07e","scripts":{"build":"tsup","test:consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/consumer.js","test:producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/producer.js","test:mixed-consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/mixed-consumer.js","test:mixed-producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/mixed-producer.js","test:broadcast-consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/broadcast-consumer.js","test:broadcast-producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/broadcast-producer.js"},"_npmUser":{"name":"sanglu","email":"connect.with.sang@gmail.com"},"repository":{"url":"git+https://github.com/a-jackie-z/event-bus.git"},"_npmVersion":"11.8.0","description":"An event bus using RabbitMQ","directories":{},"_nodeVersion":"24.13.1","dependencies":{"amqplib":"^0.10.9","@a_jackie_z/logger":"^1.0.3"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","ts-node":"^10.9.2","typescript":"^6.0.2","@types/node":"^25.5.0","@types/amqplib":"^0.10.8"},"_npmOperationalInternal":{"tmp":"tmp/event-bus_1.0.7_1774347069347_0.24331258870943273","host":"s3://npm-registry-packages-npm-production"}},"1.0.8":{"name":"@a_jackie_z/event-bus","version":"1.0.8","description":"An event bus using RabbitMQ","license":"MIT","author":{"name":"Sang Lu","email":"connect.with.sang@gmail.com"},"repository":{"url":"git+https://github.com/a-jackie-z/event-bus.git"},"type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"build":"tsup","test:consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/consumer.js","test:producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/producer.js","test:broadcast-consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/broadcast-consumer.js","test:broadcast-producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/broadcast-producer.js","test:mixed-consumer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/mixed-consumer.js","test:mixed-producer":"LOG_PRETTY=true LOG_LEVEL=debug node dist/lib/tests/mixed-producer.js"},"dependencies":{"@a_jackie_z/logger":"^1.0.4","amqplib":"^0.10.9"},"devDependencies":{"@types/amqplib":"^0.10.8","@types/node":"^25.5.0","ts-node":"^10.9.2","tsup":"^8.5.1","typescript":"^6.0.2"},"gitHead":"2f60fbd9db5ae363ee5f5c4cae2b04341b00b07e","_id":"@a_jackie_z/event-bus@1.0.8","bugs":{"url":"https://github.com/a-jackie-z/event-bus/issues"},"homepage":"https://github.com/a-jackie-z/event-bus#readme","_nodeVersion":"24.13.1","_npmVersion":"11.8.0","dist":{"integrity":"sha512-LuG2bsFPw/b6NIZuk7yRIVDwMb0WH1rhDmFYJTLr//7bcm1CBQXV85MAz9s4K5CL660DTjwlW7qyMrEsogJkqQ==","shasum":"00911d323f61af9f89ac30979c95d222f3aeccb6","tarball":"https://registry.npmjs.org/@a_jackie_z/event-bus/-/event-bus-1.0.8.tgz","fileCount":30,"unpackedSize":118588,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIGpAV8rKCj37pOi9qLnc3JZX86PB2qJhcY4t/S+7qEvHAiEA7LGTT6M8L/QOCs4pTJriroPqRtP3GcBiRqHFOJCk7B8="}]},"_npmUser":{"name":"sanglu","email":"connect.with.sang@gmail.com"},"directories":{},"maintainers":[{"name":"sanglu","email":"connect.with.sang@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/event-bus_1.0.8_1774347224405_0.20357601483542265"},"_hasShrinkwrap":false}},"time":{"created":"2026-01-19T17:55:08.863Z","modified":"2026-03-24T10:13:44.704Z","1.0.0":"2026-01-19T17:41:58.097Z","1.0.1":"2026-01-19T17:55:09.384Z","1.0.2":"2026-02-02T05:56:09.142Z","1.0.3":"2026-02-03T18:18:13.277Z","1.0.4":"2026-02-04T08:08:47.792Z","1.0.5":"2026-02-25T15:10:08.501Z","1.0.6":"2026-02-25T15:11:07.184Z","1.0.7":"2026-03-24T10:11:09.489Z","1.0.8":"2026-03-24T10:13:44.558Z"},"bugs":{"url":"https://github.com/a-jackie-z/event-bus/issues"},"author":{"name":"Sang Lu","email":"connect.with.sang@gmail.com"},"license":"MIT","homepage":"https://github.com/a-jackie-z/event-bus#readme","repository":{"url":"git+https://github.com/a-jackie-z/event-bus.git"},"description":"An event bus using RabbitMQ","maintainers":[{"name":"sanglu","email":"connect.with.sang@gmail.com"}],"readme":"# @a_jackie_z/event-bus\n\nA robust, TypeScript-first event bus implementation using RabbitMQ. Supports both point-to-point (queue-based) and broadcast (fanout exchange) messaging patterns with automatic reconnection and reliable message delivery.\n\n## Features\n\n- **Dual Messaging Patterns**: Point-to-point (load-balanced queues) and broadcast (fanout exchanges)\n- **TypeScript Support**: Full type safety with TypeScript definitions\n- **Auto-Reconnection**: Automatic reconnection with 15-second intervals\n- **Message Persistence**: Durable queues and persistent messages for reliability\n- **Fair Distribution**: Prefetch set to 1 for even load balancing across consumers\n- **Connection State Monitoring**: Track connection state changes with callbacks\n- **Graceful Shutdown**: Proper cleanup of consumers and connections\n- **Error Handling**: Fail-safe message acknowledgment strategies\n\n## Installation\n\n```bash\nnpm install @a_jackie_z/event-bus\n```\n\n## Table of Contents\n\n- [Architecture](#architecture)\n- [Pattern Comparison](#pattern-comparison)\n- [Quick Start](#quick-start)\n- [Point-to-Point Messaging](#point-to-point-messaging)\n- [Broadcast Messaging](#broadcast-messaging)\n- [Mixed Mode](#mixed-mode)\n- [Connection State Management](#connection-state-management)\n- [Scaling Strategies](#scaling-strategies)\n- [Performance Tips](#performance-tips)\n- [API Reference](#api-reference)\n- [Best Practices](#best-practices)\n\n## Architecture\n\n### Point-to-Point Pattern (Queue-Based)\n\n```\n┌──────────┐                    ┌───────────┐\n│ Producer │───── publish() ───>│   Queue   │\n└──────────┘                    │ (durable) │\n                                └─────┬─────┘\n                                      │\n                        ┌─────────────┴─────────────┐\n                        │    (Load Balanced)        │\n                        ▼                           ▼\n                  ┌───────────┐             ┌───────────┐\n                  │ Consumer1 │             │ Consumer2 │\n                  └───────────┘             └───────────┘\n                  \nEach message is delivered to ONE consumer (round-robin)\n```\n\n### Broadcast Pattern (Fanout Exchange)\n\n```\n                               ┌─────────────────┐\n                               │ Fanout Exchange │\n┌──────────┐                   └────────┬────────┘\n│ Producer │─── broadcast() ───────────>│\n└──────────┘                            │\n                        ┌───────────────┴───────────────┐\n                        │                               │\n                        ▼                               ▼\n                  ┌─────────┐                     ┌─────────┐\n                  │ Queue1  │                     │ Queue2  │\n                  │(exclusive)                    │(exclusive)\n                  └────┬────┘                     └────┬────┘\n                       │                               │\n                       ▼                               ▼\n                  ┌───────────┐                   ┌───────────┐\n                  │ Consumer1 │                   │ Consumer2 │\n                  └───────────┘                   └───────────┘\n                  \nEach message is delivered to ALL consumers\n```\n\n## Pattern Comparison\n\n| Feature | Point-to-Point (Queue) | Broadcast (Fanout Exchange) |\n|---------|------------------------|------------------------------|\n| **Use Case** | Task distribution, work queues | Event notifications, announcements |\n| **Delivery** | One consumer receives each message | All consumers receive every message |\n| **Message Persistence** | Durable queues, persistent messages | Transient messages, non-durable exchange |\n| **Queue Type** | Shared, durable queue | Exclusive, auto-delete queues per consumer |\n| **Consumer Behavior** | Load-balanced (round-robin) | All consumers process independently |\n| **Example Scenarios** | Order processing, email sending, image processing | System alerts, cache invalidation, real-time updates |\n| **Scaling** | Add consumers for parallel processing | Add consumers for redundancy/availability |\n| **Message Guarantee** | At-least-once delivery | Best-effort delivery (no persistence) |\n\n## Quick Start\n\n```typescript\nimport { EventBusProducer, EventBusConsumer, type QueueHandlers, type EventHandler } from '@a_jackie_z/event-bus';\n\n// Producer: Send messages\nconst producer = new EventBusProducer({\n  rabbitMqUrl: 'amqp://username:password@localhost:5672'\n});\n\nawait producer.connect();\nawait producer.publish('tasks', { taskId: 1, action: 'process' });\nawait producer.disconnect();\n\n// Consumer: Process messages\nconst taskHandler: EventHandler = async (data) => {\n  console.log('Processing task:', data);\n};\n\nconst queueHandlers: QueueHandlers = new Map([\n  ['tasks', [taskHandler]]\n]);\n\nconst consumer = new EventBusConsumer({\n  rabbitMqUrl: 'amqp://username:password@localhost:5672',\n  queueHandlers\n});\n\nawait consumer.connect();\n// Consumer runs until disconnect() is called\n```\n\n## Point-to-Point Messaging\n\nUse point-to-point messaging for task distribution where each message should be processed by exactly one consumer.\n\n### Producer Example\n\n```typescript\nimport { EventBusProducer, ConnectionState } from '@a_jackie_z/event-bus';\n\nconst producer = new EventBusProducer({\n  rabbitMqUrl: 'amqp://username:password@localhost:5672',\n  onStateChange: (state, reconnectCount) => {\n    console.log(`Producer state: ${state}`, { reconnectCount });\n  }\n});\n\ntry {\n  await producer.connect();\n  \n  // Publish to durable queue with persistent messages\n  await producer.publish('order_events', {\n    orderId: 1001,\n    userId: 5001,\n    items: ['laptop', 'mouse'],\n    total: 1299.99,\n    status: 'pending',\n    timestamp: new Date().toISOString()\n  });\n  \n  await producer.publish('order_events', {\n    orderId: 1002,\n    userId: 5002,\n    items: ['keyboard'],\n    total: 89.99,\n    status: 'pending',\n    timestamp: new Date().toISOString()\n  });\n  \n  console.log('Messages published successfully');\n  \n  // Graceful shutdown\n  await producer.disconnect();\n} catch (error) {\n  console.error('Failed to publish messages:', error);\n  await producer.disconnect();\n}\n```\n\n### Consumer Example\n\n```typescript\nimport { EventBusConsumer, type QueueHandlers, type EventHandler } from '@a_jackie_z/event-bus';\n\n// Define handlers for the queue\nconst processOrderHandler: EventHandler = async (data) => {\n  console.log('Processing order:', data.orderId);\n  // Process order logic here\n};\n\nconst notifyUserHandler: EventHandler = async (data) => {\n  console.log('Notifying user:', data.userId);\n  // Send notification logic here\n};\n\n// Map queue names to handlers (multiple handlers per queue)\nconst queueHandlers: QueueHandlers = new Map([\n  ['order_events', [processOrderHandler, notifyUserHandler]]\n]);\n\nconst consumer = new EventBusConsumer({\n  rabbitMqUrl: 'amqp://username:password@localhost:5672',\n  queueHandlers,\n  onStateChange: (state, reconnectCount) => {\n    console.log(`Consumer state: ${state}`, { reconnectCount });\n  }\n});\n\ntry {\n  await consumer.connect();\n  console.log('Consumer connected and listening for messages');\n  \n  // Handle graceful shutdown\n  process.on('SIGINT', async () => {\n    console.log('Shutting down gracefully...');\n    await consumer.disconnect();\n    process.exit(0);\n  });\n  \n  process.on('SIGTERM', async () => {\n    console.log('Shutting down gracefully...');\n    await consumer.disconnect();\n    process.exit(0);\n  });\n} catch (error) {\n  console.error('Failed to start consumer:', error);\n  await consumer.disconnect();\n  process.exit(1);\n}\n```\n\n## Broadcast Messaging\n\nUse broadcast messaging when all consumers need to receive every message (e.g., cache invalidation, system-wide notifications).\n\n### Producer Example\n\n```typescript\nimport { EventBusProducer } from '@a_jackie_z/event-bus';\n\nconst producer = new EventBusProducer({\n  rabbitMqUrl: 'amqp://username:password@localhost:5672'\n});\n\nawait producer.connect();\n\n// Broadcast to fanout exchange - all consumers receive this\nawait producer.broadcast('system_notifications', {\n  type: 'maintenance',\n  message: 'System maintenance scheduled for tonight',\n  priority: 'high',\n  timestamp: new Date().toISOString()\n});\n\nawait producer.broadcast('system_notifications', {\n  type: 'update',\n  message: 'New features available in version 2.0',\n  priority: 'medium',\n  timestamp: new Date().toISOString()\n});\n\nawait producer.disconnect();\n```\n\n### Consumer Example\n\n```typescript\nimport { EventBusConsumer, type QueueHandlers, type ExchangeBindings, type EventHandler } from '@a_jackie_z/event-bus';\n\n// Handler for broadcast messages\nconst notificationHandler: EventHandler = async (data) => {\n  console.log('Received system notification:', data);\n  // Each consumer instance processes the notification independently\n};\n\n// Define queue handlers\nconst queueHandlers: QueueHandlers = new Map([\n  ['notifications', [notificationHandler]]\n]);\n\n// Bind queues to exchanges for broadcast\nconst exchangeBindings: ExchangeBindings = new Map([\n  ['notifications', 'system_notifications']  // Queue -> Exchange mapping\n]);\n\nconst consumer = new EventBusConsumer({\n  rabbitMqUrl: 'amqp://username:password@localhost:5672',\n  queueHandlers,\n  exchangeBindings  // This enables broadcast mode for 'notifications' queue\n});\n\nawait consumer.connect();\nconsole.log('Consumer listening for broadcasts');\n\n// Each consumer instance will receive ALL broadcast messages\n```\n\n**Note**: When using `exchangeBindings`, the consumer creates an **exclusive queue** that is automatically deleted when the consumer disconnects. This ensures each consumer instance receives all broadcast messages.\n\n## Mixed Mode\n\nCombine both point-to-point and broadcast patterns in a single consumer.\n\n```typescript\nimport { EventBusConsumer, type QueueHandlers, type ExchangeBindings, type EventHandler } from '@a_jackie_z/event-bus';\n\n// Point-to-point handler (only one consumer processes each message)\nconst processOrderHandler: EventHandler = async (data) => {\n  console.log('Processing order (load balanced):', data.orderId);\n  // Heavy processing - distributed across consumers\n};\n\n// Broadcast handler (all consumers receive each message)\nconst cacheInvalidationHandler: EventHandler = async (data) => {\n  console.log('Invalidating cache (all consumers):', data.cacheKey);\n  // Cache invalidation - every instance must process\n};\n\nconst queueHandlers: QueueHandlers = new Map([\n  ['orders', [processOrderHandler]],           // Point-to-point queue\n  ['cache_invalidation', [cacheInvalidationHandler]]  // Broadcast queue\n]);\n\nconst exchangeBindings: ExchangeBindings = new Map([\n  ['cache_invalidation', 'cache_invalidation_broadcast']  // Only bind broadcast queues\n  // 'orders' is NOT bound, so it remains a point-to-point queue\n]);\n\nconst consumer = new EventBusConsumer({\n  rabbitMqUrl: 'amqp://username:password@localhost:5672',\n  queueHandlers,\n  exchangeBindings\n});\n\nawait consumer.connect();\n// Now handles both patterns:\n// - orders: Load-balanced across consumers\n// - cache_invalidation: All consumers receive every message\n```\n\n### Producer for Mixed Mode\n\n```typescript\nimport { EventBusProducer } from '@a_jackie_z/event-bus';\n\nconst producer = new EventBusProducer({\n  rabbitMqUrl: 'amqp://username:password@localhost:5672'\n});\n\nawait producer.connect();\n\n// Point-to-point: Only one consumer processes this\nawait producer.publish('orders', {\n  orderId: 1001,\n  customerId: 5001,\n  total: 99.99\n});\n\n// Broadcast: All consumers receive this\nawait producer.broadcast('cache_invalidation_broadcast', {\n  cacheKey: 'user:5001',\n  action: 'invalidate'\n});\n\nawait producer.disconnect();\n```\n\n## Connection State Management\n\nMonitor connection state changes and handle reconnection events.\n\n### Connection States\n\n```typescript\nimport { ConnectionState } from '@a_jackie_z/event-bus';\n\n// Available states:\nConnectionState.CONNECTED     // Successfully connected to RabbitMQ\nConnectionState.DISCONNECTED  // Intentionally disconnected\nConnectionState.RECONNECTING  // Attempting to reconnect after connection loss\n```\n\n### State Change Callback\n\n```typescript\nimport { EventBusProducer, ConnectionState } from '@a_jackie_z/event-bus';\n\nconst producer = new EventBusProducer({\n  rabbitMqUrl: 'amqp://username:password@localhost:5672',\n  onStateChange: (state, reconnectCount) => {\n    switch (state) {\n      case ConnectionState.CONNECTED:\n        console.log('✓ Connected to RabbitMQ');\n        break;\n      case ConnectionState.DISCONNECTED:\n        console.log('✗ Disconnected from RabbitMQ');\n        break;\n      case ConnectionState.RECONNECTING:\n        console.log(`⟳ Reconnecting... (attempt ${reconnectCount})`);\n        break;\n    }\n  }\n});\n\nawait producer.connect();\n```\n\n### Automatic Reconnection\n\nThe event bus automatically attempts to reconnect when:\n- Connection is lost\n- Channel errors occur\n- Network issues arise\n\n**Reconnection Behavior**:\n- Initial retry after 15 seconds\n- Continues retrying indefinitely with 15-second intervals\n- Resets retry counter on successful connection\n- Preserves queue/exchange configurations on reconnection\n\n## Scaling Strategies\n\n### Horizontal Consumer Scaling\n\n**Point-to-Point Queues** (Load Balancing):\n```typescript\n// Run multiple consumer instances - messages are distributed\n// Consumer 1\nconst consumer1 = new EventBusConsumer({\n  rabbitMqUrl: 'amqp://username:password@localhost:5672',\n  queueHandlers: new Map([['tasks', [handler]]])\n});\nawait consumer1.connect();\n\n// Consumer 2 (same configuration)\nconst consumer2 = new EventBusConsumer({\n  rabbitMqUrl: 'amqp://username:password@localhost:5672',\n  queueHandlers: new Map([['tasks', [handler]]])\n});\nawait consumer2.connect();\n\n// Messages in 'tasks' queue are distributed round-robin between consumers\n// If Consumer 1 is processing, Consumer 2 gets the next message\n```\n\n**Broadcast Exchanges** (Redundancy):\n```typescript\n// All consumer instances receive ALL broadcast messages\n// Useful for cache invalidation, configuration updates, etc.\n\n// Service Instance 1\nconst consumer1 = new EventBusConsumer({\n  rabbitMqUrl: 'amqp://username:password@localhost:5672',\n  queueHandlers: new Map([['updates', [handler]]]),\n  exchangeBindings: new Map([['updates', 'system_updates']])\n});\nawait consumer1.connect();\n\n// Service Instance 2 (receives same broadcasts)\nconst consumer2 = new EventBusConsumer({\n  rabbitMqUrl: 'amqp://username:password@localhost:5672',\n  queueHandlers: new Map([['updates', [handler]]]),\n  exchangeBindings: new Map([['updates', 'system_updates']])\n});\nawait consumer2.connect();\n\n// Both instances receive every broadcast message\n```\n\n### Queue Partitioning Strategies\n\n**Option 1: Multiple Queues by Category**\n```typescript\n// Producer distributes by category\nawait producer.publish('orders_electronics', { category: 'electronics', ... });\nawait producer.publish('orders_clothing', { category: 'clothing', ... });\n\n// Consumer specializes by category\nconst consumer = new EventBusConsumer({\n  rabbitMqUrl: 'amqp://username:password@localhost:5672',\n  queueHandlers: new Map([\n    ['orders_electronics', [electronicsHandler]],\n    ['orders_clothing', [clothingHandler]]\n  ])\n});\n```\n\n**Option 2: Consistent Hashing for Partitioning**\n```typescript\n// Hash-based queue assignment\nfunction getQueueForUser(userId: number, partitionCount: number): string {\n  const partition = userId % partitionCount;\n  return `user_events_partition_${partition}`;\n}\n\n// Producer\nconst queueName = getQueueForUser(userId, 4); // 4 partitions\nawait producer.publish(queueName, userData);\n\n// Consumer handles specific partitions\nconst consumer = new EventBusConsumer({\n  rabbitMqUrl: 'amqp://username:password@localhost:5672',\n  queueHandlers: new Map([\n    ['user_events_partition_0', [handler]],\n    ['user_events_partition_1', [handler]]\n  ])\n});\n```\n\n**Option 3: Priority Queues**\n```typescript\n// Separate queues by priority\nawait producer.publish('tasks_high_priority', { priority: 'high', ... });\nawait producer.publish('tasks_low_priority', { priority: 'low', ... });\n\n// Run more consumers on high-priority queue\n// 3 consumers for high priority\n// 1 consumer for low priority\n```\n\n### Consumer Groups Pattern\n\n```typescript\n// Consumer Group 1: Order Processing (3 instances)\n// All share the same 'orders' queue for load balancing\nfor (let i = 1; i <= 3; i++) {\n  const consumer = new EventBusConsumer({\n    rabbitMqUrl: 'amqp://username:password@localhost:5672',\n    queueHandlers: new Map([['orders', [orderHandler]]])\n  });\n  await consumer.connect();\n}\n\n// Consumer Group 2: Notifications (2 instances)\n// All share the same 'notifications' queue\nfor (let i = 1; i <= 2; i++) {\n  const consumer = new EventBusConsumer({\n    rabbitMqUrl: 'amqp://username:password@localhost:5672',\n    queueHandlers: new Map([['notifications', [notificationHandler]]])\n  });\n  await consumer.connect();\n}\n```\n\n### Monitoring for Scaling Decisions\n\n```typescript\n// Monitor queue depth to make scaling decisions\n// Use RabbitMQ Management API or CLI\n\n// Example: Check queue depth\n// rabbitmqadmin list queues name messages\n\n// Scale up when:\n// - Queue depth consistently > 1000 messages\n// - Consumer processing time increases\n// - Message age increases\n\n// Scale down when:\n// - Queue depth consistently near 0\n// - Multiple consumers idle\n// - Processing capacity exceeds demand\n```\n\n## Performance Tips\n\n### 1. Connection Reuse\n\n**DO**: Create one producer/consumer per service instance\n```typescript\n// Good: Single producer for the entire service\nclass OrderService {\n  private producer: EventBusProducer;\n  \n  async init() {\n    this.producer = new EventBusProducer({\n      rabbitMqUrl: 'amqp://username:password@localhost:5672'\n    });\n    await this.producer.connect();\n  }\n  \n  async createOrder(order: Order) {\n    await this.producer.publish('orders', order);\n  }\n}\n```\n\n**DON'T**: Create new connections per operation\n```typescript\n// Bad: Creates new connection for each publish\nasync function sendMessage(data: any) {\n  const producer = new EventBusProducer({ rabbitMqUrl: '...' });\n  await producer.connect();\n  await producer.publish('queue', data);\n  await producer.disconnect();  // Expensive!\n}\n```\n\n### 2. Message Batching\n\nFor high-throughput scenarios, batch multiple operations:\n\n```typescript\n// Batch publishing\nconst messages = [\n  { orderId: 1, ... },\n  { orderId: 2, ... },\n  { orderId: 3, ... }\n];\n\nawait producer.connect();\nfor (const message of messages) {\n  await producer.publish('orders', message);  // Uses same connection\n}\n// Confirms are awaited per message, ensuring reliability\n```\n\n### 3. Non-Blocking Handlers\n\nKeep handlers async and non-blocking:\n\n```typescript\n// Good: Non-blocking handler\nconst handler: EventHandler = async (data) => {\n  // Quick processing\n  await database.insert(data);\n  \n  // Offload heavy work to another queue\n  await producer.publish('heavy_processing', data);\n};\n\n// Bad: Blocking handler\nconst slowHandler: EventHandler = async (data) => {\n  // Blocks other messages for 10 seconds\n  await heavyComputation(data);  // 10 seconds\n  await database.insert(data);\n};\n```\n\n### 4. Prefetch Optimization\n\nThe library sets `prefetch=1` by default for fair distribution. This means:\n- Each consumer gets one message at a time\n- Fast consumers get more messages\n- Slow consumers don't get overwhelmed\n\nFor specialized scenarios:\n```typescript\n// Current behavior (prefetch=1):\n// - Fair distribution across consumers\n// - Prevents consumer overload\n// - Ideal for most use cases\n\n// If you need different prefetch values, you would need to\n// modify the consumer.ts source code (line: channel.prefetch(1))\n```\n\n### 5. Connection Pooling\n\nFor microservices with multiple queues:\n\n```typescript\n// Single consumer handles multiple queues\nconst consumer = new EventBusConsumer({\n  rabbitMqUrl: 'amqp://username:password@localhost:5672',\n  queueHandlers: new Map([\n    ['queue1', [handler1]],\n    ['queue2', [handler2]],\n    ['queue3', [handler3]]\n  ])\n});\n// One connection, multiple queues - efficient!\n```\n\n### 6. Monitor Queue Depths\n\n```typescript\n// Implement monitoring to track performance\nconst producer = new EventBusProducer({\n  rabbitMqUrl: 'amqp://username:password@localhost:5672',\n  onStateChange: (state) => {\n    // Log state changes for monitoring\n    metrics.recordConnectionState(state);\n  }\n});\n\n// External monitoring with RabbitMQ Management API:\n// - Queue depth (messages ready)\n// - Consumer count\n// - Message rate (in/out)\n// - Consumer utilization\n```\n\n### 7. Message Size Optimization\n\n```typescript\n// Keep messages small for better throughput\n// Good: Reference to data\nawait producer.publish('image_processing', {\n  imageId: 12345,\n  bucket: 's3://images',\n  key: 'photo.jpg'\n});\n\n// Bad: Embedding large data\nawait producer.publish('image_processing', {\n  imageData: base64Image  // Could be MBs!\n});\n```\n\n### 8. Batch Acknowledgments\n\nThe library handles acknowledgments efficiently:\n- Messages are acknowledged individually\n- Failed messages are not requeued (nack without requeue)\n- At least one handler must succeed for acknowledgment\n\n## API Reference\n\n### EventBusProducer\n\nProducer for publishing messages to queues or broadcasting to exchanges.\n\n#### Constructor\n\n```typescript\nnew EventBusProducer(options: EventBusProducerOptions)\n```\n\n**Options**:\n- `rabbitMqUrl: string` - RabbitMQ connection URL (e.g., `amqp://user:pass@host:5672`)\n- `onStateChange?: (state: ConnectionState, reconnectCount?: number) => void` - Callback for connection state changes\n\n#### Methods\n\n##### `connect(): Promise<void>`\n\nEstablishes connection to RabbitMQ. Must be called before publishing.\n\n```typescript\nawait producer.connect();\n```\n\n##### `publish(queueName: string, data: any): Promise<void>`\n\nPublishes a message to a durable queue with persistence enabled. Message is delivered to one consumer (load-balanced).\n\n**Parameters**:\n- `queueName: string` - Name of the queue\n- `data: any` - Message payload (will be JSON serialized)\n\n**Throws**: Error if channel is not available or publish fails\n\n```typescript\nawait producer.publish('orders', { orderId: 123, amount: 99.99 });\n```\n\n##### `broadcast(exchangeName: string, data: any): Promise<void>`\n\nBroadcasts a message to all consumers listening on the fanout exchange. All consumers receive the message.\n\n**Parameters**:\n- `exchangeName: string` - Name of the fanout exchange\n- `data: any` - Message payload (will be JSON serialized)\n\n**Throws**: Error if channel is not available or broadcast fails\n\n```typescript\nawait producer.broadcast('notifications', { type: 'alert', message: 'System update' });\n```\n\n##### `disconnect(): Promise<void>`\n\nGracefully closes the connection and stops reconnection attempts.\n\n```typescript\nawait producer.disconnect();\n```\n\n### EventBusConsumer\n\nConsumer for processing messages from queues and broadcast exchanges.\n\n#### Constructor\n\n```typescript\nnew EventBusConsumer(options: EventBusConsumerOptions)\n```\n\n**Options**:\n- `rabbitMqUrl: string` - RabbitMQ connection URL\n- `queueHandlers: QueueHandlers` - Map of queue names to handler arrays\n- `onStateChange?: (state: ConnectionState, reconnectCount?: number) => void` - State change callback\n- `exchangeBindings?: ExchangeBindings` - Map of queue names to exchange names (for broadcast mode)\n\n#### Types\n\n```typescript\ntype EventHandler<T = any> = (data: T) => Promise<void>;\ntype QueueHandlers = Map<string, EventHandler[]>;\ntype ExchangeBindings = Map<string, string>; // Map<queueName, exchangeName>\n```\n\n#### Methods\n\n##### `connect(): Promise<void>`\n\nConnects to RabbitMQ and starts consuming messages from configured queues.\n\n```typescript\nawait consumer.connect();\n```\n\n##### `disconnect(): Promise<void>`\n\nGracefully cancels all consumers and closes the connection.\n\n```typescript\nawait consumer.disconnect();\n```\n\n### ConnectionState\n\nEnum representing connection states:\n\n```typescript\nenum ConnectionState {\n  CONNECTED = 'CONNECTED',        // Successfully connected\n  DISCONNECTED = 'DISCONNECTED',  // Intentionally disconnected\n  RECONNECTING = 'RECONNECTING'   // Attempting reconnection\n}\n```\n\n## Best Practices\n\n### Error Handling in Handlers\n\n```typescript\n// Good: Handler with error handling\nconst orderHandler: EventHandler = async (data) => {\n  try {\n    await processOrder(data);\n    await updateInventory(data);\n  } catch (error) {\n    console.error('Failed to process order:', error);\n    // Log error for monitoring\n    // Handler failure is caught by the library\n    // Message is nacked if all handlers fail\n  }\n};\n\n// Multiple handlers: At least one must succeed\nconst queueHandlers: QueueHandlers = new Map([\n  ['orders', [\n    orderHandler,        // If this fails...\n    notificationHandler  // ...but this succeeds, message is acknowledged\n  ]]\n]);\n```\n\n### Graceful Shutdown\n\n```typescript\n// Always handle graceful shutdown\nconst consumer = new EventBusConsumer({\n  rabbitMqUrl: 'amqp://username:password@localhost:5672',\n  queueHandlers\n});\n\nawait consumer.connect();\n\n// Handle termination signals\nconst shutdown = async (signal: string) => {\n  console.log(`${signal} received, shutting down gracefully...`);\n  await consumer.disconnect();\n  process.exit(0);\n};\n\nprocess.on('SIGINT', () => shutdown('SIGINT'));\nprocess.on('SIGTERM', () => shutdown('SIGTERM'));\n\n// For producers\nprocess.on('beforeExit', async () => {\n  await producer.disconnect();\n});\n```\n\n### Message Persistence Configuration\n\n**Point-to-Point** (Durable and Persistent):\n```typescript\n// Producer automatically creates durable queues\nawait producer.publish('tasks', data);\n// - Queue survives broker restart (durable: true)\n// - Messages survive broker restart (persistent: true)\n// - Use for critical tasks that must not be lost\n```\n\n**Broadcast** (Transient):\n```typescript\n// Broadcast messages are transient\nawait producer.broadcast('notifications', data);\n// - Exchange is non-durable\n// - Messages are non-persistent\n// - Queues are exclusive and auto-delete\n// - Use for real-time updates that don't need persistence\n```\n\n### Handler Execution\n\nHandlers execute **sequentially** within each message:\n\n```typescript\nconst queueHandlers: QueueHandlers = new Map([\n  ['orders', [\n    handler1,  // Executes first\n    handler2,  // Executes after handler1 completes\n    handler3   // Executes after handler2 completes\n  ]]\n]);\n\n// Acknowledgment rules:\n// - If at least one handler succeeds -> message acknowledged\n// - If all handlers fail -> message nacked (not requeued)\n// - Failed handlers log errors but don't block subsequent handlers\n```\n\n### Connection Management\n\n```typescript\n// DO: Initialize once, use throughout application lifecycle\nclass MessageService {\n  private producer: EventBusProducer;\n  private consumer: EventBusConsumer;\n  \n  async initialize() {\n    this.producer = new EventBusProducer({\n      rabbitMqUrl: process.env.RABBITMQ_URL!,\n      onStateChange: this.handleStateChange\n    });\n    \n    this.consumer = new EventBusConsumer({\n      rabbitMqUrl: process.env.RABBITMQ_URL!,\n      queueHandlers: this.getHandlers()\n    });\n    \n    await Promise.all([\n      this.producer.connect(),\n      this.consumer.connect()\n    ]);\n  }\n  \n  async shutdown() {\n    await Promise.all([\n      this.producer.disconnect(),\n      this.consumer.disconnect()\n    ]);\n  }\n  \n  private handleStateChange(state: ConnectionState, reconnectCount?: number) {\n    // Log state changes for monitoring/alerting\n    logger.info({ state, reconnectCount }, 'RabbitMQ state change');\n  }\n}\n```\n\n### Testing\n\n```typescript\n// Use test containers or local RabbitMQ for testing\ndescribe('EventBus', () => {\n  let producer: EventBusProducer;\n  let consumer: EventBusConsumer;\n  \n  beforeAll(async () => {\n    producer = new EventBusProducer({\n      rabbitMqUrl: 'amqp://guest:guest@localhost:5672'\n    });\n    await producer.connect();\n  });\n  \n  afterAll(async () => {\n    await producer.disconnect();\n  });\n  \n  it('should process messages', async () => {\n    const received: any[] = [];\n    \n    const handler: EventHandler = async (data) => {\n      received.push(data);\n    };\n    \n    consumer = new EventBusConsumer({\n      rabbitMqUrl: 'amqp://guest:guest@localhost:5672',\n      queueHandlers: new Map([['test_queue', [handler]]])\n    });\n    \n    await consumer.connect();\n    await producer.publish('test_queue', { test: 'data' });\n    \n    // Wait for processing\n    await new Promise(resolve => setTimeout(resolve, 100));\n    \n    expect(received).toHaveLength(1);\n    expect(received[0]).toEqual({ test: 'data' });\n    \n    await consumer.disconnect();\n  });\n});\n```\n\n## License\n\nMIT © Sang Lu\n\n## Author\n\nSang Lu <connect.with.sang@gmail.com>\n","readmeFilename":"README.md"}