{"id":18862202,"url":"https://github.com/hapinessjs/rabbit-module","last_synced_at":"2025-04-14T13:03:01.473Z","repository":{"id":25222357,"uuid":"96995135","full_name":"hapinessjs/rabbit-module","owner":"hapinessjs","description":"RabbitMQ client module for Hapiness framework","archived":false,"fork":false,"pushed_at":"2023-02-27T16:30:51.000Z","size":580,"stargazers_count":4,"open_issues_count":9,"forks_count":0,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-04-24T13:16:17.271Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hapinessjs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-07-12T10:24:06.000Z","updated_at":"2022-04-13T10:02:57.000Z","dependencies_parsed_at":"2023-02-13T01:16:12.434Z","dependency_job_id":null,"html_url":"https://github.com/hapinessjs/rabbit-module","commit_stats":null,"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hapinessjs%2Frabbit-module","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hapinessjs%2Frabbit-module/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hapinessjs%2Frabbit-module/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hapinessjs%2Frabbit-module/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hapinessjs","download_url":"https://codeload.github.com/hapinessjs/rabbit-module/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223633859,"owners_count":17176862,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-08T04:33:38.070Z","updated_at":"2024-11-08T04:33:38.786Z","avatar_url":"https://github.com/hapinessjs.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg src=\"http://bit.ly/2mxmKKI\" width=\"500\" alt=\"Hapiness\" /\u003e\n\n\u003cdiv style=\"margin-bottom:20px;\"\u003e\n\u003cdiv style=\"line-height:60px\"\u003e\n    \u003ca href=\"https://travis-ci.org/hapinessjs/rabbit-module.svg?branch=master\"\u003e\n        \u003cimg src=\"https://travis-ci.org/hapinessjs/rabbit-module.svg?branch=master\" alt=\"build\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://coveralls.io/github/hapinessjs/rabbit-module?branch=master\"\u003e\n        \u003cimg src=\"https://coveralls.io/repos/github/hapinessjs/rabbit-module/badge.svg?branch=master\" alt=\"coveralls\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://david-dm.org/hapinessjs/rabbit-module\"\u003e\n        \u003cimg src=\"https://david-dm.org/hapinessjs/rabbit-module.svg\" alt=\"dependencies\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://david-dm.org/hapinessjs/rabbit-module?type=dev\"\u003e\n        \u003cimg src=\"https://david-dm.org/hapinessjs/rabbit-module/dev-status.svg\" alt=\"devDependencies\" /\u003e\n    \u003c/a\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n    \u003ca href=\"https://www.typescriptlang.org/docs/tutorial.html\"\u003e\n        \u003cimg src=\"https://cdn-images-1.medium.com/max/800/1*8lKzkDJVWuVbqumysxMRYw.png\"\n             align=\"right\" alt=\"Typescript logo\" width=\"50\" height=\"50\" style=\"border:none;\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"http://reactivex.io/rxjs\"\u003e\n        \u003cimg src=\"http://reactivex.io/assets/Rx_Logo_S.png\"\n             align=\"right\" alt=\"ReactiveX logo\" width=\"50\" height=\"50\" style=\"border:none;\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"http://hapijs.com\"\u003e\n        \u003cimg src=\"http://bit.ly/2lYPYPw\"\n             align=\"right\" alt=\"Hapijs logo\" width=\"75\" style=\"border:none;\" /\u003e\n    \u003c/a\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n# RabbitMQ Module\n\n```RabbitMQ``` module for the Hapiness framework.\n\nRabbitMQ is a server that implement the `AMQP 0-9-1` protocol.\n\n[Getting started with AMQP concepts](https://www.rabbitmq.com/tutorials/amqp-concepts.html)\n\nThe module uses [amqp.node](https://github.com/squaremo/amqp.node) to connect to RabbitMQ and is architectured arround [the channel API\nprovided](http://www.squaremobius.net/amqp.node/channel_api.html).\n\n## Table of contents\n\n* [How this module works](#how-this-module-works)\n* [Message and routing](#message-and-routing)\n* [Using your module inside Hapiness application](#using-your-module-inside-hapiness-application)\n\t* [`yarn` or `npm` it in your `package.json`](#yarn-or-npm-it-in-your-package.json)\n\t* [Importing `RabbitMQModule` from the library](#importing-rabbitmqmodule-from-the-library)\n\t* [Using `RabbitMQ` inside your application](#using-rabbitmq-inside-your-application)\n* [Contributing](#contributing)\n* [Change History](#change-history)\n* [Maintainers](#maintainers)\n* [License](#license)\n\n## How this module works\n\n### Prototyping your AMQP usage\n\nWith this module you will be able to configure your AMQP stack easily with the way you prefer.\n\nWe provide three decorators, ```@Exchange```, ```@Queue```, ```@Message``` that will allow you to quickly getting started.\n\n\u003c!--First defines your exchanges, then the queues that can be bound to some of those and then you can create some messages to handle your\nRabbitMQ messages. See [Message Routing](#message-routing) below.--\u003e\n\n### Configuration\n\n\u003ctable\u003e\n    \u003ctr\u003e\n        \u003cth\u003eKey\u003c/th\u003e\n        \u003cth\u003eType\u003c/th\u003e\n        \u003cth\u003eInfos\u003c/th\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003econnection\u003c/td\u003e\n        \u003ctd\u003e\u003cb\u003eobject\u003c/b\u003e\u003c/td\u003e\n        \u003ctd\u003eConnection Object\u003c/td\u003e\n    \u003c/tr\u003e\n\u003c/table\u003e\n\n### Connection object\n\n\u003ctable\u003e\n    \u003ctr\u003e\n        \u003cth\u003eKey\u003c/th\u003e\n        \u003cth\u003eType\u003c/th\u003e\n        \u003cth\u003eDefault\u003c/th\u003e\n        \u003cth\u003eInfos\u003c/th\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003euri\u003c/td\u003e\n        \u003ctd\u003e\u003cb\u003estring\u003c/b\u003e\u003c/td\u003e\n        \u003ctd\u003eundefined\u003c/td\u003e\n        \u003ctd\u003eother values are ignored if set\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003ehost\u003c/td\u003e\n        \u003ctd\u003e\u003cb\u003estring\u003c/b\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003cb\u003elocalhost\u003c/b\u003e\u003c/td\u003e\n        \u003ctd\u003e-\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003eport\u003c/td\u003e\n        \u003ctd\u003e\u003cb\u003enumber\u003c/b\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003cb\u003e5672\u003c/b\u003e\u003c/td\u003e\n        \u003ctd\u003e-\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003elogin\u003c/td\u003e\n        \u003ctd\u003e\u003cb\u003estring\u003c/b\u003e\u003c/td\u003e\n        \u003ctd\u003eundefined\u003c/td\u003e\n        \u003ctd\u003e-\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003epassword\u003c/td\u003e\n        \u003ctd\u003e\u003cb\u003estring\u003c/td\u003e\n        \u003ctd\u003eundefined\u003c/td\u003e\n        \u003ctd\u003e-\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003eparams\u003c/td\u003e\n        \u003ctd\u003e\u003cb\u003eobject\u003c/b\u003e\u003c/td\u003e\n        \u003ctd\u003eundefined\u003c/td\u003e\n        \u003ctd\u003eParameters to include in querystring, like:\u003cbr\u003e \u003cb\u003e{ heartBeat: 30 }\u003c/b\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003eretry.delay\u003c/td\u003e\n        \u003ctd\u003e\u003cb\u003enumber\u003c/b\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003cb\u003e5000\u003c/b\u003e\u003c/td\u003e\n        \u003ctd\u003eDelay in ms to wait after trying to reconnect\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003eretry.maximum_attempts\u003c/td\u003e\n        \u003ctd\u003e\u003cb\u003enumber\u003c/b\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003cb\u003e-1\u003c/b\u003e\u003c/td\u003e\n        \u003ctd\u003eMaximum reconnection attempts, \u003cb\u003e-1\u003c/b\u003e for \u003cb\u003eInfinity\u003c/b\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003edefault_prefetch\u003c/td\u003e\n        \u003ctd\u003e\u003cb\u003enumber\u003c/b\u003e\u003c/td\u003e\n        \u003ctd\u003e\u003cb\u003e10\u003c/b\u003e\u003c/td\u003e\n        \u003ctd\u003eDefault prefetch used when creating new channels\u003c/td\u003e\n    \u003c/tr\u003e\n\u003c/table\u003e\n\n### Connection \u0026 initialization\n\nThis module supports only one connection at the same time.\n\nBy default the module will retry to connect after a connection error.\nThis behaviour is configurable.\n\nWhen the connection is ready the extension will find all classes with decorators and do all the work to get everything ready.\n\n\n### Channels\n\nEach connection can open several channels. Every operation on RabbitMQ occurs through channels.\n\nYou can create them easily with the ```ChannelService```.\n\n### Exchanges\n\nExchanges needs a name and a type.\n\n### Decorator parameters:\n\n* ```name: string```\n* ```type: ExchangeType``` (```ExchangeType.Direct```, ```ExchangeType.Topic```, ```ExchangeType.Fanout```)\n* ```options: Object``` *optional* [see exchange assert options](http://www.squaremobius.net/amqp.node/channel_api.html#channel_assertExchange)\n\n### Queues\n\nQueues only requires a name.\n\n### Decorator parameters:\n\n* ```name: string```\n* ```binds: Array\u003cBind\u003e``` *optional*\n* ```options: Object``` *optional* [see queue assert options](http://www.squaremobius.net/amqp.node/channel_api.html#channel_assertQueue)\n\n## Message and routing\n\nEach message sent on RabbitMQ is consumed by a queue.\n\nYou can decide to receive all the messages on your queue onMessage method.\nThat's a good option if you have only one type of message arriving on it.\nYou can also call your own dispatcher there.\n\nIt's also possible to receive plenty of different messages on the same queue.\nCreating one class to handle each message is then a better choice.\n\nThis module allow you to link a RabbitMessage to your custom message class.\nWe provide a message router that will load the right message decorator class when receiving new messages.\nIf no message class is found the onMessage method on your queue is used as a fallback. If you did not provide this method an error\nwill be throwned.\n\n### Decorator parameters:\n\n* queue: the queue class where the message is consumed\n* exchange: the exchange class\n* routingKey: string or regex to match the routingKey of the message\n* filter: a simple one level object with keys and values. Keys are the path on the RabbitMQ message and values could be\na string, number, boolean or RegExp.\n\n\n## Using your module inside Hapiness application\n\n### `yarn` or `npm` it in your `package.json`\n\n```bash\n$ npm install --save @hapiness/core @hapiness/rabbitmq rxjs\n\nor\n\n$ yarn add @hapiness/core @hapiness/rabbitmq rxjs\n```\n\n```javascript\n\"dependencies\": {\n    \"@hapiness/core\": \"^1.3.0\",\n    \"@hapiness/rabbitmq\": \"^1.2.3\",\n    \"rxjs\": \"^5.5.6\",\n    //...\n}\n//...\n```\n\n### Importing `RabbitMQModule` from the library\n\nThis module provide an Hapiness extension for RabbitMQ.\nTo use it, simply register it during the ```bootstrap``` step of your project and provide the ```RabbitMQExt``` with its config\n\n```typescript\nimport { RabbitMQExt } from '@hapiness/rabbitmq';\n\n@HapinessModule({\n    version: '1.0.0',\n    providers: [],\n    declarations: [],\n    imports: [RabbitMQModule]\n})\nclass MyApp implements OnStart {\n    constructor() {}\n    onStart() {}\n}\n\nHapiness\n    .bootstrap(\n        MyApp,\n        [\n            /* ... */\n            RabbitMQExt.setConfig(\n                {\n                    connection: {\n                        host: 'localhost',\n                        port: 5276,\n                        vhost: 'my_vhost',\n                        login: 'xxx',\n                        password: 'xxxx'\n                    }\n                }\n            )\n        ]\n    )\n    .catch(err =\u003e {\n        /* ... */\n    });\n\n```\n\n\n### Using `RabbitMQ` inside your application\n\n#### Using decorators\n\n```typescript\n@Exchange({\n    name: 'user.exchange',\n    type: ExchangeType.Topic,\n    // See options available: http://www.squaremobius.net/amqp.node/channel_api.html#channel_assertExchange\n    options: {\n        durable: true,\n        autoDelete: false\n    }\n})\nexport class UserExchange implements ExchangeInterface {}\n\n@Queue({\n    name: 'user.queue',\n    // See options available: http://www.squaremobius.net/amqp.node/channel_api.html#channel_assertQueue\n    options: {\n        durable: true\n    },\n    binds: [{\n        exchange: UserExchange,\n        pattern: 'user.*'\n    }]\n})\nexport class UserQueue implements QueueInterface {\n\n    // Inject your services\n    constructor(private _myService; MyService) {}\n\n    // Optional\n    // Do some action when the queue is asserted\n    onAsserted() {\n        this._myService.foo();\n    }\n\n    // When a message is consumed it will arrives here if no message class has been found\n    // by the router\n    onMessage(message: RabbitMessage, ch: ChannelInterface) {\n        return Observable.of({ ack: true });\n    }\n\n}\n\n@Message({\n    queue: UserQueue,\n    exchange: UserExchange,\n    routingKey: 'user.edited'\n})\nexport class UserCreatedMessage implements MessageInterface {\n\n    constructor(private _myService: MyService) {\n        super();\n    }\n\n    // Executed when a message is consumed and dispatched here\n    onMessage(message: RabbitMessage, ch: ChannelInterface): Observable\u003cMessageResult\u003e {\n        this._myService.foo();\n        // You can return an object to let the consumer know what to do with your message:\n        // acknowleding, rejecting it or do nothing\n        return Observable.of({ ack: true });\n    }\n\n}\n```\n\nThis configuration will create:\n* One exchange of type ```topic``` named ```user.exchange```.\n* One durable queue named ```user.queue```\n  * It will bind this queue to the previously created exchange with the routingKey ```user.*```\n* It will dispatch all messages which are sent to the exchange and have the routingKey ```user.edited``` consumed by the previously created queue\nto the new message we created.\n* All other messages sent to the exchange with a routingKey matching the pattern ```user.*``` or sent directly to the queue will be consumed by\nthe ```onMessage()``` method defined in the queue.\n\n\n#### Integration in your hapiness application\n\n##### Module\n\nYou need to include ```RabbitMQModule``` in imports and all your decorated classes in declarations.\n\n```typescript\n@HapinessModule({\n            version: '1.0.0',\n            declarations: [\n                MyQueue,\n                MyExchange,\n                MyMessage,\n                ...\n            ],\n            providers: [\n                MyService\n            ],\n            exports: [],\n            imports: [RabbitMQModule]\n        })\n```\n\n##### Bootstrap\n\nYou need to inject the extension in bootstrap using setConfig to instantiate the module.\n\n```typescript\nHapiness.bootstrap(RabbitMQModuleTest, [\n    RabbitMQExt.setConfig({\n        connection: {\n            host: '....',\n            login: '....',\n            password: '....'\n        }\n    })\n]).catch(err =\u003e done(err));\n```\n\n\n#### Using the services\n\nOnce the extension is loaded and ```RabbitMQ``` is connected you can use the services in your app.\n\nWe provide two services:\n\n ```ConnectionService```, ```ChannelService```, ```MessageService```\n\n To send messages you can also use the sendMessage() utility provided.\n\n```typescript\n\nclass FooProvider {\n\n    constructor(private _channelService: ChannelService, private _messageService: MessageService) {}\n\n    bar(): Observable\u003cChannelManager\u003e {\n        // Upsert a channel by specifying a key to identify it\n        // one key per channel.\n        // The function returns a Observable of ChannelManager instance\n    \tthis._channelService.upsert('publish')\n            .subscribe(channelManager =\u003e {\n                this._myChannelManager = channelManager;\n            });\n    }\n\n\n    foo() {\n        // Use the created channel\n        // Use the manager to retrieve the channel instance\n        const ch = this._myChannelManager.getChannel();\n\n        // ... or retrieve it with the shortcut getChannel and your key\n        const ch = this._channelService.getChannel('publish');\n\n        // Use any function from amqp.node\n        ch.sendToQueue(...);\n\n        this.sendToQueue(ch, { foo: 'bar' }, UserQueue);\n        this.publish(ch, { foo: 'bar' }, UserExchange, { routingKey: 'foo.bar' });\n    }\n\n}\n\n```\n\n[Back to top](#table-of-contents)\n\n## Contributing\n\nTo set up your development environment:\n\n1. clone the repo to your workspace,\n2. in the shell `cd` to the main folder,\n3. hit `npm or yarn install`,\n4. run `npm or yarn run test`.\n    * It will lint the code and execute all tests.\n    * The test coverage report can be viewed from `./coverage/lcov-report/index.html`.\n\n[Back to top](#table-of-contents)\n\n## Change History\n* v1.7.3 (2019-12-16)\n    * v1.7.2 were not correctly published, nothing new in this version\n* v1.7.2 (2019-12-16)\n    * Handle all errors when sending a message\n    * Fix scope of \"this\" when sending message\n* v1.7.1 (2019-12-13)\n    * Handle channel closed error when sending a message to add a custom code on the thrown error\n* v1.7.0 (2019-02-27)\n    * Add method to cancel consuming queue\n    * Refactor consume queue to allow easier consume/cancel\n    * Add a QueueStore to fetch all the queues manager instances\n* v1.6.2 (2018-11-22)\n    * Create DI with providers for queues and exchanges\n* v1.6.1 (2018-11-14)\n    * force_json_decode is now true by default\n* v1.6.0 (2018-10-31)\n    * Add assert option in Exchange and Queue decorator to allow to disable assert during bootstrap\n    * Add check option in Exchange and Queue decorator to verify existence during bootstrap\n* v1.5.1 (2018-09-24)\n    * Fix reconnection error: use once instad of on and rebind event correctly\n* v1.5.0 (2018-08-24)\n    * Add possibility to provide a custom MessageRouter\n* v1.4.3 (2018-08-20)\n    * Emit RETRY_LIMIT_EXCEEDED error on ConnectionManager\n* v1.4.2 (2018-06-11)\n    * Do not retry to connect if closing server\n* v1.4.1 (2018-05-31)\n    * Fix channel creation after reconnection\n* v1.4.0 (2018-04-24)\n    * Refactor channel management to handle connection errors\n* v1.3.0 (2018-03-27)\n    * Add shutdown (SIGTERM/SIGINT) support\n* v1.2.3 (2018-02-05)\n    * Latest packages' versions.\n    * Fix typings\n    * Documentation.\n* v1.2.2 (2017-12-20)\n    * Latest packages' versions.\n    * Fix queue dispatching in routing messages\n    * Documentation.\n* v1.2.1 (2017-11-23)\n    * Latest packages' versions.\n    * Fix routing messages\n    * Documentation.\n* v1.2.0 (2017-11-20)\n    * Latest packages' versions.\n    * Update Module + Tests related to latest `core` version.\n    * Documentation.\n    * Change packaging process.\n* v1.1.2 (2017-11-02)\n    * Fix decorators prefetch\n* v1.1.1 (2017-10-31)\n    * Fix queue binding\n* v1.1.0 (2017-10-27)\n    * Allow to define queue binds without pattern\n    * Allow to define queue bind pattern as array\n    * Add default prefetch that is used for each channel creation if not specified in create() method first argument\n    * Rename decodeContent to decodeJSONContent and change logic to not throw if content is not JSON, add force argument to try to decode if headers.json boolean is missing\n    * Add force_json_decode option in queue decorator to force JSON decoding of all messages consumed\n    * Rework dispatcher logic (1)\n    * Add channel option for queue to allow using different channel for each queue with a different prefetch\n    * Export a global event object for connection and queueManager events\n    * Correct logic behind message routing\n    * Add checks and throw if messages do not have all required properties\n    * If the message has a filter property and it does not match discard the class from the selection\n    * Update tests\n    * Update documentation\n* v1.0.0 (2017-10-23)\n    * Publish all features of the module\n    * Tests\n    * Documentation\n\n[Back to top](#table-of-contents)\n\n## Maintainers\n\n\u003ctable\u003e\n    \u003ctr\u003e\n        \u003ctd colspan=\"4\" align=\"center\"\u003e\u003ca href=\"https://www.tadaweb.com\"\u003e\u003cimg src=\"http://bit.ly/2xHQkTi\" width=\"117\" alt=\"tadaweb\" /\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/Juneil\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/6546204?v=3\u0026s=117\" width=\"117\"/\u003e\u003c/a\u003e\u003c/td\u003e\n        \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/antoinegomez\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/997028?v=3\u0026s=117\" width=\"117\"/\u003e\u003c/a\u003e\u003c/td\u003e\n        \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/reptilbud\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/6841511?v=3\u0026s=117\" width=\"117\"/\u003e\u003c/a\u003e\u003c/td\u003e\n        \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/njl07\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/1673977?v=3\u0026s=117\" width=\"117\"/\u003e\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/Juneil\"\u003eJulien Fauville\u003c/a\u003e\u003c/td\u003e\n        \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/antoinegomez\"\u003eAntoine Gomez\u003c/a\u003e\u003c/td\u003e\n        \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/reptilbud\"\u003eSébastien Ritz\u003c/a\u003e\u003c/td\u003e\n        \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/njl07\"\u003eNicolas Jessel\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n\u003c/table\u003e\n\n[Back to top](#table-of-contents)\n\n## License\n\nCopyright (c) 2017 **Hapiness** Licensed under the [MIT license](https://github.com/hapinessjs/rabbit-module/blob/master/LICENSE.md).\n\n[Back to top](#table-of-contents)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhapinessjs%2Frabbit-module","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhapinessjs%2Frabbit-module","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhapinessjs%2Frabbit-module/lists"}