@theshelf/eventbroker 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,61 @@
1
+
2
+ # Event Broker | The Shelf
3
+
4
+ The event broker package provides a universal interaction layer with an actual event broker solution.
5
+
6
+ This package is based on a publish / subscribe model.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install @theshelf/eventbroker
12
+ ```
13
+
14
+ ## Implementations
15
+
16
+ Currently, there is only one implementation:
17
+
18
+ * **Memory** - non-persistent event broker based on the Node.js `EventEmitter`.
19
+
20
+ We have plans to add a Kafka implementation later on.
21
+
22
+ ## Configuration
23
+
24
+ The used implementation needs to be configured in the `.env` file.
25
+
26
+ ```env
27
+ EVENT_BROKER_IMPLEMENTATION="memory"
28
+ ```
29
+
30
+ ## How to use
31
+
32
+ An instance of the configured event broker implementation can be imported for performing event operations.
33
+
34
+ ```ts
35
+ import eventBroker from '@theshelf/eventbroker';
36
+
37
+ // Perform operations with the eventBroker instance
38
+ ```
39
+
40
+ ### Operations
41
+
42
+ ```ts
43
+ import eventBroker, { Publication, Subscription } from '@theshelf/eventbroker';
44
+
45
+ // Open connection
46
+ await eventBroker.connect();
47
+
48
+ // Close connection
49
+ await eventBroker.disconnect();
50
+
51
+ // Subscribe to an event
52
+ const subscription: Subscription = { channel: 'post', name: 'updated', handler: (postId: string) => { ... } };
53
+ await eventBroker.subscribe(subscription);
54
+
55
+ // Publish an event
56
+ const publication: Publication = { channel: 'post', name: 'updated', data: { postId: '123' } };
57
+ await eventBroker.publish(publication);
58
+
59
+ // Unsubscribe from an event
60
+ await eventBroker.unsubscribe(subscription);
61
+ ```
@@ -0,0 +1,13 @@
1
+ import type { Driver } from './definitions/interfaces';
2
+ import type { Publication, Subscription } from './definitions/types';
3
+ export default class EventBroker implements Driver {
4
+ #private;
5
+ constructor(driver: Driver);
6
+ get connected(): boolean;
7
+ connect(): Promise<void>;
8
+ disconnect(): Promise<void>;
9
+ publish<T>(publication: Publication<T>): Promise<void>;
10
+ subscribe<T>(subscription: Subscription<T>): Promise<void>;
11
+ unsubscribe<T>(subscription: Subscription<T>): Promise<void>;
12
+ clear(): Promise<void>;
13
+ }
@@ -0,0 +1,25 @@
1
+ export default class EventBroker {
2
+ #driver;
3
+ constructor(driver) {
4
+ this.#driver = driver;
5
+ }
6
+ get connected() { return this.#driver.connected; }
7
+ connect() {
8
+ return this.#driver.connect();
9
+ }
10
+ disconnect() {
11
+ return this.#driver.disconnect();
12
+ }
13
+ publish(publication) {
14
+ return this.#driver.publish(publication);
15
+ }
16
+ subscribe(subscription) {
17
+ return this.#driver.subscribe(subscription);
18
+ }
19
+ unsubscribe(subscription) {
20
+ return this.#driver.unsubscribe(subscription);
21
+ }
22
+ clear() {
23
+ return this.#driver.clear();
24
+ }
25
+ }
@@ -0,0 +1,10 @@
1
+ import type { Publication, Subscription } from './types';
2
+ export interface Driver {
3
+ get connected(): boolean;
4
+ connect(): Promise<void>;
5
+ disconnect(): Promise<void>;
6
+ publish<T>(publication: Publication<T>): Promise<void>;
7
+ subscribe<T>(subscription: Subscription<T>): Promise<void>;
8
+ unsubscribe<T>(subscription: Subscription<T>): Promise<void>;
9
+ clear(): Promise<void>;
10
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ export type Event = {
2
+ channel: string;
3
+ name: string;
4
+ };
5
+ export type EventHandler<T> = (data: T) => void;
6
+ export type Publication<T> = Event & {
7
+ data?: T;
8
+ };
9
+ export type Subscription<T> = Event & {
10
+ handler: EventHandler<T>;
11
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export default class EventBrokerError extends Error {
2
+ }
@@ -0,0 +1,2 @@
1
+ export default class EventBrokerError extends Error {
2
+ }
@@ -0,0 +1,4 @@
1
+ import EventBrokerError from './EventBrokerError';
2
+ export default class UnknownImplementation extends EventBrokerError {
3
+ constructor(name: string);
4
+ }
@@ -0,0 +1,6 @@
1
+ import EventBrokerError from './EventBrokerError';
2
+ export default class UnknownImplementation extends EventBrokerError {
3
+ constructor(name) {
4
+ super(`Unknown event broker implementation: ${name}`);
5
+ }
6
+ }
@@ -0,0 +1,3 @@
1
+ import type { Driver } from './definitions/interfaces';
2
+ declare const _default: Driver;
3
+ export default _default;
@@ -0,0 +1,12 @@
1
+ import UnknownImplementation from './errors/UnknownImplementation';
2
+ import createMemoryBroker from './implementations/memory/create';
3
+ const implementations = new Map([
4
+ ['memory', createMemoryBroker]
5
+ ]);
6
+ const DEFAULT_BROKER_IMPLEMENTATION = 'memory';
7
+ const implementationName = process.env.EVENT_BROKER_IMPLEMENTATION ?? DEFAULT_BROKER_IMPLEMENTATION;
8
+ const creator = implementations.get(implementationName.toLowerCase());
9
+ if (creator === undefined) {
10
+ throw new UnknownImplementation(implementationName);
11
+ }
12
+ export default creator();
@@ -0,0 +1,12 @@
1
+ import type { Driver } from '../../definitions/interfaces';
2
+ import type { Publication, Subscription } from '../../definitions/types';
3
+ export default class Memory implements Driver {
4
+ #private;
5
+ get connected(): boolean;
6
+ connect(): Promise<void>;
7
+ disconnect(): Promise<void>;
8
+ publish<T>(publication: Publication<T>): Promise<void>;
9
+ subscribe<T>(subscription: Subscription<T>): Promise<void>;
10
+ unsubscribe<T>(subscription: Subscription<T>): Promise<void>;
11
+ clear(): Promise<void>;
12
+ }
@@ -0,0 +1,33 @@
1
+ import { EventEmitter } from 'node:events';
2
+ export default class Memory {
3
+ #emitters = new Map();
4
+ #connected = false;
5
+ get connected() { return this.#connected; }
6
+ async connect() {
7
+ this.#connected = true;
8
+ }
9
+ async disconnect() {
10
+ this.#connected = false;
11
+ }
12
+ async publish(publication) {
13
+ const emitter = this.#getEmitter(publication);
14
+ emitter.emit(publication.name, publication.data);
15
+ }
16
+ async subscribe(subscription) {
17
+ const emitter = this.#getEmitter(subscription);
18
+ emitter.on(subscription.name, subscription.handler);
19
+ }
20
+ async unsubscribe(subscription) {
21
+ const emitter = this.#getEmitter(subscription);
22
+ emitter.off(subscription.name, subscription.handler);
23
+ }
24
+ async clear() {
25
+ this.#emitters.clear();
26
+ }
27
+ #getEmitter(event) {
28
+ if (this.#emitters.has(event.channel) === false) {
29
+ this.#emitters.set(event.channel, new EventEmitter());
30
+ }
31
+ return this.#emitters.get(event.channel);
32
+ }
33
+ }
@@ -0,0 +1,2 @@
1
+ import Memory from './Memory';
2
+ export default function create(): Memory;
@@ -0,0 +1,4 @@
1
+ import Memory from './Memory';
2
+ export default function create() {
3
+ return new Memory();
4
+ }
@@ -0,0 +1,5 @@
1
+ import EventBroker from './EventBroker';
2
+ declare const eventBroker: EventBroker;
3
+ export * from './definitions/types';
4
+ export type { EventBroker };
5
+ export default eventBroker;
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ import EventBroker from './EventBroker';
2
+ import implementation from './implementation';
3
+ const eventBroker = new EventBroker(implementation);
4
+ export * from './definitions/types';
5
+ export default eventBroker;
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "@theshelf/eventbroker",
3
+ "private": false,
4
+ "version": "0.0.1",
5
+ "type": "module",
6
+ "scripts": {
7
+ "build": "tsc",
8
+ "clean": "rimraf dist",
9
+ "test": "vitest run",
10
+ "test-coverage": "vitest run --coverage",
11
+ "lint": "eslint",
12
+ "review": "npm run build && npm run lint && npm run test",
13
+ "prepublishOnly": "npm run clean && npm run build"
14
+ },
15
+ "files": [
16
+ "README.md",
17
+ "dist"
18
+ ],
19
+ "types": "dist/index.d.ts",
20
+ "exports": "./dist/index.js"
21
+ }