@pawells/rxjs-events 1.0.1 → 1.1.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/README.md +17 -15
- package/build/async-observable.js +1 -1
- package/build/async-observable.js.map +1 -1
- package/build/event-filter.d.ts +49 -5
- package/build/event-filter.d.ts.map +1 -1
- package/build/event-filter.js +55 -13
- package/build/event-filter.js.map +1 -1
- package/build/event-operators.d.ts +92 -0
- package/build/event-operators.d.ts.map +1 -0
- package/build/event-operators.js +203 -0
- package/build/event-operators.js.map +1 -0
- package/build/event-pipeline.d.ts +96 -0
- package/build/event-pipeline.d.ts.map +1 -0
- package/build/event-pipeline.js +127 -0
- package/build/event-pipeline.js.map +1 -0
- package/build/handler.d.ts +37 -3
- package/build/handler.d.ts.map +1 -1
- package/build/handler.js +42 -4
- package/build/handler.js.map +1 -1
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -0
- package/build/index.js.map +1 -1
- package/build/nestjs-pubsub.d.ts +171 -0
- package/build/nestjs-pubsub.d.ts.map +1 -0
- package/build/nestjs-pubsub.js +226 -0
- package/build/nestjs-pubsub.js.map +1 -0
- package/package.json +10 -8
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@pawells/rxjs-events)
|
|
4
4
|
[](https://github.com/PhillipAWells/rxjs-events/releases)
|
|
5
5
|
[](https://github.com/PhillipAWells/rxjs-events/actions/workflows/ci.yml)
|
|
6
|
-
[](https://nodejs.org)
|
|
7
7
|
[](./LICENSE)
|
|
8
8
|
[](https://github.com/sponsors/PhillipAWells)
|
|
9
9
|
|
|
@@ -86,8 +86,8 @@ async function processOnce() {
|
|
|
86
86
|
import { AsyncObservable, BackpressureStrategy } from '@pawells/rxjs-events';
|
|
87
87
|
|
|
88
88
|
const obs = new AsyncObservable<string>({
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
maxBufferSize: 100,
|
|
90
|
+
overflowStrategy: BackpressureStrategy.DropOldest,
|
|
91
91
|
});
|
|
92
92
|
|
|
93
93
|
for await (const item of obs) {
|
|
@@ -117,14 +117,16 @@ Main event handler class wrapping an RxJS `Subject`.
|
|
|
117
117
|
|
|
118
118
|
| Method | Signature | Description |
|
|
119
119
|
|--------|-----------|-------------|
|
|
120
|
-
| `constructor` | `(name:
|
|
121
|
-
| `Name` | `string` (
|
|
122
|
-
| `Subscribe` | `(
|
|
123
|
-
| `Unsubscribe` | `(
|
|
124
|
-
| `Trigger` | `(data: TObject
|
|
120
|
+
| `constructor` | `(name: string)` | Creates a handler with the given event name (cannot be empty or whitespace-only) |
|
|
121
|
+
| `Name` | `string` (readonly) | Returns the event name |
|
|
122
|
+
| `Subscribe` | `(onEvent: TEventFunction<TEvent>) => number` | Subscribes and returns a numeric ID |
|
|
123
|
+
| `Unsubscribe` | `(subscription: number) => void` | Removes subscription by ID |
|
|
124
|
+
| `Trigger` | `(data: TObject) => void` | Emits the event with the given payload |
|
|
125
125
|
| `Destroy` | `() => void` | Completes the Subject and cleans up all subscriptions |
|
|
126
|
-
| `GetAsyncIterableIterator` | `() => AsyncIterableIterator<
|
|
127
|
-
| `GetAsyncIterator` | `() =>
|
|
126
|
+
| `GetAsyncIterableIterator` | `() => AsyncIterableIterator<TEvent>` | Returns an async iterable iterator |
|
|
127
|
+
| `GetAsyncIterator` | `() => AsyncIterator<TEvent>` | Returns an async iterator |
|
|
128
|
+
| `GetSubscriptionCount` | `() => number` | Returns the count of active subscriptions |
|
|
129
|
+
| `GetActiveSubscriptionIds` | `() => number[]` | Returns array of active subscription IDs |
|
|
128
130
|
|
|
129
131
|
Subscription IDs are recycled internally — allocation is O(1).
|
|
130
132
|
|
|
@@ -132,10 +134,10 @@ Subscription IDs are recycled internally — allocation is O(1).
|
|
|
132
134
|
|
|
133
135
|
An `Observable` subclass with a push buffer and configurable backpressure. Implements `Symbol.asyncIterator`.
|
|
134
136
|
|
|
135
|
-
| Option | Type | Description |
|
|
136
|
-
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
137
|
+
| Option | Type | Default | Description |
|
|
138
|
+
|--------|------|---------|-------------|
|
|
139
|
+
| `maxBufferSize` | `number` | 1000 | Maximum number of buffered items |
|
|
140
|
+
| `overflowStrategy` | `BackpressureStrategy` | `DropOldest` | How to handle buffer overflow: `DropOldest`, `DropNewest`, or `Error` |
|
|
139
141
|
|
|
140
142
|
Throws `BufferOverflowError` when strategy is `Error` and the buffer is full.
|
|
141
143
|
|
|
@@ -202,7 +204,7 @@ yarn vitest run src/path/to/file.test.ts
|
|
|
202
204
|
|
|
203
205
|
## Requirements
|
|
204
206
|
|
|
205
|
-
- Node.js >=
|
|
207
|
+
- Node.js >= 22.0.0
|
|
206
208
|
- ESM-only (`"type": "module"`) — use ESM imports throughout
|
|
207
209
|
|
|
208
210
|
## License
|
|
@@ -183,7 +183,7 @@ export class AsyncObservable extends Observable {
|
|
|
183
183
|
subscription?.unsubscribe();
|
|
184
184
|
// Resolve all pending next() promises so callers are not left hanging.
|
|
185
185
|
handleComplete();
|
|
186
|
-
return Promise.resolve({ done: true, value:
|
|
186
|
+
return Promise.resolve({ done: true, value: undefined });
|
|
187
187
|
},
|
|
188
188
|
throw: (err) => {
|
|
189
189
|
subscription?.unsubscribe();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"async-observable.js","sourceRoot":"","sources":["../src/async-observable.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"async-observable.js","sourceRoot":"","sources":["../src/async-observable.ts"],"names":[],"mappings":"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"}
|
package/build/event-filter.d.ts
CHANGED
|
@@ -3,10 +3,15 @@ import { IFilterCriteria } from './filter-criteria.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* Filters events based on payload property matching criteria.
|
|
5
5
|
* Performs strict equality comparison between event payload properties and filter arguments.
|
|
6
|
+
* Supports nested property paths using dot notation and predicate functions.
|
|
6
7
|
*
|
|
7
8
|
* @template TEvent - The event data type extending TEventData
|
|
8
9
|
* @param event - The event to filter, must have exactly one property representing the event type
|
|
9
|
-
* @param args - Filter criteria object with property-value pairs to match against the event payload
|
|
10
|
+
* @param args - Filter criteria object with property-value pairs to match against the event payload.
|
|
11
|
+
* Values can be:
|
|
12
|
+
* - Primitives: matched via strict equality
|
|
13
|
+
* - Functions: treated as predicates that must return true
|
|
14
|
+
* - Keys can use dot notation for nested paths (e.g., 'user.profile.role')
|
|
10
15
|
* @returns true if the event matches all filter criteria or if no filter is provided, false otherwise
|
|
11
16
|
*
|
|
12
17
|
* @throws {Error} 'No Event' - When event is null or undefined
|
|
@@ -20,20 +25,36 @@ import { IFilterCriteria } from './filter-criteria.js';
|
|
|
20
25
|
* userId: string;
|
|
21
26
|
* username: string;
|
|
22
27
|
* role: string;
|
|
28
|
+
* profile: {
|
|
29
|
+
* age: number;
|
|
30
|
+
* status: string;
|
|
31
|
+
* };
|
|
23
32
|
* };
|
|
24
33
|
* }
|
|
25
34
|
*
|
|
26
35
|
* const event: UserEvent = {
|
|
27
|
-
* UserCreated: {
|
|
36
|
+
* UserCreated: {
|
|
37
|
+
* userId: '123',
|
|
38
|
+
* username: 'john',
|
|
39
|
+
* role: 'admin',
|
|
40
|
+
* profile: { age: 30, status: 'active' }
|
|
41
|
+
* }
|
|
28
42
|
* };
|
|
29
43
|
*
|
|
30
44
|
* // Match by single property
|
|
31
45
|
* EventFilter(event, { role: 'admin' }); // true
|
|
32
46
|
* EventFilter(event, { role: 'user' }); // false
|
|
33
47
|
*
|
|
34
|
-
* // Match by
|
|
35
|
-
* EventFilter(event, {
|
|
36
|
-
* EventFilter(event, {
|
|
48
|
+
* // Match by nested path
|
|
49
|
+
* EventFilter(event, { 'profile.age': 30 }); // true
|
|
50
|
+
* EventFilter(event, { 'profile.status': 'active' }); // true
|
|
51
|
+
*
|
|
52
|
+
* // Match by predicate function
|
|
53
|
+
* EventFilter(event, { 'profile.age': (v) => v > 18 }); // true
|
|
54
|
+
* EventFilter(event, { role: (r) => r === 'admin' }); // true
|
|
55
|
+
*
|
|
56
|
+
* // Multiple criteria
|
|
57
|
+
* EventFilter(event, { role: 'admin', 'profile.age': (v) => v > 18 }); // true
|
|
37
58
|
*
|
|
38
59
|
* // No filter (always passes)
|
|
39
60
|
* EventFilter(event, null); // true
|
|
@@ -41,4 +62,27 @@ import { IFilterCriteria } from './filter-criteria.js';
|
|
|
41
62
|
* ```
|
|
42
63
|
*/
|
|
43
64
|
export declare function EventFilter<TEvent extends TEventData = TEventData>(event: TEvent, args: IFilterCriteria | null | undefined): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Partitions an event into matching and non-matching tuples based on filter criteria.
|
|
67
|
+
* Uses EventFilter internally to apply the filtering logic.
|
|
68
|
+
*
|
|
69
|
+
* @template TEvent - The event data type extending TEventData
|
|
70
|
+
* @param event - The event to partition
|
|
71
|
+
* @param args - Filter criteria (same as EventFilter)
|
|
72
|
+
* @returns Tuple of [matching event, non-matching event] where non-matching is null if event matches
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const event: UserEvent = {
|
|
77
|
+
* UserCreated: { userId: '123', username: 'john', role: 'admin' }
|
|
78
|
+
* };
|
|
79
|
+
*
|
|
80
|
+
* const [match, noMatch] = PartitionEventFilter(event, { role: 'admin' });
|
|
81
|
+
* // match = event, noMatch = null
|
|
82
|
+
*
|
|
83
|
+
* const [match2, noMatch2] = PartitionEventFilter(event, { role: 'user' });
|
|
84
|
+
* // match2 = null, noMatch2 = event
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export declare function PartitionEventFilter<TEvent extends TEventData = TEventData>(event: TEvent, args: IFilterCriteria | null | undefined): [TEvent | null, TEvent | null];
|
|
44
88
|
//# sourceMappingURL=event-filter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-filter.d.ts","sourceRoot":"","sources":["../src/event-filter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"event-filter.d.ts","sourceRoot":"","sources":["../src/event-filter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AACH,wBAAgB,WAAW,CAAC,MAAM,SAAS,UAAU,GAAG,UAAU,EACjE,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,GACtC,OAAO,CAmBT;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,SAAS,UAAU,GAAG,UAAU,EAC1E,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,GACtC,CAAC,MAAM,GAAG,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC,CAGhC"}
|
package/build/event-filter.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
|
+
import { ObjectFilter } from '@pawells/typescript-common';
|
|
1
2
|
/**
|
|
2
3
|
* Filters events based on payload property matching criteria.
|
|
3
4
|
* Performs strict equality comparison between event payload properties and filter arguments.
|
|
5
|
+
* Supports nested property paths using dot notation and predicate functions.
|
|
4
6
|
*
|
|
5
7
|
* @template TEvent - The event data type extending TEventData
|
|
6
8
|
* @param event - The event to filter, must have exactly one property representing the event type
|
|
7
|
-
* @param args - Filter criteria object with property-value pairs to match against the event payload
|
|
9
|
+
* @param args - Filter criteria object with property-value pairs to match against the event payload.
|
|
10
|
+
* Values can be:
|
|
11
|
+
* - Primitives: matched via strict equality
|
|
12
|
+
* - Functions: treated as predicates that must return true
|
|
13
|
+
* - Keys can use dot notation for nested paths (e.g., 'user.profile.role')
|
|
8
14
|
* @returns true if the event matches all filter criteria or if no filter is provided, false otherwise
|
|
9
15
|
*
|
|
10
16
|
* @throws {Error} 'No Event' - When event is null or undefined
|
|
@@ -18,20 +24,36 @@
|
|
|
18
24
|
* userId: string;
|
|
19
25
|
* username: string;
|
|
20
26
|
* role: string;
|
|
27
|
+
* profile: {
|
|
28
|
+
* age: number;
|
|
29
|
+
* status: string;
|
|
30
|
+
* };
|
|
21
31
|
* };
|
|
22
32
|
* }
|
|
23
33
|
*
|
|
24
34
|
* const event: UserEvent = {
|
|
25
|
-
* UserCreated: {
|
|
35
|
+
* UserCreated: {
|
|
36
|
+
* userId: '123',
|
|
37
|
+
* username: 'john',
|
|
38
|
+
* role: 'admin',
|
|
39
|
+
* profile: { age: 30, status: 'active' }
|
|
40
|
+
* }
|
|
26
41
|
* };
|
|
27
42
|
*
|
|
28
43
|
* // Match by single property
|
|
29
44
|
* EventFilter(event, { role: 'admin' }); // true
|
|
30
45
|
* EventFilter(event, { role: 'user' }); // false
|
|
31
46
|
*
|
|
32
|
-
* // Match by
|
|
33
|
-
* EventFilter(event, {
|
|
34
|
-
* EventFilter(event, {
|
|
47
|
+
* // Match by nested path
|
|
48
|
+
* EventFilter(event, { 'profile.age': 30 }); // true
|
|
49
|
+
* EventFilter(event, { 'profile.status': 'active' }); // true
|
|
50
|
+
*
|
|
51
|
+
* // Match by predicate function
|
|
52
|
+
* EventFilter(event, { 'profile.age': (v) => v > 18 }); // true
|
|
53
|
+
* EventFilter(event, { role: (r) => r === 'admin' }); // true
|
|
54
|
+
*
|
|
55
|
+
* // Multiple criteria
|
|
56
|
+
* EventFilter(event, { role: 'admin', 'profile.age': (v) => v > 18 }); // true
|
|
35
57
|
*
|
|
36
58
|
* // No filter (always passes)
|
|
37
59
|
* EventFilter(event, null); // true
|
|
@@ -47,7 +69,7 @@ export function EventFilter(event, args) {
|
|
|
47
69
|
// Identify Payload Key
|
|
48
70
|
const eventKeys = Object.keys(event);
|
|
49
71
|
if (eventKeys.length === 0)
|
|
50
|
-
throw new Error('
|
|
72
|
+
throw new Error('Event object must have exactly one top-level key, but received an empty object ({}).');
|
|
51
73
|
if (eventKeys.length > 1)
|
|
52
74
|
throw new Error('More than one payload structure.');
|
|
53
75
|
const eventKey = eventKeys[0];
|
|
@@ -55,12 +77,32 @@ export function EventFilter(event, args) {
|
|
|
55
77
|
const payload = event[eventKey];
|
|
56
78
|
if (!payload)
|
|
57
79
|
throw new Error('No Payload');
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
80
|
+
return ObjectFilter(payload, args);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Partitions an event into matching and non-matching tuples based on filter criteria.
|
|
84
|
+
* Uses EventFilter internally to apply the filtering logic.
|
|
85
|
+
*
|
|
86
|
+
* @template TEvent - The event data type extending TEventData
|
|
87
|
+
* @param event - The event to partition
|
|
88
|
+
* @param args - Filter criteria (same as EventFilter)
|
|
89
|
+
* @returns Tuple of [matching event, non-matching event] where non-matching is null if event matches
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* const event: UserEvent = {
|
|
94
|
+
* UserCreated: { userId: '123', username: 'john', role: 'admin' }
|
|
95
|
+
* };
|
|
96
|
+
*
|
|
97
|
+
* const [match, noMatch] = PartitionEventFilter(event, { role: 'admin' });
|
|
98
|
+
* // match = event, noMatch = null
|
|
99
|
+
*
|
|
100
|
+
* const [match2, noMatch2] = PartitionEventFilter(event, { role: 'user' });
|
|
101
|
+
* // match2 = null, noMatch2 = event
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export function PartitionEventFilter(event, args) {
|
|
105
|
+
const matches = EventFilter(event, args);
|
|
106
|
+
return matches ? [event, null] : [null, event];
|
|
65
107
|
}
|
|
66
108
|
//# sourceMappingURL=event-filter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-filter.js","sourceRoot":"","sources":["../src/event-filter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"event-filter.js","sourceRoot":"","sources":["../src/event-filter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAK1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AACH,MAAM,UAAU,WAAW,CAC1B,KAAa,EACb,IAAwC;IAExC,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC;IACxC,oEAAoE;IACpE,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,uBAAuB;IACvB,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAErC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,sFAAsF,CAAC,CAAC;IACpI,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IAE9E,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAiB,CAAC;IAE9C,mCAAmC;IACnC,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAiC,CAAC;IAEhE,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC;IAE5C,OAAO,YAAY,CAAC,OAAO,EAAE,IAA+B,CAAC,CAAC;AAC/D,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,oBAAoB,CACnC,KAAa,EACb,IAAwC;IAExC,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACzC,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { EventHandler } from './handler.js';
|
|
2
|
+
import { TEventData } from './event-data.js';
|
|
3
|
+
/**
|
|
4
|
+
* Collects events into batches of a specified size and yields each batch as an array.
|
|
5
|
+
* The final batch may be smaller if the total number of events is not a multiple of the batch size.
|
|
6
|
+
*
|
|
7
|
+
* @template TEvent - The event type
|
|
8
|
+
* @param handler - EventHandler to collect events from
|
|
9
|
+
* @param size - Size of each batch (must be > 0)
|
|
10
|
+
* @returns AsyncIterableIterator that yields arrays of events
|
|
11
|
+
*
|
|
12
|
+
* @throws {RangeError} When size is <= 0
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const handler = new EventHandler<MessageData, MessageEvent>('Message');
|
|
17
|
+
*
|
|
18
|
+
* // Batch events in groups of 5
|
|
19
|
+
* for await (const batch of ChunkEvents(handler, 5)) {
|
|
20
|
+
* console.log(`Processing batch of ${batch.length} events`);
|
|
21
|
+
* batch.forEach(event => processEvent(event));
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function ChunkEvents<TEvent extends TEventData = TEventData>(handler: EventHandler<any, TEvent>, size: number): AsyncIterableIterator<TEvent[]>;
|
|
26
|
+
/**
|
|
27
|
+
* Partitions an event stream into two separate async iterators: one for matching events and one for non-matching.
|
|
28
|
+
* The predicate function determines which iterator receives each event.
|
|
29
|
+
*
|
|
30
|
+
* @template TEvent - The event type
|
|
31
|
+
* @param handler - EventHandler to partition events from
|
|
32
|
+
* @param predicate - Function that determines if an event matches (true = matching, false = non-matching)
|
|
33
|
+
* @returns Tuple of [matching iterator, non-matching iterator]
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* const handler = new EventHandler<UserEvent, UserEvent>('UserCreated');
|
|
38
|
+
*
|
|
39
|
+
* // Split events by admin status
|
|
40
|
+
* const [admins, users] = PartitionEvents(handler, (event) => {
|
|
41
|
+
* return 'UserCreated' in event && event.UserCreated.role === 'admin';
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* // Process matching (admin) events
|
|
45
|
+
* for await (const event of admins) {
|
|
46
|
+
* console.log('Admin created:', event);
|
|
47
|
+
* }
|
|
48
|
+
*
|
|
49
|
+
* // Process non-matching (regular user) events in parallel
|
|
50
|
+
* for await (const event of users) {
|
|
51
|
+
* console.log('User created:', event);
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare function PartitionEvents<TEvent extends TEventData = TEventData>(handler: EventHandler<any, TEvent>, predicate: (event: TEvent) => boolean): [AsyncIterableIterator<TEvent>, AsyncIterableIterator<TEvent>];
|
|
56
|
+
/**
|
|
57
|
+
* Groups events by a key function and yields each group as a Map when the group reaches a specified size.
|
|
58
|
+
* Groups are keyed by the result of applying the key function to each event.
|
|
59
|
+
*
|
|
60
|
+
* @template TEvent - The event type
|
|
61
|
+
* @template TKey - The type of the grouping key
|
|
62
|
+
* @param handler - EventHandler to group events from
|
|
63
|
+
* @param keyFn - Function that extracts the grouping key from an event
|
|
64
|
+
* @param flushSize - Number of events needed to trigger a flush of a group
|
|
65
|
+
* @returns AsyncIterableIterator that yields Maps of grouped events
|
|
66
|
+
*
|
|
67
|
+
* @throws {RangeError} When flushSize is <= 0
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```typescript
|
|
71
|
+
* interface UserEvent extends TEventData {
|
|
72
|
+
* UserActivity: {
|
|
73
|
+
* userId: string;
|
|
74
|
+
* action: string;
|
|
75
|
+
* timestamp: number;
|
|
76
|
+
* };
|
|
77
|
+
* }
|
|
78
|
+
*
|
|
79
|
+
* const handler = new EventHandler<any, UserEvent>('UserActivity');
|
|
80
|
+
*
|
|
81
|
+
* // Group events by userId, flush each group after 10 events
|
|
82
|
+
* for await (const groups of GroupEventsByPayload(handler, (event) => {
|
|
83
|
+
* return 'UserActivity' in event ? event.UserActivity.userId : 'unknown';
|
|
84
|
+
* }, 10)) {
|
|
85
|
+
* groups.forEach((events, userId) => {
|
|
86
|
+
* console.log(`User ${userId} has ${events.length} events`);
|
|
87
|
+
* });
|
|
88
|
+
* }
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export declare function GroupEventsByPayload<TEvent extends TEventData = TEventData, TKey = string>(handler: EventHandler<any, TEvent>, keyFn: (event: TEvent) => TKey, flushSize: number): AsyncIterableIterator<Map<TKey, TEvent[]>>;
|
|
92
|
+
//# sourceMappingURL=event-operators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-operators.d.ts","sourceRoot":"","sources":["../src/event-operators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,WAAW,CAAC,MAAM,SAAS,UAAU,GAAG,UAAU,EACjE,OAAO,EAAE,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,EAClC,IAAI,EAAE,MAAM,GACV,qBAAqB,CAAC,MAAM,EAAE,CAAC,CAsBjC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,eAAe,CAAC,MAAM,SAAS,UAAU,GAAG,UAAU,EACrE,OAAO,EAAE,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,EAClC,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,GACnC,CAAC,qBAAqB,CAAC,MAAM,CAAC,EAAE,qBAAqB,CAAC,MAAM,CAAC,CAAC,CA2EhE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,SAAS,UAAU,GAAG,UAAU,EAAE,IAAI,GAAG,MAAM,EACzF,OAAO,EAAE,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,EAClC,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EAC9B,SAAS,EAAE,MAAM,GACf,qBAAqB,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAmC5C"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collects events into batches of a specified size and yields each batch as an array.
|
|
3
|
+
* The final batch may be smaller if the total number of events is not a multiple of the batch size.
|
|
4
|
+
*
|
|
5
|
+
* @template TEvent - The event type
|
|
6
|
+
* @param handler - EventHandler to collect events from
|
|
7
|
+
* @param size - Size of each batch (must be > 0)
|
|
8
|
+
* @returns AsyncIterableIterator that yields arrays of events
|
|
9
|
+
*
|
|
10
|
+
* @throws {RangeError} When size is <= 0
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const handler = new EventHandler<MessageData, MessageEvent>('Message');
|
|
15
|
+
*
|
|
16
|
+
* // Batch events in groups of 5
|
|
17
|
+
* for await (const batch of ChunkEvents(handler, 5)) {
|
|
18
|
+
* console.log(`Processing batch of ${batch.length} events`);
|
|
19
|
+
* batch.forEach(event => processEvent(event));
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function ChunkEvents(handler, size) {
|
|
24
|
+
if (size <= 0) {
|
|
25
|
+
throw new RangeError('Batch size must be greater than 0');
|
|
26
|
+
}
|
|
27
|
+
return (async function* () {
|
|
28
|
+
const batch = [];
|
|
29
|
+
for await (const event of handler) {
|
|
30
|
+
batch.push(event);
|
|
31
|
+
if (batch.length === size) {
|
|
32
|
+
yield [...batch];
|
|
33
|
+
batch.length = 0;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Yield any remaining events in the final batch
|
|
37
|
+
if (batch.length > 0) {
|
|
38
|
+
yield batch;
|
|
39
|
+
}
|
|
40
|
+
})();
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Partitions an event stream into two separate async iterators: one for matching events and one for non-matching.
|
|
44
|
+
* The predicate function determines which iterator receives each event.
|
|
45
|
+
*
|
|
46
|
+
* @template TEvent - The event type
|
|
47
|
+
* @param handler - EventHandler to partition events from
|
|
48
|
+
* @param predicate - Function that determines if an event matches (true = matching, false = non-matching)
|
|
49
|
+
* @returns Tuple of [matching iterator, non-matching iterator]
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const handler = new EventHandler<UserEvent, UserEvent>('UserCreated');
|
|
54
|
+
*
|
|
55
|
+
* // Split events by admin status
|
|
56
|
+
* const [admins, users] = PartitionEvents(handler, (event) => {
|
|
57
|
+
* return 'UserCreated' in event && event.UserCreated.role === 'admin';
|
|
58
|
+
* });
|
|
59
|
+
*
|
|
60
|
+
* // Process matching (admin) events
|
|
61
|
+
* for await (const event of admins) {
|
|
62
|
+
* console.log('Admin created:', event);
|
|
63
|
+
* }
|
|
64
|
+
*
|
|
65
|
+
* // Process non-matching (regular user) events in parallel
|
|
66
|
+
* for await (const event of users) {
|
|
67
|
+
* console.log('User created:', event);
|
|
68
|
+
* }
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export function PartitionEvents(handler, predicate) {
|
|
72
|
+
const matchingQueue = [];
|
|
73
|
+
const nonMatchingQueue = [];
|
|
74
|
+
let matchingResolve;
|
|
75
|
+
let nonMatchingResolve;
|
|
76
|
+
// Track reference count for proper cleanup
|
|
77
|
+
let activeIterators = 2;
|
|
78
|
+
// Subscribe to the handler and distribute events to appropriate queues
|
|
79
|
+
const subscriptionId = handler.Subscribe((event) => {
|
|
80
|
+
if (predicate(event)) {
|
|
81
|
+
matchingQueue.push(event);
|
|
82
|
+
if (matchingResolve) {
|
|
83
|
+
matchingResolve();
|
|
84
|
+
matchingResolve = undefined;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
nonMatchingQueue.push(event);
|
|
89
|
+
if (nonMatchingResolve) {
|
|
90
|
+
nonMatchingResolve();
|
|
91
|
+
nonMatchingResolve = undefined;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
const createIterator = (queue) => {
|
|
96
|
+
let closed = false;
|
|
97
|
+
return {
|
|
98
|
+
async next() {
|
|
99
|
+
if (closed) {
|
|
100
|
+
return { done: true, value: undefined };
|
|
101
|
+
}
|
|
102
|
+
while (queue.length === 0) {
|
|
103
|
+
await new Promise((resolve) => {
|
|
104
|
+
if (queue === matchingQueue) {
|
|
105
|
+
matchingResolve = resolve;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
nonMatchingResolve = resolve;
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (queue.length > 0) {
|
|
113
|
+
const event = queue.shift();
|
|
114
|
+
return { done: false, value: event };
|
|
115
|
+
}
|
|
116
|
+
return { done: true, value: undefined };
|
|
117
|
+
},
|
|
118
|
+
[Symbol.asyncIterator]() {
|
|
119
|
+
return this;
|
|
120
|
+
},
|
|
121
|
+
async return() {
|
|
122
|
+
await Promise.resolve();
|
|
123
|
+
closed = true;
|
|
124
|
+
activeIterators--;
|
|
125
|
+
// Only unsubscribe when all iterators have closed
|
|
126
|
+
if (activeIterators === 0) {
|
|
127
|
+
handler.Unsubscribe(subscriptionId);
|
|
128
|
+
}
|
|
129
|
+
return { done: true, value: undefined };
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
// Create iterators that share the same queues and handler
|
|
134
|
+
const matchingIterator = createIterator(matchingQueue);
|
|
135
|
+
const nonMatchingIterator = createIterator(nonMatchingQueue);
|
|
136
|
+
return [matchingIterator, nonMatchingIterator];
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Groups events by a key function and yields each group as a Map when the group reaches a specified size.
|
|
140
|
+
* Groups are keyed by the result of applying the key function to each event.
|
|
141
|
+
*
|
|
142
|
+
* @template TEvent - The event type
|
|
143
|
+
* @template TKey - The type of the grouping key
|
|
144
|
+
* @param handler - EventHandler to group events from
|
|
145
|
+
* @param keyFn - Function that extracts the grouping key from an event
|
|
146
|
+
* @param flushSize - Number of events needed to trigger a flush of a group
|
|
147
|
+
* @returns AsyncIterableIterator that yields Maps of grouped events
|
|
148
|
+
*
|
|
149
|
+
* @throws {RangeError} When flushSize is <= 0
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```typescript
|
|
153
|
+
* interface UserEvent extends TEventData {
|
|
154
|
+
* UserActivity: {
|
|
155
|
+
* userId: string;
|
|
156
|
+
* action: string;
|
|
157
|
+
* timestamp: number;
|
|
158
|
+
* };
|
|
159
|
+
* }
|
|
160
|
+
*
|
|
161
|
+
* const handler = new EventHandler<any, UserEvent>('UserActivity');
|
|
162
|
+
*
|
|
163
|
+
* // Group events by userId, flush each group after 10 events
|
|
164
|
+
* for await (const groups of GroupEventsByPayload(handler, (event) => {
|
|
165
|
+
* return 'UserActivity' in event ? event.UserActivity.userId : 'unknown';
|
|
166
|
+
* }, 10)) {
|
|
167
|
+
* groups.forEach((events, userId) => {
|
|
168
|
+
* console.log(`User ${userId} has ${events.length} events`);
|
|
169
|
+
* });
|
|
170
|
+
* }
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
export function GroupEventsByPayload(handler, keyFn, flushSize) {
|
|
174
|
+
if (flushSize <= 0) {
|
|
175
|
+
throw new RangeError('Flush size must be greater than 0');
|
|
176
|
+
}
|
|
177
|
+
return (async function* () {
|
|
178
|
+
const groups = new Map();
|
|
179
|
+
let totalCount = 0;
|
|
180
|
+
for await (const event of handler) {
|
|
181
|
+
const key = keyFn(event);
|
|
182
|
+
if (!groups.has(key)) {
|
|
183
|
+
groups.set(key, []);
|
|
184
|
+
}
|
|
185
|
+
const group = groups.get(key);
|
|
186
|
+
if (group) {
|
|
187
|
+
group.push(event);
|
|
188
|
+
totalCount++;
|
|
189
|
+
// Flush all groups when any reaches the flush size
|
|
190
|
+
if (group.length >= flushSize) {
|
|
191
|
+
yield new Map(groups);
|
|
192
|
+
groups.clear();
|
|
193
|
+
totalCount = 0;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// Yield any remaining groups
|
|
198
|
+
if (totalCount > 0) {
|
|
199
|
+
yield groups;
|
|
200
|
+
}
|
|
201
|
+
})();
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=event-operators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-operators.js","sourceRoot":"","sources":["../src/event-operators.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,WAAW,CAC1B,OAAkC,EAClC,IAAY;IAEZ,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC;QACf,MAAM,IAAI,UAAU,CAAC,mCAAmC,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,CAAC,KAAK,SAAS,CAAC;QACtB,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YACnC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAElB,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;gBAC3B,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC;gBACjB,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;YAClB,CAAC;QACF,CAAC;QAED,gDAAgD;QAChD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,KAAK,CAAC;QACb,CAAC;IACF,CAAC,CAAC,EAAE,CAAC;AACN,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,eAAe,CAC9B,OAAkC,EAClC,SAAqC;IAErC,MAAM,aAAa,GAAa,EAAE,CAAC;IACnC,MAAM,gBAAgB,GAAa,EAAE,CAAC;IACtC,IAAI,eAAyC,CAAC;IAC9C,IAAI,kBAA4C,CAAC;IAEjD,2CAA2C;IAC3C,IAAI,eAAe,GAAG,CAAC,CAAC;IAExB,uEAAuE;IACvE,MAAM,cAAc,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;QAClD,IAAI,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;YACtB,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,eAAe,EAAE,CAAC;gBACrB,eAAe,EAAE,CAAC;gBAClB,eAAe,GAAG,SAAS,CAAC;YAC7B,CAAC;QACF,CAAC;aAAM,CAAC;YACP,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC7B,IAAI,kBAAkB,EAAE,CAAC;gBACxB,kBAAkB,EAAE,CAAC;gBACrB,kBAAkB,GAAG,SAAS,CAAC;YAChC,CAAC;QACF,CAAC;IACF,CAAC,CAAC,CAAC;IAEH,MAAM,cAAc,GAAG,CAAC,KAAe,EAAiC,EAAE;QACzE,IAAI,MAAM,GAAG,KAAK,CAAC;QAEnB,OAAO;YACN,KAAK,CAAC,IAAI;gBACT,IAAI,MAAM,EAAE,CAAC;oBACZ,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;gBACzC,CAAC;gBAED,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC3B,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;wBACnC,IAAI,KAAK,KAAK,aAAa,EAAE,CAAC;4BAC7B,eAAe,GAAG,OAAO,CAAC;wBAC3B,CAAC;6BAAM,CAAC;4BACP,kBAAkB,GAAG,OAAO,CAAC;wBAC9B,CAAC;oBACF,CAAC,CAAC,CAAC;gBACJ,CAAC;gBAED,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACtB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,EAAY,CAAC;oBACtC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;gBACtC,CAAC;gBAED,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;YACzC,CAAC;YAED,CAAC,MAAM,CAAC,aAAa,CAAC;gBACrB,OAAO,IAAI,CAAC;YACb,CAAC;YAED,KAAK,CAAC,MAAM;gBACX,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;gBACxB,MAAM,GAAG,IAAI,CAAC;gBACd,eAAe,EAAE,CAAC;gBAClB,kDAAkD;gBAClD,IAAI,eAAe,KAAK,CAAC,EAAE,CAAC;oBAC3B,OAAO,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;gBACrC,CAAC;gBACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;YACzC,CAAC;SACD,CAAC;IACH,CAAC,CAAC;IAEF,0DAA0D;IAC1D,MAAM,gBAAgB,GAAG,cAAc,CAAC,aAAa,CAAC,CAAC;IACvD,MAAM,mBAAmB,GAAG,cAAc,CAAC,gBAAgB,CAAC,CAAC;IAE7D,OAAO,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,CAAC;AAChD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,UAAU,oBAAoB,CACnC,OAAkC,EAClC,KAA8B,EAC9B,SAAiB;IAEjB,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,UAAU,CAAC,mCAAmC,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,CAAC,KAAK,SAAS,CAAC;QACtB,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;QACzC,IAAI,UAAU,GAAG,CAAC,CAAC;QAEnB,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YACnC,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;YAEzB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACrB,CAAC;YAED,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC9B,IAAI,KAAK,EAAE,CAAC;gBACX,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAClB,UAAU,EAAE,CAAC;gBAEb,mDAAmD;gBACnD,IAAI,KAAK,CAAC,MAAM,IAAI,SAAS,EAAE,CAAC;oBAC/B,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;oBACtB,MAAM,CAAC,KAAK,EAAE,CAAC;oBACf,UAAU,GAAG,CAAC,CAAC;gBAChB,CAAC;YACF,CAAC;QACF,CAAC;QAED,6BAA6B;QAC7B,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACpB,MAAM,MAAM,CAAC;QACd,CAAC;IACF,CAAC,CAAC,EAAE,CAAC;AACN,CAAC"}
|