@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.
Files changed (94) hide show
  1. package/README.md +92 -0
  2. package/dist/Coordinate.d.ts +7 -0
  3. package/dist/errors/ActionError.d.ts +51 -0
  4. package/dist/errors/BusinessLogicError.d.ts +4 -0
  5. package/dist/errors/DuplicateError.d.ts +4 -0
  6. package/dist/errors/NotFoundError.d.ts +4 -0
  7. package/dist/errors/PermissionError.d.ts +4 -0
  8. package/dist/errors/ValidationError.d.ts +4 -0
  9. package/dist/errors/index.d.ts +6 -0
  10. package/dist/event/emitter.d.ts +140 -0
  11. package/dist/event/events.d.ts +81 -0
  12. package/dist/event/index.d.ts +38 -0
  13. package/dist/event/matching.d.ts +54 -0
  14. package/dist/event/subscription.d.ts +74 -0
  15. package/dist/event/types.d.ts +186 -0
  16. package/dist/index.d.ts +13 -0
  17. package/dist/index.js +1584 -47
  18. package/dist/item/IUtils.d.ts +6 -3
  19. package/dist/operations/OperationContext.d.ts +10 -0
  20. package/dist/operations/Operations.d.ts +259 -0
  21. package/dist/operations/contained.d.ts +65 -0
  22. package/dist/operations/errorEnhancer.d.ts +79 -0
  23. package/dist/operations/index.d.ts +2 -0
  24. package/dist/operations/methods.d.ts +134 -0
  25. package/dist/operations/primary.d.ts +57 -0
  26. package/dist/operations/specialized.d.ts +41 -0
  27. package/dist/operations/wrappers/createActionWrapper.d.ts +28 -0
  28. package/dist/operations/wrappers/createAllActionWrapper.d.ts +28 -0
  29. package/dist/operations/wrappers/createAllFacetWrapper.d.ts +27 -0
  30. package/dist/operations/wrappers/createAllWrapper.d.ts +28 -0
  31. package/dist/operations/wrappers/createCreateWrapper.d.ts +28 -0
  32. package/dist/operations/wrappers/createFacetWrapper.d.ts +27 -0
  33. package/dist/operations/wrappers/createFindOneWrapper.d.ts +28 -0
  34. package/dist/operations/wrappers/createFindWrapper.d.ts +28 -0
  35. package/dist/operations/wrappers/createGetWrapper.d.ts +28 -0
  36. package/dist/operations/wrappers/createOneWrapper.d.ts +38 -0
  37. package/dist/operations/wrappers/createRemoveWrapper.d.ts +28 -0
  38. package/dist/operations/wrappers/createUpdateWrapper.d.ts +28 -0
  39. package/dist/operations/wrappers/createUpsertWrapper.d.ts +28 -0
  40. package/dist/operations/wrappers/index.d.ts +34 -0
  41. package/dist/operations/wrappers/types.d.ts +48 -0
  42. package/dist/validation/ItemValidator.d.ts +43 -0
  43. package/dist/validation/KeyValidator.d.ts +56 -0
  44. package/dist/validation/LocationValidator.d.ts +39 -0
  45. package/dist/validation/QueryValidator.d.ts +57 -0
  46. package/dist/validation/index.d.ts +15 -0
  47. package/dist/validation/index.js +501 -0
  48. package/dist/validation/types.d.ts +38 -0
  49. package/package.json +7 -2
  50. package/src/Coordinate.ts +35 -0
  51. package/src/errors/ActionError.ts +69 -0
  52. package/src/errors/BusinessLogicError.ts +24 -0
  53. package/src/errors/DuplicateError.ts +57 -0
  54. package/src/errors/NotFoundError.ts +24 -0
  55. package/src/errors/PermissionError.ts +31 -0
  56. package/src/errors/ValidationError.ts +27 -0
  57. package/src/errors/index.ts +7 -0
  58. package/src/event/emitter.ts +247 -0
  59. package/src/event/events.ts +178 -0
  60. package/src/event/index.ts +130 -0
  61. package/src/event/matching.ts +264 -0
  62. package/src/event/subscription.ts +181 -0
  63. package/src/event/types.ts +282 -0
  64. package/src/index.ts +57 -0
  65. package/src/item/IUtils.ts +9 -80
  66. package/src/operations/OperationContext.ts +12 -0
  67. package/src/operations/Operations.ts +357 -0
  68. package/src/operations/contained.ts +134 -0
  69. package/src/operations/errorEnhancer.ts +204 -0
  70. package/src/operations/index.ts +2 -0
  71. package/src/operations/methods.ts +363 -0
  72. package/src/operations/primary.ts +101 -0
  73. package/src/operations/specialized.ts +71 -0
  74. package/src/operations/wrappers/createActionWrapper.ts +108 -0
  75. package/src/operations/wrappers/createAllActionWrapper.ts +109 -0
  76. package/src/operations/wrappers/createAllFacetWrapper.ts +98 -0
  77. package/src/operations/wrappers/createAllWrapper.ts +103 -0
  78. package/src/operations/wrappers/createCreateWrapper.ts +117 -0
  79. package/src/operations/wrappers/createFacetWrapper.ts +97 -0
  80. package/src/operations/wrappers/createFindOneWrapper.ts +105 -0
  81. package/src/operations/wrappers/createFindWrapper.ts +105 -0
  82. package/src/operations/wrappers/createGetWrapper.ts +96 -0
  83. package/src/operations/wrappers/createOneWrapper.ts +128 -0
  84. package/src/operations/wrappers/createRemoveWrapper.ts +91 -0
  85. package/src/operations/wrappers/createUpdateWrapper.ts +106 -0
  86. package/src/operations/wrappers/createUpsertWrapper.ts +108 -0
  87. package/src/operations/wrappers/index.ts +39 -0
  88. package/src/operations/wrappers/types.ts +63 -0
  89. package/src/validation/ItemValidator.ts +131 -0
  90. package/src/validation/KeyValidator.ts +365 -0
  91. package/src/validation/LocationValidator.ts +136 -0
  92. package/src/validation/QueryValidator.ts +250 -0
  93. package/src/validation/index.ts +32 -0
  94. 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
+ }