@fjell/core 4.4.49 → 4.4.50

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/index.js CHANGED
@@ -1519,6 +1519,50 @@ function getErrorInfo(error) {
1519
1519
  };
1520
1520
  }
1521
1521
 
1522
+ // src/event/events.ts
1523
+ function isCreateEvent(event) {
1524
+ return event.eventType === "create";
1525
+ }
1526
+ function isUpdateEvent(event) {
1527
+ return event.eventType === "update";
1528
+ }
1529
+ function isDeleteEvent(event) {
1530
+ return event.eventType === "delete";
1531
+ }
1532
+ function isActionEvent(event) {
1533
+ return event.eventType === "action";
1534
+ }
1535
+
1536
+ // src/event/subscription.ts
1537
+ function isItemSubscription(subscription) {
1538
+ return "key" in subscription;
1539
+ }
1540
+ function isLocationSubscription(subscription) {
1541
+ return "kta" in subscription && "location" in subscription;
1542
+ }
1543
+ function generateSubscriptionId() {
1544
+ return `sub-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1545
+ }
1546
+ function createItemSubscription(key, options) {
1547
+ return {
1548
+ id: generateSubscriptionId(),
1549
+ key,
1550
+ eventTypes: options?.eventTypes,
1551
+ scopes: options?.scopes,
1552
+ query: options?.query
1553
+ };
1554
+ }
1555
+ function createLocationSubscription(kta, location, options) {
1556
+ return {
1557
+ id: generateSubscriptionId(),
1558
+ kta,
1559
+ location,
1560
+ eventTypes: options?.eventTypes,
1561
+ scopes: options?.scopes,
1562
+ query: options?.query
1563
+ };
1564
+ }
1565
+
1522
1566
  // src/operations/Operations.ts
1523
1567
  function isPriKey2(key) {
1524
1568
  return !("loc" in key) || !key.loc;
@@ -1527,6 +1571,203 @@ function isComKey2(key) {
1527
1571
  return "loc" in key && key.loc && Array.isArray(key.loc) && key.loc.length > 0;
1528
1572
  }
1529
1573
 
1574
+ // src/event/matching.ts
1575
+ function doesEventMatchSubscription(event, subscription) {
1576
+ if (!doesScopeMatch(event.scopes, subscription.scopes)) {
1577
+ return false;
1578
+ }
1579
+ if (!doesEventTypeMatch(event.eventType, subscription.eventTypes)) {
1580
+ return false;
1581
+ }
1582
+ if (isItemSubscription(subscription)) {
1583
+ return doesKeyMatch(event.key, subscription.key);
1584
+ } else if (isLocationSubscription(subscription)) {
1585
+ return doesKeyMatchLocation(event.key, subscription.kta, subscription.location);
1586
+ }
1587
+ return false;
1588
+ }
1589
+ function doesScopeMatch(eventScopes, subscriptionScopes) {
1590
+ if (!subscriptionScopes || subscriptionScopes.length === 0) {
1591
+ return true;
1592
+ }
1593
+ return subscriptionScopes.some(
1594
+ (requiredScope) => eventScopes.includes(requiredScope)
1595
+ );
1596
+ }
1597
+ function doesEventTypeMatch(eventType, subscriptionEventTypes) {
1598
+ if (!subscriptionEventTypes || subscriptionEventTypes.length === 0) {
1599
+ return true;
1600
+ }
1601
+ return subscriptionEventTypes.includes(eventType);
1602
+ }
1603
+ function doesKeyMatch(eventKey, subscriptionKey) {
1604
+ if (isPriKey2(eventKey) && isPriKey2(subscriptionKey)) {
1605
+ return eventKey.pk === subscriptionKey.pk && eventKey.kt === subscriptionKey.kt;
1606
+ }
1607
+ if (isComKey2(eventKey) && isComKey2(subscriptionKey)) {
1608
+ const eventComKey = eventKey;
1609
+ const subscriptionComKey = subscriptionKey;
1610
+ if (eventComKey.pk !== subscriptionComKey.pk || eventComKey.kt !== subscriptionComKey.kt) {
1611
+ return false;
1612
+ }
1613
+ if (eventComKey.loc.length !== subscriptionComKey.loc.length) {
1614
+ return false;
1615
+ }
1616
+ return eventComKey.loc.every((eventLocKey, index) => {
1617
+ const subLocKey = subscriptionComKey.loc[index];
1618
+ return eventLocKey.lk === subLocKey.lk && eventLocKey.kt === subLocKey.kt;
1619
+ });
1620
+ }
1621
+ return false;
1622
+ }
1623
+ function doesKeyMatchLocation(eventKey, subscriptionKta, subscriptionLocation) {
1624
+ const targetItemType = subscriptionKta[subscriptionKta.length - 1];
1625
+ if (eventKey.kt !== targetItemType) {
1626
+ return false;
1627
+ }
1628
+ if (isPriKey2(eventKey)) {
1629
+ return subscriptionLocation.length === 0;
1630
+ }
1631
+ if (isComKey2(eventKey)) {
1632
+ const comKey = eventKey;
1633
+ return doesLocationMatch(comKey.loc, subscriptionLocation, subscriptionKta);
1634
+ }
1635
+ return false;
1636
+ }
1637
+ function doesLocationMatch(eventLocation, subscriptionLocation, _subscriptionKta) {
1638
+ if (subscriptionLocation.length === 0) {
1639
+ return true;
1640
+ }
1641
+ if (eventLocation.length < subscriptionLocation.length) {
1642
+ return false;
1643
+ }
1644
+ for (let i = 0; i < subscriptionLocation.length; i++) {
1645
+ const eventLocKey = eventLocation[i];
1646
+ const subLocKey = subscriptionLocation[i];
1647
+ if (!eventLocKey || !subLocKey) {
1648
+ return false;
1649
+ }
1650
+ if (eventLocKey.lk !== subLocKey.lk || eventLocKey.kt !== subLocKey.kt) {
1651
+ return false;
1652
+ }
1653
+ }
1654
+ return true;
1655
+ }
1656
+ function findMatchingSubscriptions(event, subscriptions) {
1657
+ return subscriptions.filter(
1658
+ (subscription) => doesEventMatchSubscription(event, subscription)
1659
+ );
1660
+ }
1661
+ function extractLocationValues(location) {
1662
+ return location.map((locKey) => String(locKey.lk));
1663
+ }
1664
+ function compareLocationValues(location1, location2) {
1665
+ if (location1.length !== location2.length) {
1666
+ return false;
1667
+ }
1668
+ return location1.every((locKey1, index) => {
1669
+ const locKey2 = location2[index];
1670
+ return locKey1.lk === locKey2.lk && locKey1.kt === locKey2.kt;
1671
+ });
1672
+ }
1673
+
1674
+ // src/event/types.ts
1675
+ var STANDARD_EVENT_TYPES = {
1676
+ CREATE: "create",
1677
+ UPDATE: "update",
1678
+ DELETE: "delete",
1679
+ ACTION: "action"
1680
+ };
1681
+ var STANDARD_SCOPES = {
1682
+ FIRESTORE: "firestore",
1683
+ SEQUELIZE: "sequelize",
1684
+ POSTGRESQL: "postgresql",
1685
+ MYSQL: "mysql",
1686
+ MONGODB: "mongodb",
1687
+ REDIS: "redis"
1688
+ };
1689
+ var SubscriptionStatus = /* @__PURE__ */ ((SubscriptionStatus2) => {
1690
+ SubscriptionStatus2["PENDING"] = "pending";
1691
+ SubscriptionStatus2["ACTIVE"] = "active";
1692
+ SubscriptionStatus2["PAUSED"] = "paused";
1693
+ SubscriptionStatus2["ERROR"] = "error";
1694
+ SubscriptionStatus2["CANCELLED"] = "cancelled";
1695
+ return SubscriptionStatus2;
1696
+ })(SubscriptionStatus || {});
1697
+ var DEFAULT_EVENT_CONFIG = {
1698
+ maxBatchSize: 100,
1699
+ maxBatchWaitTime: 50,
1700
+ // 50ms
1701
+ maxRetryAttempts: 3,
1702
+ retryDelay: 1e3,
1703
+ // 1 second
1704
+ enableStats: true,
1705
+ maxSubscriptions: 1e3,
1706
+ subscriptionCleanupInterval: 3e5
1707
+ // 5 minutes
1708
+ };
1709
+ var EventSystemError = class extends Error {
1710
+ constructor(message, code, details) {
1711
+ super(message);
1712
+ this.code = code;
1713
+ this.details = details;
1714
+ this.name = "EventSystemError";
1715
+ }
1716
+ };
1717
+ var SubscriptionError = class extends EventSystemError {
1718
+ constructor(message, subscriptionId, details) {
1719
+ super(message, "SUBSCRIPTION_ERROR", { subscriptionId, ...details });
1720
+ this.subscriptionId = subscriptionId;
1721
+ this.name = "SubscriptionError";
1722
+ }
1723
+ };
1724
+ var EventEmissionError = class extends EventSystemError {
1725
+ constructor(message, eventType, details) {
1726
+ super(message, "EVENT_EMISSION_ERROR", { eventType, ...details });
1727
+ this.eventType = eventType;
1728
+ this.name = "EventEmissionError";
1729
+ }
1730
+ };
1731
+ var EventMatchingError = class extends EventSystemError {
1732
+ constructor(message, details) {
1733
+ super(message, "EVENT_MATCHING_ERROR", details);
1734
+ this.name = "EventMatchingError";
1735
+ }
1736
+ };
1737
+ function createEventSystemError(type, message, details) {
1738
+ switch (type) {
1739
+ case "subscription":
1740
+ return new SubscriptionError(message, details?.subscriptionId || "unknown", details);
1741
+ case "emission":
1742
+ return new EventEmissionError(message, details?.eventType || "unknown", details);
1743
+ case "matching":
1744
+ return new EventMatchingError(message, details);
1745
+ case "general":
1746
+ default:
1747
+ return new EventSystemError(message, "GENERAL_ERROR", details);
1748
+ }
1749
+ }
1750
+ function isEventSystemError(error) {
1751
+ return error instanceof EventSystemError;
1752
+ }
1753
+
1754
+ // src/event/index.ts
1755
+ var EVENT_SYSTEM_VERSION = "1.0.0";
1756
+ var SUPPORTED_EVENT_TYPES = [
1757
+ "create",
1758
+ "update",
1759
+ "delete",
1760
+ "action"
1761
+ ];
1762
+ var SUPPORTED_SCOPES = [
1763
+ "firestore",
1764
+ "sequelize",
1765
+ "postgresql",
1766
+ "mysql",
1767
+ "mongodb",
1768
+ "redis"
1769
+ ];
1770
+
1530
1771
  // src/operations/wrappers/createOneWrapper.ts
1531
1772
  var logger9 = logger_default.get("operations", "wrappers", "one");
1532
1773
  function createOneWrapper(coordinate, implementation, options = {}) {
@@ -2078,12 +2319,23 @@ export {
2078
2319
  AItemService,
2079
2320
  ActionError,
2080
2321
  BusinessLogicError,
2322
+ DEFAULT_EVENT_CONFIG,
2081
2323
  Dictionary,
2082
2324
  DuplicateError,
2325
+ EVENT_SYSTEM_VERSION,
2326
+ EventEmissionError,
2327
+ EventMatchingError,
2328
+ EventSystemError,
2083
2329
  IFactory,
2084
2330
  IQFactory,
2085
2331
  NotFoundError,
2086
2332
  PermissionError,
2333
+ STANDARD_EVENT_TYPES,
2334
+ STANDARD_SCOPES,
2335
+ SUPPORTED_EVENT_TYPES,
2336
+ SUPPORTED_SCOPES,
2337
+ SubscriptionError,
2338
+ SubscriptionStatus,
2087
2339
  ValidationError,
2088
2340
  abbrevAgg,
2089
2341
  abbrevCompoundCondition,
@@ -2093,6 +2345,7 @@ export {
2093
2345
  abbrevQuery,
2094
2346
  abbrevRef,
2095
2347
  cPK,
2348
+ compareLocationValues,
2096
2349
  constructPriKey,
2097
2350
  createActionWrapper,
2098
2351
  createAllActionWrapper,
@@ -2100,34 +2353,52 @@ export {
2100
2353
  createAllWrapper,
2101
2354
  createCoordinate,
2102
2355
  createCreateWrapper,
2356
+ createEventSystemError,
2103
2357
  createFacetWrapper,
2104
2358
  createFindOneWrapper,
2105
2359
  createFindWrapper,
2106
2360
  createGetWrapper,
2361
+ createItemSubscription,
2362
+ createLocationSubscription,
2107
2363
  createNormalizedHashFunction,
2108
2364
  createOneWrapper,
2109
2365
  createRemoveWrapper,
2110
2366
  createUpdateWrapper,
2111
2367
  createUpsertWrapper,
2368
+ doesEventMatchSubscription,
2369
+ doesEventTypeMatch,
2370
+ doesKeyMatch,
2371
+ doesKeyMatchLocation,
2372
+ doesLocationMatch,
2373
+ doesScopeMatch,
2112
2374
  enhanceError,
2113
2375
  executeWithContext,
2114
2376
  executeWithContextSync,
2115
2377
  extractKeyTypeArray,
2378
+ extractLocationValues,
2379
+ findMatchingSubscriptions,
2116
2380
  generateKeyArray,
2381
+ generateSubscriptionId,
2117
2382
  getErrorInfo,
2118
2383
  ikToLKA,
2119
2384
  isActionError,
2385
+ isActionEvent,
2120
2386
  isComItem,
2121
2387
  isComKey,
2122
2388
  isComKeyEqual,
2123
2389
  isComKeyEqualNormalized,
2124
2390
  isCondition,
2391
+ isCreateEvent,
2392
+ isDeleteEvent,
2393
+ isEventSystemError,
2125
2394
  isItemKey,
2126
2395
  isItemKeyEqual,
2127
2396
  isItemKeyEqualNormalized,
2397
+ isItemSubscription,
2128
2398
  isLocKey,
2129
2399
  isLocKeyEqual,
2130
2400
  isLocKeyEqualNormalized,
2401
+ isLocationSubscription,
2131
2402
  isComKey2 as isOperationComKey,
2132
2403
  isPriKey2 as isOperationPriKey,
2133
2404
  isPriItem,
@@ -2135,6 +2406,7 @@ export {
2135
2406
  isPriKeyEqual,
2136
2407
  isPriKeyEqualNormalized,
2137
2408
  isQueryMatch,
2409
+ isUpdateEvent,
2138
2410
  isValidComKey,
2139
2411
  isValidItemKey,
2140
2412
  isValidLocKey,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fjell/core",
3
3
  "description": "Core Item and Key Framework for Fjell",
4
- "version": "4.4.49",
4
+ "version": "4.4.50",
5
5
  "keywords": [
6
6
  "core",
7
7
  "fjell"
@@ -0,0 +1,247 @@
1
+ import { ComKey, ItemTypeArray, LocKeyArray, PriKey } from '../keys';
2
+ import { Item } from '../items';
3
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
4
+ import { ActionEvent, BaseEvent, CreateEvent, DeleteEvent, UpdateEvent } from './events';
5
+ import { Subscription, SubscriptionOptions } from './subscription';
6
+
7
+ /**
8
+ * Core EventEmitter interface that storage libraries implement.
9
+ * Each item type gets its own EventEmitter instance for full type safety.
10
+ * Libraries implement separate EventEmitters per item type (UserEventEmitter, MessageEventEmitter, etc.)
11
+ */
12
+ export interface EventEmitter<
13
+ S extends string,
14
+ L1 extends string = never,
15
+ L2 extends string = never,
16
+ L3 extends string = never,
17
+ L4 extends string = never,
18
+ L5 extends string = never
19
+ > {
20
+ /**
21
+ * Emit a generic event with full control over event properties.
22
+ * Libraries can use this for custom events or when they need full control.
23
+ */
24
+ emit(event: BaseEvent<S, L1, L2, L3, L4, L5>): Promise<void>;
25
+
26
+ /**
27
+ * Emit a create event when an item is created.
28
+ * Convenience method that constructs a properly typed CreateEvent.
29
+ */
30
+ emitCreate(
31
+ key: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>,
32
+ scopes: string[],
33
+ item: Item<S, L1, L2, L3, L4, L5>
34
+ ): Promise<void>;
35
+
36
+ /**
37
+ * Emit an update event when an item is modified.
38
+ * Convenience method that constructs a properly typed UpdateEvent.
39
+ */
40
+ emitUpdate(
41
+ key: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>,
42
+ scopes: string[],
43
+ changes: string[],
44
+ before?: Item<S, L1, L2, L3, L4, L5>,
45
+ after?: Item<S, L1, L2, L3, L4, L5>
46
+ ): Promise<void>;
47
+
48
+ /**
49
+ * Emit a delete event when an item is deleted.
50
+ * Convenience method that constructs a properly typed DeleteEvent.
51
+ */
52
+ emitDelete(
53
+ key: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>,
54
+ scopes: string[],
55
+ item?: Item<S, L1, L2, L3, L4, L5>
56
+ ): Promise<void>;
57
+
58
+ /**
59
+ * Emit an action event when a custom action is performed.
60
+ * Convenience method that constructs a properly typed ActionEvent.
61
+ */
62
+ emitAction(
63
+ key: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>,
64
+ scopes: string[],
65
+ actionName: string,
66
+ actionData?: Record<string, unknown>
67
+ ): Promise<void>;
68
+
69
+ /**
70
+ * Create a scoped emitter that automatically includes the specified scopes.
71
+ * Libraries can use this to avoid passing scopes to every emit call.
72
+ */
73
+ withScopes(scopes: string[]): ScopedEventEmitter<S, L1, L2, L3, L4, L5>;
74
+ }
75
+
76
+ /**
77
+ * Scoped EventEmitter that automatically includes configured scopes.
78
+ * Convenience interface for libraries to avoid passing scopes repeatedly.
79
+ */
80
+ export interface ScopedEventEmitter<
81
+ S extends string,
82
+ L1 extends string = never,
83
+ L2 extends string = never,
84
+ L3 extends string = never,
85
+ L4 extends string = never,
86
+ L5 extends string = never
87
+ > {
88
+ /** The scopes that will be automatically included in all events */
89
+ readonly scopes: string[];
90
+
91
+ /**
92
+ * Emit a generic event with automatic scope inclusion.
93
+ * The event should omit scopes since they'll be added automatically.
94
+ */
95
+ emit(event: Omit<BaseEvent<S, L1, L2, L3, L4, L5>, 'scopes'>): Promise<void>;
96
+
97
+ /**
98
+ * Emit a create event with automatic scope inclusion.
99
+ */
100
+ emitCreate(
101
+ key: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>,
102
+ item: Item<S, L1, L2, L3, L4, L5>
103
+ ): Promise<void>;
104
+
105
+ /**
106
+ * Emit an update event with automatic scope inclusion.
107
+ */
108
+ emitUpdate(
109
+ key: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>,
110
+ changes: string[],
111
+ before?: Item<S, L1, L2, L3, L4, L5>,
112
+ after?: Item<S, L1, L2, L3, L4, L5>
113
+ ): Promise<void>;
114
+
115
+ /**
116
+ * Emit a delete event with automatic scope inclusion.
117
+ */
118
+ emitDelete(
119
+ key: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>,
120
+ item?: Item<S, L1, L2, L3, L4, L5>
121
+ ): Promise<void>;
122
+
123
+ /**
124
+ * Emit an action event with automatic scope inclusion.
125
+ */
126
+ emitAction(
127
+ key: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>,
128
+ actionName: string,
129
+ actionData?: Record<string, unknown>
130
+ ): Promise<void>;
131
+ }
132
+
133
+ /**
134
+ * EventSubscriber interface for subscribing to and receiving events.
135
+ * Each item type gets its own EventSubscriber instance for full type safety.
136
+ */
137
+ export interface EventSubscriber<
138
+ S extends string,
139
+ L1 extends string = never,
140
+ L2 extends string = never,
141
+ L3 extends string = never,
142
+ L4 extends string = never,
143
+ L5 extends string = never
144
+ > {
145
+ /**
146
+ * Subscribe to events using a full subscription object.
147
+ * Returns the subscription ID for later unsubscribing.
148
+ */
149
+ subscribe(subscription: Omit<Subscription<S, L1, L2, L3, L4, L5>, 'id'>): Promise<string>;
150
+
151
+ /**
152
+ * Unsubscribe from events using the subscription ID.
153
+ */
154
+ unsubscribe(subscriptionId: string): Promise<void>;
155
+
156
+ /**
157
+ * Register a callback to be called when events are received.
158
+ * Multiple callbacks can be registered and they'll all be called.
159
+ */
160
+ onEvent(callback: (event: BaseEvent<S, L1, L2, L3, L4, L5>) => void): void;
161
+
162
+ /**
163
+ * Remove a previously registered event callback.
164
+ */
165
+ removeEventListener(callback: (event: BaseEvent<S, L1, L2, L3, L4, L5>) => void): void;
166
+
167
+ /**
168
+ * Convenience method to subscribe to a specific item.
169
+ * Automatically creates an ItemSubscription with the provided options.
170
+ */
171
+ subscribeToItem(
172
+ key: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>,
173
+ options?: SubscriptionOptions<S, L1, L2, L3, L4, L5>
174
+ ): Promise<string>;
175
+
176
+ /**
177
+ * Convenience method to subscribe to a location.
178
+ * Automatically creates a LocationSubscription with the provided options.
179
+ */
180
+ subscribeToLocation(
181
+ kta: ItemTypeArray<S, L1, L2, L3, L4, L5>,
182
+ location: LocKeyArray<L1, L2, L3, L4, L5>,
183
+ options?: SubscriptionOptions<S, L1, L2, L3, L4, L5>
184
+ ): Promise<string>;
185
+
186
+ /**
187
+ * Get all currently active subscriptions.
188
+ * Useful for debugging and subscription management.
189
+ */
190
+ getActiveSubscriptions(): Subscription<S, L1, L2, L3, L4, L5>[];
191
+
192
+ /**
193
+ * Check if an event matches any active subscriptions.
194
+ * Used internally by libraries to determine if an event should be processed.
195
+ */
196
+ matchesSubscription(event: BaseEvent<S, L1, L2, L3, L4, L5>): boolean;
197
+
198
+ /**
199
+ * Check if an event matches a specific subscription.
200
+ * Used internally for subscription matching logic.
201
+ */
202
+ matchesSpecificSubscription(
203
+ event: BaseEvent<S, L1, L2, L3, L4, L5>,
204
+ subscription: Subscription<S, L1, L2, L3, L4, L5>
205
+ ): boolean;
206
+ }
207
+
208
+ /**
209
+ * Combined EventSystem interface that includes both emitter and subscriber.
210
+ * Libraries can implement this interface to provide both event emission and subscription.
211
+ */
212
+ export interface EventSystem<
213
+ S extends string,
214
+ L1 extends string = never,
215
+ L2 extends string = never,
216
+ L3 extends string = never,
217
+ L4 extends string = never,
218
+ L5 extends string = never
219
+ > {
220
+ /** Event emitter for publishing events */
221
+ readonly emitter: EventEmitter<S, L1, L2, L3, L4, L5>;
222
+
223
+ /** Event subscriber for receiving events */
224
+ readonly subscriber: EventSubscriber<S, L1, L2, L3, L4, L5>;
225
+ }
226
+
227
+ /**
228
+ * Factory function type for creating EventSystems.
229
+ * Libraries implement this to create properly configured event systems.
230
+ */
231
+ export type EventSystemFactory<
232
+ S extends string,
233
+ L1 extends string = never,
234
+ L2 extends string = never,
235
+ L3 extends string = never,
236
+ L4 extends string = never,
237
+ L5 extends string = never
238
+ > = (scopes: string[]) => EventSystem<S, L1, L2, L3, L4, L5>;
239
+
240
+ // Type aliases for common usage patterns in libraries
241
+ export type UserEventEmitter = EventEmitter<'User'>;
242
+ export type UserEventSubscriber = EventSubscriber<'User'>;
243
+ export type UserEventSystem = EventSystem<'User'>;
244
+
245
+ export type MessageEventEmitter<L1 extends string, L2 extends string> = EventEmitter<'Message', L1, L2>;
246
+ export type MessageEventSubscriber<L1 extends string, L2 extends string> = EventSubscriber<'Message', L1, L2>;
247
+ export type MessageEventSystem<L1 extends string, L2 extends string> = EventSystem<'Message', L1, L2>;