{"id":21514794,"url":"https://github.com/dashlane/ts-event-bus","last_synced_at":"2025-04-05T12:04:51.254Z","repository":{"id":30309205,"uuid":"124375963","full_name":"Dashlane/ts-event-bus","owner":"Dashlane","description":"📨 Distributed messaging in TypeScript","archived":false,"fork":false,"pushed_at":"2024-02-29T10:30:35.000Z","size":493,"stargazers_count":139,"open_issues_count":7,"forks_count":14,"subscribers_count":19,"default_branch":"master","last_synced_at":"2025-03-29T11:05:52.816Z","etag":null,"topics":["distributed-messaging","eventbus","typescript","websocket"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/ts-event-bus","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Dashlane.png","metadata":{"files":{"readme":"README.md","changelog":null,"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}},"created_at":"2018-03-08T10:31:15.000Z","updated_at":"2025-02-19T16:18:56.000Z","dependencies_parsed_at":"2024-02-28T14:51:11.793Z","dependency_job_id":"2f2d2667-df1f-4ed0-8d65-f292ec9596c2","html_url":"https://github.com/Dashlane/ts-event-bus","commit_stats":{"total_commits":78,"total_committers":13,"mean_commits":6.0,"dds":0.8076923076923077,"last_synced_commit":"973d63b902de402b26d6161d92fa6f8a370cabea"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dashlane%2Fts-event-bus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dashlane%2Fts-event-bus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dashlane%2Fts-event-bus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dashlane%2Fts-event-bus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Dashlane","download_url":"https://codeload.github.com/Dashlane/ts-event-bus/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247332602,"owners_count":20921853,"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":["distributed-messaging","eventbus","typescript","websocket"],"created_at":"2024-11-23T23:53:00.388Z","updated_at":"2025-04-05T12:04:51.231Z","avatar_url":"https://github.com/Dashlane.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ts-event-bus\n\n[![by Dashlane](https://rawgit.com/dashlane/ts-event-bus/master/by_dashlane.svg)](https://www.dashlane.com/)\n\n[![Build Status](https://github.com/Dashlane/ts-event-bus/actions/workflows/nodejs.yml/badge.svg)](https://github.com/Dashlane/ts-event-bus/actions/workflows/nodejs.yml)\n[![Dependency Status](https://david-dm.org/Dashlane/ts-event-bus.svg)](https://david-dm.org/Dashlane/ts-event-bus)\n\n\u003e [!CAUTION]\n\u003e This package is no longer maintained. It is strongly advised against using it in any new project.\n\nDistributed messaging in Typescript\n\n`ts-event-bus` is a lightweight distributed messaging system. It allows several modules, potentially distributed over different runtime spaces to communicate through typed messages.\n\n## Getting started\n\n### Declare your events\n\nUsing `ts-event-bus` starts with the declaration of the interface that your components share:\n\n```typescript\n// MyEvents.ts\nimport { slot, Slot } from \"ts-event-bus\";\n\nconst MyEvents = {\n  sayHello: slot\u003cstring\u003e(),\n  getTime: slot\u003cnull, string\u003e(),\n  multiply: slot\u003c{ a: number; b: number }, number\u003e(),\n  ping: slot\u003cvoid\u003e(),\n};\n\nexport default MyEvents;\n```\n\n### Create EventBus\n\nYour components will then instantiate an event bus based on this declaration, using whatever channel they may want to communicate on.\nIf you specify no `Channel`, it means that you will exchange events in the same memory space.\n\nFor instance, one could connect two node processes over WebSocket:\n\n```typescript\n// firstModule.EventBus.ts\nimport { createEventBus } from \"ts-event-bus\";\nimport MyEvents from \"./MyEvents.ts\";\nimport MyBasicWebSocketClientChannel from \"./MyBasicWebSocketClientChannel.ts\";\n\nconst EventBus = createEventBus({\n  events: MyEvents,\n  channels: [new MyBasicWebSocketClientChannel(\"ws://your_host\")],\n});\n\nexport default EventBus;\n```\n\n```typescript\n// secondModule.EventBus.ts\nimport { createEventBus } from \"ts-event-bus\";\nimport MyEvents from \"./MyEvents.ts\";\nimport MyBasicWebSocketServerChannel from \"./MyBasicWebSocketServerChannel.ts\";\n\nconst EventBus = createEventBus({\n  events: MyEvents,\n  channels: [new MyBasicWebSocketServerChannel(\"ws://your_host\")],\n});\n```\n\n### Usage\n\nOnce connected, the clients can start by using the slots on the event bus\n\n```typescript\n// firstModule.ts\nimport EventBus from './firstModule.EventBus.ts'\n\n// Slots can be called with a parameter, here 'michel'\nEventBus.say('michel', 'Hello')\n\n// Or one can rely on the default parameter: here DEFAULT_PARAMETER\n// is implicitely used.\nEventBus.say('Hello')\n\n// Triggering an event always returns a promise\nEventBus.say('michel', 'Hello').then(() =\u003e {\n    ...\n})\n\nEventBus.getTime().then((time) =\u003e {\n    ...\n})\n\nEventBus.multiply({a: 2, b: 5 }).then((result) =\u003e {\n    ...\n})\n\nEventBus.ping()\n```\n\n```typescript\n// secondModule.ts\nimport EventBus from \"./secondModule.EventBus.ts\";\n\n// Add a listener on the default parameter\nEventBus.ping.on(() =\u003e {\n  console.log(\"pong\");\n});\n\n// Or listen to a specific parameter\nEventBus.say.on(\"michel\", (words) =\u003e {\n  console.log(\"michel said\", words);\n});\n\n// Event subscribers can respond to the event synchronously (by returning a value)\nEventBus.getTime.on(() =\u003e new Date().toString);\n\n// Or asynchronously (by returning a Promise that resolves with the value).\nEventBus.multiply.on(\n  ({ a, b }) =\u003e\n    new Promise((resolve, reject) =\u003e {\n      AsynchronousMultiplier(a, b, (err, result) =\u003e {\n        if (err) {\n          return reject(err);\n        }\n        resolve(result);\n      });\n    })\n);\n```\n\nCalls and subscriptions on slots are typechecked\n\n```typescript\nEventBus.multiply({a: 1, c: 2}) // Compile error: property 'c' does not exist on type {a: number, b: number}\n\nEventBus.multiply.on(({a, b}) =\u003e {\n    if (a.length \u003e 2) { // Compile error: property 'length' does not exist on type 'number'\n        ...\n    }\n})\n```\n\n### Lazy callbacks\n\nSlots expose a `lazy` method that will allow you to call a \"connect\" callback when a first\nclient connects to the slot, and a \"disconnect\" callback when the last client disconnect.\n\nRemote or local clients are considered equally. If a client was already connected to the slot\nat the time when `lazy` is called, the \"connect\" callback is called immediately.\n\n```typescript\nconst connect = (param) =\u003e {\n  console.log(\n    `Someone somewhere has begun listening to the slot with .on on ${param}.`\n  );\n};\n\nconst disconnect = (param) =\u003e {\n  console.log(`No one is listening to the slot anymore on ${param}.`);\n};\n\nconst disconnectLazy = EventBus.ping.lazy(connect, disconnect);\n\nconst unsubscribe = EventBus.ping().on(() =\u003e {});\n// console output: 'Someone somewhere has begun listening to the slot with .on on $_DEFAULT_$.'\n\nunsubscribe();\n// console output: 'No one is listening to the slot anymore on $_DEFAULT_$.'\n\nconst unsubscribe = EventBus.ping().on(\"parameter\", () =\u003e {});\n// console output: 'Someone somewhere has begun listening to the slot with .on on parameter.'\n\nunsubscribe();\n// console output: 'No one is listening to the slot anymore on parameter.'\n\n// Remove the callbacks.\n// \"disconnect\" is called one last time if there were subscribers left on the slot.\ndisconnectLazy();\n```\n\n### Buffering\n\nWhen the eventBus is created with channels, slots will wait for all transports to have\nregistered callbacks before triggering.\n\nThis buffering mechanism can be disabled at the slot level with the `noBuffer` config option:\n\n```typescript\nconst MyEvents = {\n  willWait: slot\u003cstring\u003e(),\n  wontWait: slot\u003cstring\u003e({ noBuffer: true }),\n};\n```\n\n### Auto-reconnection\n\nIn order to re-establish a lost connection when triggering an event a `Channel`\nneeds to implement the `autoReconnect` method.\nSee example: [RuntimeConnect](./examples/channels/RuntimeConnect.ts)\nIt's also possible to fine tune and deactivate this feature on a per-slot basis :\n\n```typescript\nconst MyEvents = {\n  willAutoReconnect: slot\u003cstring\u003e(),\n  wontNotAutoReconnect: slot\u003cstring\u003e({ autoReconnect: false }),\n};\n```\n\n### Syntactic sugar\n\nYou can combine events from different sources.\n\n```typescript\nimport { combineEvents } from \"ts-event-bus\";\nimport MyEvents from \"./MyEvents.ts\";\nimport MyOtherEvents from \"./MyOtherEvents.ts\";\n\nconst MyCombinedEvents = combineEvents(MyEvents, MyOtherEvents);\n\nexport default MyCombinedEvents;\n```\n\n## Using and Implementing Channels\n\n`ts-event-bus` comes with an abstract class [GenericChannel](./src/Channel.ts).\nTo implement your own channel create a new class extending `GenericChannel`, and call the method given by the abstract class: `_connected()`, `_disconnected()`, `_error(e: Error)` and `_messageReceived(data: any)`.\n\nBasic WebSocket Channel example:\n\n```typescript\nimport { GenericChannel } from \"ts-event-bus\";\n\nexport class MyBasicWebSocketChannel extends GenericChannel {\n  private _ws: WebSocket | null = null;\n  private _host: string;\n\n  constructor(host: string) {\n    super();\n    this._host = host;\n    this._init();\n  }\n\n  private _init(): void {\n    const ws = new WebSocket(this._host);\n\n    ws.onopen = (e: Event) =\u003e {\n      this._connected();\n      this._ws = ws;\n    };\n\n    ws.onerror = (e: Event) =\u003e {\n      this._ws = null;\n      this._error(e);\n      this._disconnected();\n      setTimeout(() =\u003e {\n        this._init();\n      }, 2000);\n    };\n\n    ws.onclose = (e: CloseEvent) =\u003e {\n      if (ws === this._ws) {\n        this._ws = null;\n        this._disconnected();\n        this._init();\n      }\n    };\n\n    ws.onmessage = (e: MessageEvent) =\u003e {\n      this._messageReceived(e.data);\n    };\n  }\n}\n```\n\n## Examples\n\n- [Channel implementation](./examples/channels)\n- [Usage](./examples/usage)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdashlane%2Fts-event-bus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdashlane%2Fts-event-bus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdashlane%2Fts-event-bus/lists"}