comes 0.0.2 → 0.0.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.
- package/CLAUDE.md +35 -0
- package/README.md +269 -0
- package/build/index.d.ts +46 -12
- package/build/index.js +72 -16
- package/nul +2 -0
- package/package.json +1 -1
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
**comes** is a TypeScript event system library for simple pub/sub communication. It provides an `EventSystem` class with address-based events, lazy loaders, and interceptors.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
- **Build:** `npm run build` (cleans `build/` then runs `tsc`)
|
|
12
|
+
- **Test:** `npm test` (runs vitest with coverage enabled by default)
|
|
13
|
+
- **Run single test:** `npx vitest run -t "Test name"` or `npx vitest run test/simple-emit.test.ts`
|
|
14
|
+
|
|
15
|
+
## Architecture
|
|
16
|
+
|
|
17
|
+
Single-file library (`src/index.ts`) exporting:
|
|
18
|
+
|
|
19
|
+
- **`EventSystem`** class — the core. Manages a `data` map (keyed by string "address") where each address holds an `ES_ValueType` containing the last value, listeners array, optional loader, and loader error handler.
|
|
20
|
+
- **`es`** — a default singleton `EventSystem` instance exported for convenience.
|
|
21
|
+
|
|
22
|
+
Key concepts:
|
|
23
|
+
- **Addresses** are string keys identifying event channels.
|
|
24
|
+
- **`send(id, event)`** — async; runs interceptors (chain of responsibility), then notifies all listeners. Both interceptors and listeners are awaited sequentially.
|
|
25
|
+
- **`listen(id, listener)`** — registers a listener. If a value was already sent (has a `date`), the listener is immediately called with the cached `last` value. If no value exists but a loader is configured, the loader is triggered. Returns an unregister function.
|
|
26
|
+
- **Interceptors** (`addInter`) — transform/validate events before they reach listeners. The empty string `""` address matches all events. Throwing in an interceptor stops the chain and prevents listener notification.
|
|
27
|
+
- **Loaders** (`setLoader`) — lazy data fetchers invoked when the first listener registers on an address that has no value yet. `loaderCatch` handles loader errors and can optionally return a fallback value.
|
|
28
|
+
|
|
29
|
+
## Build Output
|
|
30
|
+
|
|
31
|
+
TypeScript compiles from `src/` to `build/` (ES2017, Node16 modules). Declarations (`.d.ts`) are generated. Entry point: `build/index.js`.
|
|
32
|
+
|
|
33
|
+
## Test Structure
|
|
34
|
+
|
|
35
|
+
Tests are in `test/` using vitest. A single test file (`test/simple-emit.test.ts`) covers: send/get, listen before/after emit, unregistering, listener errors, loader lifecycle (with/without error handlers), and interceptor chains.
|
package/README.md
CHANGED
|
@@ -1,3 +1,272 @@
|
|
|
1
1
|
# comes - Communication Event System
|
|
2
2
|
|
|
3
|
+
A simple, lightweight event system for TypeScript/JavaScript applications. It provides address-based pub/sub communication with built-in value caching, lazy loaders, and interceptors.
|
|
3
4
|
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install comes
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { es } from 'comes';
|
|
15
|
+
|
|
16
|
+
// Send a value to an address
|
|
17
|
+
await es.send('user/name', 'Alice');
|
|
18
|
+
|
|
19
|
+
// Listen for values on an address
|
|
20
|
+
const unregister = es.listen('user/name', (value) => {
|
|
21
|
+
console.log(value); // "Alice" (immediately, from cache)
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Stop listening
|
|
25
|
+
unregister();
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Core Concepts
|
|
29
|
+
|
|
30
|
+
- **Address**: A string key that identifies an event channel (e.g. `'user/name'`, `'app/status'`).
|
|
31
|
+
- **Value caching**: The last value sent to each address is cached. When a new listener registers, it immediately receives the cached value.
|
|
32
|
+
- **Interceptors**: Middleware functions that can transform, validate, or monitor values before they reach listeners.
|
|
33
|
+
- **Loaders**: Lazy data fetchers that run automatically when the first listener registers on an address that has no value yet.
|
|
34
|
+
|
|
35
|
+
## API
|
|
36
|
+
|
|
37
|
+
### Importing
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
// Use the default singleton instance
|
|
41
|
+
import { es } from 'comes';
|
|
42
|
+
|
|
43
|
+
// Or create your own isolated instance
|
|
44
|
+
import { EventSystem } from 'comes';
|
|
45
|
+
const es = new EventSystem();
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
### `send<T>(id: string, event: T): Promise<T>`
|
|
51
|
+
|
|
52
|
+
Sends a value to all listeners of the given address. Interceptors are executed first (in order), then each listener is called with the resulting value. The final value (after interceptors) is cached.
|
|
53
|
+
|
|
54
|
+
Returns the value after interceptor transformations.
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
await es.send('counter', 1);
|
|
58
|
+
await es.send('user/profile', { name: 'Alice', age: 30 });
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
If an interceptor or listener throws an error, `send` will throw that error.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
### `listen(id: string, listener: EventListenerType): () => void`
|
|
66
|
+
|
|
67
|
+
Registers a listener on the given address. Returns an **unregister function** to remove the listener later.
|
|
68
|
+
|
|
69
|
+
**Behavior on registration:**
|
|
70
|
+
- If a value was already sent to this address, the listener is **immediately called** with the cached value.
|
|
71
|
+
- If no value exists but a **loader** is configured, the loader is triggered to fetch the initial value.
|
|
72
|
+
- If neither exists, the listener simply waits for the next `send`.
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
// Basic usage
|
|
76
|
+
const unregister = es.listen('counter', (value) => {
|
|
77
|
+
console.log('Counter:', value);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Later, stop listening
|
|
81
|
+
unregister();
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
### `unlisten(id: string, listener: EventListenerType): void`
|
|
87
|
+
|
|
88
|
+
Removes a specific listener from the given address. This is useful when you need to unregister **inside** the listener itself, where the unregister function returned by `listen` may not be assigned yet.
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
const listener = (value: string) => {
|
|
92
|
+
es.unlisten('my-event', listener); // safe to call here
|
|
93
|
+
console.log('Received once:', value);
|
|
94
|
+
};
|
|
95
|
+
es.listen('my-event', listener);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
### `get(id: string): ES_ValueType`
|
|
101
|
+
|
|
102
|
+
Returns a reference to the internal state object for the given address. Useful for inspecting the current cached value, the listener list, or the loader state.
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
await es.send('status', 'online');
|
|
106
|
+
|
|
107
|
+
const data = es.get('status');
|
|
108
|
+
console.log(data.last); // "online"
|
|
109
|
+
console.log(data.date); // Date when last value was sent
|
|
110
|
+
console.log(data.listeners); // Array of registered listeners
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**`ES_ValueType` fields:**
|
|
114
|
+
|
|
115
|
+
| Field | Type | Description |
|
|
116
|
+
|---|---|---|
|
|
117
|
+
| `last` | `any` | The last value sent to this address |
|
|
118
|
+
| `listeners` | `EventListenerType[]` | Array of registered listeners |
|
|
119
|
+
| `date` | `Date \| undefined` | Timestamp of the last `send`. `undefined` means no value was sent yet |
|
|
120
|
+
| `loader` | `Function \| undefined` | The loader function, if configured |
|
|
121
|
+
| `loaderCatch` | `Function \| undefined` | The loader error handler, if configured |
|
|
122
|
+
| `loaderProm` | `Promise \| undefined` | The loader promise, while the loader is running |
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
### `addInter(id: string, interceptor: EventInterceptorType): () => void`
|
|
127
|
+
|
|
128
|
+
Adds an interceptor for the given address. Interceptors are called **before** listeners, in the order they were added. Each interceptor receives the value, can transform it, and must return the (possibly modified) value for the next interceptor in the chain.
|
|
129
|
+
|
|
130
|
+
Returns an **unregister function** to remove the interceptor.
|
|
131
|
+
|
|
132
|
+
**Special address `""`:** An interceptor registered with an empty string `""` as the address is called for **every** event on the `EventSystem`, regardless of address.
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
// Transform values before listeners receive them
|
|
136
|
+
es.addInter('counter', async (id, event, es) => {
|
|
137
|
+
return event * 2; // double the value
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
es.listen('counter', (value) => {
|
|
141
|
+
console.log(value); // 20
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
await es.send('counter', 10);
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Interceptor chain:**
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
es.addInter('price', async (id, event, es) => {
|
|
151
|
+
return event + 1; // first: add 1
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
es.addInter('price', async (id, event, es) => {
|
|
155
|
+
return event * 10; // second: multiply by 10
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
await es.send('price', 5); // (5 + 1) * 10 = 60
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Global interceptor (logging example):**
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
es.addInter('', async (id, event, es) => {
|
|
165
|
+
console.log(`[${id}]`, event);
|
|
166
|
+
return event; // pass through unchanged
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
If an interceptor throws an error, the chain stops and listeners are **not** called.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
### `removeInter(id: string, interceptor: EventInterceptorType): void`
|
|
175
|
+
|
|
176
|
+
Removes a specific interceptor from the given address.
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
const interceptor = async (id: string, event: number, es: EventSystem) => {
|
|
180
|
+
return event + 1;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
es.addInter('counter', interceptor);
|
|
184
|
+
es.removeInter('counter', interceptor);
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
### `setLoader(id: string, loader, loaderCatch?): void`
|
|
190
|
+
|
|
191
|
+
Configures a **loader** function for the given address. The loader is a lazy data fetcher that runs automatically when:
|
|
192
|
+
|
|
193
|
+
1. The first listener registers on an address, **and**
|
|
194
|
+
2. No value has been sent to that address yet.
|
|
195
|
+
|
|
196
|
+
If a value was already sent before the first listener, the loader is **never** called.
|
|
197
|
+
|
|
198
|
+
The loader function receives the address `id` as the first argument, and should call `es.send(id, value)` to deliver the loaded value.
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
es.setLoader('user/profile', async (id) => {
|
|
202
|
+
const response = await fetch('/api/profile');
|
|
203
|
+
const data = await response.json();
|
|
204
|
+
es.send(id, data);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// The loader runs automatically when the first listener registers
|
|
208
|
+
es.listen('user/profile', (profile) => {
|
|
209
|
+
console.log(profile); // data from API
|
|
210
|
+
});
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**With error handler (`loaderCatch`):**
|
|
214
|
+
|
|
215
|
+
The optional third argument is an error handler invoked when the loader throws. It has three possible behaviors:
|
|
216
|
+
|
|
217
|
+
- **Return a value**: The loader resolves successfully with that value (sent to listeners).
|
|
218
|
+
- **Return `undefined`** (or no return): The loader rejects with the original error.
|
|
219
|
+
- **Throw a new error**: The loader rejects with the new error, and the original error is attached as `error.loaderEx`.
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
es.setLoader(
|
|
223
|
+
'user/profile',
|
|
224
|
+
async (id) => {
|
|
225
|
+
throw new Error('Network error');
|
|
226
|
+
},
|
|
227
|
+
async (id, error) => {
|
|
228
|
+
console.warn('Loader failed:', error.message);
|
|
229
|
+
return { name: 'Guest' }; // fallback value sent to listeners
|
|
230
|
+
}
|
|
231
|
+
);
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
### `setLoaderCatch(id: string, loaderCatch): void`
|
|
237
|
+
|
|
238
|
+
Sets (or replaces) the error handler for the loader of a given address, independently from `setLoader`.
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
es.setLoaderCatch('user/profile', async (id, error) => {
|
|
242
|
+
return { name: 'Default' }; // fallback value
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
### `load<T>(id: string, ...args: any[]): Promise<T>`
|
|
249
|
+
|
|
250
|
+
Manually triggers the loader for the given address. Extra arguments are forwarded to the loader function.
|
|
251
|
+
|
|
252
|
+
If no loader is configured, returns the current cached value immediately.
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
es.setLoader('data', async (id, page, limit) => {
|
|
256
|
+
const res = await fetch(`/api/data?page=${page}&limit=${limit}`);
|
|
257
|
+
es.send(id, await res.json());
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// Manually trigger with parameters
|
|
261
|
+
await es.load('data', 1, 20);
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Types
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
// Listener function signature
|
|
268
|
+
type EventListenerType<T = any> = (event: T) => void;
|
|
269
|
+
|
|
270
|
+
// Interceptor function signature
|
|
271
|
+
type EventInterceptorType<T = any> = (id: string, event: T, es: EventSystem) => T;
|
|
272
|
+
```
|
package/build/index.d.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* @param item Item that will be removed
|
|
4
|
-
* @param list Array where to find the item
|
|
5
|
-
*/
|
|
6
|
-
export declare function deleteFromArray(item: any, list: any[]): void;
|
|
1
|
+
export type EventListenerType<T = any> = (event: T) => void;
|
|
2
|
+
export type EventInterceptorType<T = any> = (id: string, event: T, es: EventSystem) => T;
|
|
7
3
|
/**
|
|
8
4
|
* Type that holds the value for an event address.
|
|
9
5
|
*/
|
|
@@ -15,14 +11,14 @@ export type ES_ValueType = {
|
|
|
15
11
|
/**
|
|
16
12
|
* Listeners of this event.
|
|
17
13
|
*/
|
|
18
|
-
listeners:
|
|
14
|
+
listeners: EventListenerType[];
|
|
19
15
|
/**
|
|
20
16
|
* Last time an event was emitted.
|
|
21
17
|
*
|
|
22
18
|
* If this value is "null" or "undefined" so no event/value was emitted yet.
|
|
23
19
|
* In this case, the "last" field will be "null" or "undefined" also.
|
|
24
20
|
*/
|
|
25
|
-
date?:
|
|
21
|
+
date?: number;
|
|
26
22
|
/**
|
|
27
23
|
* Loader to run when the first listeners is registered and no event was
|
|
28
24
|
* emitted yet.
|
|
@@ -72,6 +68,19 @@ export declare class EventSystem {
|
|
|
72
68
|
data: {
|
|
73
69
|
[id: string]: ES_ValueType;
|
|
74
70
|
};
|
|
71
|
+
/**
|
|
72
|
+
* Interceptors to transform data.
|
|
73
|
+
* Interceptors are called in the installation order.
|
|
74
|
+
* The special empty string event address will be called for all events sent.
|
|
75
|
+
*
|
|
76
|
+
* The interceptors exists to transform, monitor, prepare or validate (or many other uses)
|
|
77
|
+
* the event sent to an address. The sequence of interceptors will be called like a
|
|
78
|
+
* "chain of responsibility" pattern, if any exception is thrown the following interceptors
|
|
79
|
+
* will not be executed, and the listeners not called.
|
|
80
|
+
*/
|
|
81
|
+
inters: {
|
|
82
|
+
[id: string]: EventInterceptorType[];
|
|
83
|
+
};
|
|
75
84
|
/**
|
|
76
85
|
* Gets a reference to {@link ES_ValueType} of the address informed.
|
|
77
86
|
* @param id The address name of the event
|
|
@@ -81,9 +90,8 @@ export declare class EventSystem {
|
|
|
81
90
|
* Sends the value to the listeners of the event address.
|
|
82
91
|
* @param id The address name of the event
|
|
83
92
|
* @param event The value to send to listeners
|
|
84
|
-
* @returns The value informed
|
|
85
93
|
*/
|
|
86
|
-
|
|
94
|
+
send<T>(id: string, event: T): Promise<T>;
|
|
87
95
|
/**
|
|
88
96
|
* Register a listener for the address.
|
|
89
97
|
* The listener will receive the last value emitted.
|
|
@@ -95,7 +103,7 @@ export declare class EventSystem {
|
|
|
95
103
|
* @param listener The listener, will be called every time a new value is emitted to this address
|
|
96
104
|
* @returns An unregister function. Use this function to remove the listener
|
|
97
105
|
*/
|
|
98
|
-
listen(id: string, listener:
|
|
106
|
+
listen(id: string, listener: EventListenerType): () => void;
|
|
99
107
|
/**
|
|
100
108
|
* Remove the listener from the list of this event address.
|
|
101
109
|
*
|
|
@@ -115,7 +123,33 @@ export declare class EventSystem {
|
|
|
115
123
|
* @param id The address name of the event
|
|
116
124
|
* @param listener Listener to remove
|
|
117
125
|
*/
|
|
118
|
-
unlisten(id: string, listener:
|
|
126
|
+
unlisten(id: string, listener: EventListenerType): void;
|
|
127
|
+
/**
|
|
128
|
+
* Add an interceptor to transform data.
|
|
129
|
+
* Interceptors are called in the installation order.
|
|
130
|
+
* The special empty string event address will be called for all events sent.
|
|
131
|
+
*
|
|
132
|
+
* The interceptors exists to transform, monitor, prepare or validate (or many other uses)
|
|
133
|
+
* the event sent to an address. The sequence of interceptors will be called like a
|
|
134
|
+
* "chain of responsibility" pattern, if any exception is thrown the following interceptors
|
|
135
|
+
* will not be executed, and the listeners not called.
|
|
136
|
+
*
|
|
137
|
+
* Interceptors will be executed synchronous in the call of the {@link send} method.
|
|
138
|
+
* So any exception thrown will be thrown also in the {@link send} call.
|
|
139
|
+
*
|
|
140
|
+
* @param id The address name of the event
|
|
141
|
+
* @param listener Interceptor to add
|
|
142
|
+
* @returns An unregister function. Use this function to remove the interceptor
|
|
143
|
+
*/
|
|
144
|
+
addInter(id: string, listener: EventInterceptorType): () => void;
|
|
145
|
+
/**
|
|
146
|
+
* Remove an interceptor.
|
|
147
|
+
*
|
|
148
|
+
* @param id The address name of the event
|
|
149
|
+
* @param listener Interceptor to add
|
|
150
|
+
* @returns An unregister function. Use this function to remove the interceptor
|
|
151
|
+
*/
|
|
152
|
+
removeInter(id: string, listener: EventInterceptorType): void;
|
|
119
153
|
/**
|
|
120
154
|
* Configure a {@link ES_ValueType.loader loader} to execute when the first listener is registered and no value exists yet.
|
|
121
155
|
*
|
package/build/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.es = exports.EventSystem = void 0;
|
|
4
|
-
exports.deleteFromArray = deleteFromArray;
|
|
5
4
|
// -------
|
|
6
5
|
/**
|
|
7
6
|
* Function to exclude an item from the array.
|
|
@@ -9,13 +8,9 @@ exports.deleteFromArray = deleteFromArray;
|
|
|
9
8
|
* @param list Array where to find the item
|
|
10
9
|
*/
|
|
11
10
|
function deleteFromArray(item, list) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
list.splice(i, 1);
|
|
16
|
-
break;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
11
|
+
const i = list.indexOf(item);
|
|
12
|
+
if (i !== -1)
|
|
13
|
+
list.splice(i, 1);
|
|
19
14
|
}
|
|
20
15
|
/**
|
|
21
16
|
* Class that creates the field through which communication will occur.
|
|
@@ -27,6 +22,17 @@ class EventSystem {
|
|
|
27
22
|
* holds the last value for the address.
|
|
28
23
|
*/
|
|
29
24
|
this.data = {};
|
|
25
|
+
/**
|
|
26
|
+
* Interceptors to transform data.
|
|
27
|
+
* Interceptors are called in the installation order.
|
|
28
|
+
* The special empty string event address will be called for all events sent.
|
|
29
|
+
*
|
|
30
|
+
* The interceptors exists to transform, monitor, prepare or validate (or many other uses)
|
|
31
|
+
* the event sent to an address. The sequence of interceptors will be called like a
|
|
32
|
+
* "chain of responsibility" pattern, if any exception is thrown the following interceptors
|
|
33
|
+
* will not be executed, and the listeners not called.
|
|
34
|
+
*/
|
|
35
|
+
this.inters = {};
|
|
30
36
|
}
|
|
31
37
|
/**
|
|
32
38
|
* Gets a reference to {@link ES_ValueType} of the address informed.
|
|
@@ -41,15 +47,32 @@ class EventSystem {
|
|
|
41
47
|
* Sends the value to the listeners of the event address.
|
|
42
48
|
* @param id The address name of the event
|
|
43
49
|
* @param event The value to send to listeners
|
|
44
|
-
* @returns The value informed
|
|
45
50
|
*/
|
|
46
|
-
|
|
51
|
+
async send(id, event) {
|
|
52
|
+
let inters = (this.inters[''] || []).concat(this.inters[id] || []);
|
|
53
|
+
let newValue = event;
|
|
54
|
+
try {
|
|
55
|
+
for (let inte of inters) {
|
|
56
|
+
newValue = await inte(id, newValue, this);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
console.error(`inter:${id}`, err);
|
|
61
|
+
throw err;
|
|
62
|
+
}
|
|
47
63
|
let esData = this.get(id);
|
|
48
|
-
esData.last =
|
|
49
|
-
esData.date =
|
|
50
|
-
for (let func of esData.listeners)
|
|
51
|
-
|
|
52
|
-
|
|
64
|
+
esData.last = newValue;
|
|
65
|
+
esData.date = Date.now();
|
|
66
|
+
for (let func of esData.listeners) {
|
|
67
|
+
try {
|
|
68
|
+
await func(newValue);
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
console.error(`listen:${id}`, err);
|
|
72
|
+
throw err;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return newValue;
|
|
53
76
|
}
|
|
54
77
|
/**
|
|
55
78
|
* Register a listener for the address.
|
|
@@ -94,6 +117,39 @@ class EventSystem {
|
|
|
94
117
|
let esData = this.get(id);
|
|
95
118
|
deleteFromArray(listener, esData.listeners);
|
|
96
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Add an interceptor to transform data.
|
|
122
|
+
* Interceptors are called in the installation order.
|
|
123
|
+
* The special empty string event address will be called for all events sent.
|
|
124
|
+
*
|
|
125
|
+
* The interceptors exists to transform, monitor, prepare or validate (or many other uses)
|
|
126
|
+
* the event sent to an address. The sequence of interceptors will be called like a
|
|
127
|
+
* "chain of responsibility" pattern, if any exception is thrown the following interceptors
|
|
128
|
+
* will not be executed, and the listeners not called.
|
|
129
|
+
*
|
|
130
|
+
* Interceptors will be executed synchronous in the call of the {@link send} method.
|
|
131
|
+
* So any exception thrown will be thrown also in the {@link send} call.
|
|
132
|
+
*
|
|
133
|
+
* @param id The address name of the event
|
|
134
|
+
* @param listener Interceptor to add
|
|
135
|
+
* @returns An unregister function. Use this function to remove the interceptor
|
|
136
|
+
*/
|
|
137
|
+
addInter(id, listener) {
|
|
138
|
+
if (!this.inters[id])
|
|
139
|
+
this.inters[id] = [];
|
|
140
|
+
this.inters[id].push(listener);
|
|
141
|
+
return () => this.removeInter(id, listener);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Remove an interceptor.
|
|
145
|
+
*
|
|
146
|
+
* @param id The address name of the event
|
|
147
|
+
* @param listener Interceptor to add
|
|
148
|
+
* @returns An unregister function. Use this function to remove the interceptor
|
|
149
|
+
*/
|
|
150
|
+
removeInter(id, listener) {
|
|
151
|
+
deleteFromArray(listener, this.inters[id]);
|
|
152
|
+
}
|
|
97
153
|
/**
|
|
98
154
|
* Configure a {@link ES_ValueType.loader loader} to execute when the first listener is registered and no value exists yet.
|
|
99
155
|
*
|
|
@@ -149,7 +205,7 @@ class EventSystem {
|
|
|
149
205
|
try {
|
|
150
206
|
const catchRes = await esData.loaderCatch(id, ex);
|
|
151
207
|
if (catchRes !== undefined) {
|
|
152
|
-
this.
|
|
208
|
+
this.send(id, catchRes);
|
|
153
209
|
res(catchRes);
|
|
154
210
|
}
|
|
155
211
|
}
|
package/nul
ADDED