@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,69 @@
1
+ export interface ErrorInfo {
2
+ code: string;
3
+ message: string;
4
+ operation: {
5
+ type: 'get' | 'create' | 'update' | 'remove' | 'upsert' |
6
+ 'all' | 'one' | 'find' | 'findOne' |
7
+ 'action' | 'allAction' | 'facet' | 'allFacet';
8
+ name: string;
9
+ params: Record<string, any>;
10
+ };
11
+ context: {
12
+ itemType: string;
13
+ key?: {
14
+ primary?: string | number;
15
+ composite?: {
16
+ sk: string | number;
17
+ kta: string[];
18
+ locations?: Array<{ lk: string | number; kt: string }>;
19
+ };
20
+ };
21
+ affectedItems?: Array<{
22
+ id: string | number;
23
+ type: string;
24
+ displayName?: string;
25
+ }>;
26
+ parentLocation?: {
27
+ id: string | number;
28
+ type: string;
29
+ };
30
+ requiredPermission?: string;
31
+ };
32
+ details?: {
33
+ validOptions?: string[];
34
+ suggestedAction?: string;
35
+ retryable?: boolean;
36
+ conflictingValue?: any;
37
+ expectedValue?: any;
38
+ };
39
+ technical?: {
40
+ timestamp: string;
41
+ requestId?: string;
42
+ stackTrace?: string;
43
+ cause?: any;
44
+ };
45
+ }
46
+
47
+ export class ActionError extends Error {
48
+ constructor(
49
+ public readonly errorInfo: ErrorInfo,
50
+ cause?: Error
51
+ ) {
52
+ super(errorInfo.message);
53
+ this.name = 'ActionError';
54
+ this.cause = cause;
55
+
56
+ // Ensure timestamp is always set
57
+ if (!this.errorInfo.technical) {
58
+ this.errorInfo.technical = { timestamp: new Date().toISOString() };
59
+ }
60
+ if (!this.errorInfo.technical.timestamp) {
61
+ this.errorInfo.technical.timestamp = new Date().toISOString();
62
+ }
63
+ }
64
+
65
+ toJSON(): ErrorInfo {
66
+ return this.errorInfo;
67
+ }
68
+ }
69
+
@@ -0,0 +1,24 @@
1
+ import { ActionError } from './ActionError';
2
+
3
+ export class BusinessLogicError extends ActionError {
4
+ constructor(
5
+ message: string,
6
+ suggestedAction?: string,
7
+ retryable: boolean = false
8
+ ) {
9
+ super({
10
+ code: 'BUSINESS_LOGIC_ERROR',
11
+ message,
12
+ operation: { type: 'action', name: '', params: {} },
13
+ context: { itemType: '' },
14
+ details: {
15
+ suggestedAction,
16
+ retryable
17
+ },
18
+ technical: {
19
+ timestamp: new Date().toISOString()
20
+ }
21
+ });
22
+ }
23
+ }
24
+
@@ -0,0 +1,57 @@
1
+ import { ActionError } from './ActionError';
2
+
3
+ export class DuplicateError extends ActionError {
4
+ constructor(
5
+ message: string,
6
+ existingItemIdOrKey?: string | number | any,
7
+ duplicateField?: string
8
+ ) {
9
+ // Extract ID and build key info
10
+ let existingItemId: string | number | null = null;
11
+ let keyInfo: any = null;
12
+
13
+ if (typeof existingItemIdOrKey === 'object' && existingItemIdOrKey !== null) {
14
+ // It's a key object - extract the primary key value and build proper key structure
15
+ existingItemId = existingItemIdOrKey.pk || existingItemIdOrKey.id || existingItemIdOrKey.primary || null;
16
+
17
+ // Build key info with primary field set
18
+ if (existingItemId !== null) {
19
+ keyInfo = {
20
+ primary: existingItemId,
21
+ ...existingItemIdOrKey
22
+ };
23
+ } else {
24
+ keyInfo = existingItemIdOrKey;
25
+ }
26
+ } else if (typeof existingItemIdOrKey !== 'undefined') {
27
+ // It's a simple ID
28
+ existingItemId = existingItemIdOrKey;
29
+ keyInfo = { primary: existingItemId };
30
+ }
31
+
32
+ super({
33
+ code: 'DUPLICATE_ERROR',
34
+ message,
35
+ operation: { type: 'create', name: '', params: {} },
36
+ context: {
37
+ itemType: '',
38
+ ...(keyInfo && { key: keyInfo }),
39
+ ...(existingItemId && {
40
+ affectedItems: [{
41
+ id: existingItemId,
42
+ type: '',
43
+ displayName: `Existing item with ${duplicateField || 'key'}`
44
+ }]
45
+ })
46
+ },
47
+ details: {
48
+ retryable: false,
49
+ conflictingValue: duplicateField
50
+ },
51
+ technical: {
52
+ timestamp: new Date().toISOString()
53
+ }
54
+ });
55
+ }
56
+ }
57
+
@@ -0,0 +1,24 @@
1
+ import { ActionError } from './ActionError';
2
+
3
+ export class NotFoundError extends ActionError {
4
+ constructor(
5
+ message: string,
6
+ itemType: string,
7
+ key?: any
8
+ ) {
9
+ super({
10
+ code: 'NOT_FOUND',
11
+ message,
12
+ operation: { type: 'get', name: '', params: {} },
13
+ context: {
14
+ itemType,
15
+ key: typeof key === 'object' ? key : { primary: key }
16
+ },
17
+ details: { retryable: false },
18
+ technical: {
19
+ timestamp: new Date().toISOString()
20
+ }
21
+ });
22
+ }
23
+ }
24
+
@@ -0,0 +1,31 @@
1
+ import { ActionError } from './ActionError';
2
+
3
+ export class PermissionError extends ActionError {
4
+ constructor(
5
+ message: string,
6
+ requiredPermission?: string,
7
+ currentPermissions?: string[]
8
+ ) {
9
+ super({
10
+ code: 'PERMISSION_DENIED',
11
+ message,
12
+ operation: { type: 'action', name: '', params: {} },
13
+ context: {
14
+ itemType: '',
15
+ ...(requiredPermission && { requiredPermission })
16
+ },
17
+ details: {
18
+ ...(requiredPermission && {
19
+ suggestedAction: `Required permission: ${requiredPermission}`,
20
+ expectedValue: requiredPermission
21
+ }),
22
+ ...(currentPermissions && { conflictingValue: currentPermissions }),
23
+ retryable: false
24
+ },
25
+ technical: {
26
+ timestamp: new Date().toISOString()
27
+ }
28
+ });
29
+ }
30
+ }
31
+
@@ -0,0 +1,27 @@
1
+ import { ActionError } from './ActionError';
2
+
3
+ export class ValidationError extends ActionError {
4
+ constructor(
5
+ message: string,
6
+ validOptions?: string[],
7
+ suggestedAction?: string,
8
+ conflictingValue?: any
9
+ ) {
10
+ super({
11
+ code: 'VALIDATION_ERROR',
12
+ message,
13
+ operation: { type: 'create', name: '', params: {} }, // Will be filled by wrapper
14
+ context: { itemType: '' }, // Will be filled by wrapper
15
+ details: {
16
+ validOptions,
17
+ suggestedAction,
18
+ retryable: true,
19
+ conflictingValue
20
+ },
21
+ technical: {
22
+ timestamp: new Date().toISOString()
23
+ }
24
+ });
25
+ }
26
+ }
27
+
@@ -0,0 +1,7 @@
1
+ export * from './ActionError';
2
+ export * from './ValidationError';
3
+ export * from './NotFoundError';
4
+ export * from './BusinessLogicError';
5
+ export * from './PermissionError';
6
+ export * from './DuplicateError';
7
+
@@ -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>;
@@ -0,0 +1,178 @@
1
+ import { ComKey, PriKey } from '../keys';
2
+ import { Item } from '../items';
3
+
4
+ /**
5
+ * Base event interface that all events extend.
6
+ * Provides core event properties with full type safety using the existing PriKey/ComKey system.
7
+ */
8
+ export interface BaseEvent<
9
+ S extends string,
10
+ L1 extends string = never,
11
+ L2 extends string = never,
12
+ L3 extends string = never,
13
+ L4 extends string = never,
14
+ L5 extends string = never
15
+ > {
16
+ /** Type of event - "create", "update", "delete", etc. */
17
+ eventType: string;
18
+
19
+ /** The key of the item that was affected - maintains full type safety */
20
+ key: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>;
21
+
22
+ /** Which storage backend(s) generated this event - enables filtering by implementation */
23
+ scopes: string[];
24
+
25
+ /** When the event occurred */
26
+ timestamp: Date;
27
+
28
+ /** Optional: the full item content - fully typed, no loss of type information */
29
+ item?: Item<S, L1, L2, L3, L4, L5>;
30
+ }
31
+
32
+ /**
33
+ * Event emitted when an item is created.
34
+ * The item property is required since we always have the created item data.
35
+ */
36
+ export interface CreateEvent<
37
+ S extends string,
38
+ L1 extends string = never,
39
+ L2 extends string = never,
40
+ L3 extends string = never,
41
+ L4 extends string = never,
42
+ L5 extends string = never
43
+ > extends BaseEvent<S, L1, L2, L3, L4, L5> {
44
+ eventType: 'create';
45
+ /** The created item - always available for create events */
46
+ item: Item<S, L1, L2, L3, L4, L5>;
47
+ }
48
+
49
+ /**
50
+ * Event emitted when an item is updated.
51
+ * Provides detailed change tracking with before/after states.
52
+ */
53
+ export interface UpdateEvent<
54
+ S extends string,
55
+ L1 extends string = never,
56
+ L2 extends string = never,
57
+ L3 extends string = never,
58
+ L4 extends string = never,
59
+ L5 extends string = never
60
+ > extends BaseEvent<S, L1, L2, L3, L4, L5> {
61
+ eventType: 'update';
62
+ /** List of field names that were changed */
63
+ changes: string[];
64
+ /** Optional: item state before the update */
65
+ before?: Item<S, L1, L2, L3, L4, L5>;
66
+ /** Optional: item state after the update */
67
+ after?: Item<S, L1, L2, L3, L4, L5>;
68
+ // Note: item property (from BaseEvent) contains current state if provided
69
+ }
70
+
71
+ /**
72
+ * Event emitted when an item is deleted.
73
+ * May include the deleted item data for cleanup/undo operations.
74
+ */
75
+ export interface DeleteEvent<
76
+ S extends string,
77
+ L1 extends string = never,
78
+ L2 extends string = never,
79
+ L3 extends string = never,
80
+ L4 extends string = never,
81
+ L5 extends string = never
82
+ > extends BaseEvent<S, L1, L2, L3, L4, L5> {
83
+ eventType: 'delete';
84
+ /** Optional: the deleted item content - useful for cleanup/undo */
85
+ item?: Item<S, L1, L2, L3, L4, L5>;
86
+ }
87
+
88
+ /**
89
+ * Event emitted when a custom action is performed on an item.
90
+ * Allows libraries to define custom event types beyond standard CRUD.
91
+ */
92
+ export interface ActionEvent<
93
+ S extends string,
94
+ L1 extends string = never,
95
+ L2 extends string = never,
96
+ L3 extends string = never,
97
+ L4 extends string = never,
98
+ L5 extends string = never
99
+ > extends BaseEvent<S, L1, L2, L3, L4, L5> {
100
+ eventType: 'action';
101
+ /** Name of the action that was performed */
102
+ actionName: string;
103
+ /** Optional: action-specific data */
104
+ actionData?: Record<string, unknown>;
105
+ }
106
+
107
+ /**
108
+ * Union type of all standard event types.
109
+ * Libraries can extend this with custom events if needed.
110
+ */
111
+ export type Event<
112
+ S extends string,
113
+ L1 extends string = never,
114
+ L2 extends string = never,
115
+ L3 extends string = never,
116
+ L4 extends string = never,
117
+ L5 extends string = never
118
+ > =
119
+ | CreateEvent<S, L1, L2, L3, L4, L5>
120
+ | UpdateEvent<S, L1, L2, L3, L4, L5>
121
+ | DeleteEvent<S, L1, L2, L3, L4, L5>
122
+ | ActionEvent<S, L1, L2, L3, L4, L5>;
123
+
124
+ /**
125
+ * Type guard to check if an event is a CreateEvent
126
+ */
127
+ export function isCreateEvent<
128
+ S extends string,
129
+ L1 extends string = never,
130
+ L2 extends string = never,
131
+ L3 extends string = never,
132
+ L4 extends string = never,
133
+ L5 extends string = never
134
+ >(event: BaseEvent<S, L1, L2, L3, L4, L5>): event is CreateEvent<S, L1, L2, L3, L4, L5> {
135
+ return event.eventType === 'create';
136
+ }
137
+
138
+ /**
139
+ * Type guard to check if an event is an UpdateEvent
140
+ */
141
+ export function isUpdateEvent<
142
+ S extends string,
143
+ L1 extends string = never,
144
+ L2 extends string = never,
145
+ L3 extends string = never,
146
+ L4 extends string = never,
147
+ L5 extends string = never
148
+ >(event: BaseEvent<S, L1, L2, L3, L4, L5>): event is UpdateEvent<S, L1, L2, L3, L4, L5> {
149
+ return event.eventType === 'update';
150
+ }
151
+
152
+ /**
153
+ * Type guard to check if an event is a DeleteEvent
154
+ */
155
+ export function isDeleteEvent<
156
+ S extends string,
157
+ L1 extends string = never,
158
+ L2 extends string = never,
159
+ L3 extends string = never,
160
+ L4 extends string = never,
161
+ L5 extends string = never
162
+ >(event: BaseEvent<S, L1, L2, L3, L4, L5>): event is DeleteEvent<S, L1, L2, L3, L4, L5> {
163
+ return event.eventType === 'delete';
164
+ }
165
+
166
+ /**
167
+ * Type guard to check if an event is an ActionEvent
168
+ */
169
+ export function isActionEvent<
170
+ S extends string,
171
+ L1 extends string = never,
172
+ L2 extends string = never,
173
+ L3 extends string = never,
174
+ L4 extends string = never,
175
+ L5 extends string = never
176
+ >(event: BaseEvent<S, L1, L2, L3, L4, L5>): event is ActionEvent<S, L1, L2, L3, L4, L5> {
177
+ return event.eventType === 'action';
178
+ }