@dungarees/event-broker 0.11.4

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.
@@ -0,0 +1,2 @@
1
+ import type { EventBrokerBackend } from './type.ts';
2
+ export declare const createEventEmitterBackend: () => EventBrokerBackend;
@@ -0,0 +1,12 @@
1
+ import { EventEmitter } from 'node:events';
2
+ export const createEventEmitterBackend = () => {
3
+ const target = new EventEmitter();
4
+ return {
5
+ dispatch: (event, args) => {
6
+ target.emit(event, args);
7
+ },
8
+ on: (event, handler) => {
9
+ target.addListener(event, handler);
10
+ },
11
+ };
12
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,30 @@
1
+ import { createEventEmitterBackend } from './event-emitter.js';
2
+ import { expect, test } from 'vitest';
3
+ test('the backend hands a dispatched payload to a handler registered for that event', () => {
4
+ const backend = createEventEmitterBackend();
5
+ const received = [];
6
+ backend.on('some-event', (args) => {
7
+ received.push(args);
8
+ });
9
+ backend.dispatch('some-event', { a: 1 });
10
+ expect(received).toEqual([{ a: 1 }]);
11
+ });
12
+ test('the backend keeps one event from reaching another event handler', () => {
13
+ const backend = createEventEmitterBackend();
14
+ const received = [];
15
+ backend.on('some-event', (args) => {
16
+ received.push(args);
17
+ });
18
+ backend.dispatch('other-event', { a: 1 });
19
+ expect(received).toEqual([]);
20
+ });
21
+ test('the backend delivers to a handler as many times as the event is dispatched', () => {
22
+ const backend = createEventEmitterBackend();
23
+ const received = [];
24
+ backend.on('some-event', (args) => {
25
+ received.push(args);
26
+ });
27
+ backend.dispatch('some-event', 1);
28
+ backend.dispatch('some-event', 2);
29
+ expect(received).toEqual([1, 2]);
30
+ });
package/fake.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import type { EventBrokerBackend } from './type.ts';
2
+ type Subscription = [string, (args: never) => void];
3
+ type DispatchedEvent = [string, unknown];
4
+ export type FakeEventBrokerBackend = {
5
+ backend: EventBrokerBackend;
6
+ subscriptions: Subscription[];
7
+ dispatchedEvents: DispatchedEvent[];
8
+ invokeHandlers: (event: string, args: unknown) => void;
9
+ };
10
+ export declare const createFakeEventBrokerBackend: () => FakeEventBrokerBackend;
11
+ export {};
package/fake.js ADDED
@@ -0,0 +1,28 @@
1
+ // Records rather than delivers, so a test can assert what its subject dispatched without standing
2
+ // up a listener, and can drive the registered handlers itself when it wants the other direction.
3
+ export const createFakeEventBrokerBackend = () => {
4
+ const subscriptions = [];
5
+ const dispatchedEvents = [];
6
+ return {
7
+ backend: {
8
+ on: (event, handler) => {
9
+ subscriptions.push([event, handler]);
10
+ },
11
+ dispatch: (event, args) => {
12
+ dispatchedEvents.push([event, args]);
13
+ },
14
+ },
15
+ subscriptions,
16
+ dispatchedEvents,
17
+ invokeHandlers: (event, args) => {
18
+ subscriptions
19
+ .filter(([subscribedEvent]) => subscribedEvent === event)
20
+ // The handler's parameter is `never` on the untyped side of the boundary, so calling it
21
+ // means handing over a value the backend cannot describe; the typed broker above is what
22
+ // guarantees the payload matches the event.
23
+ .forEach(([_, handler]) => {
24
+ handler(args);
25
+ });
26
+ },
27
+ };
28
+ };
package/fake.test.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
package/fake.test.js ADDED
@@ -0,0 +1,69 @@
1
+ import { createFakeEventBrokerBackend } from './fake.js';
2
+ import { createBroker } from './service.js';
3
+ import { expect, test } from 'vitest';
4
+ test('the fake backend records what a broker dispatched through it', () => {
5
+ const { backend, dispatchedEvents } = createFakeEventBrokerBackend();
6
+ const broker = createBroker(backend);
7
+ broker.dispatch('counted', 7);
8
+ expect(dispatchedEvents).toEqual([['counted', 7]]);
9
+ });
10
+ test('the fake backend records dispatches in the order they happened', () => {
11
+ const { backend, dispatchedEvents } = createFakeEventBrokerBackend();
12
+ const broker = createBroker(backend);
13
+ broker.dispatch('counted', 1);
14
+ broker.dispatch('counted', 2);
15
+ expect(dispatchedEvents).toEqual([
16
+ ['counted', 1],
17
+ ['counted', 2],
18
+ ]);
19
+ });
20
+ test('the fake backend does not deliver a dispatch to handlers on its own', () => {
21
+ const { backend } = createFakeEventBrokerBackend();
22
+ const broker = createBroker(backend);
23
+ const received = [];
24
+ broker.on('counted', (args) => {
25
+ received.push(args);
26
+ });
27
+ broker.dispatch('counted', 7);
28
+ expect(received).toEqual([]);
29
+ });
30
+ test('invokeHandlers drives the handlers registered for that event', () => {
31
+ const { backend, invokeHandlers } = createFakeEventBrokerBackend();
32
+ const broker = createBroker(backend);
33
+ const received = [];
34
+ broker.on('counted', (args) => {
35
+ received.push(args);
36
+ });
37
+ invokeHandlers('counted', 7);
38
+ expect(received).toEqual([7]);
39
+ });
40
+ test('invokeHandlers leaves handlers for other events alone', () => {
41
+ const { backend, invokeHandlers } = createFakeEventBrokerBackend();
42
+ const broker = createBroker(backend);
43
+ const received = [];
44
+ broker.on('counted', (args) => {
45
+ received.push(args);
46
+ });
47
+ invokeHandlers('other-event', 7);
48
+ expect(received).toEqual([]);
49
+ });
50
+ test('invokeHandlers drives every handler registered for the event', () => {
51
+ const { backend, invokeHandlers } = createFakeEventBrokerBackend();
52
+ const broker = createBroker(backend);
53
+ const received = [];
54
+ broker.on('counted', (args) => {
55
+ received.push(args);
56
+ });
57
+ broker.on('counted', (args) => {
58
+ received.push(args * 2);
59
+ });
60
+ invokeHandlers('counted', 7);
61
+ expect(received).toEqual([7, 14]);
62
+ });
63
+ test('the fake backend records what a broker subscribed to', () => {
64
+ const { backend, subscriptions } = createFakeEventBrokerBackend();
65
+ const broker = createBroker(backend);
66
+ const handler = () => undefined;
67
+ broker.on('counted', handler);
68
+ expect(subscriptions).toEqual([['counted', handler]]);
69
+ });
package/package.json ADDED
@@ -0,0 +1,455 @@
1
+ {
2
+ "name": "@dungarees/event-broker",
3
+ "engines": {
4
+ "node": ">=25.0.0"
5
+ },
6
+ "scripts": {
7
+ "type-check": "tsc --noEmit"
8
+ },
9
+ "type": "module",
10
+ "devDependencies": {
11
+ "typescript": "^5.9.3",
12
+ "vitest": "^3.0.2"
13
+ },
14
+ "author": "info@productkind.com",
15
+ "license": "MIT",
16
+ "version": "0.11.4",
17
+ "exports": {
18
+ "./event-emitter.test.ts": {
19
+ "import": "./event-emitter.test.js",
20
+ "types": "./event-emitter.test.d.ts"
21
+ },
22
+ "./event-emitter.ts": {
23
+ "import": "./event-emitter.js",
24
+ "types": "./event-emitter.d.ts"
25
+ },
26
+ "./fake.test.ts": {
27
+ "import": "./fake.test.js",
28
+ "types": "./fake.test.d.ts"
29
+ },
30
+ "./fake.ts": {
31
+ "import": "./fake.js",
32
+ "types": "./fake.d.ts"
33
+ },
34
+ "./node_modules/typescript/lib/lib.d.ts": {
35
+ "import": "./node_modules/typescript/lib/lib.d.js",
36
+ "types": "./node_modules/typescript/lib/lib.d.d.ts"
37
+ },
38
+ "./node_modules/typescript/lib/lib.decorators.d.ts": {
39
+ "import": "./node_modules/typescript/lib/lib.decorators.d.js",
40
+ "types": "./node_modules/typescript/lib/lib.decorators.d.d.ts"
41
+ },
42
+ "./node_modules/typescript/lib/lib.decorators.legacy.d.ts": {
43
+ "import": "./node_modules/typescript/lib/lib.decorators.legacy.d.js",
44
+ "types": "./node_modules/typescript/lib/lib.decorators.legacy.d.d.ts"
45
+ },
46
+ "./node_modules/typescript/lib/lib.dom.asynciterable.d.ts": {
47
+ "import": "./node_modules/typescript/lib/lib.dom.asynciterable.d.js",
48
+ "types": "./node_modules/typescript/lib/lib.dom.asynciterable.d.d.ts"
49
+ },
50
+ "./node_modules/typescript/lib/lib.dom.d.ts": {
51
+ "import": "./node_modules/typescript/lib/lib.dom.d.js",
52
+ "types": "./node_modules/typescript/lib/lib.dom.d.d.ts"
53
+ },
54
+ "./node_modules/typescript/lib/lib.dom.iterable.d.ts": {
55
+ "import": "./node_modules/typescript/lib/lib.dom.iterable.d.js",
56
+ "types": "./node_modules/typescript/lib/lib.dom.iterable.d.d.ts"
57
+ },
58
+ "./node_modules/typescript/lib/lib.es2015.collection.d.ts": {
59
+ "import": "./node_modules/typescript/lib/lib.es2015.collection.d.js",
60
+ "types": "./node_modules/typescript/lib/lib.es2015.collection.d.d.ts"
61
+ },
62
+ "./node_modules/typescript/lib/lib.es2015.core.d.ts": {
63
+ "import": "./node_modules/typescript/lib/lib.es2015.core.d.js",
64
+ "types": "./node_modules/typescript/lib/lib.es2015.core.d.d.ts"
65
+ },
66
+ "./node_modules/typescript/lib/lib.es2015.d.ts": {
67
+ "import": "./node_modules/typescript/lib/lib.es2015.d.js",
68
+ "types": "./node_modules/typescript/lib/lib.es2015.d.d.ts"
69
+ },
70
+ "./node_modules/typescript/lib/lib.es2015.generator.d.ts": {
71
+ "import": "./node_modules/typescript/lib/lib.es2015.generator.d.js",
72
+ "types": "./node_modules/typescript/lib/lib.es2015.generator.d.d.ts"
73
+ },
74
+ "./node_modules/typescript/lib/lib.es2015.iterable.d.ts": {
75
+ "import": "./node_modules/typescript/lib/lib.es2015.iterable.d.js",
76
+ "types": "./node_modules/typescript/lib/lib.es2015.iterable.d.d.ts"
77
+ },
78
+ "./node_modules/typescript/lib/lib.es2015.promise.d.ts": {
79
+ "import": "./node_modules/typescript/lib/lib.es2015.promise.d.js",
80
+ "types": "./node_modules/typescript/lib/lib.es2015.promise.d.d.ts"
81
+ },
82
+ "./node_modules/typescript/lib/lib.es2015.proxy.d.ts": {
83
+ "import": "./node_modules/typescript/lib/lib.es2015.proxy.d.js",
84
+ "types": "./node_modules/typescript/lib/lib.es2015.proxy.d.d.ts"
85
+ },
86
+ "./node_modules/typescript/lib/lib.es2015.reflect.d.ts": {
87
+ "import": "./node_modules/typescript/lib/lib.es2015.reflect.d.js",
88
+ "types": "./node_modules/typescript/lib/lib.es2015.reflect.d.d.ts"
89
+ },
90
+ "./node_modules/typescript/lib/lib.es2015.symbol.d.ts": {
91
+ "import": "./node_modules/typescript/lib/lib.es2015.symbol.d.js",
92
+ "types": "./node_modules/typescript/lib/lib.es2015.symbol.d.d.ts"
93
+ },
94
+ "./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts": {
95
+ "import": "./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.js",
96
+ "types": "./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.d.ts"
97
+ },
98
+ "./node_modules/typescript/lib/lib.es2016.array.include.d.ts": {
99
+ "import": "./node_modules/typescript/lib/lib.es2016.array.include.d.js",
100
+ "types": "./node_modules/typescript/lib/lib.es2016.array.include.d.d.ts"
101
+ },
102
+ "./node_modules/typescript/lib/lib.es2016.d.ts": {
103
+ "import": "./node_modules/typescript/lib/lib.es2016.d.js",
104
+ "types": "./node_modules/typescript/lib/lib.es2016.d.d.ts"
105
+ },
106
+ "./node_modules/typescript/lib/lib.es2016.full.d.ts": {
107
+ "import": "./node_modules/typescript/lib/lib.es2016.full.d.js",
108
+ "types": "./node_modules/typescript/lib/lib.es2016.full.d.d.ts"
109
+ },
110
+ "./node_modules/typescript/lib/lib.es2016.intl.d.ts": {
111
+ "import": "./node_modules/typescript/lib/lib.es2016.intl.d.js",
112
+ "types": "./node_modules/typescript/lib/lib.es2016.intl.d.d.ts"
113
+ },
114
+ "./node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts": {
115
+ "import": "./node_modules/typescript/lib/lib.es2017.arraybuffer.d.js",
116
+ "types": "./node_modules/typescript/lib/lib.es2017.arraybuffer.d.d.ts"
117
+ },
118
+ "./node_modules/typescript/lib/lib.es2017.d.ts": {
119
+ "import": "./node_modules/typescript/lib/lib.es2017.d.js",
120
+ "types": "./node_modules/typescript/lib/lib.es2017.d.d.ts"
121
+ },
122
+ "./node_modules/typescript/lib/lib.es2017.date.d.ts": {
123
+ "import": "./node_modules/typescript/lib/lib.es2017.date.d.js",
124
+ "types": "./node_modules/typescript/lib/lib.es2017.date.d.d.ts"
125
+ },
126
+ "./node_modules/typescript/lib/lib.es2017.full.d.ts": {
127
+ "import": "./node_modules/typescript/lib/lib.es2017.full.d.js",
128
+ "types": "./node_modules/typescript/lib/lib.es2017.full.d.d.ts"
129
+ },
130
+ "./node_modules/typescript/lib/lib.es2017.intl.d.ts": {
131
+ "import": "./node_modules/typescript/lib/lib.es2017.intl.d.js",
132
+ "types": "./node_modules/typescript/lib/lib.es2017.intl.d.d.ts"
133
+ },
134
+ "./node_modules/typescript/lib/lib.es2017.object.d.ts": {
135
+ "import": "./node_modules/typescript/lib/lib.es2017.object.d.js",
136
+ "types": "./node_modules/typescript/lib/lib.es2017.object.d.d.ts"
137
+ },
138
+ "./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts": {
139
+ "import": "./node_modules/typescript/lib/lib.es2017.sharedmemory.d.js",
140
+ "types": "./node_modules/typescript/lib/lib.es2017.sharedmemory.d.d.ts"
141
+ },
142
+ "./node_modules/typescript/lib/lib.es2017.string.d.ts": {
143
+ "import": "./node_modules/typescript/lib/lib.es2017.string.d.js",
144
+ "types": "./node_modules/typescript/lib/lib.es2017.string.d.d.ts"
145
+ },
146
+ "./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts": {
147
+ "import": "./node_modules/typescript/lib/lib.es2017.typedarrays.d.js",
148
+ "types": "./node_modules/typescript/lib/lib.es2017.typedarrays.d.d.ts"
149
+ },
150
+ "./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts": {
151
+ "import": "./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.js",
152
+ "types": "./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.d.ts"
153
+ },
154
+ "./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts": {
155
+ "import": "./node_modules/typescript/lib/lib.es2018.asynciterable.d.js",
156
+ "types": "./node_modules/typescript/lib/lib.es2018.asynciterable.d.d.ts"
157
+ },
158
+ "./node_modules/typescript/lib/lib.es2018.d.ts": {
159
+ "import": "./node_modules/typescript/lib/lib.es2018.d.js",
160
+ "types": "./node_modules/typescript/lib/lib.es2018.d.d.ts"
161
+ },
162
+ "./node_modules/typescript/lib/lib.es2018.full.d.ts": {
163
+ "import": "./node_modules/typescript/lib/lib.es2018.full.d.js",
164
+ "types": "./node_modules/typescript/lib/lib.es2018.full.d.d.ts"
165
+ },
166
+ "./node_modules/typescript/lib/lib.es2018.intl.d.ts": {
167
+ "import": "./node_modules/typescript/lib/lib.es2018.intl.d.js",
168
+ "types": "./node_modules/typescript/lib/lib.es2018.intl.d.d.ts"
169
+ },
170
+ "./node_modules/typescript/lib/lib.es2018.promise.d.ts": {
171
+ "import": "./node_modules/typescript/lib/lib.es2018.promise.d.js",
172
+ "types": "./node_modules/typescript/lib/lib.es2018.promise.d.d.ts"
173
+ },
174
+ "./node_modules/typescript/lib/lib.es2018.regexp.d.ts": {
175
+ "import": "./node_modules/typescript/lib/lib.es2018.regexp.d.js",
176
+ "types": "./node_modules/typescript/lib/lib.es2018.regexp.d.d.ts"
177
+ },
178
+ "./node_modules/typescript/lib/lib.es2019.array.d.ts": {
179
+ "import": "./node_modules/typescript/lib/lib.es2019.array.d.js",
180
+ "types": "./node_modules/typescript/lib/lib.es2019.array.d.d.ts"
181
+ },
182
+ "./node_modules/typescript/lib/lib.es2019.d.ts": {
183
+ "import": "./node_modules/typescript/lib/lib.es2019.d.js",
184
+ "types": "./node_modules/typescript/lib/lib.es2019.d.d.ts"
185
+ },
186
+ "./node_modules/typescript/lib/lib.es2019.full.d.ts": {
187
+ "import": "./node_modules/typescript/lib/lib.es2019.full.d.js",
188
+ "types": "./node_modules/typescript/lib/lib.es2019.full.d.d.ts"
189
+ },
190
+ "./node_modules/typescript/lib/lib.es2019.intl.d.ts": {
191
+ "import": "./node_modules/typescript/lib/lib.es2019.intl.d.js",
192
+ "types": "./node_modules/typescript/lib/lib.es2019.intl.d.d.ts"
193
+ },
194
+ "./node_modules/typescript/lib/lib.es2019.object.d.ts": {
195
+ "import": "./node_modules/typescript/lib/lib.es2019.object.d.js",
196
+ "types": "./node_modules/typescript/lib/lib.es2019.object.d.d.ts"
197
+ },
198
+ "./node_modules/typescript/lib/lib.es2019.string.d.ts": {
199
+ "import": "./node_modules/typescript/lib/lib.es2019.string.d.js",
200
+ "types": "./node_modules/typescript/lib/lib.es2019.string.d.d.ts"
201
+ },
202
+ "./node_modules/typescript/lib/lib.es2019.symbol.d.ts": {
203
+ "import": "./node_modules/typescript/lib/lib.es2019.symbol.d.js",
204
+ "types": "./node_modules/typescript/lib/lib.es2019.symbol.d.d.ts"
205
+ },
206
+ "./node_modules/typescript/lib/lib.es2020.bigint.d.ts": {
207
+ "import": "./node_modules/typescript/lib/lib.es2020.bigint.d.js",
208
+ "types": "./node_modules/typescript/lib/lib.es2020.bigint.d.d.ts"
209
+ },
210
+ "./node_modules/typescript/lib/lib.es2020.d.ts": {
211
+ "import": "./node_modules/typescript/lib/lib.es2020.d.js",
212
+ "types": "./node_modules/typescript/lib/lib.es2020.d.d.ts"
213
+ },
214
+ "./node_modules/typescript/lib/lib.es2020.date.d.ts": {
215
+ "import": "./node_modules/typescript/lib/lib.es2020.date.d.js",
216
+ "types": "./node_modules/typescript/lib/lib.es2020.date.d.d.ts"
217
+ },
218
+ "./node_modules/typescript/lib/lib.es2020.full.d.ts": {
219
+ "import": "./node_modules/typescript/lib/lib.es2020.full.d.js",
220
+ "types": "./node_modules/typescript/lib/lib.es2020.full.d.d.ts"
221
+ },
222
+ "./node_modules/typescript/lib/lib.es2020.intl.d.ts": {
223
+ "import": "./node_modules/typescript/lib/lib.es2020.intl.d.js",
224
+ "types": "./node_modules/typescript/lib/lib.es2020.intl.d.d.ts"
225
+ },
226
+ "./node_modules/typescript/lib/lib.es2020.number.d.ts": {
227
+ "import": "./node_modules/typescript/lib/lib.es2020.number.d.js",
228
+ "types": "./node_modules/typescript/lib/lib.es2020.number.d.d.ts"
229
+ },
230
+ "./node_modules/typescript/lib/lib.es2020.promise.d.ts": {
231
+ "import": "./node_modules/typescript/lib/lib.es2020.promise.d.js",
232
+ "types": "./node_modules/typescript/lib/lib.es2020.promise.d.d.ts"
233
+ },
234
+ "./node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts": {
235
+ "import": "./node_modules/typescript/lib/lib.es2020.sharedmemory.d.js",
236
+ "types": "./node_modules/typescript/lib/lib.es2020.sharedmemory.d.d.ts"
237
+ },
238
+ "./node_modules/typescript/lib/lib.es2020.string.d.ts": {
239
+ "import": "./node_modules/typescript/lib/lib.es2020.string.d.js",
240
+ "types": "./node_modules/typescript/lib/lib.es2020.string.d.d.ts"
241
+ },
242
+ "./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts": {
243
+ "import": "./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.js",
244
+ "types": "./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.d.ts"
245
+ },
246
+ "./node_modules/typescript/lib/lib.es2021.d.ts": {
247
+ "import": "./node_modules/typescript/lib/lib.es2021.d.js",
248
+ "types": "./node_modules/typescript/lib/lib.es2021.d.d.ts"
249
+ },
250
+ "./node_modules/typescript/lib/lib.es2021.full.d.ts": {
251
+ "import": "./node_modules/typescript/lib/lib.es2021.full.d.js",
252
+ "types": "./node_modules/typescript/lib/lib.es2021.full.d.d.ts"
253
+ },
254
+ "./node_modules/typescript/lib/lib.es2021.intl.d.ts": {
255
+ "import": "./node_modules/typescript/lib/lib.es2021.intl.d.js",
256
+ "types": "./node_modules/typescript/lib/lib.es2021.intl.d.d.ts"
257
+ },
258
+ "./node_modules/typescript/lib/lib.es2021.promise.d.ts": {
259
+ "import": "./node_modules/typescript/lib/lib.es2021.promise.d.js",
260
+ "types": "./node_modules/typescript/lib/lib.es2021.promise.d.d.ts"
261
+ },
262
+ "./node_modules/typescript/lib/lib.es2021.string.d.ts": {
263
+ "import": "./node_modules/typescript/lib/lib.es2021.string.d.js",
264
+ "types": "./node_modules/typescript/lib/lib.es2021.string.d.d.ts"
265
+ },
266
+ "./node_modules/typescript/lib/lib.es2021.weakref.d.ts": {
267
+ "import": "./node_modules/typescript/lib/lib.es2021.weakref.d.js",
268
+ "types": "./node_modules/typescript/lib/lib.es2021.weakref.d.d.ts"
269
+ },
270
+ "./node_modules/typescript/lib/lib.es2022.array.d.ts": {
271
+ "import": "./node_modules/typescript/lib/lib.es2022.array.d.js",
272
+ "types": "./node_modules/typescript/lib/lib.es2022.array.d.d.ts"
273
+ },
274
+ "./node_modules/typescript/lib/lib.es2022.d.ts": {
275
+ "import": "./node_modules/typescript/lib/lib.es2022.d.js",
276
+ "types": "./node_modules/typescript/lib/lib.es2022.d.d.ts"
277
+ },
278
+ "./node_modules/typescript/lib/lib.es2022.error.d.ts": {
279
+ "import": "./node_modules/typescript/lib/lib.es2022.error.d.js",
280
+ "types": "./node_modules/typescript/lib/lib.es2022.error.d.d.ts"
281
+ },
282
+ "./node_modules/typescript/lib/lib.es2022.full.d.ts": {
283
+ "import": "./node_modules/typescript/lib/lib.es2022.full.d.js",
284
+ "types": "./node_modules/typescript/lib/lib.es2022.full.d.d.ts"
285
+ },
286
+ "./node_modules/typescript/lib/lib.es2022.intl.d.ts": {
287
+ "import": "./node_modules/typescript/lib/lib.es2022.intl.d.js",
288
+ "types": "./node_modules/typescript/lib/lib.es2022.intl.d.d.ts"
289
+ },
290
+ "./node_modules/typescript/lib/lib.es2022.object.d.ts": {
291
+ "import": "./node_modules/typescript/lib/lib.es2022.object.d.js",
292
+ "types": "./node_modules/typescript/lib/lib.es2022.object.d.d.ts"
293
+ },
294
+ "./node_modules/typescript/lib/lib.es2022.regexp.d.ts": {
295
+ "import": "./node_modules/typescript/lib/lib.es2022.regexp.d.js",
296
+ "types": "./node_modules/typescript/lib/lib.es2022.regexp.d.d.ts"
297
+ },
298
+ "./node_modules/typescript/lib/lib.es2022.string.d.ts": {
299
+ "import": "./node_modules/typescript/lib/lib.es2022.string.d.js",
300
+ "types": "./node_modules/typescript/lib/lib.es2022.string.d.d.ts"
301
+ },
302
+ "./node_modules/typescript/lib/lib.es2023.array.d.ts": {
303
+ "import": "./node_modules/typescript/lib/lib.es2023.array.d.js",
304
+ "types": "./node_modules/typescript/lib/lib.es2023.array.d.d.ts"
305
+ },
306
+ "./node_modules/typescript/lib/lib.es2023.collection.d.ts": {
307
+ "import": "./node_modules/typescript/lib/lib.es2023.collection.d.js",
308
+ "types": "./node_modules/typescript/lib/lib.es2023.collection.d.d.ts"
309
+ },
310
+ "./node_modules/typescript/lib/lib.es2023.d.ts": {
311
+ "import": "./node_modules/typescript/lib/lib.es2023.d.js",
312
+ "types": "./node_modules/typescript/lib/lib.es2023.d.d.ts"
313
+ },
314
+ "./node_modules/typescript/lib/lib.es2023.full.d.ts": {
315
+ "import": "./node_modules/typescript/lib/lib.es2023.full.d.js",
316
+ "types": "./node_modules/typescript/lib/lib.es2023.full.d.d.ts"
317
+ },
318
+ "./node_modules/typescript/lib/lib.es2023.intl.d.ts": {
319
+ "import": "./node_modules/typescript/lib/lib.es2023.intl.d.js",
320
+ "types": "./node_modules/typescript/lib/lib.es2023.intl.d.d.ts"
321
+ },
322
+ "./node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts": {
323
+ "import": "./node_modules/typescript/lib/lib.es2024.arraybuffer.d.js",
324
+ "types": "./node_modules/typescript/lib/lib.es2024.arraybuffer.d.d.ts"
325
+ },
326
+ "./node_modules/typescript/lib/lib.es2024.collection.d.ts": {
327
+ "import": "./node_modules/typescript/lib/lib.es2024.collection.d.js",
328
+ "types": "./node_modules/typescript/lib/lib.es2024.collection.d.d.ts"
329
+ },
330
+ "./node_modules/typescript/lib/lib.es2024.d.ts": {
331
+ "import": "./node_modules/typescript/lib/lib.es2024.d.js",
332
+ "types": "./node_modules/typescript/lib/lib.es2024.d.d.ts"
333
+ },
334
+ "./node_modules/typescript/lib/lib.es2024.full.d.ts": {
335
+ "import": "./node_modules/typescript/lib/lib.es2024.full.d.js",
336
+ "types": "./node_modules/typescript/lib/lib.es2024.full.d.d.ts"
337
+ },
338
+ "./node_modules/typescript/lib/lib.es2024.object.d.ts": {
339
+ "import": "./node_modules/typescript/lib/lib.es2024.object.d.js",
340
+ "types": "./node_modules/typescript/lib/lib.es2024.object.d.d.ts"
341
+ },
342
+ "./node_modules/typescript/lib/lib.es2024.promise.d.ts": {
343
+ "import": "./node_modules/typescript/lib/lib.es2024.promise.d.js",
344
+ "types": "./node_modules/typescript/lib/lib.es2024.promise.d.d.ts"
345
+ },
346
+ "./node_modules/typescript/lib/lib.es2024.regexp.d.ts": {
347
+ "import": "./node_modules/typescript/lib/lib.es2024.regexp.d.js",
348
+ "types": "./node_modules/typescript/lib/lib.es2024.regexp.d.d.ts"
349
+ },
350
+ "./node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts": {
351
+ "import": "./node_modules/typescript/lib/lib.es2024.sharedmemory.d.js",
352
+ "types": "./node_modules/typescript/lib/lib.es2024.sharedmemory.d.d.ts"
353
+ },
354
+ "./node_modules/typescript/lib/lib.es2024.string.d.ts": {
355
+ "import": "./node_modules/typescript/lib/lib.es2024.string.d.js",
356
+ "types": "./node_modules/typescript/lib/lib.es2024.string.d.d.ts"
357
+ },
358
+ "./node_modules/typescript/lib/lib.es5.d.ts": {
359
+ "import": "./node_modules/typescript/lib/lib.es5.d.js",
360
+ "types": "./node_modules/typescript/lib/lib.es5.d.d.ts"
361
+ },
362
+ "./node_modules/typescript/lib/lib.es6.d.ts": {
363
+ "import": "./node_modules/typescript/lib/lib.es6.d.js",
364
+ "types": "./node_modules/typescript/lib/lib.es6.d.d.ts"
365
+ },
366
+ "./node_modules/typescript/lib/lib.esnext.array.d.ts": {
367
+ "import": "./node_modules/typescript/lib/lib.esnext.array.d.js",
368
+ "types": "./node_modules/typescript/lib/lib.esnext.array.d.d.ts"
369
+ },
370
+ "./node_modules/typescript/lib/lib.esnext.collection.d.ts": {
371
+ "import": "./node_modules/typescript/lib/lib.esnext.collection.d.js",
372
+ "types": "./node_modules/typescript/lib/lib.esnext.collection.d.d.ts"
373
+ },
374
+ "./node_modules/typescript/lib/lib.esnext.d.ts": {
375
+ "import": "./node_modules/typescript/lib/lib.esnext.d.js",
376
+ "types": "./node_modules/typescript/lib/lib.esnext.d.d.ts"
377
+ },
378
+ "./node_modules/typescript/lib/lib.esnext.decorators.d.ts": {
379
+ "import": "./node_modules/typescript/lib/lib.esnext.decorators.d.js",
380
+ "types": "./node_modules/typescript/lib/lib.esnext.decorators.d.d.ts"
381
+ },
382
+ "./node_modules/typescript/lib/lib.esnext.disposable.d.ts": {
383
+ "import": "./node_modules/typescript/lib/lib.esnext.disposable.d.js",
384
+ "types": "./node_modules/typescript/lib/lib.esnext.disposable.d.d.ts"
385
+ },
386
+ "./node_modules/typescript/lib/lib.esnext.error.d.ts": {
387
+ "import": "./node_modules/typescript/lib/lib.esnext.error.d.js",
388
+ "types": "./node_modules/typescript/lib/lib.esnext.error.d.d.ts"
389
+ },
390
+ "./node_modules/typescript/lib/lib.esnext.float16.d.ts": {
391
+ "import": "./node_modules/typescript/lib/lib.esnext.float16.d.js",
392
+ "types": "./node_modules/typescript/lib/lib.esnext.float16.d.d.ts"
393
+ },
394
+ "./node_modules/typescript/lib/lib.esnext.full.d.ts": {
395
+ "import": "./node_modules/typescript/lib/lib.esnext.full.d.js",
396
+ "types": "./node_modules/typescript/lib/lib.esnext.full.d.d.ts"
397
+ },
398
+ "./node_modules/typescript/lib/lib.esnext.intl.d.ts": {
399
+ "import": "./node_modules/typescript/lib/lib.esnext.intl.d.js",
400
+ "types": "./node_modules/typescript/lib/lib.esnext.intl.d.d.ts"
401
+ },
402
+ "./node_modules/typescript/lib/lib.esnext.iterator.d.ts": {
403
+ "import": "./node_modules/typescript/lib/lib.esnext.iterator.d.js",
404
+ "types": "./node_modules/typescript/lib/lib.esnext.iterator.d.d.ts"
405
+ },
406
+ "./node_modules/typescript/lib/lib.esnext.promise.d.ts": {
407
+ "import": "./node_modules/typescript/lib/lib.esnext.promise.d.js",
408
+ "types": "./node_modules/typescript/lib/lib.esnext.promise.d.d.ts"
409
+ },
410
+ "./node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts": {
411
+ "import": "./node_modules/typescript/lib/lib.esnext.sharedmemory.d.js",
412
+ "types": "./node_modules/typescript/lib/lib.esnext.sharedmemory.d.d.ts"
413
+ },
414
+ "./node_modules/typescript/lib/lib.scripthost.d.ts": {
415
+ "import": "./node_modules/typescript/lib/lib.scripthost.d.js",
416
+ "types": "./node_modules/typescript/lib/lib.scripthost.d.d.ts"
417
+ },
418
+ "./node_modules/typescript/lib/lib.webworker.asynciterable.d.ts": {
419
+ "import": "./node_modules/typescript/lib/lib.webworker.asynciterable.d.js",
420
+ "types": "./node_modules/typescript/lib/lib.webworker.asynciterable.d.d.ts"
421
+ },
422
+ "./node_modules/typescript/lib/lib.webworker.d.ts": {
423
+ "import": "./node_modules/typescript/lib/lib.webworker.d.js",
424
+ "types": "./node_modules/typescript/lib/lib.webworker.d.d.ts"
425
+ },
426
+ "./node_modules/typescript/lib/lib.webworker.importscripts.d.ts": {
427
+ "import": "./node_modules/typescript/lib/lib.webworker.importscripts.d.js",
428
+ "types": "./node_modules/typescript/lib/lib.webworker.importscripts.d.d.ts"
429
+ },
430
+ "./node_modules/typescript/lib/lib.webworker.iterable.d.ts": {
431
+ "import": "./node_modules/typescript/lib/lib.webworker.iterable.d.js",
432
+ "types": "./node_modules/typescript/lib/lib.webworker.iterable.d.d.ts"
433
+ },
434
+ "./node_modules/typescript/lib/tsserverlibrary.d.ts": {
435
+ "import": "./node_modules/typescript/lib/tsserverlibrary.d.js",
436
+ "types": "./node_modules/typescript/lib/tsserverlibrary.d.d.ts"
437
+ },
438
+ "./node_modules/typescript/lib/typescript.d.ts": {
439
+ "import": "./node_modules/typescript/lib/typescript.d.js",
440
+ "types": "./node_modules/typescript/lib/typescript.d.d.ts"
441
+ },
442
+ "./service.test.ts": {
443
+ "import": "./service.test.js",
444
+ "types": "./service.test.d.ts"
445
+ },
446
+ "./service.ts": {
447
+ "import": "./service.js",
448
+ "types": "./service.d.ts"
449
+ },
450
+ "./type.ts": {
451
+ "import": "./type.js",
452
+ "types": "./type.d.ts"
453
+ }
454
+ }
455
+ }
package/service.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ import type { EventBroker, EventBrokerBackend } from './type.ts';
2
+ export declare const createBroker: <PAYLOADS extends Record<string, unknown>>(brokerBackend: EventBrokerBackend) => EventBroker<PAYLOADS>;
package/service.js ADDED
@@ -0,0 +1,8 @@
1
+ export const createBroker = (brokerBackend) => ({
2
+ dispatch: (event, args) => {
3
+ brokerBackend.dispatch(event, args);
4
+ },
5
+ on: (event, handler) => {
6
+ brokerBackend.on(event, handler);
7
+ },
8
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,72 @@
1
+ import { createEventEmitterBackend } from './event-emitter.js';
2
+ import { createBroker } from './service.js';
3
+ import { expect, expectTypeOf, test } from 'vitest';
4
+ test('a handler receives the payload dispatched for its event', () => {
5
+ const broker = createBroker(createEventEmitterBackend());
6
+ const received = [];
7
+ broker.on('greeted', (args) => {
8
+ received.push(args);
9
+ });
10
+ broker.dispatch('greeted', { name: 'Ada' });
11
+ expect(received).toEqual([{ name: 'Ada' }]);
12
+ });
13
+ test('a handler is left alone when a different event is dispatched', () => {
14
+ const broker = createBroker(createEventEmitterBackend());
15
+ const received = [];
16
+ broker.on('counted', (args) => {
17
+ received.push(args);
18
+ });
19
+ broker.dispatch('greeted', { name: 'Ada' });
20
+ expect(received).toEqual([]);
21
+ });
22
+ test('every handler registered for an event receives it', () => {
23
+ const broker = createBroker(createEventEmitterBackend());
24
+ const first = [];
25
+ const second = [];
26
+ broker.on('counted', (args) => {
27
+ first.push(args);
28
+ });
29
+ broker.on('counted', (args) => {
30
+ second.push(args);
31
+ });
32
+ broker.dispatch('counted', 7);
33
+ expect([first, second]).toEqual([[7], [7]]);
34
+ });
35
+ test('a handler receives each dispatch in turn', () => {
36
+ const broker = createBroker(createEventEmitterBackend());
37
+ const received = [];
38
+ broker.on('counted', (args) => {
39
+ received.push(args);
40
+ });
41
+ broker.dispatch('counted', 1);
42
+ broker.dispatch('counted', 2);
43
+ expect(received).toEqual([1, 2]);
44
+ });
45
+ test('dispatching an event nobody listens for is not an error', () => {
46
+ const broker = createBroker(createEventEmitterBackend());
47
+ expect(() => broker.dispatch('counted', 7)).not.toThrow();
48
+ });
49
+ test('the handler payload is typed from the event it is registered for', () => {
50
+ const broker = createBroker(createEventEmitterBackend());
51
+ broker.on('greeted', (args) => {
52
+ expectTypeOf(args).toEqualTypeOf();
53
+ });
54
+ broker.on('counted', (args) => {
55
+ expectTypeOf(args).toEqualTypeOf();
56
+ });
57
+ });
58
+ test('dispatch rejects a payload that belongs to a different event', () => {
59
+ const broker = createBroker(createEventEmitterBackend());
60
+ // @ts-expect-error the 'greeted' payload is an object, so a number is never valid for it
61
+ broker.dispatch('greeted', 7);
62
+ });
63
+ test('dispatch rejects an event the payload map does not declare', () => {
64
+ const broker = createBroker(createEventEmitterBackend());
65
+ // @ts-expect-error 'shouted' is not one of the declared events
66
+ broker.dispatch('shouted', { name: 'Ada' });
67
+ });
68
+ test('on rejects an event the payload map does not declare', () => {
69
+ const broker = createBroker(createEventEmitterBackend());
70
+ // @ts-expect-error 'shouted' is not one of the declared events
71
+ broker.on('shouted', () => undefined);
72
+ });
package/type.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ export type EventBrokerBackend = {
2
+ on: <PAYLOAD>(event: string, handler: (args: PAYLOAD) => void) => void;
3
+ dispatch: <PAYLOAD>(event: string, args: PAYLOAD) => void;
4
+ };
5
+ export type EventBroker<PAYLOADS extends Record<string, unknown>> = {
6
+ on: <TYPE extends keyof PAYLOADS & string>(event: TYPE, handler: (args: PAYLOADS[TYPE]) => void) => void;
7
+ dispatch: <TYPE extends keyof PAYLOADS & string>(event: TYPE, args: PAYLOADS[TYPE]) => void;
8
+ };
package/type.js ADDED
@@ -0,0 +1 @@
1
+ export {};