fastevent 2.5.0 → 2.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fastevent",
3
- "version": "2.5.0",
3
+ "version": "2.5.1",
4
4
  "description": "The Ultimate Event Trigger Library – Fast, Feature-Rich, Battle-Tested!",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
package/readme.md CHANGED
@@ -55,7 +55,7 @@ events.onAny((message) => {
55
55
  Listener functions receive a `Message` object that contains the following properties:
56
56
 
57
57
  ```ts
58
- events.on('user/login', (message) => {
58
+ events.on("user/login", (message) => {
59
59
  // {
60
60
  // type: 'user/login', // Event name
61
61
  // payload: { id: 1 }, // Event data
@@ -72,13 +72,13 @@ Retain the last event data, so subsequent subscribers can immediately receive th
72
72
  const events = new FastEvent();
73
73
 
74
74
  // Publish and retain event
75
- events.emit('config/theme', { dark: true }, true);
75
+ events.emit("config/theme", { dark: true }, true);
76
76
  // Equivalent to
77
- events.emit('config/theme', { dark: true }, { retain: true });
77
+ events.emit("config/theme", { dark: true }, { retain: true });
78
78
 
79
79
  // Subsequent subscribers immediately receive the retained value
80
- events.on('config/theme', (message) => {
81
- console.log('Theme:', message.payload); // Immediately outputs: { dark: true }
80
+ events.on("config/theme", (message) => {
81
+ console.log("Theme:", message.payload); // Immediately outputs: { dark: true }
82
82
  });
83
83
  ```
84
84
 
@@ -86,25 +86,25 @@ events.on('config/theme', (message) => {
86
86
 
87
87
  `FastEvent` supports hierarchical event publishing and subscription.
88
88
 
89
- - The default event hierarchy delimiter is `/`, which can be modified via `options.delimiter`
90
- - Two types of wildcards are supported when subscribing to events: `*` matches a single path level, `**` matches multiple path levels (only used at the end of event names)
89
+ - The default event hierarchy delimiter is `/`, which can be modified via `options.delimiter`
90
+ - Two types of wildcards are supported when subscribing to events: `*` matches a single path level, `**` matches multiple path levels (only used at the end of event names)
91
91
 
92
92
  ```typescript
93
93
  const events = new FastEvent();
94
94
 
95
95
  // Match user/*/login
96
- events.on('user/*/login', (message) => {
97
- console.log('Any user type login:', message.payload);
96
+ events.on("user/*/login", (message) => {
97
+ console.log("Any user type login:", message.payload);
98
98
  });
99
99
 
100
100
  // Match all events under user
101
- events.on('user/**', (message) => {
102
- console.log('All user-related events:', message.payload);
101
+ events.on("user/**", (message) => {
102
+ console.log("All user-related events:", message.payload);
103
103
  });
104
104
 
105
105
  // Trigger events
106
- events.emit('user/admin/login', { id: 1 }); // Both handlers will be called
107
- events.emit('user/admin/profile/update', { name: 'New' }); // Only the ** handler will be called
106
+ events.emit("user/admin/login", { id: 1 }); // Both handlers will be called
107
+ events.emit("user/admin/profile/update", { name: "New" }); // Only the ** handler will be called
108
108
  ```
109
109
 
110
110
  ## Removing Listeners
@@ -113,21 +113,21 @@ events.emit('user/admin/profile/update', { name: 'New' }); // Only the ** handle
113
113
 
114
114
  ```typescript
115
115
  // Return a subscriber object to remove the listener, recommended approach
116
- const subscriber = events.on('user/login', handler);
116
+ const subscriber = events.on("user/login", handler);
117
117
  subscriber.off();
118
118
 
119
119
  // Remove a specific listener
120
120
  events.off(listener);
121
121
  // Remove all listeners for a specific event
122
- events.off('user/login');
122
+ events.off("user/login");
123
123
  // Remove a specific listener for a specific event
124
- events.off('user/login', listener);
124
+ events.off("user/login", listener);
125
125
  // Remove listeners using wildcard patterns
126
- events.off('user/*');
126
+ events.off("user/*");
127
127
  // Remove all listeners
128
128
  events.offAll();
129
129
  // Remove all listeners under a specific prefix
130
- events.offAll('user');
130
+ events.offAll("user");
131
131
  ```
132
132
 
133
133
  ## Event Scopes
@@ -140,15 +140,15 @@ Scopes allow you to handle events within a specific namespace.
140
140
  const events = new FastEvent();
141
141
 
142
142
  // Create a user-related scope
143
- const userScope = events.scope('user');
143
+ const userScope = events.scope("user");
144
144
 
145
145
  // The following two approaches are equivalent:
146
- userScope.on('login', handler);
147
- events.on('user/login', handler);
146
+ userScope.on("login", handler);
147
+ events.on("user/login", handler);
148
148
 
149
149
  // The following two approaches are also equivalent:
150
- userScope.emit('login', data);
151
- events.emit('user/login', data);
150
+ userScope.emit("login", data);
151
+ events.emit("user/login", data);
152
152
 
153
153
  // Clear all listeners in the scope
154
154
  userScope.offAll(); // Equivalent to events.offAll('user')
@@ -164,16 +164,16 @@ const events = new FastEvent();
164
164
  async function waitForLogin() {
165
165
  try {
166
166
  // Wait for login event with a 5-second timeout
167
- const userData = await events.waitFor('user/login', 5000);
168
- console.log('User logged in:', userData);
167
+ const userData = await events.waitFor("user/login", 5000);
168
+ console.log("User logged in:", userData);
169
169
  } catch (error) {
170
- console.log('Login wait timeout');
170
+ console.log("Login wait timeout");
171
171
  }
172
172
  }
173
173
 
174
174
  waitForLogin();
175
175
  // Later trigger the login event
176
- events.emit('user/login', { id: 1, name: 'Alice' });
176
+ events.emit("user/login", { id: 1, name: "Alice" });
177
177
  ```
178
178
 
179
179
  ## Event Hooks
@@ -184,23 +184,24 @@ events.emit('user/login', { id: 1, name: 'Alice' });
184
184
  const otherEvents = new FastEvent();
185
185
  const events = new FastEvent({
186
186
  // Called when a new listener is added
187
- onAddListener: (type, listener, options) => {
188
- console.log('Added new listener:', type);
187
+ onAddBeforeListener: (type, listener, options) => {
188
+ console.log("Added new listener:", type);
189
189
  // Return false to prevent the listener from being added
190
190
  return false;
191
191
  // Can directly return a FastEventSubscriber
192
192
  // For example: transfer events starting with `@` to another FastEvent
193
- if (type.startsWith('@')) {
193
+ if (type.startsWith("@")) {
194
194
  return otherEvents.on(type, listener, options);
195
195
  }
196
196
  },
197
+ onAddBeforeListener
197
198
  // Called when a listener is removed
198
199
  onRemoveListener: (type, listener) => {
199
- console.log('Removed listener:', type);
200
+ console.log("Removed listener:", type);
200
201
  },
201
202
  // Called when listeners are cleared
202
203
  onClearListeners: () => {
203
- console.log('All listeners cleared');
204
+ console.log("All listeners cleared");
204
205
  },
205
206
  // Called when a listener throws an error
206
207
  onListenerError: (error, listener, message, args) => {
@@ -208,19 +209,19 @@ const events = new FastEvent({
208
209
  },
209
210
  // Called before a listener executes
210
211
  onBeforeExecuteListener: (message, args) => {
211
- console.log('Before executing event listener');
212
+ console.log("Before executing event listener");
212
213
  // Return false to prevent listener execution
213
214
  return false;
214
215
 
215
216
  // Forward events to another FastEvent
216
217
  // For example: forward events starting with `@` to another FastEvent
217
- if (type.startsWith('@')) {
218
+ if (type.startsWith("@")) {
218
219
  return otherEvents.emit(message.type);
219
220
  }
220
221
  },
221
222
  // Called after a listener executes
222
223
  onAfterExecuteListener: (message, returns, listeners) => {
223
- console.log('After executing event listener');
224
+ console.log("After executing event listener");
224
225
  // Can intercept and modify return values here
225
226
  },
226
227
  });
@@ -233,20 +234,20 @@ By default, all listeners are executed in parallel when an event is triggered.
233
234
  `FastEvent` provides powerful listener execution mechanisms that allow developers to control how listeners are executed.
234
235
 
235
236
  ```typescript
236
- import { race } from 'fastevent/executors';
237
+ import { race } from "fastevent/executors";
237
238
  const events = new FastEvent({
238
239
  executor: race(),
239
240
  });
240
241
 
241
- events.on('task/start', async () => {
242
+ events.on("task/start", async () => {
242
243
  /* Time-consuming operation 1 */
243
244
  });
244
- events.on('task/start', async () => {
245
+ events.on("task/start", async () => {
245
246
  /* Time-consuming operation 2 */
246
247
  });
247
248
 
248
249
  // The two listeners will execute in parallel, returning the fastest result
249
- await events.emitAsync('task/start');
250
+ await events.emitAsync("task/start");
250
251
  ```
251
252
 
252
253
  **Built-in Support**:
@@ -268,14 +269,14 @@ await events.emitAsync('task/start');
268
269
  Listener pipes are used to wrap listener functions during event subscription to implement various common advanced features.
269
270
 
270
271
  ```typescript
271
- import { queue } from 'fastevent/pipes';
272
+ import { queue } from "fastevent/pipes";
272
273
  const events = new FastEvent();
273
274
 
274
275
  // default queue size is 10
275
276
  events.on(
276
- 'data/update',
277
+ "data/update",
277
278
  (data) => {
278
- console.log('Processing data:', data);
279
+ console.log("Processing data:", data);
279
280
  },
280
281
  {
281
282
  pipes: [queue({ size: 10 })],
@@ -303,29 +304,29 @@ const otherEmitter = new FastEvent();
303
304
  const emitter = new FastEvent({
304
305
  onAddListener: (type, listener, options) => {
305
306
  // Subscription forwarding rule: when event name starts with `@/`, forward subscription to another `FastEvent` instance
306
- if (type.startsWith('@/')) {
307
+ if (type.startsWith("@/")) {
307
308
  return otherEmitter.on(type.substring(2), listener, options);
308
309
  }
309
310
  },
310
311
  onBeforeExecuteListener: (message, args) => {
311
312
  // Event forwarding rule: when event name starts with `@/`, publish to another `FastEvent` instance
312
- if (message.type.startsWith('@/')) {
313
+ if (message.type.startsWith("@/")) {
313
314
  message.type = message.type.substring(2);
314
315
  return otherEmitter.emit(message, args);
315
316
  }
316
317
  },
317
318
  });
318
319
  const events: any[] = [];
319
- otherEmitter.on('data', ({ payload }) => {
320
+ otherEmitter.on("data", ({ payload }) => {
320
321
  events.push(payload);
321
322
  });
322
323
  // Subscribe to otherEmitter's data event
323
- emitter.on('@/data', ({ payload }) => {
324
+ emitter.on("@/data", ({ payload }) => {
324
325
  expect(payload).toBe(1);
325
326
  events.push(payload);
326
327
  });
327
328
  // Publish data event to otherEmitter
328
- const subscriber = emitter.emit('@/data', 1);
329
+ const subscriber = emitter.emit("@/data", 1);
329
330
  subscriber.off();
330
331
  ```
331
332
 
@@ -338,32 +339,32 @@ You can set metadata at different levels: global, scope level, or event-specific
338
339
  ```typescript
339
340
  const events = new FastEvent({
340
341
  meta: {
341
- version: '1.0',
342
- environment: 'production',
342
+ version: "1.0",
343
+ environment: "production",
343
344
  },
344
345
  });
345
346
 
346
- events.on('user/login', (message) => {
347
- console.log('Event data:', message.payload);
348
- console.log('Metadata:', message.meta); // Includes type, version, and environment
347
+ events.on("user/login", (message) => {
348
+ console.log("Event data:", message.payload);
349
+ console.log("Metadata:", message.meta); // Includes type, version, and environment
349
350
  });
350
351
 
351
352
  // Using scope-level metadata
352
- const userScope = events.scope('user', {
353
- meta: { domain: 'user' },
353
+ const userScope = events.scope("user", {
354
+ meta: { domain: "user" },
354
355
  });
355
356
  // Add specific metadata when publishing events
356
357
  userScope.emit(
357
- 'login',
358
- { userId: '123' },
358
+ "login",
359
+ { userId: "123" },
359
360
  {
360
361
  meta: { timestamp: Date.now() }, // Event-specific metadata
361
362
  },
362
363
  );
363
364
 
364
365
  // Listeners receive merged metadata
365
- userScope.on('login', (message) => {
366
- console.log('Metadata:', message.meta);
366
+ userScope.on("login", (message) => {
367
+ console.log("Metadata:", message.meta);
367
368
  });
368
369
  ```
369
370
 
@@ -374,22 +375,22 @@ userScope.on('login', (message) => {
374
375
  ```typescript
375
376
  // Define events with different payload types
376
377
  interface ComplexEvents {
377
- 'data/number': number;
378
- 'data/string': string;
379
- 'data/object': { value: any };
378
+ "data/number": number;
379
+ "data/string": string;
380
+ "data/object": { value: any };
380
381
  }
381
382
 
382
383
  const events = new FastEvent<ComplexEvents>();
383
384
 
384
385
  // TypeScript ensures type safety for each event
385
- events.on('data/number', (message) => {
386
+ events.on("data/number", (message) => {
386
387
  const sum = message.payload + 1; // payload type is number
387
388
  });
388
389
 
389
390
  // All event emissions are type-checked
390
- events.emit('data/number', 42);
391
- events.emit('data/string', 'hello');
392
- events.emit('data/object', { value: true });
391
+ events.emit("data/number", 42);
392
+ events.emit("data/string", "hello");
393
+ events.emit("data/object", { value: true });
393
394
  ```
394
395
 
395
396
  ## Unit Testing