@contember/bindx 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/dist/adapter/ContemberAdapter.d.ts +40 -0
  2. package/dist/adapter/ContemberAdapter.d.ts.map +1 -0
  3. package/dist/adapter/MockAdapter.d.ts +81 -0
  4. package/dist/adapter/MockAdapter.d.ts.map +1 -0
  5. package/dist/adapter/MockQueryEngine.d.ts +43 -0
  6. package/dist/adapter/MockQueryEngine.d.ts.map +1 -0
  7. package/dist/adapter/index.d.ts +5 -0
  8. package/dist/adapter/index.d.ts.map +1 -0
  9. package/dist/adapter/types.d.ts +184 -0
  10. package/dist/adapter/types.d.ts.map +1 -0
  11. package/dist/brand/ComponentBrand.d.ts +25 -0
  12. package/dist/brand/ComponentBrand.d.ts.map +1 -0
  13. package/dist/contember/index.d.ts +10 -0
  14. package/dist/contember/index.d.ts.map +1 -0
  15. package/dist/core/ActionDispatcher.d.ts +64 -0
  16. package/dist/core/ActionDispatcher.d.ts.map +1 -0
  17. package/dist/core/Disposable.d.ts +57 -0
  18. package/dist/core/Disposable.d.ts.map +1 -0
  19. package/dist/core/EntityLoader.d.ts +80 -0
  20. package/dist/core/EntityLoader.d.ts.map +1 -0
  21. package/dist/core/PersistenceManager.d.ts +126 -0
  22. package/dist/core/PersistenceManager.d.ts.map +1 -0
  23. package/dist/core/SelectionResolver.d.ts +21 -0
  24. package/dist/core/SelectionResolver.d.ts.map +1 -0
  25. package/dist/core/actionClassification.d.ts +48 -0
  26. package/dist/core/actionClassification.d.ts.map +1 -0
  27. package/dist/core/actions.d.ts +301 -0
  28. package/dist/core/actions.d.ts.map +1 -0
  29. package/dist/core/index.d.ts +4 -0
  30. package/dist/core/index.d.ts.map +1 -0
  31. package/dist/dataview/filterHandlers.d.ts +18 -0
  32. package/dist/dataview/filterHandlers.d.ts.map +1 -0
  33. package/dist/dataview/index.d.ts +3 -0
  34. package/dist/dataview/index.d.ts.map +1 -0
  35. package/dist/dataview/types.d.ts +164 -0
  36. package/dist/dataview/types.d.ts.map +1 -0
  37. package/dist/errors/UnfetchedFieldError.d.ts +11 -0
  38. package/dist/errors/UnfetchedFieldError.d.ts.map +1 -0
  39. package/dist/errors/errorPathResolver.d.ts +52 -0
  40. package/dist/errors/errorPathResolver.d.ts.map +1 -0
  41. package/dist/errors/index.d.ts +5 -0
  42. package/dist/errors/index.d.ts.map +1 -0
  43. package/dist/errors/pathMapper.d.ts +42 -0
  44. package/dist/errors/pathMapper.d.ts.map +1 -0
  45. package/dist/errors/types.d.ts +131 -0
  46. package/dist/errors/types.d.ts.map +1 -0
  47. package/dist/events/EventEmitter.d.ts +97 -0
  48. package/dist/events/EventEmitter.d.ts.map +1 -0
  49. package/dist/events/eventFactory.d.ts +40 -0
  50. package/dist/events/eventFactory.d.ts.map +1 -0
  51. package/dist/events/index.d.ts +15 -0
  52. package/dist/events/index.d.ts.map +1 -0
  53. package/dist/events/types.d.ts +264 -0
  54. package/dist/events/types.d.ts.map +1 -0
  55. package/dist/handles/BaseHandle.d.ts +64 -0
  56. package/dist/handles/BaseHandle.d.ts.map +1 -0
  57. package/dist/handles/EntityHandle.d.ts +208 -0
  58. package/dist/handles/EntityHandle.d.ts.map +1 -0
  59. package/dist/handles/FieldHandle.d.ts +111 -0
  60. package/dist/handles/FieldHandle.d.ts.map +1 -0
  61. package/dist/handles/HasManyListHandle.d.ts +166 -0
  62. package/dist/handles/HasManyListHandle.d.ts.map +1 -0
  63. package/dist/handles/HasOneHandle.d.ts +168 -0
  64. package/dist/handles/HasOneHandle.d.ts.map +1 -0
  65. package/dist/handles/PlaceholderHandle.d.ts +117 -0
  66. package/dist/handles/PlaceholderHandle.d.ts.map +1 -0
  67. package/dist/handles/index.d.ts +8 -0
  68. package/dist/handles/index.d.ts.map +1 -0
  69. package/dist/handles/proxyFactory.d.ts +66 -0
  70. package/dist/handles/proxyFactory.d.ts.map +1 -0
  71. package/dist/handles/types.d.ts +430 -0
  72. package/dist/handles/types.d.ts.map +1 -0
  73. package/dist/index.d.ts +53 -0
  74. package/dist/index.d.ts.map +1 -0
  75. package/dist/internal.d.ts +11 -0
  76. package/dist/internal.d.ts.map +1 -0
  77. package/dist/persistence/BatchPersister.d.ts +142 -0
  78. package/dist/persistence/BatchPersister.d.ts.map +1 -0
  79. package/dist/persistence/ChangeRegistry.d.ts +87 -0
  80. package/dist/persistence/ChangeRegistry.d.ts.map +1 -0
  81. package/dist/persistence/ContemberSchemaMutationAdapter.d.ts +16 -0
  82. package/dist/persistence/ContemberSchemaMutationAdapter.d.ts.map +1 -0
  83. package/dist/persistence/MutationCollector.d.ts +96 -0
  84. package/dist/persistence/MutationCollector.d.ts.map +1 -0
  85. package/dist/persistence/MutationSchemaProvider.d.ts +30 -0
  86. package/dist/persistence/MutationSchemaProvider.d.ts.map +1 -0
  87. package/dist/persistence/index.d.ts +7 -0
  88. package/dist/persistence/index.d.ts.map +1 -0
  89. package/dist/persistence/types.d.ts +189 -0
  90. package/dist/persistence/types.d.ts.map +1 -0
  91. package/dist/roles/RoleSchemaRegistry.d.ts +77 -0
  92. package/dist/roles/RoleSchemaRegistry.d.ts.map +1 -0
  93. package/dist/roles/index.d.ts +11 -0
  94. package/dist/roles/index.d.ts.map +1 -0
  95. package/dist/roles/types.d.ts +242 -0
  96. package/dist/roles/types.d.ts.map +1 -0
  97. package/dist/schema/ContemberSchema.d.ts +98 -0
  98. package/dist/schema/ContemberSchema.d.ts.map +1 -0
  99. package/dist/schema/SchemaLoader.d.ts +28 -0
  100. package/dist/schema/SchemaLoader.d.ts.map +1 -0
  101. package/dist/schema/SchemaRegistry.d.ts +95 -0
  102. package/dist/schema/SchemaRegistry.d.ts.map +1 -0
  103. package/dist/schema/index.d.ts +6 -0
  104. package/dist/schema/index.d.ts.map +1 -0
  105. package/dist/schema/roles.d.ts +62 -0
  106. package/dist/schema/roles.d.ts.map +1 -0
  107. package/dist/schema/types.d.ts +179 -0
  108. package/dist/schema/types.d.ts.map +1 -0
  109. package/dist/selection/SelectionMetaCollector.d.ts +32 -0
  110. package/dist/selection/SelectionMetaCollector.d.ts.map +1 -0
  111. package/dist/selection/SelectionScope.d.ts +77 -0
  112. package/dist/selection/SelectionScope.d.ts.map +1 -0
  113. package/dist/selection/buildQuery.d.ts +45 -0
  114. package/dist/selection/buildQuery.d.ts.map +1 -0
  115. package/dist/selection/createFragment.d.ts +29 -0
  116. package/dist/selection/createFragment.d.ts.map +1 -0
  117. package/dist/selection/createSelectionBuilder.d.ts +18 -0
  118. package/dist/selection/createSelectionBuilder.d.ts.map +1 -0
  119. package/dist/selection/index.d.ts +8 -0
  120. package/dist/selection/index.d.ts.map +1 -0
  121. package/dist/selection/queryTypes.d.ts +84 -0
  122. package/dist/selection/queryTypes.d.ts.map +1 -0
  123. package/dist/selection/types.d.ts +238 -0
  124. package/dist/selection/types.d.ts.map +1 -0
  125. package/dist/store/DirtyTracker.d.ts +26 -0
  126. package/dist/store/DirtyTracker.d.ts.map +1 -0
  127. package/dist/store/EntityMetaStore.d.ts +52 -0
  128. package/dist/store/EntityMetaStore.d.ts.map +1 -0
  129. package/dist/store/EntitySnapshotStore.d.ts +63 -0
  130. package/dist/store/EntitySnapshotStore.d.ts.map +1 -0
  131. package/dist/store/ErrorStore.d.ts +82 -0
  132. package/dist/store/ErrorStore.d.ts.map +1 -0
  133. package/dist/store/RelationStore.d.ts +175 -0
  134. package/dist/store/RelationStore.d.ts.map +1 -0
  135. package/dist/store/SnapshotStore.d.ts +143 -0
  136. package/dist/store/SnapshotStore.d.ts.map +1 -0
  137. package/dist/store/SubscriptionManager.d.ts +90 -0
  138. package/dist/store/SubscriptionManager.d.ts.map +1 -0
  139. package/dist/store/TouchedStore.d.ts +24 -0
  140. package/dist/store/TouchedStore.d.ts.map +1 -0
  141. package/dist/store/entityId.d.ts +29 -0
  142. package/dist/store/entityId.d.ts.map +1 -0
  143. package/dist/store/index.d.ts +1 -0
  144. package/dist/store/index.d.ts.map +1 -0
  145. package/dist/store/snapshots.d.ts +144 -0
  146. package/dist/store/snapshots.d.ts.map +1 -0
  147. package/dist/undo/UndoManager.d.ts +120 -0
  148. package/dist/undo/UndoManager.d.ts.map +1 -0
  149. package/dist/undo/index.d.ts +3 -0
  150. package/dist/undo/index.d.ts.map +1 -0
  151. package/dist/undo/types.d.ts +74 -0
  152. package/dist/undo/types.d.ts.map +1 -0
  153. package/dist/utils/aliasGenerator.d.ts +25 -0
  154. package/dist/utils/aliasGenerator.d.ts.map +1 -0
  155. package/dist/utils/deepEqual.d.ts +6 -0
  156. package/dist/utils/deepEqual.d.ts.map +1 -0
  157. package/dist/utils/index.d.ts +3 -0
  158. package/dist/utils/index.d.ts.map +1 -0
  159. package/package.json +29 -0
  160. package/src/adapter/ContemberAdapter.ts +239 -0
  161. package/src/adapter/MockAdapter.ts +394 -0
  162. package/src/adapter/MockQueryEngine.ts +236 -0
  163. package/src/adapter/index.ts +21 -0
  164. package/src/adapter/types.ts +199 -0
  165. package/src/brand/ComponentBrand.ts +28 -0
  166. package/src/contember/index.ts +17 -0
  167. package/src/core/ActionDispatcher.ts +450 -0
  168. package/src/core/Disposable.ts +126 -0
  169. package/src/core/EntityLoader.ts +169 -0
  170. package/src/core/SelectionResolver.ts +78 -0
  171. package/src/core/actionClassification.ts +196 -0
  172. package/src/core/actions.ts +491 -0
  173. package/src/core/index.ts +20 -0
  174. package/src/dataview/filterHandlers.ts +443 -0
  175. package/src/dataview/index.ts +36 -0
  176. package/src/dataview/types.ts +220 -0
  177. package/src/errors/UnfetchedFieldError.ts +18 -0
  178. package/src/errors/errorPathResolver.ts +239 -0
  179. package/src/errors/index.ts +40 -0
  180. package/src/errors/pathMapper.ts +40 -0
  181. package/src/errors/types.ts +223 -0
  182. package/src/events/EventEmitter.ts +447 -0
  183. package/src/events/eventFactory.ts +430 -0
  184. package/src/events/index.ts +89 -0
  185. package/src/events/types.ts +374 -0
  186. package/src/handles/BaseHandle.ts +100 -0
  187. package/src/handles/EntityHandle.ts +538 -0
  188. package/src/handles/FieldHandle.ts +268 -0
  189. package/src/handles/HasManyListHandle.ts +500 -0
  190. package/src/handles/HasOneHandle.ts +500 -0
  191. package/src/handles/PlaceholderHandle.ts +321 -0
  192. package/src/handles/index.ts +37 -0
  193. package/src/handles/proxyFactory.ts +218 -0
  194. package/src/handles/types.ts +743 -0
  195. package/src/index.ts +384 -0
  196. package/src/internal.ts +19 -0
  197. package/src/persistence/BatchPersister.ts +911 -0
  198. package/src/persistence/ChangeRegistry.ts +150 -0
  199. package/src/persistence/ContemberSchemaMutationAdapter.ts +57 -0
  200. package/src/persistence/MutationCollector.ts +567 -0
  201. package/src/persistence/MutationSchemaProvider.ts +33 -0
  202. package/src/persistence/index.ts +23 -0
  203. package/src/persistence/types.ts +220 -0
  204. package/src/schema/ContemberSchema.ts +132 -0
  205. package/src/schema/SchemaLoader.ts +93 -0
  206. package/src/schema/SchemaRegistry.ts +286 -0
  207. package/src/schema/index.ts +51 -0
  208. package/src/schema/roles.ts +83 -0
  209. package/src/schema/types.ts +238 -0
  210. package/src/selection/SelectionMetaCollector.ts +122 -0
  211. package/src/selection/SelectionScope.ts +208 -0
  212. package/src/selection/buildQuery.ts +134 -0
  213. package/src/selection/createFragment.ts +50 -0
  214. package/src/selection/createSelectionBuilder.ts +283 -0
  215. package/src/selection/index.ts +31 -0
  216. package/src/selection/queryTypes.ts +135 -0
  217. package/src/selection/types.ts +320 -0
  218. package/src/store/DirtyTracker.ts +117 -0
  219. package/src/store/EntityMetaStore.ts +143 -0
  220. package/src/store/EntitySnapshotStore.ts +260 -0
  221. package/src/store/ErrorStore.ts +251 -0
  222. package/src/store/RelationStore.ts +696 -0
  223. package/src/store/SnapshotStore.ts +765 -0
  224. package/src/store/SubscriptionManager.ts +241 -0
  225. package/src/store/TouchedStore.ts +42 -0
  226. package/src/store/entityId.ts +43 -0
  227. package/src/store/index.ts +2 -0
  228. package/src/store/snapshots.ts +203 -0
  229. package/src/undo/UndoManager.ts +418 -0
  230. package/src/undo/index.ts +9 -0
  231. package/src/undo/types.ts +84 -0
  232. package/src/utils/aliasGenerator.ts +56 -0
  233. package/src/utils/deepEqual.ts +33 -0
  234. package/src/utils/index.ts +2 -0
