fastevent 1.1.3 → 2.0.0
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/dist/devTools.js +2 -2
- package/dist/devTools.js.map +1 -1
- package/dist/devTools.mjs +2 -2
- package/dist/devTools.mjs.map +1 -1
- package/dist/index.d.mts +285 -53
- package/dist/index.d.ts +285 -53
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +64 -50
- package/readme.md +517 -50
- package/.changeset/README.md +0 -8
- package/.changeset/config.json +0 -11
- package/.github/workflows/publish.yaml +0 -50
- package/.prettierrc.js +0 -20
- package/.vscode/launch.json +0 -20
- package/.vscode/settings.json +0 -18
- package/CHANGELOG.md +0 -60
- package/LICENSE +0 -21
- package/bench.png +0 -0
- package/dist/devTools.d.mts +0 -543
- package/dist/devTools.d.ts +0 -543
- package/example/README.md +0 -54
- package/example/eslint.config.js +0 -28
- package/example/index.html +0 -13
- package/example/package.json +0 -29
- package/example/pnpm-lock.yaml +0 -2047
- package/example/public/vite.svg +0 -1
- package/example/src/App.css +0 -42
- package/example/src/App.tsx +0 -60
- package/example/src/assets/react.svg +0 -1
- package/example/src/index.css +0 -68
- package/example/src/main.tsx +0 -10
- package/example/src/myEvent.ts +0 -32
- package/example/src/vite-env.d.ts +0 -1
- package/example/tsconfig.app.json +0 -26
- package/example/tsconfig.json +0 -7
- package/example/tsconfig.node.json +0 -24
- package/example/vite.config.ts +0 -7
- package/packages/native/index.ts +0 -1
- package/packages/turbo/.zig-cache/h/271c82d991949fd7788fd5451f0ca834.txt +0 -0
- package/packages/turbo/.zig-cache/h/timestamp +0 -0
- package/packages/turbo/.zig-cache/o/ebd7ddab8ffe003267120d598aecce68/dependencies.zig +0 -2
- package/packages/turbo/.zig-cache/z/c8114b040daa461a9e2eabd0357554a4 +0 -0
- package/packages/turbo/build.zig +0 -60
- package/packages/turbo/examples/basic.zig +0 -107
- package/packages/turbo/src/event.zig +0 -251
- package/packages/turbo/src/index.zig +0 -70
- package/packages/turbo/src/scope.zig +0 -104
- package/packages/turbo/src/types.zig +0 -88
- package/packages/turbo/src/utils.zig +0 -171
- package/readme_cn.md +0 -491
- package/src/__benchmarks__/index.ts +0 -3
- package/src/__benchmarks__/multi-level.ts +0 -40
- package/src/__benchmarks__/sample.ts +0 -40
- package/src/__benchmarks__/wildcard.ts +0 -41
- package/src/__tests__/emit.test.ts +0 -106
- package/src/__tests__/emitAsync.test.ts +0 -64
- package/src/__tests__/isPathMatched.test.ts +0 -205
- package/src/__tests__/many.test.ts +0 -22
- package/src/__tests__/meta.test.ts +0 -28
- package/src/__tests__/off.test.ts +0 -214
- package/src/__tests__/onany.test.ts +0 -212
- package/src/__tests__/once.test.ts +0 -70
- package/src/__tests__/retain.test.ts +0 -66
- package/src/__tests__/scope.test.ts +0 -110
- package/src/__tests__/types.test.ts +0 -145
- package/src/__tests__/waitFor.test.ts +0 -116
- package/src/__tests__/wildcard.test.ts +0 -185
- package/src/devTools.ts +0 -166
- package/src/event.ts +0 -741
- package/src/index.ts +0 -3
- package/src/scope.ts +0 -130
- package/src/types.ts +0 -66
- package/src/utils/WeakObjectMap.ts +0 -64
- package/src/utils/isPathMatched.ts +0 -40
- package/src/utils/removeItem.ts +0 -16
- package/tsconfig.json +0 -104
- package/tsup.config.ts +0 -30
package/readme.md
CHANGED
|
@@ -48,10 +48,105 @@ events.emit({
|
|
|
48
48
|
payload: { id: 1, name: 'Alice' },
|
|
49
49
|
meta: { timestamp: Date.now() },
|
|
50
50
|
});
|
|
51
|
+
|
|
52
|
+
// Using TypeScript with type safety
|
|
53
|
+
interface MyEvents {
|
|
54
|
+
'user/login': { id: number; name: string };
|
|
55
|
+
'user/logout': { id: number };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const typedEvents = new FastEvent<MyEvents>();
|
|
59
|
+
|
|
60
|
+
// TypeScript will enforce correct event types and payloads
|
|
61
|
+
typedEvents.on('user/login', (message) => {
|
|
62
|
+
const { id, name } = message.payload; // Properly typed
|
|
63
|
+
});
|
|
51
64
|
```
|
|
52
65
|
|
|
53
66
|
# Guide
|
|
54
67
|
|
|
68
|
+
## Event Triggering
|
|
69
|
+
|
|
70
|
+
FastEvent provides flexible ways to trigger events with different parameter combinations:
|
|
71
|
+
|
|
72
|
+
### Basic Event Triggering
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
const events = new FastEvent();
|
|
76
|
+
|
|
77
|
+
// Method 1: Parameters form
|
|
78
|
+
events.emit('user/login', { id: 1, name: 'Alice' });
|
|
79
|
+
|
|
80
|
+
// Method 2: Message object form
|
|
81
|
+
events.emit({
|
|
82
|
+
type: 'user/login',
|
|
83
|
+
payload: { id: 1, name: 'Alice' },
|
|
84
|
+
meta: { timestamp: Date.now() },
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Retained Events
|
|
89
|
+
|
|
90
|
+
Set `retain=true` to store the event for new subscribers:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
// Emit and retain the event
|
|
94
|
+
events.emit('config/update', { theme: 'dark' }, true);
|
|
95
|
+
|
|
96
|
+
// Later subscribers will immediately receive the retained event
|
|
97
|
+
events.on('config/update', (message) => {
|
|
98
|
+
console.log('Config:', message.payload); // { theme: 'dark' }
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Event Metadata
|
|
103
|
+
|
|
104
|
+
Metadata can be provided at different levels and will be merged:
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
const events = new FastEvent({
|
|
108
|
+
meta: { app: 'MyApp' }, // Global metadata
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Event-specific metadata
|
|
112
|
+
events.emit('order/create', { id: '123' }, false, {
|
|
113
|
+
timestamp: Date.now(),
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Listener receives merged metadata:
|
|
117
|
+
// { type: 'order/create', app: 'MyApp', timestamp: ... }
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Return Values
|
|
121
|
+
|
|
122
|
+
`emit()` returns an array of listener results:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
events.on('calculate', () => 1);
|
|
126
|
+
events.on('calculate', () => 2);
|
|
127
|
+
|
|
128
|
+
const results = events.emit('calculate');
|
|
129
|
+
console.log(results); // [1, 2]
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Type-safe Event Triggering
|
|
133
|
+
|
|
134
|
+
With TypeScript, event payloads are type-checked:
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
interface MyEvents {
|
|
138
|
+
'user/login': { id: number; name: string };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const events = new FastEvent<MyEvents>();
|
|
142
|
+
|
|
143
|
+
// Valid - payload matches type
|
|
144
|
+
events.emit('user/login', { id: 1, name: 'Alice' });
|
|
145
|
+
|
|
146
|
+
// Error - payload type mismatch
|
|
147
|
+
events.emit('user/login', { id: '1' }); // TypeScript error
|
|
148
|
+
```
|
|
149
|
+
|
|
55
150
|
## Event Message Format
|
|
56
151
|
|
|
57
152
|
FastEvent uses a standardized message format for all events:
|
|
@@ -111,8 +206,45 @@ events.emit('user/login', data);
|
|
|
111
206
|
|
|
112
207
|
// Clear all listeners in the scope
|
|
113
208
|
userScope.offAll(); // Equivalent to events.offAll('user')
|
|
209
|
+
|
|
210
|
+
// Nested scopes
|
|
211
|
+
const profileScope = userScope.scope('profile');
|
|
212
|
+
profileScope.on('update', (message) => {
|
|
213
|
+
// Will receive events emitted as 'user/profile/update'
|
|
214
|
+
console.log('Profile update:', message.payload);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// Scope with metadata
|
|
218
|
+
const adminScope = events.scope('admin', {
|
|
219
|
+
meta: { role: 'admin' },
|
|
220
|
+
context: { adminId: 1 },
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
adminScope.on('action', function (message) {
|
|
224
|
+
console.log('Admin meta:', message.meta); // Contains { role: 'admin' }
|
|
225
|
+
console.log('Context:', this.adminId); // Access to scope context
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// Type-safe scopes
|
|
229
|
+
interface UserEvents {
|
|
230
|
+
login: { id: number };
|
|
231
|
+
logout: { id: number };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const typedUserScope = events.scope<'user', UserEvents>('user');
|
|
235
|
+
typedUserScope.on('login', (message) => {
|
|
236
|
+
const { id } = message.payload; // Properly typed as { id: number }
|
|
237
|
+
});
|
|
114
238
|
```
|
|
115
239
|
|
|
240
|
+
Scopes provide several benefits:
|
|
241
|
+
|
|
242
|
+
1. Namespace organization - Group related events under a common prefix
|
|
243
|
+
2. Code organization - Separate event handling logic by domain
|
|
244
|
+
3. Metadata inheritance - Share common metadata across related events
|
|
245
|
+
4. Context binding - Provide specific execution context for event handlers
|
|
246
|
+
5. Type safety - Enforce type checking for scoped events
|
|
247
|
+
|
|
116
248
|
## Listener Options
|
|
117
249
|
|
|
118
250
|
When subscribing to events, you can specify additional options:
|
|
@@ -253,18 +385,146 @@ events.on('config/update', (message) => {
|
|
|
253
385
|
});
|
|
254
386
|
```
|
|
255
387
|
|
|
256
|
-
## Multi-level Events
|
|
388
|
+
## Multi-level Events and Wildcards
|
|
257
389
|
|
|
258
|
-
|
|
390
|
+
FastEvent supports hierarchical event structures with powerful wildcard matching capabilities.
|
|
259
391
|
|
|
260
|
-
|
|
392
|
+
### Event Path Structure
|
|
393
|
+
|
|
394
|
+
Events can be organized in a hierarchical structure using path delimiters (default is '/'):
|
|
261
395
|
|
|
262
396
|
```typescript
|
|
263
|
-
const events = new FastEvent(
|
|
397
|
+
const events = new FastEvent();
|
|
398
|
+
|
|
399
|
+
// Basic multi-level events
|
|
400
|
+
events.on('user/profile/update', handler);
|
|
401
|
+
events.on('user/settings/theme/change', handler);
|
|
402
|
+
|
|
403
|
+
// Custom delimiter
|
|
404
|
+
const customEvents = new FastEvent({
|
|
264
405
|
delimiter: '.',
|
|
265
406
|
});
|
|
407
|
+
customEvents.on('user.profile.update', handler);
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Wildcard Patterns
|
|
411
|
+
|
|
412
|
+
FastEvent supports two types of wildcards:
|
|
413
|
+
|
|
414
|
+
1. Single-level wildcard (`*`):
|
|
415
|
+
- Matches exactly one level in the event path
|
|
416
|
+
- Can be used at any level in the path
|
|
417
|
+
|
|
418
|
+
```typescript
|
|
419
|
+
// Match any user type
|
|
420
|
+
events.on('user/*/login', (message) => {
|
|
421
|
+
console.log('User type:', message.type.split('/')[1]);
|
|
422
|
+
// Matches: user/admin/login, user/guest/login, etc.
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
// Match any action
|
|
426
|
+
events.on('api/users/*/action/*', (message) => {
|
|
427
|
+
const [, , userId, , action] = message.type.split('/');
|
|
428
|
+
console.log(`User ${userId} performed ${action}`);
|
|
429
|
+
// Matches: api/users/123/action/update, api/users/456/action/delete, etc.
|
|
430
|
+
});
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
2. Multi-level wildcard (`**`):
|
|
434
|
+
- Matches zero or more levels in the event path
|
|
435
|
+
- Must be used at the end of the path pattern
|
|
436
|
+
|
|
437
|
+
```typescript
|
|
438
|
+
// Match all user-related events
|
|
439
|
+
events.on('user/**', (message) => {
|
|
440
|
+
console.log('User event:', message.type);
|
|
441
|
+
// Matches: user/login, user/profile/update, user/settings/theme/change, etc.
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
// Match all API events
|
|
445
|
+
events.on('api/**', (message) => {
|
|
446
|
+
console.log('API event:', message.type, message.payload);
|
|
447
|
+
// Matches: api/get, api/users/create, api/posts/123/comments/add, etc.
|
|
448
|
+
});
|
|
266
449
|
```
|
|
267
450
|
|
|
451
|
+
### Advanced Wildcard Usage
|
|
452
|
+
|
|
453
|
+
```typescript
|
|
454
|
+
const events = new FastEvent();
|
|
455
|
+
|
|
456
|
+
// Using single-level wildcards
|
|
457
|
+
events.on('service/*/user/update', (message) => {
|
|
458
|
+
// Matches patterns like:
|
|
459
|
+
// service/auth/user/update
|
|
460
|
+
// service/admin/user/update
|
|
461
|
+
const parts = message.type.split('/');
|
|
462
|
+
const serviceType = parts[1];
|
|
463
|
+
console.log(`${serviceType} service user update:`, message.payload);
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
// Using multi-level wildcard at the end
|
|
467
|
+
events.on('service/auth/**', (message) => {
|
|
468
|
+
// Matches patterns like:
|
|
469
|
+
// service/auth/user/update
|
|
470
|
+
// service/auth/user/profile/update
|
|
471
|
+
// service/auth/settings/theme/change
|
|
472
|
+
console.log('Auth service event:', message.type, message.payload);
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
// Type-safe events with TypeScript
|
|
476
|
+
interface ApiEvents {
|
|
477
|
+
'api/users/profile': { userId: string; data: any };
|
|
478
|
+
'api/posts/comments': { postId: string; commentId: string; text: string };
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
const typedEvents = new FastEvent<ApiEvents>();
|
|
482
|
+
|
|
483
|
+
// Exact match with type safety
|
|
484
|
+
typedEvents.on('api/users/profile', (message) => {
|
|
485
|
+
const { userId, data } = message.payload; // Properly typed
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
// Wildcard listeners still work but lose some type safety
|
|
489
|
+
typedEvents.on('api/*', (message) => {
|
|
490
|
+
// message.payload type is any here
|
|
491
|
+
console.log('API event:', message.type);
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
// Wildcard event monitoring
|
|
495
|
+
events.on('**', (message) => {
|
|
496
|
+
console.log('Event intercepted:', {
|
|
497
|
+
type: message.type,
|
|
498
|
+
timestamp: new Date(),
|
|
499
|
+
payload: message.payload,
|
|
500
|
+
});
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
// Example usage
|
|
504
|
+
events.emit('service/auth/user/profile/update', { name: 'John' });
|
|
505
|
+
events.emit('api/users/123/profile', { userId: '123', data: { age: 30 } });
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
### Important Notes
|
|
509
|
+
|
|
510
|
+
1. Wildcard Limitations:
|
|
511
|
+
|
|
512
|
+
- `**` wildcard must be at the end of the path
|
|
513
|
+
- `*` can be used multiple times in a path
|
|
514
|
+
- Wildcards cannot be combined in a single segment (e.g., 'a/\*\*/b' is invalid)
|
|
515
|
+
|
|
516
|
+
2. Performance Considerations:
|
|
517
|
+
|
|
518
|
+
- Specific patterns (without wildcards) are matched faster
|
|
519
|
+
- `*` wildcards are more efficient than `**`
|
|
520
|
+
- Excessive use of `**` wildcards may impact performance
|
|
521
|
+
|
|
522
|
+
3. Best Practices:
|
|
523
|
+
- Use specific patterns when possible
|
|
524
|
+
- Limit the use of `**` wildcards
|
|
525
|
+
- Consider the event hierarchy carefully
|
|
526
|
+
- Use TypeScript interfaces for type safety
|
|
527
|
+
|
|
268
528
|
## Global Event Listening
|
|
269
529
|
|
|
270
530
|
Use `onAny` to listen to all events:
|
|
@@ -282,7 +542,7 @@ events.onAny(handler, { prepend: true });
|
|
|
282
542
|
|
|
283
543
|
## Metadata (Meta)
|
|
284
544
|
|
|
285
|
-
Metadata is a mechanism for providing additional context information for events. You can set metadata
|
|
545
|
+
Metadata is a mechanism for providing additional context information for events. You can set metadata at different levels: globally, scope-level, or event-specific.
|
|
286
546
|
|
|
287
547
|
### Global Metadata
|
|
288
548
|
|
|
@@ -302,30 +562,83 @@ events.on('user/login', (message) => {
|
|
|
302
562
|
});
|
|
303
563
|
```
|
|
304
564
|
|
|
565
|
+
### Scope Metadata
|
|
566
|
+
|
|
567
|
+
When creating a scope, you can provide metadata that will be merged with global metadata:
|
|
568
|
+
|
|
569
|
+
```typescript
|
|
570
|
+
const events = new FastEvent({
|
|
571
|
+
meta: { app: 'MyApp' },
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
const userScope = events.scope('user', {
|
|
575
|
+
meta: { domain: 'user' },
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
userScope.on('login', (message) => {
|
|
579
|
+
console.log('Metadata:', message.meta);
|
|
580
|
+
// { type: 'user/login', app: 'MyApp', domain: 'user' }
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
// Nested scopes merge metadata recursively
|
|
584
|
+
const profileScope = userScope.scope('profile', {
|
|
585
|
+
meta: { section: 'profile' },
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
profileScope.on('update', (message) => {
|
|
589
|
+
console.log('Metadata:', message.meta);
|
|
590
|
+
// { type: 'user/profile/update', app: 'MyApp', domain: 'user', section: 'profile' }
|
|
591
|
+
});
|
|
592
|
+
```
|
|
593
|
+
|
|
305
594
|
### Event-specific Metadata
|
|
306
595
|
|
|
307
|
-
Additional metadata can be passed when publishing events, which will be merged with
|
|
596
|
+
Additional metadata can be passed when publishing events, which will be merged with higher-level metadata:
|
|
308
597
|
|
|
309
598
|
```typescript
|
|
310
599
|
const events = new FastEvent({
|
|
311
600
|
meta: { app: 'MyApp' },
|
|
312
601
|
});
|
|
313
602
|
|
|
603
|
+
const userScope = events.scope('user', {
|
|
604
|
+
meta: { domain: 'user' },
|
|
605
|
+
});
|
|
606
|
+
|
|
314
607
|
// Add specific metadata when publishing event
|
|
315
|
-
|
|
316
|
-
'
|
|
317
|
-
{
|
|
608
|
+
userScope.emit(
|
|
609
|
+
'login',
|
|
610
|
+
{ userId: '123' }, // Event data
|
|
318
611
|
false, // Don't retain
|
|
319
612
|
{ timestamp: Date.now() }, // Event-specific metadata
|
|
320
613
|
);
|
|
321
614
|
|
|
322
615
|
// Listener receives merged metadata
|
|
323
|
-
|
|
324
|
-
console.log('
|
|
325
|
-
|
|
616
|
+
userScope.on('login', (message) => {
|
|
617
|
+
console.log('Metadata:', message.meta);
|
|
618
|
+
// { type: 'user/login', app: 'MyApp', domain: 'user', timestamp: ... }
|
|
326
619
|
});
|
|
327
620
|
```
|
|
328
621
|
|
|
622
|
+
### Metadata Merge Rules
|
|
623
|
+
|
|
624
|
+
1. Priority (highest to lowest):
|
|
625
|
+
|
|
626
|
+
- Event-specific metadata
|
|
627
|
+
- Scope metadata (innermost to outermost)
|
|
628
|
+
- Global metadata
|
|
629
|
+
- System metadata (type is always added)
|
|
630
|
+
|
|
631
|
+
2. Merge behavior:
|
|
632
|
+
|
|
633
|
+
- Shallow merge (top-level properties only)
|
|
634
|
+
- Later values override earlier ones
|
|
635
|
+
- No deep merging of nested objects
|
|
636
|
+
|
|
637
|
+
3. Special cases:
|
|
638
|
+
- `type` is always preserved as the full event path
|
|
639
|
+
- `undefined` values will remove the property from the result
|
|
640
|
+
- Arrays are replaced, not concatenated
|
|
641
|
+
|
|
329
642
|
## Error Handling
|
|
330
643
|
|
|
331
644
|
FastEvent provides error handling mechanisms:
|
|
@@ -440,51 +753,205 @@ events.emit('data/string', 'hello');
|
|
|
440
753
|
events.emit('data/object', { value: true });
|
|
441
754
|
```
|
|
442
755
|
|
|
443
|
-
##
|
|
756
|
+
## Event Hooks
|
|
757
|
+
|
|
758
|
+
FastEvent provides several hooks for monitoring and debugging the event system:
|
|
759
|
+
|
|
760
|
+
```typescript
|
|
761
|
+
const events = new FastEvent({
|
|
762
|
+
// Called when a new listener is added
|
|
763
|
+
onAddListener: (path: string[], listener: Function) => {
|
|
764
|
+
console.log('New listener added for:', path.join('/'));
|
|
765
|
+
},
|
|
766
|
+
|
|
767
|
+
// Called when a listener is removed
|
|
768
|
+
onRemoveListener: (path: string[], listener: Function) => {
|
|
769
|
+
console.log('Listener removed from:', path.join('/'));
|
|
770
|
+
},
|
|
771
|
+
|
|
772
|
+
// Called when listeners are cleared
|
|
773
|
+
onClearListeners: () => {
|
|
774
|
+
console.log('All listeners cleared');
|
|
775
|
+
},
|
|
776
|
+
|
|
777
|
+
// Called when a listener throws an error
|
|
778
|
+
onListenerError: (type: string, error: Error) => {
|
|
779
|
+
console.error(`Error in listener for ${type}:`, error);
|
|
780
|
+
},
|
|
781
|
+
|
|
782
|
+
// Called after listeners are executed (debug mode only)
|
|
783
|
+
onExecuteListener: (message, returns, listeners) => {
|
|
784
|
+
console.log('Event executed:', {
|
|
785
|
+
type: message.type,
|
|
786
|
+
payload: message.payload,
|
|
787
|
+
results: returns,
|
|
788
|
+
listenerCount: listeners.length,
|
|
789
|
+
});
|
|
790
|
+
},
|
|
791
|
+
});
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
These hooks provide valuable insights into the event system's operation:
|
|
795
|
+
|
|
796
|
+
1. `onAddListener`: Monitor listener registration
|
|
797
|
+
|
|
798
|
+
- Called whenever a new event listener is added
|
|
799
|
+
- Receives the event path array and listener function
|
|
800
|
+
- Useful for tracking event subscriptions
|
|
444
801
|
|
|
445
|
-
|
|
802
|
+
2. `onRemoveListener`: Track listener removal
|
|
803
|
+
|
|
804
|
+
- Called when a listener is removed
|
|
805
|
+
- Helps monitor event unsubscription patterns
|
|
806
|
+
- Receives the same parameters as onAddListener
|
|
807
|
+
|
|
808
|
+
3. `onClearListeners`: Notifies of bulk listener removal
|
|
809
|
+
|
|
810
|
+
- Called when offAll() is invoked
|
|
811
|
+
- Useful for cleanup monitoring
|
|
812
|
+
- No parameters provided
|
|
813
|
+
|
|
814
|
+
4. `onListenerError`: Error handling hook
|
|
815
|
+
|
|
816
|
+
- Called when a listener throws an error
|
|
817
|
+
- Receives the event type and error object
|
|
818
|
+
- Enables centralized error handling
|
|
819
|
+
- Only called if ignoreErrors is true
|
|
820
|
+
|
|
821
|
+
5. `onExecuteListener`: Execution monitoring (debug mode)
|
|
822
|
+
- Only active when debug: true is set
|
|
823
|
+
- Provides detailed execution information
|
|
824
|
+
- Includes message, return values, and listener list
|
|
825
|
+
- Useful for debugging and performance monitoring
|
|
826
|
+
|
|
827
|
+
Example usage:
|
|
446
828
|
|
|
447
829
|
```typescript
|
|
448
830
|
const events = new FastEvent({
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
831
|
+
debug: true, // Enable debug mode for onExecuteListener
|
|
832
|
+
onAddListener: (path, listener) => {
|
|
833
|
+
console.log(`Listener added for ${path.join('/')}`);
|
|
834
|
+
// Track listener count or patterns
|
|
835
|
+
},
|
|
836
|
+
onListenerError: (type, error) => {
|
|
837
|
+
console.error(`Error in ${type}:`, error);
|
|
838
|
+
// Log to monitoring system
|
|
839
|
+
},
|
|
840
|
+
onExecuteListener: (message, returns, listeners) => {
|
|
841
|
+
console.log(`Event ${message.type} executed:`, {
|
|
842
|
+
executionTime: Date.now(),
|
|
843
|
+
listenerCount: listeners.length,
|
|
844
|
+
results: returns,
|
|
845
|
+
});
|
|
846
|
+
// Monitor event execution patterns
|
|
847
|
+
},
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
// Example events that trigger hooks
|
|
851
|
+
events.on('user/login', () => {
|
|
852
|
+
// onAddListener will be called
|
|
853
|
+
});
|
|
854
|
+
|
|
855
|
+
events.on('data/process', () => {
|
|
856
|
+
throw new Error('Process failed');
|
|
857
|
+
// onListenerError will be called
|
|
858
|
+
});
|
|
859
|
+
|
|
860
|
+
events.emit('user/login', { id: 1 });
|
|
861
|
+
// onExecuteListener will be called (if debug: true)
|
|
862
|
+
|
|
863
|
+
events.offAll();
|
|
864
|
+
// onClearListeners will be called
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
# Parameters
|
|
868
|
+
|
|
869
|
+
FastEvent constructor accepts the following configuration options:
|
|
870
|
+
|
|
871
|
+
````typescript
|
|
872
|
+
interface FastEventOptions<Meta = Record<string, any>, Context = any> {
|
|
873
|
+
/**
|
|
874
|
+
* Unique identifier for the emitter instance
|
|
875
|
+
* @default Randomly generated string
|
|
876
|
+
*/
|
|
877
|
+
id?: string;
|
|
878
|
+
|
|
879
|
+
/**
|
|
880
|
+
* Whether to enable debug mode
|
|
881
|
+
* @default false
|
|
882
|
+
* @remarks When true, events can be viewed in Redux DevTools
|
|
883
|
+
*/
|
|
884
|
+
debug?: boolean;
|
|
885
|
+
|
|
886
|
+
/**
|
|
887
|
+
* Delimiter for event path segments
|
|
888
|
+
* @default '/'
|
|
889
|
+
* @example
|
|
890
|
+
* ```ts
|
|
891
|
+
* new FastEvent({ delimiter: '.' }); // Use dot as delimiter
|
|
892
|
+
* ```
|
|
893
|
+
*/
|
|
894
|
+
delimiter?: string;
|
|
895
|
+
|
|
896
|
+
/**
|
|
897
|
+
* Default execution context for event handlers
|
|
898
|
+
* @default null
|
|
899
|
+
*/
|
|
900
|
+
context?: Context;
|
|
901
|
+
|
|
902
|
+
/**
|
|
903
|
+
* Whether to ignore listener errors
|
|
904
|
+
* @default true
|
|
905
|
+
*/
|
|
906
|
+
ignoreErrors?: boolean;
|
|
907
|
+
|
|
908
|
+
/**
|
|
909
|
+
* Global metadata attached to all events
|
|
910
|
+
* @default undefined
|
|
911
|
+
*/
|
|
912
|
+
meta?: Meta;
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* Callback when a listener is added
|
|
916
|
+
* @param path - Array of path segments
|
|
917
|
+
* @param listener - The listener function
|
|
918
|
+
*/
|
|
919
|
+
onAddListener?: (path: string[], listener: Function) => void;
|
|
920
|
+
|
|
921
|
+
/**
|
|
922
|
+
* Callback when a listener is removed
|
|
923
|
+
* @param path - Array of path segments
|
|
924
|
+
* @param listener - The listener function
|
|
925
|
+
*/
|
|
926
|
+
onRemoveListener?: (path: string[], listener: Function) => void;
|
|
927
|
+
|
|
928
|
+
/**
|
|
929
|
+
* Callback when all listeners are cleared
|
|
930
|
+
*/
|
|
931
|
+
onClearListeners?: () => void;
|
|
932
|
+
|
|
933
|
+
/**
|
|
934
|
+
* Callback when a listener throws an error
|
|
935
|
+
* @param type - Event type
|
|
936
|
+
* @param error - The error object
|
|
937
|
+
*/
|
|
938
|
+
onListenerError?: (type: string, error: Error) => void;
|
|
939
|
+
|
|
940
|
+
/**
|
|
941
|
+
* Callback after listeners are executed (debug mode only)
|
|
942
|
+
* @param message - Event message
|
|
943
|
+
* @param returns - Array of listener return values
|
|
944
|
+
* @param listeners - Array of executed listeners
|
|
945
|
+
*/
|
|
946
|
+
onExecuteListener?: (message: FastEventMessage, returns: any[], listeners: (FastEventListener<any, any, any> | [FastEventListener<any, any>, number])[]) => void;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
// Debug mode usage
|
|
483
950
|
import 'fastevent/devtools';
|
|
484
951
|
const emitter = new FastEvent({
|
|
485
|
-
debug: true,
|
|
952
|
+
debug: true, // Enable debug mode to view events in Redux DevTools
|
|
486
953
|
});
|
|
487
|
-
|
|
954
|
+
````
|
|
488
955
|
|
|
489
956
|
# Performance
|
|
490
957
|
|
package/.changeset/README.md
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
# Changesets
|
|
2
|
-
|
|
3
|
-
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
|
4
|
-
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
|
5
|
-
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
|
|
6
|
-
|
|
7
|
-
We have a quick list of common questions to get you started engaging with this project in
|
|
8
|
-
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
package/.changeset/config.json
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
|
|
3
|
-
"changelog": "@changesets/cli/changelog",
|
|
4
|
-
"commit": true,
|
|
5
|
-
"fixed": [],
|
|
6
|
-
"linked": [],
|
|
7
|
-
"access": "public",
|
|
8
|
-
"baseBranch": "master",
|
|
9
|
-
"updateInternalDependencies": "patch",
|
|
10
|
-
"ignore": []
|
|
11
|
-
}
|