{"id":22489657,"url":"https://github.com/trutoo/event-bus","last_synced_at":"2025-08-02T22:30:54.093Z","repository":{"id":37727165,"uuid":"244340541","full_name":"trutoo/event-bus","owner":"trutoo","description":"Typesafe cross-platform pubsub event bus ensuring reliable communication between fragments and micro frontends.","archived":false,"fork":false,"pushed_at":"2024-06-03T12:41:56.000Z","size":1556,"stargazers_count":144,"open_issues_count":2,"forks_count":9,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-11-08T19:47:41.677Z","etag":null,"topics":["event-communication","fragments","micro-frontends","pubsub","typesafe"],"latest_commit_sha":null,"homepage":"https://trutoo.github.io/event-bus","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/trutoo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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":"2020-03-02T10:16:41.000Z","updated_at":"2024-09-28T07:42:12.000Z","dependencies_parsed_at":"2024-06-03T13:13:26.433Z","dependency_job_id":null,"html_url":"https://github.com/trutoo/event-bus","commit_stats":null,"previous_names":[],"tags_count":290,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trutoo%2Fevent-bus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trutoo%2Fevent-bus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trutoo%2Fevent-bus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trutoo%2Fevent-bus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/trutoo","download_url":"https://codeload.github.com/trutoo/event-bus/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228500414,"owners_count":17930061,"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":["event-communication","fragments","micro-frontends","pubsub","typesafe"],"created_at":"2024-12-06T17:20:22.527Z","updated_at":"2025-08-02T22:30:54.048Z","avatar_url":"https://github.com/trutoo.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# Event Bus\n\n![Continuous Delivery](https://github.com/trutoo/event-bus/workflows/Continuous%20Delivery/badge.svg)\n[![Coverage Status](https://coveralls.io/repos/github/trutoo/event-bus/badge.svg?branch=main)](https://coveralls.io/github/trutoo/event-bus?branch=main) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/trutoo/event-bus) [![[npm downloads]](https://img.shields.io/npm/dt/@trutoo/event-bus)](https://www.npmjs.com/package/@trutoo/event-bus) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/@trutoo/event-bus/latest) ![License](https://img.shields.io/github/license/trutoo/event-bus?kill_cache=0)\n\nSimple typesafe cross-platform pubsub communication between different single page applications, web components, fragments, or services. Purposefully built for a micro frontend architecture with a distributed responsibility for deployment. Allowing for framework agnostic and safe communication between different implementations and version. Catch those pesky event errors early :heart:.\n\n---\n\n## Table of Contents\n\n- [Event Bus](#event-bus)\n  - [Table of Contents](#table-of-contents)\n  - [Purpose](#purpose)\n  - [Installation](#installation)\n  - [Usage](#usage)\n    - [Advanced Schema](#advanced-schema)\n  - [API](#api)\n    - [Constructor Options](#constructor-options)\n    - [Register](#register)\n      - [Parameters](#parameters)\n    - [Unregister](#unregister)\n      - [Parameters](#parameters-1)\n    - [Subscribe](#subscribe)\n      - [Parameters](#parameters-2)\n    - [Publish](#publish)\n      - [Parameters](#parameters-3)\n    - [Get Latest](#get-latest)\n      - [Parameters](#parameters-4)\n    - [Get Schema](#get-schema)\n      - [Parameters](#parameters-5)\n    - [Clear Replay](#clear-replay)\n      - [Parameters](#parameters-6)\n\n---\n\n## Purpose\n\nThis project was created to improve upon some of the deficits CustomEvents has in relation to event communication between separate web components or fragments, which often is the preferred way of communication. Below points are some of the benefits of using this pub-sub solution over the native solution.\n\n1. Each fragment can register on a custom named event channel with an optional [JSON schema draft-07](https://json-schema.org/draft-07) to ensure all future traffic on that channel follows the specification. This means incompatibilities are reported before any payload is sent and every payload will be typesafe.\n\n2. The individual event channels stores the last payload allowing new fragments or asynchronous subscriptions to ask for a replay of the last payloads data as a first callback.\n\n3. CustomEvents require a polyfill to work in older browsers, while this project works out of the box with Internet Explorer 11.\n\n## Installation\n\nInstall the package from the [npm registry @trutoo/event-bus](https://www.npmjs.com/package/@trutoo/event-bus) as a production/runtime dependency.\n\n```bash\nnpm install @trutoo/event-bus\n```\n\nor\n\n```bash\nyarn add @trutoo/event-bus\n```\n\n_**Note: dropped publishing to GitHub packages to simplify releases.**_\n\nThen either import the side effects only exposing a `eventBus` global instance.\n\n```javascript\nimport '@trutoo/event-bus';\n// or\nrequire('@trutoo/event-bus');\n\neventBus.register(/*...*/);\n```\n\nor import the `EventBus` class to create your own instance.\n\n```javascript\nimport { EventBus } from '@trutoo/event-bus';\n// or\nconst { EventBus } = require('@trutoo/event-bus');\n\nconst myEventBus = new EventBus();\nmyEventBus.register(/*...*/);\n```\n\nor using the UMD module and instance.\n\n```html\n\u003cscript src=\"https://unpkg.com/@trutoo/event-bus@latest/dist/index.umd.min.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n  eventBus.register(/*...*/);\n  // or\n  const myEventBus = new EventBus.EventBus();\n  myEventBus.register(/*...*/);\n\u003c/script\u003e\n```\n\n## Usage\n\nSimple event bus registration with communication between a standard web component and a React component, as the event bus is framework agnostic. In addition a basic [JSON schema draft-04](https://tools.ietf.org/html/draft-zyp-json-schema-04) is used to restrict communication to a single boolean. Below outlines the basic usage, but can also be seen under [`/docs`](https://github.com/trutoo/event-bus/tree/main/docs) folder.\n\n`JSON Schema`\n\n```json\n{\n  \"type\": \"boolean\"\n}\n```\n\n`Fragment One - Web Component`\n\n```typescript\nclass PublisherElement extends HTMLElement {\n  connectedCallback() {\n    eventBus.register('namespace:eventName', { type: 'boolean' });\n    this.render();\n    this.firstChild \u0026\u0026 this.firstChild.addEventListener('click', this.send);\n  }\n  async send() {\n    await eventBus.publish('namespace:eventName', true);\n  }\n  render() {\n    this.innerHTML = `\u003cbutton type=\"button\"\u003esend\u003c/button\u003e`;\n  }\n  disconnectedCallback() {\n    this.firstChild \u0026\u0026 this.firstChild.removeEventListener('click', this.send);\n  }\n}\n```\n\n`Fragment Two - React Component`\n\n```typescript\nimport React from 'react';\n\n// Custom hook for event bus subscriptions\nfunction useEventSubscription\u003cT\u003e(eventName: string, schema: object) {\n  const [value, setValue] = React.useState\u003cT\u003e();\n\n  React.useEffect(() =\u003e {\n    let sub: { unsubscribe(): void };\n\n    async function init() {\n      try {\n        eventBus.register(eventName, schema);\n        sub = await eventBus.subscribe\u003cT\u003e(eventName, (event) =\u003e setValue(event.payload));\n      } catch (e) {\n        console.error(`Failed to subscribe to ${eventName}:`, e);\n      }\n    }\n\n    init();\n    return () =\u003e {\n      if (sub) sub.unsubscribe();\n    };\n  }, [eventName, schema]);\n\n  return value;\n}\n\nfunction SubscriberComponent() {\n  const isFavorite = useEventSubscription\u003cboolean\u003e('namespace:eventName', { type: 'boolean' });\n  return isFavorite ? 'This is a favorite' : 'This is not interesting';\n}\n```\n\n### Advanced Schema\n\nFollowing is an example of a more a more complex use-case with a larger [JSON schema draft-04](https://tools.ietf.org/html/draft-zyp-json-schema-04) and registration on multiple channels.\n\n`JSON Schema`\n\n```json\n{\n  \"type\": \"object\",\n  \"required\": [\"name\", \"amount\", \"price\"],\n  \"properties\": {\n    \"name\": {\n      \"type\": \"string\"\n    },\n    \"amount\": {\n      \"type\": \"string\"\n    },\n    \"price\": {\n      \"type\": \"number\"\n    },\n    \"organic\": {\n      \"type\": \"boolean\"\n    },\n    \"stores\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"object\",\n        \"required\": [],\n        \"properties\": {\n          \"name\": {\n            \"type\": \"string\"\n          },\n          \"url\": {\n            \"type\": \"string\"\n          }\n        }\n      }\n    }\n  }\n}\n```\n\n`Fragment - Angular Component`\n\n```typescript\nimport { Component } from '@angular/core';\nimport eventSchema from './event-schema.json';\n\n@Component({\n  selector: 'app-store',\n  template: '\u003cbutton (onClick)=\"onSend()\"\u003eAdd to cart\u003c/button\u003e',\n})\nexport class StoreComponent implements OnInit, OnDestroy {\n  private subs: { unsubscribe(): void }[] = [];\n\n  ngOnInit() {\n    // Register on add to cart channel\n    eventBus.register('store:addToCart', eventSchema);\n\n    // No need to register if no schema is required\n    this.sub.push(eventBus.subscribe\u003cboolean\u003e('store:newDeals', this.onNewDeals));\n  }\n\n  onNewDeals() {\n    /* handle new deals ... */\n  }\n\n  async onSend() {\n    await eventBus.publish('store:addToCart', {\n      name: 'Milk',\n      amount: '1000 ml',\n      price: 0.99,\n      organic: true,\n      stores: [\n        {\n          name: 'ACME Food AB',\n          url: 'acme-food.com',\n        },\n      ],\n    });\n  }\n\n  ngOnDestroy() {\n    this.subs.forEach((sub) =\u003e sub.unsubscribe());\n  }\n}\n```\n\n## API\n\n### Constructor Options\n\nThe EventBus constructor accepts an options object with the following properties:\n\n```typescript\ninterface EventBusOptions {\n  /**\n   * The logging level for the event bus\n   * - 'none': No logging\n   * - 'error': Only log errors (default)\n   * - 'warn': Log warnings and errors\n   * - 'info': Log everything\n   */\n  logLevel?: 'none' | 'error' | 'warn' | 'info';\n}\n```\n\n### Register\n\nRegister a schema for the specified event type and equality checking on subsequent registers. Subsequent registers must use an equal schema or an error will be thrown.\n\n```typescript\nregister(channel: string, schema: Record\u003cstring, unknown\u003e): boolean;\n```\n\n#### Parameters\n\n| Name    | Type                      | Description                                          |\n| ------- | ------------------------- | ---------------------------------------------------- |\n| channel | `string`                  | name of event channel to register schema to          |\n| schema  | `Record\u003cstring, unknown\u003e` | all communication on channel must follow this schema |\n\n**Returns** - returns true if event channel already existed of false if a new one was created.\n\n---\n\n### Unregister\n\nUnregister the schema for the specified event type if channel exists.\n\n```typescript\nunregister(channel: string): boolean;\n```\n\n#### Parameters\n\n| Name    | Type     | Description                                     |\n| ------- | -------- | ----------------------------------------------- |\n| channel | `string` | name of event channel to unregister schema from |\n\n**Returns** - returns true if event channel existed and an existing schema was removed.\n\n---\n\n### Subscribe\n\nSubscribe to an event channel triggering callback on received event matching type,\nwith an optional replay of last event at initial subscription.\nThe channel may be the wildcard `'*'` to subscribe to all channels.\n\n```typescript\nasync subscribe\u003cT\u003e(channel: string, callback: Callback\u003cT\u003e): Promise\u003c{ unsubscribe(): void }\u003e;\n\nasync subscribe\u003cT\u003e(channel: string, replay: boolean, callback: Callback\u003cT\u003e): Promise\u003c{ unsubscribe(): void }\u003e;\n```\n\nNote: Subscribe is an async function that returns a Promise with the subscription.\n\nCallbacks will be fired when event is published on a subscribed channel with the argument:\n\n```typescript\n{\n  channel: string,\n  payload: T,\n}\n```\n\n#### Parameters\n\n| Name     | Type            | Description                                                     |\n| -------- | --------------- | --------------------------------------------------------------- |\n| channel  | `string`        | name of event channel to receive data from                      |\n| replay   | `boolean=false` | flag indicating if initial description should return last event |\n| callback | `function`      | function executed on when event channel receives new data       |\n\n**Returns** - object containing an unsubscribe method\n\n---\n\n### Publish\n\nPublish to event channel with an optional payload triggering all subscription callbacks. Returns a Promise that resolves when all callbacks have completed.\n\n```typescript\nasync publish\u003cT\u003e(channel: string, payload?: T): Promise\u003cvoid\u003e;\n```\n\n#### Parameters\n\n| Name    | Type     | Description                              |\n| ------- | -------- | ---------------------------------------- |\n| channel | `string` | name of event channel to send payload on |\n| payload | `any`    | payload to be sent                       |\n\n**Returns** - Promise that resolves when all callbacks have completed\n\n---\n\n### Get Latest\n\nGet the latest published payload on the specified event channel.\n\n```typescript\ngetLatest\u003cT\u003e(channel: string): T | undefined;\n```\n\n#### Parameters\n\n| Name    | Type     | Description                                                |\n| ------- | -------- | ---------------------------------------------------------- |\n| channel | `string` | name of the event channel to fetch the latest payload from |\n\n**Returns** - the latest payload or `undefined`\n\n---\n\n### Get Schema\n\nGet the schema registered on the specified event channel.\n\n```typescript\ngetSchema\u003cT\u003e(channel: string): any | undefined;\n```\n\n#### Parameters\n\n| Name    | Type     | Description                                        |\n| ------- | -------- | -------------------------------------------------- |\n| channel | `string` | name of the event channel to fetch the schema from |\n\n**Returns** - the schema or `undefined`\n\n---\n\n### Clear Replay\n\nClears the replay event for the specified channel.\n\n```typescript\nclearReplay(channel: string): boolean;\n```\n\n#### Parameters\n\n| Name    | Type     | Description                                        |\n| ------- | -------- | -------------------------------------------------- |\n| channel | `string` | name of the event channel to clear the replay from |\n\n**Returns** - returns true if the replay event was cleared, false otherwise.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrutoo%2Fevent-bus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftrutoo%2Fevent-bus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrutoo%2Fevent-bus/lists"}