{"id":15056309,"url":"https://github.com/yertools/event_hub","last_synced_at":"2025-06-30T09:37:48.341Z","repository":{"id":240591898,"uuid":"802997714","full_name":"yerTools/event_hub","owner":"yerTools","description":"Event-Hub is a Gleam library that provides simple hubs with publishers and subscribers for event-driven observers. It supports asynchronous message handling and event notifications, decoupling components efficiently. It works on Erlang and JavaScript.","archived":false,"fork":false,"pushed_at":"2025-06-09T13:24:04.000Z","size":91,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-29T06:05:00.449Z","etag":null,"topics":["erlang","events","gleam","javascript","notifications","observer","observer-pattern","publisher","subscriber"],"latest_commit_sha":null,"homepage":"https://hexdocs.pm/event_hub/index.html","language":"Gleam","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/yerTools.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","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,"zenodo":null}},"created_at":"2024-05-19T20:29:03.000Z","updated_at":"2025-06-23T18:59:14.000Z","dependencies_parsed_at":"2025-04-13T00:33:42.912Z","dependency_job_id":null,"html_url":"https://github.com/yerTools/event_hub","commit_stats":null,"previous_names":["yertools/observer","yertools/event_hub"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/yerTools/event_hub","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yerTools%2Fevent_hub","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yerTools%2Fevent_hub/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yerTools%2Fevent_hub/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yerTools%2Fevent_hub/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yerTools","download_url":"https://codeload.github.com/yerTools/event_hub/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yerTools%2Fevent_hub/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262749027,"owners_count":23358322,"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":["erlang","events","gleam","javascript","notifications","observer","observer-pattern","publisher","subscriber"],"created_at":"2024-09-24T21:49:51.085Z","updated_at":"2025-06-30T09:37:48.308Z","avatar_url":"https://github.com/yerTools.png","language":"Gleam","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Event-Hub\n\n[![Package Version](https://img.shields.io/hexpm/v/event_hub)](https://hex.pm/packages/event_hub)\n[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/event_hub/)\n\nEvent-Hub is a Gleam library that provides simple hubs with publishers and\nsubscribers for event-driven observers. It supports asynchronous message\nhandling and event notifications, decoupling components efficiently. It works on\nErlang and JavaScript.\n\n---\n\nFurther documentation can be found at \u003chttps://hexdocs.pm/event_hub\u003e.\n\n- [event_hub](https://hexdocs.pm/event_hub/event_hub.html)\n- [event_hub/filtered](https://hexdocs.pm/event_hub/event_hub/filtered.html)\n- [event_hub/reactive](https://hexdocs.pm/event_hub/event_hub/reactive.html)\n- [event_hub/stateful](https://hexdocs.pm/event_hub/event_hub/stateful.html)\n- [event_hub/topic](https://hexdocs.pm/event_hub/event_hub/topic.html)\n\n## Try it yourself!\n\n```sh\ngleam add event_hub\n```\n\n## Examples\n\n### Imports:\n\nThe following imports where used for the examples:\n\n```gleam\nimport gleam/int\nimport gleam/io\nimport event_hub\nimport event_hub/filtered\nimport event_hub/reactive\nimport event_hub/stateful\nimport event_hub/topic\n```\n\n### Simple Observer\n\nA simple observer implementation. This example demonstrates the basic usage of\nthe Event-Hub library. It is an easy way to use publishers and subscribers to\nhandle events.\n\n```gleam\nfn simple_observer() {\n  // Creates a new hub for distributing events.\n  use hub \u003c- event_hub.new()\n\n  // Notifies all subscribers of the hub that an event has occurred.\n  event_hub.notify(hub, 1)\n\n  // You can forward the hub to other functions or components.\n  {\n    // Using syntactic sugar for handling the callback.\n    use value \u003c- event_hub.subscribe(hub)\n\n    // This function gets called when the hub receives an event.\n    io.println(\"[1] | Received an event with value: \" \u003c\u003e int.to_string(value))\n  }\n\n  // You can also subscribe using a normal callback function.\n  // This also returns an unsubscribe function.\n  let unsubscribe =\n    event_hub.subscribe(hub, fn(value) {\n      io.println(\"[2] | Received an event with value: \" \u003c\u003e int.to_string(value))\n    })\n\n  // Notifies all subscribers of the hub that an event has occurred with the value `2`.\n  // These notifications occur in parallel but notify waits for all of them to complete.\n  event_hub.notify(hub, 2)\n\n  // Unsubscribe if you no longer need to receive events.\n  unsubscribe()\n\n  // Notify again to demonstrate that the unsubscribe function works.\n  event_hub.notify(hub, 3)\n}\n```\n\n#### Output:\n\n\u003e [1] | Received an event with value: 2  \n\u003e [2] | Received an event with value: 2  \n\u003e [1] | Received an event with value: 3\n\n### Simple Observer with State\n\nA simple stateful observer implementation. This is like the previous example,\nbut it uses a stateful event_hub.\n\n```gleam\nfn simple_observer_with_state() {\n  // Creates a new hub for distributing events with an initial state.\n  use hub \u003c- stateful.new(\"initial state\")\n\n  // Gets the current state.\n  let current_state = stateful.state(hub)\n  io.println(\"Current state: \" \u003c\u003e current_state)\n\n  // Notifies all subscribers of the hub that an event has occurred.\n  stateful.notify(hub, \"test value\")\n\n  // See that the state has changed.\n  let current_state = stateful.state(hub)\n  io.println(\"Current state: \" \u003c\u003e current_state)\n\n  // You can forward the hub to other functions or components.\n  {\n    // Using syntactic sugar for handling the callback.\n    // With the second argument, you can specify whether the callback should be called with the current state.\n    use value \u003c- stateful.subscribe(hub, True)\n\n    // This function gets called when the hub receives an event.\n    // In this case, it prints the current state because the second argument was `True`.\n    io.println(\"[1] | Received an event with value: \" \u003c\u003e value)\n  }\n\n  // You can also subscribe using a normal callback function.\n  // This also returns a tuple with the current state and an unsubscribe function.\n  // The second argument specifies that the callback should not be called with the current state.\n  let #(current_state, unsubscribe) =\n    stateful.subscribe(hub, False, fn(value) {\n      io.println(\"[2] | Received an event with value: \" \u003c\u003e value)\n    })\n\n  // See that the state is still the same.\n  io.println(\"Current state: \" \u003c\u003e current_state)\n\n  // Notifies all subscribers of the hub that an event has occurred with the value `\"third event\"`.\n  // These notifications occur in parallel but notify waits for all of them to complete.\n  stateful.notify(hub, \"third event\")\n\n  // Unsubscribe if you no longer need to receive events.\n  unsubscribe()\n\n  // Notify again to demonstrate that the unsubscribe function works.\n  stateful.notify(hub, \"last one\")\n}\n```\n\n#### Output:\n\n\u003e Current state: initial state  \n\u003e Current state: test value  \n\u003e [1] | Received an event with value: test val  \n\u003e Current state: test value  \n\u003e [1] | Received an event with value: third ev  \n\u003e [2] | Received an event with value: third ev  \n\u003e [1] | Received an event with value: last one\n\n### Reactive Observer\n\nA simple reactive observer implementation. This can be used to broadcast things\nthat constantly change like the current time to clients. Another use case would\nbe to broadcast database updates to listeners.\n\n```gleam\nfn reactive_observer() {\n  // This is a mockup of the current time function.\n  // In a real application, you would use a real time function.\n  let now = fn() { \"2024-05-21T16:30:00Z\" }\n\n  // Creates a new hub for distributing events with a current time function.\n  use time_hub \u003c- reactive.new(now)\n\n  // Subscribes to the hub to get notified when the current time changes.\n  let unsubscribe_a =\n    reactive.subscribe(time_hub, fn(value) {\n      io.println(\"[A] | Current time: \" \u003c\u003e value)\n    })\n\n  // This is another subscription to the hub.\n  let unsubscribe_b =\n    reactive.subscribe(time_hub, fn(value) {\n      io.println(\"[B] | Current time: \" \u003c\u003e value)\n    })\n\n  // Just another client.\n  let unsubscribe_c =\n    reactive.subscribe(time_hub, fn(value) {\n      io.println(\"[C] | Current time: \" \u003c\u003e value)\n    })\n\n  // Notifies all subscribers of the hub that the current time has changed.\n  // This will call the provided function when the hub was created and broadcast the return value.\n  reactive.notify(time_hub)\n\n  // Unsubscribes from the hub.\n  unsubscribe_b()\n\n  // Notifies all subscribers again.\n  // If a real-time function is used, the current time will be updated.\n  reactive.notify(time_hub)\n\n  // Unsubscribe all subscribers.\n  unsubscribe_c()\n  unsubscribe_a()\n}\n```\n\n#### Output:\n\n\u003e [A] | Current time: 2024-05-21T16:30:00Z  \n\u003e [B] | Current time: 2024-05-21T16:30:00Z  \n\u003e [C] | Current time: 2024-05-21T16:30:00Z  \n\u003e [A] | Current time: 2024-05-21T16:30:00Z  \n\u003e [C] | Current time: 2024-05-21T16:30:00Z\n\n### Single topic-based Observer\n\nA simple topic-based observer implementation. Topics can be used to organize and\nfilter events.\n\n```gleam\nfn single_topic() {\n  use hub \u003c- topic.new()\n\n  // Creates a listener for the topics `\"a\"`, `\"ab\"` and `\"*\"`.\n  let unsubscribe_a =\n    topic.subscribe(hub, [\"a\", \"ab\", \"*\"], fn(value) {\n      io.println(\"[A] | Received an event with value: \" \u003c\u003e value)\n    })\n\n  // Creates a listener for the topics `\"b\"`, `\"ab\"` and `\"*\"`.\n  let unsubscribe_b =\n    topic.subscribe(hub, [\"b\", \"ab\", \"*\"], fn(value) {\n      io.println(\"[B] | Received an event with value: \" \u003c\u003e value)\n    })\n\n  // Creates a listener for the topics `\"c\"` and `\"*\"`.\n  let unsubscribe_c =\n    topic.subscribe(hub, [\"c\", \"*\"], fn(value) {\n      io.println(\"[C] | Received an event with value: \" \u003c\u003e value)\n    })\n\n  // Notifies listeners with the topics `\"a\"` and `\"c\"`.\n  topic.notify(hub, [\"a\", \"c\"], \"Hello A and C!\")\n\n  // Notifies listeners with the topic `\"*\"`.\n  topic.notify(hub, [\"*\"], \"Hello all!\")\n\n  // Notifies listeners with the topic `\"ab\"`.\n  topic.notify(hub, [\"ab\"], \"Hello AB!\")\n\n  // Notifies listeners with the topics `\"a\"`, `\"ab\"`, `\"b\"`, `\"c\"` and `\"*\"`.\n  topic.notify(hub, [\"a\", \"ab\", \"b\", \"c\", \"*\"], \"Hello A, AB, B, C, and all!\")\n\n  // Unsubscribe all listeners.\n  unsubscribe_a()\n  unsubscribe_b()\n  unsubscribe_c()\n}\n```\n\n#### Output:\n\n\u003e [A] | Received an event with value: Hello A and C!  \n\u003e [C] | Received an event with value: Hello A and C!  \n\u003e [A] | Received an event with value: Hello all!  \n\u003e [B] | Received an event with value: Hello all!  \n\u003e [C] | Received an event with value: Hello all!  \n\u003e [A] | Received an event with value: Hello AB!  \n\u003e [B] | Received an event with value: Hello AB!  \n\u003e [A] | Received an event with value: Hello A, AB, B, C, and all!  \n\u003e [B] | Received an event with value: Hello A, AB, B, C, and all!  \n\u003e [C] | Received an event with value: Hello A, AB, B, C, and all!\n\n### Multiple topic-based Observer\n\nExample of using multiple topics. This can be used for advanced filtering and\ngrouping of events. A possible example would be to propagate database changes to\nlisteners. In this case, the first topic would be the table name and the second\ntopics could be the column names.\n\n```gleam\nfn multiple_topics() {\n  use hub \u003c- topic.new2()\n\n  // Creates a listener for the `\"user\"` table and the columns `\"name\"` and `\"age\"`.\n  let unsubscribe_user_name_age =\n    topic.subscribe2(hub, [\"user\"], [\"name\", \"age\", \"*\"], fn(value) {\n      io.println(\"[User: name, age] | Received an event with value: \" \u003c\u003e value)\n    })\n\n  // Creates a listener for the `\"user\"` table and the columns `\"name\"`, `\"age\"` and `\"email\"`.\n  let unsubscribe_user_details =\n    topic.subscribe2(hub, [\"user\"], [\"name\", \"age\", \"email\", \"*\"], fn(value) {\n      io.println(\n        \"[User: name, age, email] | Received an event with value: \" \u003c\u003e value,\n      )\n    })\n\n  // Update the user name\n  topic.notify2(hub, [\"user\"], [\"name\"], \"John Doe\")\n\n  // Update the user email\n  topic.notify2(hub, [\"user\"], [\"email\"], \"john.doe@example.com\")\n\n  // Add a new user\n  topic.notify2(hub, [\"user\"], [\"*\"], \"Hello World!\")\n\n  unsubscribe_user_name_age()\n  unsubscribe_user_details()\n}\n```\n\n#### Output:\n\n\u003e [User: name, age] | Received an event with value: John Doe  \n\u003e [User: name, age, email] | Received an event with value: John Doe  \n\u003e [User: name, age, email] | Received an event with value:\n\u003e john.doe@example.com  \n\u003e [User: name, age] | Received an event with value: Hello World!  \n\u003e [User: name, age, email] | Received an event with value: Hello World!\n\n### Filtered Observer\n\nThis example demonstrates the usage of the filtered event_hub. It is an easy way\nto filter events based on a list of topics. They work in a similar way, but you\ncan use generics to filter by any type.\n\n```gleam\nfn filtered_observer() {\n  use hub \u003c- filtered.new3()\n\n  let unsubscribe_a =\n    filtered.subscribe3(hub, [0, 1], [\"A\", \"*\"], [Ok(Nil)], fn(value) {\n      io.println(\"[A] | Received an event with value: \" \u003c\u003e value)\n    })\n\n  let unsubscribe_b =\n    filtered.subscribe3(hub, [0, 2], [\"B\", \"*\"], [Ok(Nil)], fn(value) {\n      io.println(\"[B] | Received an event with value: \" \u003c\u003e value)\n    })\n\n  // This should notify all subscribers.\n  filtered.notify3(hub, [0], [\"*\"], [Ok(Nil)], \"Hello all!\")\n\n  // This should notify only subscriber A.\n  filtered.notify3(hub, [1], [\"A\", \"*\"], [Ok(Nil)], \"Hello A\")\n\n  // This should notify only subscriber B.\n  filtered.notify3(hub, [0, 1, 2], [\"B\"], [Ok(Nil)], \"Hello B\")\n\n  // This should notify none.\n  filtered.notify3(hub, [0, 1, 2], [\"A\", \"B\", \"*\"], [Error(Nil)], \"Hello C\")\n\n  unsubscribe_a()\n  unsubscribe_b()\n}\n```\n\n#### Output:\n\n\u003e [A] | Received an event with value: Hello all!  \n\u003e [B] | Received an event with value: Hello all!  \n\u003e [A] | Received an event with value: Hello A  \n\u003e [B] | Received an event with value: Hello B\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyertools%2Fevent_hub","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyertools%2Fevent_hub","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyertools%2Fevent_hub/lists"}