{"id":28431066,"url":"https://github.com/neuronetio/eventorjs","last_synced_at":"2026-03-03T06:36:43.424Z","repository":{"id":99021661,"uuid":"78512879","full_name":"neuronetio/eventorjs","owner":"neuronetio","description":"promise based event emitter (pub/sub, message bus) on steroids (cascade waterfall,middlewares,namespaces,wildcards) (nodejs and browser)","archived":false,"fork":false,"pushed_at":"2020-01-30T00:56:02.000Z","size":544,"stargazers_count":7,"open_issues_count":1,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-11-24T02:06:50.578Z","etag":null,"topics":["cascade","emitter","event-emitter","events","listeners","message","message-bus","middleware","namespaces","pub-sub","waterfall","wildcards"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/neuronetio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-01-10T08:23:49.000Z","updated_at":"2022-01-11T18:53:02.000Z","dependencies_parsed_at":"2023-05-03T21:15:37.243Z","dependency_job_id":null,"html_url":"https://github.com/neuronetio/eventorjs","commit_stats":{"total_commits":246,"total_committers":3,"mean_commits":82.0,"dds":0.1260162601626016,"last_synced_commit":"6eda44fffca3a77053573e98a1d6230800762621"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/neuronetio/eventorjs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neuronetio%2Feventorjs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neuronetio%2Feventorjs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neuronetio%2Feventorjs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neuronetio%2Feventorjs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/neuronetio","download_url":"https://codeload.github.com/neuronetio/eventorjs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neuronetio%2Feventorjs/sbom","scorecard":{"id":681469,"data":{"date":"2025-08-11","repo":{"name":"github.com/neuronetio/eventorjs","commit":"6eda44fffca3a77053573e98a1d6230800762621"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.6,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-21T23:18:52.863Z","repository_id":99021661,"created_at":"2025-08-21T23:18:52.863Z","updated_at":"2025-08-21T23:18:52.863Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30034124,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-03T06:09:21.518Z","status":"ssl_error","status_checked_at":"2026-03-03T06:08:47.858Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["cascade","emitter","event-emitter","events","listeners","message","message-bus","middleware","namespaces","pub-sub","waterfall","wildcards"],"created_at":"2025-06-05T14:36:14.848Z","updated_at":"2026-03-03T06:36:43.419Z","avatar_url":"https://github.com/neuronetio.png","language":"JavaScript","readme":"# eventorjs\nasync event emitter on steroids with\n- emit (`Promise.all`)\n- cascade (waterfall = output of one listener is passed as input for the next one),\n- middlewares (useBefore, useAfter and useBeforeAll,useAfterAll)\n- before and after events to easly create events before some action and after it\n- event namespaces (event grouping,removing \u0026 executing specified group only)\n- wildcards \u0026 express-like path params \u0026 regexp (\"user.\\*\" = user.created user.destroyed, \"/user/:id/created\")\n- timeouts\n- prepend\n\n`eventorjs` was build for loosely coupled inter-module communication and for hooks system, but can be used for other purposes as well, just like normal event emitter with extra features.\n\nEventor was created to make your code more reusable.\nEventor gives you super easy way of build apps/modules that are easly extendable with no need to change original code. You can write a module, and then write another module that will extend (loosely) the first one, without touching the code of the first one. You will have two modules that you can copy elsewhere and copy only those functions (submodules) that you need.\nEventor should be used as hooks that can be used to change behaviour of the module without changing the original code.\nEventor is also good way for creating micro-modules or functions which will be responsible for only one thing. Instead of building large customized module with different jobs running here and there - you can create one module for general use case and a lot of micro-modules that will extend (loosely) the main one. You will have ability to copy and paste or install those micro-modules in other projects. You will have a lot of benefits if you compose your system that way. With eventor your system will be more composeable.\n\nFor example you have built a nice user module, that you can copy and paste or install in other projects. Some day your client wants to add some custom feature to the user module. If you modify this module you loose ability to copy and paste it in other projects or to update it. With eventor you can save original module and use `eventor` to add new feature in other specialized micro-module that will be listening \"user.create\" event (for example) and add custom data before saving it to database (for example).\nWith eventor you can create micro modules - specialized modules that do only one thing and do it well.\nAll modules and submodules will be loosely coupled - if nobody listen, nothing will happen - you don't need to `require` the user module to extend it.\n\n\n## nodejs usage\n```\nnpm install --save eventorjs\n```\n```javascript\nconst Eventor = require(\"eventorjs\");\nconst eventor = Eventor();\n// or just\nconst eventor = require(\"eventorjs\")();\n```\n## browser usage\n```html\n\u003cscript src=\"http://yourwebsite/js/eventor.min.js\"\u003e\u003c/script\u003e\n```\n```javascript\nconst eventor = Eventor();\n```\n\n## emit\n\n```javascript\nlet eventor = Eventor();\n\nfunction doSomething(data,event){\n  return new Promise((resolve,reject)=\u003e{\n    resolve(\"test1\");\n  });\n}\neventor.on(\"test\",doSomething);\n\n// you can use promises as return value but it is not necessary\nlet event2id = eventor.on(\"test\",(data,event)=\u003e{\n  return \"test2\";\n});\n\neventor.emit(\"test\",{someData:\"someValue\"}).then((results)=\u003e{\n  console.log(results); // -\u003e [\"test1\",\"test2\"]\n});\n\nlet testEventListeners = eventor.listeners(\"test\");\n\neventor.off(doSomething); // function\neventor.off(event2id); // or listener id\n\n\n```\n\n\n## cascade\nCascade is when output of one listener is passed as input to the next one.\n```javascript\nlet eventor = new Eventor();\n\neventor.on(\"test\",(data,event)=\u003e{\n  return new Promise((resolve,reject)=\u003e{\n    resolve(data+2);\n  });\n});\n\neventor.on(\"test\",(data,event)=\u003e{\n  return new Promise((resolve,reject)=\u003e{\n    resolve(data+3);\n  });\n});\n\neventor.cascade(\"test\",5)\n.then((result)=\u003e{\n    console.log(result); // -\u003e 10\n});\n```\n\n### Cascade is a sequence\n\n`emit` run `on` listeners simultaneously but `cascade` is waiting for each listener to finish - to go further.\nSo when you have ten `on` listeners which need 1 second to do their job,\nwhen you `emit` an event, the total work time will be just one second,\nbut when you `cascade` an event, the total time will be 10 seconds so be aware of it\n\n\n## promises\nEventor is based on promises. You can choose your A+ implementation of promises like bluebird.\nWe are recommending bluebird, because it is the **fastest one**, and have a lot of features.\nIf you need native Promise in your project just do nothing.\n```javascript\nconst bluebird = require(\"bluebird\");\nlet eventor = Eventor({promise:bluebird});\n```\nor\n```javascript\nconst Promise = require(\"bluebird\");\nlet eventor = Eventor({promise:Promise});\n```\n\n## namespace\n```javascript\nlet eventor = new Eventor();\n\neventor.on(\"module1\",\"test\",(data,event)=\u003e{\n  return new Promise((resolve,reject)=\u003e{\n    resolve(data+\"-module1\");\n  });\n});\n\neventor.on(\"module2\",\"test\",(data,event)=\u003e{\n  return new Promise((resolve,reject)=\u003e{\n    resolve(data+\"-module2\");\n  });\n});\n\n\neventor.cascade(\"module1\",\"test\",\"someData\")\n.then((result)=\u003e{\n    console.log(result); // -\u003e \"someData-module1\"\n});\n\neventor.cascade(\"module2\",\"test\",\"someData\")\n.then((result)=\u003e{\n    console.log(result); // -\u003e \"someData-module2\"\n});\n\neventor.emit(\"module2\",\"test\",\"someData\")\n.then((results)=\u003e{\n  console.log(results); // -\u003e [\"someData-module2\"]\n});\n\nlet module1Listeners = eventor.getListenersFromNamespace(\"module1\");\n//or\nlet module1TestListeners = eventor.listeners(\"module1\",\"test\");\n\nlet module2Listeners = eventor.getListenersFromNamespace(\"module2\");\n//or\nlet module2TestListeners = eventor.listeners(\"module2\",\"test\");\n\neventor.removeListenersFromNamespace(\"module1\");\n\n```\n\n\n## Middlewares (useBefore, useAfter \u0026 useBeforeAll, useAfterAll)\n\nMiddlewares are fired before or after normal `on` listeners.\nThey can modify input before passing it to the listeners and output before result is returned to emitter.\nThe can be used for other things as well (for example prepare or remove something before and after some job).\n\n\"image is worth a thousand words\"\n\n### middleware diagram\n\nEMIT:\n\n![emit diagram](http://neuronet.it:8080/images/emit.jpg)\n\nCASCADE:\n\n![emit diagram](http://neuronet.it:8080/images/cascade.jpg)\n\n### middleware example\nFor example we can prepare some data before normal event is fired like db connection.\n(It is not really cool way to play with db connections, but for demonstration purpose we can do this)\n```javascript\nlet eventor = new Eventor();\n\neventor.useBeforeAll(\"doSomething\",(data,event)=\u003e{\n  return new Promise((resolve,reject)=\u003e{\n    let db = connectToTheDatabase();\n    data.db = db;\n    resolve(data);\n  });\n});\n\neventor.on(\"doSomething\",(data,event)=\u003e{\n  return new Promise((resolve,reject)=\u003e{\n    data.result = data.db(\"read from database\");\n    resolve(data);\n  });\n});\n\neventor.useAfterAll(\"doSomething\",(data,event)=\u003e{\n  return new Promise((resolve,reject)=\u003e{\n    delete data.db;\n    resolve(data);\n  });\n});\n\neventor.cascade(\"doSomething\",{}).then((result)=\u003e{\n  console.log(result); // -\u003e {result:databaseResult} without db connection\n});\n```\n**IMPORTANT** `useAfterAll` will have an array of results in `emit` mode and just result (value) in `cascade` mode.\nTo figure out blindly in wich mode you are you can use `event.type` parameter.\n\n```javascript\neventor.useAfterAll(\"doSomething\",(data,event)=\u003e{\n\n    if(event.type==\"emit\"){ // in emit mode input is an array\n\n      data=data.map((item,index)=\u003e{\n        return \"test \"+index;\n      }); // result of the emit process will be [\"test 1\",\"test 2\",\"test 3\",...]\n\n    }else if(event.type==\"cascade\"){ // in cascade mode input is just value\n\n      return \"test\";\n\n    }// result of the cascade process will be just \"test\"\n\n});\n```\n\n## timeouts\n\nDefault timeout is 60sec. but if you want other timetout then pass it to the options.\nWhen timeout happened the `timeout` event is emited but no other action will be taken.\n```javascript\nlet eventor = Eventor({timeout:500}); //500ms timeout\n\neventor.on(\"timeout\",(data,event)=\u003e{\n  // do something with timeout\n  console.log(data.arguments); // arguments from cascade or emit -\u003e [\"test\",\"testData\"]\n  console.log(data.type); // -\u003e \"cascade\"\n  console.log(data.error); // -\u003e instance of new Error(\"timeout\"); to track source code\n});\n\neventor.on(\"test\",(data,event)=\u003e{\n  return new Promise((resolve)=\u003e{\n    setTimeout(()=\u003e{\n      resolve(\"yeahhh\");\n    },900);// more than 500 = timeout\n  });\n});\n\neventor.cascade(\"test\",\"testData\").then((result)=\u003e{\n  console.log(result); // -\u003e yeahhh\n}).catch((e)=\u003e{\n  // there will be no error at all - only 'timeout' event\n});\n\n```\n\n## prepend\n\nIf you want to prepend listener to the beginning just add another argument `0` at the end of argument list. If you have multiple listeners that was prepended, then later declared will be the first one.\n\n```javascript\nlet eventor=Eventor();\n\nlet order = [];\n\neventor.on(\"test\",(data,event)=\u003e{\n  order.push(\"first\");\n});\n\neventor.on(\"test\",(data,event)=\u003e{\n  order.push(\"second\");\n},0); // \u003c- 0 here\n\neventor.on(\"test\",(data,event)=\u003e{\n  order.push(\"third\");\n},0); // \u003c- 0 here\n\neventor.cascade(\"test\",\"data\").then(()=\u003e{\n  console.log(order); // -\u003e [\"third\",\"second\",\"first\"]\n});\n```\n\n```javascript\nlet eventor=Eventor();\n\nlet order = [];\n\neventor.on(\"namespace\",\"test\",(data,event)=\u003e{\n  order.push(\"first\");\n});\n\neventor.on(\"namespace\",\"test\",(data,event)=\u003e{\n  order.push(\"second\");\n},0); // \u003c- 0 add here\n\neventor.on(\"namespace\",\"test\",(data,event)=\u003e{\n  order.push(\"third\");\n});\n\neventor.on(\"namespace\",\"test\",(data,event)=\u003e{\n  order.push(\"fourth\");\n},0); // \u003c- 0 add here\n\neventor.cascade(\"namespace\",\"test\",\"data\").then(()=\u003e{\n  console.log(order); // -\u003e [\"fourth\",\"second\",\"first\",\"third\"]\n});\n```\n\n## Eventor.before \u0026 Eventor.after\n\nThere are often situations that you need to emit something and get results from listeners before some action (for example db.write).\nFor this purpose you have built in `Eventor.before` emitter so you don't need to make ugly event names like `user.create:before`.\nWith `Eventor.before` you can emit two events that are named same way but are separated.\n```javascript\nlet eventor = Eventor();\neventor.before.on(\"user.create\",(userData,event)=\u003e{\n  userData.phone=\"911\"; // you can modify some data before db.write\n  return userData;\n});\neventor.after.on(\"user.create\",(userData,event)=\u003e{\n  //user was saved in the database so we can do some action after that\n  return userData;\n});\neventor.before.cascade(\"user.create\",userData)\n.then((user)=\u003e{\n  // now we have modified data\n  db.write(user);\n  return eventor.cascade(\"user.create\",user);// same as eventor.after.cascade\n});\n```\nSo now you have clean event naming without weird things going on at the end of the eventName.\n`eventor.after.cascade` is the same as `eventor.cascade`. This is just helper so you can make an image in your mind where you are (before or after some action).\n```javascript\nlet eventor = Eventor();\neventor.before.cascade(\"user.create\",userData)\n.then((user)=\u003e{\n  db.write(user);\n  return eventor.after.cascade(\"user.create\",user); // same as eventor.cascade\n});\n```\nSo for clarity, you can use `eventor.before` \u0026 `eventor.after` like\n```javascript\neventor.before.emit(\"someAction\",{});\ndoSomeAction()\neventor.after.emit(\"someAction\",{});\n```\nBoth `eventor.before.*` and `eventor.after.*` are separated, so you can add different middlewares to both emitters.\n```javascript\neventor.before.useBefore(...)\neventor.after.useBefore(...) // same as eventor.useBefore\n```\nSo when you want to add a middleware to `eventor.before.*` and to `eventor.after.*` you must add two middlewares becasue they are different emitters/listeners.\n```javascript\nfunction myMiddleware(data,event){\n  return \"modified\";\n}\neventor.useBefore(\"test\",myMiddleware);\neventor.before.on(\"test\",(data,event)=\u003e{\n  console.log(data); // -\u003e \"original\"\n  return \"onTest\";\n});\neventor.on(\"test\",(data,event)=\u003e{\n  console.log(data); // -\u003e \"modified\"\n  return \"onTest\";\n});\neventor.after.on(\"test\",(data,event)=\u003e{\n  console.log(data); // -\u003e \"modified\"\n  return \"onTest\";\n});\neventor.before.cascade(\"test\",\"original\");\neventor.after.cascade(\"test\",\"original\"); // same as eventor.cascade(\"test\",\"original\")\n```\n\n## Wildcards\nWildcards are regular expression patterns. So if you want to execute one callback on multiple events - now you can.\nWildcars may be a string like `system.*.created` or `system.**` where one `*` replaces all characters in one level beetwen delimeters and `**` replaces all characters to the end of the eventName no matter which level.\nDelimeter is a dot `.` by default. You can change it by passign delimeter option to the constructor to override it `let eventor = Eventor({ delimeter:':' });`. Delimeter should be just one special character.\n\n```javascript\nlet eventor = new Eventor();\neventor.on(/^test.*$/gi,()=\u003e{}); // will match something like 'test','testing','testosteron' ...\neventor.on(/test/gi,()=\u003e{}); // will match 'test'\neventor.on(\"te*\",()=\u003e{}); // will match 'te','test','testing','testosteron' ...\neventor.on(\"te**\",()=\u003e{}); // will match 'te','test','testing','testosteron' ...\neventor.on(\"test.*.next\",()=\u003e{}); // will match 'test.go.next','test.something.next','test.are.next' ...\neventor.on(\"test.**.next\",()=\u003e{}); // will match 'test.go.to.the.next','test.something.next','test.are.next' ...\neventor.on(\"test.**\",()=\u003e{}); // will match 'test.are.awe.some','test.something.next','test.are.good' ...\n```\n\nYou can use normal RegExp object as eventName too. All matches will be inside `event.matches` parameter.\n```javascript\neventor.on(/user\\.(.*)/gi,(data,event)=\u003e{\n  let matches = event.matches; // result from /user\\.(.*)/gi.exec(eventName)\n});\n```\n\nEventor has built-in express-like route wildcard/params system so when you want to use some params - just add percent `%` sign at the beginning of the eventName like `%web-request:/user/:id/jobs` - of course `%` sign will be removed. You will have those \"route\" params inside `event.params` object. If there is a percent `%` character at the beginning of the event name - eventor will try to parse params inside those eventNames.\n\nhttp://expressjs.com/en/guide/routing.html\n\n```javascript\nlet eventor = Eventor();\neventor.on(\"%do-something:/with/:number\",(data,event)=\u003e{\n  let nr = event.params.number;\n});\neventor.emit(\"do-something:/with/10\");\n\neventor.on(\"%/call/user/:id\",(data,event)=\u003e{\n  let nr = event.params.id;\n});\neventor.cascade(\"/call/user/10\")\n\neventor.on(\"%system.:module.:action\",(data,event)=\u003e{\n  console.log(event.params.module); // -\u003e \"user\"\n  console.log(event.params.action); // -\u003e \"create\"\n});\neventor.cascade(\"system.user.create\")\n```\nYou can test params here: http://forbeslindesay.github.io/express-route-tester/\n\nRegular expression can be slow - sometimes veeeeeeryyy slow (slow as hell), so you must decide whenever use it or not in your specific case.\nYou have an ability to do so, but if you decide to not use it - it will not affect your performance.\nFor more information try to search something on this topic: **ReDoS**\n\n\n## Error handling\n\nAll errors that lives inside listener will be handled by `error` event.\n\n\n**IMPORTANT** errorObject inside `error` event will have an object with two keys :`error` and `event` so you can have more information about error and/or clean up something when error occurs inside some listener with `event.eventId`.\n\n```javascript\neventor.on(\"error\",(errorObject)=\u003e{// test error will be emitted here\n  let originalErrorThatWasThrown = errorObject.error;\n  let event=errorObject.event;\n  console.log(event.eventName); // -\u003e test\n  // now we can do something with event.eventId\n  // or have more information about event\n});\n\neventor.on(\"test\",(data,event)=\u003e{\n  return new Promise((resolve,reject)=\u003e{\n    throw new Error(\"test error\");\n  });\n});\n\neventor.emit(\"test\",{value:\"someData\"})\n.then((results)=\u003e{\n  // this code will not be executed\n}).catch((error)=\u003e{\n  console.log(error.message); // -\u003e \"test error\"\n});\n\n```\n\nAll type of errors inside listener will be handled - even promise `reject`.\n\n```javascript\neventor.on(\"test\",(data,event)=\u003e{\n  throw \"test error\"; // will be handled\n  return new Promise((resolve,reject)=\u003e{\n    resolve(\"will not be resolved\");\n  });\n});\n```\n```javascript\neventor.on(\"test\",(data,event)=\u003e{\n  return new Promise((resolve,reject)=\u003e{\n    reject(\"will be handled\"); // yes it will be handled by 'error' event\n  });\n});\n```\nbut in javascript all errors that was thrown after `resolve` are silenced so will not be handled\n```javascript\neventor.on(\"test\",(data,event)=\u003e{\n  return new Promise((resolve,reject)=\u003e{\n    resolve(\"will resolve normally\");\n    throw \"oh no!\"; // this error will be silenced and not handled by 'error' event\n  });\n});\n```\nanother example\n```javascript\neventor.cascade(\"test\",\"testData\").then((result)=\u003e{\n  throw \"plain error\";\n}).catch((e)=\u003e{\n  console.log(e); // -\u003e \"plain error\";\n});\n\neventor.cascade(\"test\",\"testData\").then((result)=\u003e{\n  throw {yeah:\"plain error\"};\n}).catch((e)=\u003e{\n  console.log(e); // -\u003e {yeah:\"plain error\"};\n});\n```\n\n```javascript\neventor.cascade(\"test\",\"testData\").then((result)=\u003e{\n  throw new Error(\"error message\");\n}).catch((e)=\u003e{\n  if(e instanceof Error){\n    console.log(e.message); // -\u003e \"error message\";\n  }else{\n    console.log(e);\n  }\n})\n```\n\nYou can even catch errors that are inside `error` event listener :O with `errorEventsErrorHandler` option.\nIf you have an error inside `error` event listener you can handle it too.\nFor example when you handle your app erros and want to save your errors to a log file, but disk is full or there is a problem with permissions - you can catch this errors too.\n```javascript\nfunction errorEventsErrorHandler(error){\n  // handle 'error' event errors :O\n}\nlet eventor = Eventor({errorEventsErrorHandler});\neventor.on(\"error\",(errorObj,event)=\u003e{\n  throw \"this error will be handled in errorEventsErrorHandler\";\n});\n```\n### How about other listeners?\nWhen you have couple of listeners and there is an error inside one of them, other listeners can be executed or not - it depends.\nWhen you `emit` an event, all listeners for this event will be executed no matter what, but when you `cascade` your event all later listeners will be stopped (look at the diagram above to see what and how promises are chained).\n```javascript\neventor.on(\"test\",(data,event)=\u003e{\n  return \"test01\";\n});\neventor.on(\"test\",(data,event)=\u003e{\n  throw \"test error\";\n});\neventor.on(\"test\",(data,event)=\u003e{\n  return \"test03\";\n});\neventor.on(\"test\",(data,event)=\u003e{\n  return \"test04\";\n});\n\neventor.emit(\"test\",\"someData\").then((results)=\u003e{\n  // this code will not be executed\n}).catch((error)=\u003e{\n  // all of the listeners were executed but we dont have a results because of error\n});\n\neventor.cascade(\"test\",\"someData\").then((results)=\u003e{\n  // this code will not be executed\n}).catch((error)=\u003e{\n  // only first and second listeners were executed\n});\n```\n\n### What about middlewares?\n\nIf there was an exception inside `useBeforeAll` listener, no other listeners will be fired (`useBefore`,`on`,`useAfter`,`useAfterAll` will not be executed).\n\n\nIf there was an exception inside `useBefore` listener, `on` and `useAfter` will not be executed (they are chained).\nEmit and Cascade work different - look at the diagram above to find out how listeners are chained together.\nWhen we emit and there was an error inside one brach - other branches will continue to work, but useAfterAll will not be fired up because emit is using `Promise.all` method. In Cascade mode when something bad happened along the path no other listener will be fired up.\n\nAt the end .catch() method will execute for those two scenarios.\n\n\n## event.eventId\nEach event have an unique id called `eventId`.\n`eventId` is a combination of timestamp, random generated numbers using `crypto`(nodejs) or `window.crypto` (browser), machine \\ browser id ,and local number that is increased each generation process. If you want other unique id generation method, just start eventor with `unique` option like `Eventor({unique:yourUniqueIdGeneratorFunc})` and your function will be used instead of default one.\nWhy? For example for cleaning up things. Let say you doesn't have a transactions in your db.\nWhen you emit an event and there was an error during execution in some listener, you can rollback your database inserts (when you save eventId along with your data).\nYou can clean up memory or realease some 'things' after an error event to prevent memory leaks.\nYou can use `eventId` for logging purposes as well. You can use it if you want to store some data that can be used between listeners and remove this data after event was finished or some error occurs.\n\nExample of storing data between listeners for individual events.\n```javascript\nlet eventor = Eventor();\nlet sharedEventData = {};\n\neventor.useBeforeAll(\"test\",(data,event)=\u003e{\n  let dbConnection = connectToTheDatabase(); //pseudo code ;)\n  sharedEventData[event.eventId]=dbConnection;\n});\neventor.on(\"test\",(data,eventId)=\u003e{\n  let dbConnection = sharedEventData[event.eventId];\n  // we have shared data withoud modifying \"data\" argument\n});\neventor.useAfterAll(\"test\",(data,event)=\u003e{\n  delete sharedEventData[event.eventId]; // cleaning up - we dont need any memory leak\n});\neventor.on(\"error\",(errorObj,event)=\u003e{ // in case of error (useAfterAll will not be fired)\n  if(typeof sharedEventData[errorObj.event.eventId]!=\"undefined\"){\n    delete sharedEventData[errorObj.event.eventId];\n  }\n});\neventor.emit(\"test\",{}).then((results)=\u003e{\n\n}).catch((error)=\u003e{\n  // error here is just object that was thrown  - (new Error(\"for example\"))\n  // we doesn't have an eventId here so we must clean up thing on 'error' event\n});\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneuronetio%2Feventorjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fneuronetio%2Feventorjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneuronetio%2Feventorjs/lists"}