@fjell/core 4.4.48 → 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/README.md +92 -0
- package/dist/Coordinate.d.ts +7 -0
- package/dist/errors/ActionError.d.ts +51 -0
- package/dist/errors/BusinessLogicError.d.ts +4 -0
- package/dist/errors/DuplicateError.d.ts +4 -0
- package/dist/errors/NotFoundError.d.ts +4 -0
- package/dist/errors/PermissionError.d.ts +4 -0
- package/dist/errors/ValidationError.d.ts +4 -0
- package/dist/errors/index.d.ts +6 -0
- package/dist/event/emitter.d.ts +140 -0
- package/dist/event/events.d.ts +81 -0
- package/dist/event/index.d.ts +38 -0
- package/dist/event/matching.d.ts +54 -0
- package/dist/event/subscription.d.ts +74 -0
- package/dist/event/types.d.ts +186 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +1584 -47
- package/dist/item/IUtils.d.ts +6 -3
- package/dist/operations/OperationContext.d.ts +10 -0
- package/dist/operations/Operations.d.ts +259 -0
- package/dist/operations/contained.d.ts +65 -0
- package/dist/operations/errorEnhancer.d.ts +79 -0
- package/dist/operations/index.d.ts +2 -0
- package/dist/operations/methods.d.ts +134 -0
- package/dist/operations/primary.d.ts +57 -0
- package/dist/operations/specialized.d.ts +41 -0
- package/dist/operations/wrappers/createActionWrapper.d.ts +28 -0
- package/dist/operations/wrappers/createAllActionWrapper.d.ts +28 -0
- package/dist/operations/wrappers/createAllFacetWrapper.d.ts +27 -0
- package/dist/operations/wrappers/createAllWrapper.d.ts +28 -0
- package/dist/operations/wrappers/createCreateWrapper.d.ts +28 -0
- package/dist/operations/wrappers/createFacetWrapper.d.ts +27 -0
- package/dist/operations/wrappers/createFindOneWrapper.d.ts +28 -0
- package/dist/operations/wrappers/createFindWrapper.d.ts +28 -0
- package/dist/operations/wrappers/createGetWrapper.d.ts +28 -0
- package/dist/operations/wrappers/createOneWrapper.d.ts +38 -0
- package/dist/operations/wrappers/createRemoveWrapper.d.ts +28 -0
- package/dist/operations/wrappers/createUpdateWrapper.d.ts +28 -0
- package/dist/operations/wrappers/createUpsertWrapper.d.ts +28 -0
- package/dist/operations/wrappers/index.d.ts +34 -0
- package/dist/operations/wrappers/types.d.ts +48 -0
- package/dist/validation/ItemValidator.d.ts +43 -0
- package/dist/validation/KeyValidator.d.ts +56 -0
- package/dist/validation/LocationValidator.d.ts +39 -0
- package/dist/validation/QueryValidator.d.ts +57 -0
- package/dist/validation/index.d.ts +15 -0
- package/dist/validation/index.js +501 -0
- package/dist/validation/types.d.ts +38 -0
- package/package.json +7 -2
- package/src/Coordinate.ts +35 -0
- package/src/errors/ActionError.ts +69 -0
- package/src/errors/BusinessLogicError.ts +24 -0
- package/src/errors/DuplicateError.ts +57 -0
- package/src/errors/NotFoundError.ts +24 -0
- package/src/errors/PermissionError.ts +31 -0
- package/src/errors/ValidationError.ts +27 -0
- package/src/errors/index.ts +7 -0
- package/src/event/emitter.ts +247 -0
- package/src/event/events.ts +178 -0
- package/src/event/index.ts +130 -0
- package/src/event/matching.ts +264 -0
- package/src/event/subscription.ts +181 -0
- package/src/event/types.ts +282 -0
- package/src/index.ts +57 -0
- package/src/item/IUtils.ts +9 -80
- package/src/operations/OperationContext.ts +12 -0
- package/src/operations/Operations.ts +357 -0
- package/src/operations/contained.ts +134 -0
- package/src/operations/errorEnhancer.ts +204 -0
- package/src/operations/index.ts +2 -0
- package/src/operations/methods.ts +363 -0
- package/src/operations/primary.ts +101 -0
- package/src/operations/specialized.ts +71 -0
- package/src/operations/wrappers/createActionWrapper.ts +108 -0
- package/src/operations/wrappers/createAllActionWrapper.ts +109 -0
- package/src/operations/wrappers/createAllFacetWrapper.ts +98 -0
- package/src/operations/wrappers/createAllWrapper.ts +103 -0
- package/src/operations/wrappers/createCreateWrapper.ts +117 -0
- package/src/operations/wrappers/createFacetWrapper.ts +97 -0
- package/src/operations/wrappers/createFindOneWrapper.ts +105 -0
- package/src/operations/wrappers/createFindWrapper.ts +105 -0
- package/src/operations/wrappers/createGetWrapper.ts +96 -0
- package/src/operations/wrappers/createOneWrapper.ts +128 -0
- package/src/operations/wrappers/createRemoveWrapper.ts +91 -0
- package/src/operations/wrappers/createUpdateWrapper.ts +106 -0
- package/src/operations/wrappers/createUpsertWrapper.ts +108 -0
- package/src/operations/wrappers/index.ts +39 -0
- package/src/operations/wrappers/types.ts +63 -0
- package/src/validation/ItemValidator.ts +131 -0
- package/src/validation/KeyValidator.ts +365 -0
- package/src/validation/LocationValidator.ts +136 -0
- package/src/validation/QueryValidator.ts +250 -0
- package/src/validation/index.ts +32 -0
- package/src/validation/types.ts +45 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Event System Public API
|
|
3
|
+
*
|
|
4
|
+
* This module exports all the public interfaces and utilities for the Fjell event system.
|
|
5
|
+
* The event system provides type-safe, item-level change events with full PriKey/ComKey integration.
|
|
6
|
+
*
|
|
7
|
+
* Key Features:
|
|
8
|
+
* - Full type safety using existing PriKey/ComKey system
|
|
9
|
+
* - Storage-agnostic event interfaces
|
|
10
|
+
* - Item-specific and location-based subscriptions
|
|
11
|
+
* - Separate EventEmitters per item type for optimal type safety
|
|
12
|
+
* - Real-time awareness for application needs (not reliable business execution)
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* - Libraries implement EventEmitter/EventSubscriber interfaces
|
|
16
|
+
* - Applications subscribe to events through library instances
|
|
17
|
+
* - Events are delivered through callback functions with full type safety
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
// Core Event Types
|
|
21
|
+
export {
|
|
22
|
+
BaseEvent,
|
|
23
|
+
CreateEvent,
|
|
24
|
+
UpdateEvent,
|
|
25
|
+
DeleteEvent,
|
|
26
|
+
ActionEvent,
|
|
27
|
+
Event,
|
|
28
|
+
isCreateEvent,
|
|
29
|
+
isUpdateEvent,
|
|
30
|
+
isDeleteEvent,
|
|
31
|
+
isActionEvent,
|
|
32
|
+
} from './events';
|
|
33
|
+
|
|
34
|
+
// Subscription Interfaces
|
|
35
|
+
export {
|
|
36
|
+
BaseSubscription,
|
|
37
|
+
ItemSubscription,
|
|
38
|
+
LocationSubscription,
|
|
39
|
+
Subscription,
|
|
40
|
+
SubscriptionOptions,
|
|
41
|
+
isItemSubscription,
|
|
42
|
+
isLocationSubscription,
|
|
43
|
+
generateSubscriptionId,
|
|
44
|
+
createItemSubscription,
|
|
45
|
+
createLocationSubscription,
|
|
46
|
+
} from './subscription';
|
|
47
|
+
|
|
48
|
+
// Event Emitter/Subscriber Interfaces
|
|
49
|
+
export {
|
|
50
|
+
EventEmitter,
|
|
51
|
+
ScopedEventEmitter,
|
|
52
|
+
EventSubscriber,
|
|
53
|
+
EventSystem,
|
|
54
|
+
EventSystemFactory,
|
|
55
|
+
// Type aliases for common patterns
|
|
56
|
+
UserEventEmitter,
|
|
57
|
+
UserEventSubscriber,
|
|
58
|
+
UserEventSystem,
|
|
59
|
+
MessageEventEmitter,
|
|
60
|
+
MessageEventSubscriber,
|
|
61
|
+
MessageEventSystem,
|
|
62
|
+
} from './emitter';
|
|
63
|
+
|
|
64
|
+
// Subscription Matching Logic
|
|
65
|
+
export {
|
|
66
|
+
doesEventMatchSubscription,
|
|
67
|
+
doesScopeMatch,
|
|
68
|
+
doesEventTypeMatch,
|
|
69
|
+
doesKeyMatch,
|
|
70
|
+
doesKeyMatchLocation,
|
|
71
|
+
doesLocationMatch,
|
|
72
|
+
findMatchingSubscriptions,
|
|
73
|
+
extractLocationValues,
|
|
74
|
+
compareLocationValues,
|
|
75
|
+
} from './matching';
|
|
76
|
+
|
|
77
|
+
// Shared Types and Utilities
|
|
78
|
+
export {
|
|
79
|
+
STANDARD_EVENT_TYPES,
|
|
80
|
+
StandardEventType,
|
|
81
|
+
STANDARD_SCOPES,
|
|
82
|
+
StandardScope,
|
|
83
|
+
SubscriptionStatus,
|
|
84
|
+
SubscriptionMetadata,
|
|
85
|
+
ManagedSubscription,
|
|
86
|
+
EventHandler,
|
|
87
|
+
SafeEventHandler,
|
|
88
|
+
EventBatch,
|
|
89
|
+
EventStats,
|
|
90
|
+
EventSystemConfig,
|
|
91
|
+
DEFAULT_EVENT_CONFIG,
|
|
92
|
+
EventSystemError,
|
|
93
|
+
SubscriptionError,
|
|
94
|
+
EventEmissionError,
|
|
95
|
+
EventMatchingError,
|
|
96
|
+
createEventSystemError,
|
|
97
|
+
isEventSystemError,
|
|
98
|
+
ExtractItemType,
|
|
99
|
+
ExtractEventTypes,
|
|
100
|
+
} from './types';
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Version of the event system API.
|
|
104
|
+
* Used for compatibility checking and debugging.
|
|
105
|
+
*/
|
|
106
|
+
export const EVENT_SYSTEM_VERSION = '1.0.0';
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Supported event types for reference.
|
|
110
|
+
* Libraries should use these standard types for consistency.
|
|
111
|
+
*/
|
|
112
|
+
export const SUPPORTED_EVENT_TYPES = [
|
|
113
|
+
'create',
|
|
114
|
+
'update',
|
|
115
|
+
'delete',
|
|
116
|
+
'action',
|
|
117
|
+
] as const;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Supported storage scopes for reference.
|
|
121
|
+
* Libraries should use these standard scopes for consistency.
|
|
122
|
+
*/
|
|
123
|
+
export const SUPPORTED_SCOPES = [
|
|
124
|
+
'firestore',
|
|
125
|
+
'sequelize',
|
|
126
|
+
'postgresql',
|
|
127
|
+
'mysql',
|
|
128
|
+
'mongodb',
|
|
129
|
+
'redis',
|
|
130
|
+
] as const;
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { ComKey, ItemTypeArray, LocKeyArray, PriKey } from '../keys';
|
|
2
|
+
import { isComKey, isPriKey } from '../operations/Operations';
|
|
3
|
+
import { BaseEvent } from './events';
|
|
4
|
+
import { isItemSubscription, isLocationSubscription, Subscription } from './subscription';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Core subscription matching logic.
|
|
8
|
+
* Determines whether an event should be delivered to a specific subscription.
|
|
9
|
+
*/
|
|
10
|
+
export function doesEventMatchSubscription<
|
|
11
|
+
S extends string,
|
|
12
|
+
L1 extends string = never,
|
|
13
|
+
L2 extends string = never,
|
|
14
|
+
L3 extends string = never,
|
|
15
|
+
L4 extends string = never,
|
|
16
|
+
L5 extends string = never
|
|
17
|
+
>(
|
|
18
|
+
event: BaseEvent<S, L1, L2, L3, L4, L5>,
|
|
19
|
+
subscription: Subscription<S, L1, L2, L3, L4, L5>
|
|
20
|
+
): boolean {
|
|
21
|
+
// Check scope compatibility first (most efficient filter)
|
|
22
|
+
if (!doesScopeMatch(event.scopes, subscription.scopes)) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Check event type compatibility
|
|
27
|
+
if (!doesEventTypeMatch(event.eventType, subscription.eventTypes)) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Check key/location pattern matching
|
|
32
|
+
if (isItemSubscription(subscription)) {
|
|
33
|
+
return doesKeyMatch(event.key, subscription.key);
|
|
34
|
+
} else if (isLocationSubscription(subscription)) {
|
|
35
|
+
return doesKeyMatchLocation(event.key, subscription.kta, subscription.location);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Check if event scopes match subscription scope requirements.
|
|
43
|
+
*
|
|
44
|
+
* @param eventScopes - Scopes from the event (e.g., ["firestore"])
|
|
45
|
+
* @param subscriptionScopes - Optional scopes required by subscription
|
|
46
|
+
* @returns true if scopes are compatible
|
|
47
|
+
*/
|
|
48
|
+
export function doesScopeMatch(
|
|
49
|
+
eventScopes: string[],
|
|
50
|
+
subscriptionScopes?: string[]
|
|
51
|
+
): boolean {
|
|
52
|
+
// If subscription doesn't specify scopes, accept events from any scope
|
|
53
|
+
if (!subscriptionScopes || subscriptionScopes.length === 0) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Check if any of the event's scopes match any of the subscription's required scopes
|
|
58
|
+
return subscriptionScopes.some(requiredScope =>
|
|
59
|
+
eventScopes.includes(requiredScope)
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Check if event type matches subscription event type requirements.
|
|
65
|
+
*
|
|
66
|
+
* @param eventType - Type from the event (e.g., "create", "update")
|
|
67
|
+
* @param subscriptionEventTypes - Optional event types required by subscription
|
|
68
|
+
* @returns true if event type is compatible
|
|
69
|
+
*/
|
|
70
|
+
export function doesEventTypeMatch(
|
|
71
|
+
eventType: string,
|
|
72
|
+
subscriptionEventTypes?: string[]
|
|
73
|
+
): boolean {
|
|
74
|
+
// If subscription doesn't specify event types, accept all event types
|
|
75
|
+
if (!subscriptionEventTypes || subscriptionEventTypes.length === 0) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Check if the event type is in the subscription's allowed types
|
|
80
|
+
return subscriptionEventTypes.includes(eventType);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Check if two keys are exactly equal.
|
|
85
|
+
* Used for item-based subscriptions that want events for a specific key.
|
|
86
|
+
*/
|
|
87
|
+
export function doesKeyMatch<
|
|
88
|
+
S extends string,
|
|
89
|
+
L1 extends string = never,
|
|
90
|
+
L2 extends string = never,
|
|
91
|
+
L3 extends string = never,
|
|
92
|
+
L4 extends string = never,
|
|
93
|
+
L5 extends string = never
|
|
94
|
+
>(
|
|
95
|
+
eventKey: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>,
|
|
96
|
+
subscriptionKey: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>
|
|
97
|
+
): boolean {
|
|
98
|
+
// Both must be the same type (PriKey or ComKey)
|
|
99
|
+
if (isPriKey(eventKey) && isPriKey(subscriptionKey)) {
|
|
100
|
+
return eventKey.pk === subscriptionKey.pk && eventKey.kt === subscriptionKey.kt;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (isComKey(eventKey) && isComKey(subscriptionKey)) {
|
|
104
|
+
const eventComKey = eventKey as ComKey<S, L1, L2, L3, L4, L5>;
|
|
105
|
+
const subscriptionComKey = subscriptionKey as ComKey<S, L1, L2, L3, L4, L5>;
|
|
106
|
+
|
|
107
|
+
// Compare primary key and key type
|
|
108
|
+
if (eventComKey.pk !== subscriptionComKey.pk || eventComKey.kt !== subscriptionComKey.kt) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Compare location arrays
|
|
113
|
+
if (eventComKey.loc.length !== subscriptionComKey.loc.length) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Check each location key
|
|
118
|
+
return eventComKey.loc.every((eventLocKey, index) => {
|
|
119
|
+
const subLocKey = subscriptionComKey.loc[index];
|
|
120
|
+
return eventLocKey.lk === subLocKey.lk && eventLocKey.kt === subLocKey.kt;
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return false; // Different key types don't match
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Check if an event key matches a location-based subscription.
|
|
129
|
+
* This is more complex as it needs to determine if the event key is "within" the subscription location.
|
|
130
|
+
*/
|
|
131
|
+
export function doesKeyMatchLocation<
|
|
132
|
+
S extends string,
|
|
133
|
+
L1 extends string = never,
|
|
134
|
+
L2 extends string = never,
|
|
135
|
+
L3 extends string = never,
|
|
136
|
+
L4 extends string = never,
|
|
137
|
+
L5 extends string = never
|
|
138
|
+
>(
|
|
139
|
+
eventKey: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>,
|
|
140
|
+
subscriptionKta: ItemTypeArray<S, L1, L2, L3, L4, L5>,
|
|
141
|
+
subscriptionLocation: LocKeyArray<L1, L2, L3, L4, L5>
|
|
142
|
+
): boolean {
|
|
143
|
+
// First, check if the key type matches the target type in the KTA
|
|
144
|
+
const targetItemType = subscriptionKta[subscriptionKta.length - 1];
|
|
145
|
+
if (eventKey.kt !== targetItemType) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// For PriKey events
|
|
150
|
+
if (isPriKey(eventKey)) {
|
|
151
|
+
// PriKey can only match location subscriptions with empty locations (root level)
|
|
152
|
+
return subscriptionLocation.length === 0;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// For ComKey events
|
|
156
|
+
if (isComKey(eventKey)) {
|
|
157
|
+
const comKey = eventKey as ComKey<S, L1, L2, L3, L4, L5>;
|
|
158
|
+
// The event's location must match the subscription location exactly or be a sub-location
|
|
159
|
+
return doesLocationMatch(comKey.loc, subscriptionLocation, subscriptionKta);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Check if an event's location keys match a subscription's location requirements.
|
|
167
|
+
* This implements the hierarchical location matching logic.
|
|
168
|
+
*/
|
|
169
|
+
export function doesLocationMatch<
|
|
170
|
+
L1 extends string = never,
|
|
171
|
+
L2 extends string = never,
|
|
172
|
+
L3 extends string = never,
|
|
173
|
+
L4 extends string = never,
|
|
174
|
+
L5 extends string = never
|
|
175
|
+
>(
|
|
176
|
+
eventLocation: LocKeyArray<L1, L2, L3, L4, L5>,
|
|
177
|
+
subscriptionLocation: LocKeyArray<L1, L2, L3, L4, L5>,
|
|
178
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
179
|
+
_subscriptionKta: ItemTypeArray<string, L1, L2, L3, L4, L5>
|
|
180
|
+
): boolean {
|
|
181
|
+
// If subscription location is empty, it matches all locations (root level subscription)
|
|
182
|
+
if (subscriptionLocation.length === 0) {
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Event location must be at least as deep as subscription location
|
|
187
|
+
if (eventLocation.length < subscriptionLocation.length) {
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Check that all subscription location keys match the corresponding event location keys
|
|
192
|
+
for (let i = 0; i < subscriptionLocation.length; i++) {
|
|
193
|
+
const eventLocKey = eventLocation[i];
|
|
194
|
+
const subLocKey = subscriptionLocation[i];
|
|
195
|
+
|
|
196
|
+
if (!eventLocKey || !subLocKey) {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (eventLocKey.lk !== subLocKey.lk || eventLocKey.kt !== subLocKey.kt) {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Find all subscriptions that match a given event.
|
|
210
|
+
* Used by EventSubscriber implementations to determine which subscriptions should receive an event.
|
|
211
|
+
*/
|
|
212
|
+
export function findMatchingSubscriptions<
|
|
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: BaseEvent<S, L1, L2, L3, L4, L5>,
|
|
221
|
+
subscriptions: Subscription<S, L1, L2, L3, L4, L5>[]
|
|
222
|
+
): Subscription<S, L1, L2, L3, L4, L5>[] {
|
|
223
|
+
return subscriptions.filter(subscription =>
|
|
224
|
+
doesEventMatchSubscription(event, subscription)
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Utility function to extract the location from a ComKey for comparison purposes.
|
|
230
|
+
* Returns the location key values as strings for easier comparison.
|
|
231
|
+
*/
|
|
232
|
+
export function extractLocationValues<
|
|
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
|
+
>(location: LocKeyArray<L1, L2, L3, L4, L5>): string[] {
|
|
239
|
+
return location.map(locKey => String(locKey.lk));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Utility function to compare two location arrays by their values.
|
|
244
|
+
* Useful for debugging and testing location matching logic.
|
|
245
|
+
*/
|
|
246
|
+
export function compareLocationValues<
|
|
247
|
+
L1 extends string = never,
|
|
248
|
+
L2 extends string = never,
|
|
249
|
+
L3 extends string = never,
|
|
250
|
+
L4 extends string = never,
|
|
251
|
+
L5 extends string = never
|
|
252
|
+
>(
|
|
253
|
+
location1: LocKeyArray<L1, L2, L3, L4, L5>,
|
|
254
|
+
location2: LocKeyArray<L1, L2, L3, L4, L5>
|
|
255
|
+
): boolean {
|
|
256
|
+
if (location1.length !== location2.length) {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return location1.every((locKey1, index) => {
|
|
261
|
+
const locKey2 = location2[index];
|
|
262
|
+
return locKey1.lk === locKey2.lk && locKey1.kt === locKey2.kt;
|
|
263
|
+
});
|
|
264
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
import { ComKey, ItemTypeArray, LocKeyArray, PriKey } from '../keys';
|
|
3
|
+
import { ItemQuery } from '../item/ItemQuery';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Base subscription interface that all subscription types extend.
|
|
7
|
+
* Provides core subscription properties with full type safety.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export interface BaseSubscription {
|
|
11
|
+
/** Unique subscription identifier - generated when subscription is created */
|
|
12
|
+
id: string;
|
|
13
|
+
|
|
14
|
+
/** Optional: specific event types to listen for (defaults to all if not specified) */
|
|
15
|
+
eventTypes?: string[];
|
|
16
|
+
|
|
17
|
+
/** Optional: storage backends to listen to (defaults to all if not specified) */
|
|
18
|
+
scopes?: string[];
|
|
19
|
+
|
|
20
|
+
/** Optional: additional filtering criteria using existing ItemQuery system */
|
|
21
|
+
query?: ItemQuery;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Subscription to events for a specific item using PriKey or ComKey.
|
|
26
|
+
* Provides exact item-level event subscriptions with full type safety.
|
|
27
|
+
*/
|
|
28
|
+
export interface ItemSubscription<
|
|
29
|
+
S extends string,
|
|
30
|
+
L1 extends string = never,
|
|
31
|
+
L2 extends string = never,
|
|
32
|
+
L3 extends string = never,
|
|
33
|
+
L4 extends string = never,
|
|
34
|
+
L5 extends string = never
|
|
35
|
+
> extends BaseSubscription {
|
|
36
|
+
/** The specific key to subscribe to - fully typed PriKey or ComKey */
|
|
37
|
+
key: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Subscription to events for all items in a location using KTA + location array.
|
|
42
|
+
* Provides location-based event subscriptions with full type safety.
|
|
43
|
+
*/
|
|
44
|
+
export interface LocationSubscription<
|
|
45
|
+
S extends string,
|
|
46
|
+
L1 extends string = never,
|
|
47
|
+
L2 extends string = never,
|
|
48
|
+
L3 extends string = never,
|
|
49
|
+
L4 extends string = never,
|
|
50
|
+
L5 extends string = never
|
|
51
|
+
> extends BaseSubscription {
|
|
52
|
+
/** Item type array defining the type hierarchy */
|
|
53
|
+
kta: ItemTypeArray<S, L1, L2, L3, L4, L5>;
|
|
54
|
+
|
|
55
|
+
/** Location key array defining the specific location */
|
|
56
|
+
location: LocKeyArray<L1, L2, L3, L4, L5>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Union type of all subscription types.
|
|
61
|
+
* This allows handling any subscription type generically while maintaining type safety.
|
|
62
|
+
*/
|
|
63
|
+
export type Subscription<
|
|
64
|
+
S extends string,
|
|
65
|
+
L1 extends string = never,
|
|
66
|
+
L2 extends string = never,
|
|
67
|
+
L3 extends string = never,
|
|
68
|
+
L4 extends string = never,
|
|
69
|
+
L5 extends string = never
|
|
70
|
+
> = ItemSubscription<S, L1, L2, L3, L4, L5> | LocationSubscription<S, L1, L2, L3, L4, L5>;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Options for creating subscriptions.
|
|
74
|
+
* Used by convenience methods to create subscriptions without requiring full subscription objects.
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
export interface SubscriptionOptions<
|
|
78
|
+
S extends string,
|
|
79
|
+
L1 extends string = never,
|
|
80
|
+
L2 extends string = never,
|
|
81
|
+
L3 extends string = never,
|
|
82
|
+
L4 extends string = never,
|
|
83
|
+
L5 extends string = never
|
|
84
|
+
> {
|
|
85
|
+
/** Optional: specific event types to listen for */
|
|
86
|
+
eventTypes?: string[];
|
|
87
|
+
|
|
88
|
+
/** Optional: storage backends to listen to */
|
|
89
|
+
scopes?: string[];
|
|
90
|
+
|
|
91
|
+
/** Optional: additional filtering criteria */
|
|
92
|
+
query?: ItemQuery;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Type guard to check if a subscription is an ItemSubscription
|
|
97
|
+
*/
|
|
98
|
+
|
|
99
|
+
export function isItemSubscription<
|
|
100
|
+
S extends string,
|
|
101
|
+
L1 extends string = never,
|
|
102
|
+
L2 extends string = never,
|
|
103
|
+
L3 extends string = never,
|
|
104
|
+
L4 extends string = never,
|
|
105
|
+
L5 extends string = never
|
|
106
|
+
>(subscription: Subscription<S, L1, L2, L3, L4, L5>): subscription is ItemSubscription<S, L1, L2, L3, L4, L5> {
|
|
107
|
+
return 'key' in subscription;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Type guard to check if a subscription is a LocationSubscription
|
|
112
|
+
*/
|
|
113
|
+
|
|
114
|
+
export function isLocationSubscription<
|
|
115
|
+
S extends string,
|
|
116
|
+
L1 extends string = never,
|
|
117
|
+
L2 extends string = never,
|
|
118
|
+
L3 extends string = never,
|
|
119
|
+
L4 extends string = never,
|
|
120
|
+
L5 extends string = never
|
|
121
|
+
>(subscription: Subscription<S, L1, L2, L3, L4, L5>): subscription is LocationSubscription<S, L1, L2, L3, L4, L5> {
|
|
122
|
+
return 'kta' in subscription && 'location' in subscription;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Utility function to generate unique subscription IDs.
|
|
127
|
+
* Libraries can use this or implement their own ID generation strategy.
|
|
128
|
+
*/
|
|
129
|
+
export function generateSubscriptionId(): string {
|
|
130
|
+
return `sub-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Utility function to create an ItemSubscription with generated ID.
|
|
135
|
+
* Simplifies subscription creation for library implementations.
|
|
136
|
+
*/
|
|
137
|
+
export function createItemSubscription<
|
|
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
|
+
key: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>,
|
|
146
|
+
options?: SubscriptionOptions<S, L1, L2, L3, L4, L5>
|
|
147
|
+
): ItemSubscription<S, L1, L2, L3, L4, L5> {
|
|
148
|
+
return {
|
|
149
|
+
id: generateSubscriptionId(),
|
|
150
|
+
key,
|
|
151
|
+
eventTypes: options?.eventTypes,
|
|
152
|
+
scopes: options?.scopes,
|
|
153
|
+
query: options?.query,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Utility function to create a LocationSubscription with generated ID.
|
|
159
|
+
* Simplifies subscription creation for library implementations.
|
|
160
|
+
*/
|
|
161
|
+
export function createLocationSubscription<
|
|
162
|
+
S extends string,
|
|
163
|
+
L1 extends string = never,
|
|
164
|
+
L2 extends string = never,
|
|
165
|
+
L3 extends string = never,
|
|
166
|
+
L4 extends string = never,
|
|
167
|
+
L5 extends string = never
|
|
168
|
+
>(
|
|
169
|
+
kta: ItemTypeArray<S, L1, L2, L3, L4, L5>,
|
|
170
|
+
location: LocKeyArray<L1, L2, L3, L4, L5>,
|
|
171
|
+
options?: SubscriptionOptions<S, L1, L2, L3, L4, L5>
|
|
172
|
+
): LocationSubscription<S, L1, L2, L3, L4, L5> {
|
|
173
|
+
return {
|
|
174
|
+
id: generateSubscriptionId(),
|
|
175
|
+
kta,
|
|
176
|
+
location,
|
|
177
|
+
eventTypes: options?.eventTypes,
|
|
178
|
+
scopes: options?.scopes,
|
|
179
|
+
query: options?.query,
|
|
180
|
+
};
|
|
181
|
+
}
|