@@ -0,0 +1,374 @@
1
+ /**
2
+ * Type-safe event system for bindx.
3
+ *
4
+ * Events are categorized into:
5
+ * - Before events (interceptable): Can be cancelled or modified
6
+ * - After events (notifications): Fired after state changes
7
+ */
8
+
9
+ import type { FieldError } from '../errors/types.js'
10
+
11
+ // ============================================================================
12
+ // Base Event Types
13
+ // ============================================================================
14
+
15
+ /**
16
+ * Base interface for all bindx events.
17
+ */
18
+ export interface BindxEvent<TType extends string = string> {
19
+ readonly type: TType
20
+ readonly timestamp: number
21
+ readonly entityType: string
22
+ readonly entityId: string
23
+ }
24
+
25
+ /**
26
+ * Base interface for field-scoped events.
27
+ */
28
+ export interface FieldScopedEvent<TType extends string> extends BindxEvent<TType> {
29
+ readonly fieldName: string
30
+ }
31
+
32
+ // ============================================================================
33
+ // Field Events
34
+ // ============================================================================
35
+
36
+ /**
37
+ * Fired before a field value changes. Can be intercepted to cancel or modify.
38
+ */
39
+ export interface FieldChangingEvent extends FieldScopedEvent<'field:changing'> {
40
+ readonly fieldPath: readonly string[]
41
+ readonly oldValue: unknown
42
+ readonly newValue: unknown
43
+ }
44
+
45
+ /**
46
+ * Fired after a field value has changed.
47
+ */
48
+ export interface FieldChangedEvent extends FieldScopedEvent<'field:changed'> {
49
+ readonly fieldPath: readonly string[]
50
+ readonly oldValue: unknown
51
+ readonly newValue: unknown
52
+ }
53
+
54
+ // ============================================================================
55
+ // HasOne Relation Events
56
+ // ============================================================================
57
+
58
+ /**
59
+ * Fired before a has-one relation is connected.
60
+ */
61
+ export interface RelationConnectingEvent extends FieldScopedEvent<'relation:connecting'> {
62
+ readonly targetId: string
63
+ readonly previousId: string | null
64
+ }
65
+
66
+ /**
67
+ * Fired after a has-one relation has been connected.
68
+ */
69
+ export interface RelationConnectedEvent extends FieldScopedEvent<'relation:connected'> {
70
+ readonly targetId: string
71
+ readonly previousId: string | null
72
+ }
73
+
74
+ /**
75
+ * Fired before a has-one relation is disconnected.
76
+ */
77
+ export interface RelationDisconnectingEvent extends FieldScopedEvent<'relation:disconnecting'> {
78
+ readonly currentId: string | null
79
+ }
80
+
81
+ /**
82
+ * Fired after a has-one relation has been disconnected.
83
+ */
84
+ export interface RelationDisconnectedEvent extends FieldScopedEvent<'relation:disconnected'> {
85
+ readonly previousId: string | null
86
+ }
87
+
88
+ /**
89
+ * Fired before a has-one relation is deleted.
90
+ */
91
+ export interface RelationDeletingEvent extends FieldScopedEvent<'relation:deleting'> {
92
+ readonly currentId: string | null
93
+ }
94
+
95
+ /**
96
+ * Fired after a has-one relation has been deleted.
97
+ */
98
+ export interface RelationDeletedEvent extends FieldScopedEvent<'relation:deleted'> {
99
+ readonly previousId: string | null
100
+ }
101
+
102
+ // ============================================================================
103
+ // HasMany Relation Events
104
+ // ============================================================================
105
+
106
+ /**
107
+ * Fired before an item is connected to a has-many relation.
108
+ */
109
+ export interface HasManyConnectingEvent extends FieldScopedEvent<'hasMany:connecting'> {
110
+ readonly itemId: string
111
+ }
112
+
113
+ /**
114
+ * Fired after an item has been connected to a has-many relation.
115
+ */
116
+ export interface HasManyConnectedEvent extends FieldScopedEvent<'hasMany:connected'> {
117
+ readonly itemId: string
118
+ }
119
+
120
+ /**
121
+ * Fired before an item is disconnected from a has-many relation.
122
+ */
123
+ export interface HasManyDisconnectingEvent extends FieldScopedEvent<'hasMany:disconnecting'> {
124
+ readonly itemId: string
125
+ }
126
+
127
+ /**
128
+ * Fired after an item has been disconnected from a has-many relation.
129
+ */
130
+ export interface HasManyDisconnectedEvent extends FieldScopedEvent<'hasMany:disconnected'> {
131
+ readonly itemId: string
132
+ }
133
+
134
+ // ============================================================================
135
+ // Entity Lifecycle Events
136
+ // ============================================================================
137
+
138
+ /**
139
+ * Fired before an entity is persisted (create or update).
140
+ */
141
+ export interface EntityPersistingEvent extends BindxEvent<'entity:persisting'> {
142
+ readonly isNew: boolean
143
+ }
144
+
145
+ /**
146
+ * Fired after an entity has been successfully persisted.
147
+ */
148
+ export interface EntityPersistedEvent extends BindxEvent<'entity:persisted'> {
149
+ readonly isNew: boolean
150
+ readonly persistedId: string
151
+ }
152
+
153
+ /**
154
+ * Fired when entity persistence fails.
155
+ */
156
+ export interface EntityPersistFailedEvent extends BindxEvent<'entity:persistFailed'> {
157
+ readonly isNew: boolean
158
+ readonly error: Error
159
+ }
160
+
161
+ /**
162
+ * Fired before an entity is reset to server state.
163
+ */
164
+ export interface EntityResettingEvent extends BindxEvent<'entity:resetting'> {}
165
+
166
+ /**
167
+ * Fired after an entity has been reset to server state.
168
+ */
169
+ export interface EntityResetEvent extends BindxEvent<'entity:reset'> {}
170
+
171
+ /**
172
+ * Fired before an entity is deleted.
173
+ */
174
+ export interface EntityDeletingEvent extends BindxEvent<'entity:deleting'> {}
175
+
176
+ /**
177
+ * Fired after an entity has been deleted.
178
+ */
179
+ export interface EntityDeletedEvent extends BindxEvent<'entity:deleted'> {}
180
+
181
+ // ============================================================================
182
+ // Error Events
183
+ // ============================================================================
184
+
185
+ /**
186
+ * Fired when an error is added to a field, entity, or relation.
187
+ */
188
+ export interface ErrorAddedEvent extends BindxEvent<'error:added'> {
189
+ readonly target: 'entity' | 'field' | 'relation'
190
+ readonly targetName: string | null
191
+ readonly error: FieldError
192
+ }
193
+
194
+ /**
195
+ * Fired when errors are cleared.
196
+ */
197
+ export interface ErrorsClearedEvent extends BindxEvent<'errors:cleared'> {
198
+ readonly target: 'entity' | 'field' | 'relation' | 'all'
199
+ readonly targetName: string | null
200
+ }
201
+
202
+ // ============================================================================
203
+ // Load State Events
204
+ // ============================================================================
205
+
206
+ /**
207
+ * Fired when entity load state changes.
208
+ */
209
+ export interface LoadStateChangedEvent extends BindxEvent<'load:stateChanged'> {
210
+ readonly previousStatus: string | undefined
211
+ readonly newStatus: string
212
+ readonly error?: FieldError
213
+ }
214
+
215
+ // ============================================================================
216
+ // Union Types
217
+ // ============================================================================
218
+
219
+ /**
220
+ * All "before" events that can be intercepted and cancelled.
221
+ */
222
+ export type BeforeEvent =
223
+ | FieldChangingEvent
224
+ | RelationConnectingEvent
225
+ | RelationDisconnectingEvent
226
+ | RelationDeletingEvent
227
+ | HasManyConnectingEvent
228
+ | HasManyDisconnectingEvent
229
+ | EntityPersistingEvent
230
+ | EntityResettingEvent
231
+ | EntityDeletingEvent
232
+
233
+ /**
234
+ * All "after" events (notifications).
235
+ */
236
+ export type AfterEvent =
237
+ | FieldChangedEvent
238
+ | RelationConnectedEvent
239
+ | RelationDisconnectedEvent
240
+ | RelationDeletedEvent
241
+ | HasManyConnectedEvent
242
+ | HasManyDisconnectedEvent
243
+ | EntityPersistedEvent
244
+ | EntityPersistFailedEvent
245
+ | EntityResetEvent
246
+ | EntityDeletedEvent
247
+ | ErrorAddedEvent
248
+ | ErrorsClearedEvent
249
+ | LoadStateChangedEvent
250
+
251
+ /**
252
+ * All bindx events.
253
+ */
254
+ export type AnyBindxEvent = BeforeEvent | AfterEvent
255
+
256
+ /**
257
+ * All before event type strings.
258
+ */
259
+ export type BeforeEventType = BeforeEvent['type']
260
+
261
+ /**
262
+ * All after event type strings.
263
+ */
264
+ export type AfterEventType = AfterEvent['type']
265
+
266
+ /**
267
+ * All event type strings.
268
+ */
269
+ export type AnyEventType = AnyBindxEvent['type']
270
+
271
+ // ============================================================================
272
+ // Event Type Map
273
+ // ============================================================================
274
+
275
+ /**
276
+ * Map of event types to their event objects.
277
+ * Enables type-safe subscriptions.
278
+ */
279
+ export interface EventTypeMap {
280
+ // Field events
281
+ 'field:changing': FieldChangingEvent
282
+ 'field:changed': FieldChangedEvent
283
+
284
+ // HasOne relation events
285
+ 'relation:connecting': RelationConnectingEvent
286
+ 'relation:connected': RelationConnectedEvent
287
+ 'relation:disconnecting': RelationDisconnectingEvent
288
+ 'relation:disconnected': RelationDisconnectedEvent
289
+ 'relation:deleting': RelationDeletingEvent
290
+ 'relation:deleted': RelationDeletedEvent
291
+
292
+ // HasMany relation events
293
+ 'hasMany:connecting': HasManyConnectingEvent
294
+ 'hasMany:connected': HasManyConnectedEvent
295
+ 'hasMany:disconnecting': HasManyDisconnectingEvent
296
+ 'hasMany:disconnected': HasManyDisconnectedEvent
297
+
298
+ // Entity lifecycle events
299
+ 'entity:persisting': EntityPersistingEvent
300
+ 'entity:persisted': EntityPersistedEvent
301
+ 'entity:persistFailed': EntityPersistFailedEvent
302
+ 'entity:resetting': EntityResettingEvent
303
+ 'entity:reset': EntityResetEvent
304
+ 'entity:deleting': EntityDeletingEvent
305
+ 'entity:deleted': EntityDeletedEvent
306
+
307
+ // Error events
308
+ 'error:added': ErrorAddedEvent
309
+ 'errors:cleared': ErrorsClearedEvent
310
+
311
+ // Load state events
312
+ 'load:stateChanged': LoadStateChangedEvent
313
+ }
314
+
315
+ /**
316
+ * Extract event type from event name.
317
+ */
318
+ export type EventByType<T extends keyof EventTypeMap> = EventTypeMap[T]
319
+
320
+ // ============================================================================
321
+ // Interceptor Types
322
+ // ============================================================================
323
+
324
+ /**
325
+ * Result of an interceptor execution.
326
+ */
327
+ export type InterceptorResult<T extends BeforeEvent = BeforeEvent> =
328
+ | { readonly action: 'cancel' }
329
+ | { readonly action: 'continue' }
330
+ | { readonly action: 'modify'; readonly event: T }
331
+
332
+ /**
333
+ * Interceptor function type.
334
+ * Can be sync or async.
335
+ * Return undefined/void to continue without changes.
336
+ */
337
+ export type Interceptor<T extends BeforeEvent> = (
338
+ event: T,
339
+ ) => InterceptorResult<T> | Promise<InterceptorResult<T>> | void | Promise<void>
340
+
341
+ /**
342
+ * Event listener function type.
343
+ */
344
+ export type EventListener<T extends AfterEvent> = (event: T) => void
345
+
346
+ /**
347
+ * Unsubscribe function returned by subscription methods.
348
+ */
349
+ export type Unsubscribe = () => void
350
+
351
+ // ============================================================================
352
+ // Helper Types
353
+ // ============================================================================
354
+
355
+ /**
356
+ * Extract before events from EventTypeMap.
357
+ */
358
+ export type BeforeEventTypes = {
359
+ [K in keyof EventTypeMap]: EventTypeMap[K] extends BeforeEvent ? K : never
360
+ }[keyof EventTypeMap]
361
+
362
+ /**
363
+ * Extract after events from EventTypeMap.
364
+ */
365
+ export type AfterEventTypes = {
366
+ [K in keyof EventTypeMap]: EventTypeMap[K] extends AfterEvent ? K : never
367
+ }[keyof EventTypeMap]
368
+
369
+ /**
370
+ * Extract field-scoped events.
371
+ */
372
+ export type FieldScopedEventTypes = {
373
+ [K in keyof EventTypeMap]: EventTypeMap[K] extends FieldScopedEvent<string> ? K : never
374
+ }[keyof EventTypeMap]
@@ -0,0 +1,100 @@
1
+ import type { Disposable, DisposableGroup } from '../core/Disposable.js'
2
+ import type { ActionDispatcher } from '../core/ActionDispatcher.js'
3
+ import type { SnapshotStore } from '../store/SnapshotStore.js'
4
+
5
+ /**
6
+ * Base class for all handles.
7
+ * Provides common functionality for subscription and disposal.
8
+ *
9
+ * Handles are stable objects that:
10
+ * - Have stable identity (same instance across renders)
11
+ * - Provide subscribe/getSnapshot for useSyncExternalStore
12
+ * - Dispatch actions for mutations
13
+ */
14
+ export abstract class BaseHandle implements Disposable {
15
+ protected _disposed = false
16
+
17
+ constructor(
18
+ protected readonly store: SnapshotStore,
19
+ protected readonly dispatcher: ActionDispatcher,
20
+ ) {}
21
+
22
+ /**
23
+ * Subscribe to changes. Used by useSyncExternalStore.
24
+ */
25
+ abstract subscribe(callback: () => void): () => void
26
+
27
+ /**
28
+ * Get current version for change detection.
29
+ */
30
+ abstract getVersion(): number
31
+
32
+ /**
33
+ * Dispose resources (unsubscribe, cleanup).
34
+ */
35
+ dispose(): void {
36
+ this._disposed = true
37
+ }
38
+
39
+ /**
40
+ * Check if the handle has been disposed.
41
+ */
42
+ get isDisposed(): boolean {
43
+ return this._disposed
44
+ }
45
+
46
+ /**
47
+ * Throws if the handle has been disposed.
48
+ */
49
+ protected assertNotDisposed(): void {
50
+ if (this._disposed) {
51
+ throw new Error('Handle has been disposed')
52
+ }
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Base class for entity-related handles.
58
+ * Provides common entity subscription logic.
59
+ */
60
+ export abstract class EntityRelatedHandle extends BaseHandle {
61
+ constructor(
62
+ protected readonly entityType: string,
63
+ protected readonly entityId: string,
64
+ store: SnapshotStore,
65
+ dispatcher: ActionDispatcher,
66
+ ) {
67
+ super(store, dispatcher)
68
+ }
69
+
70
+ /**
71
+ * Subscribe to entity changes.
72
+ */
73
+ subscribe(callback: () => void): () => void {
74
+ return this.store.subscribeToEntity(this.entityType, this.entityId, callback)
75
+ }
76
+
77
+ /**
78
+ * Get entity snapshot version.
79
+ */
80
+ getVersion(): number {
81
+ const snapshot = this.store.getEntitySnapshot(this.entityType, this.entityId)
82
+ return snapshot?.version ?? 0
83
+ }
84
+
85
+ /**
86
+ * Get entity data.
87
+ */
88
+ protected getEntityData(): Record<string, unknown> | undefined {
89
+ const snapshot = this.store.getEntitySnapshot(this.entityType, this.entityId)
90
+ return snapshot?.data as Record<string, unknown> | undefined
91
+ }
92
+
93
+ /**
94
+ * Get entity server data.
95
+ */
96
+ protected getServerData(): Record<string, unknown> | undefined {
97
+ const snapshot = this.store.getEntitySnapshot(this.entityType, this.entityId)
98
+ return snapshot?.serverData as Record<string, unknown> | undefined
99
+ }
100
+ }