@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.
- package/dist/adapter/ContemberAdapter.d.ts +40 -0
- package/dist/adapter/ContemberAdapter.d.ts.map +1 -0
- package/dist/adapter/MockAdapter.d.ts +81 -0
- package/dist/adapter/MockAdapter.d.ts.map +1 -0
- package/dist/adapter/MockQueryEngine.d.ts +43 -0
- package/dist/adapter/MockQueryEngine.d.ts.map +1 -0
- package/dist/adapter/index.d.ts +5 -0
- package/dist/adapter/index.d.ts.map +1 -0
- package/dist/adapter/types.d.ts +184 -0
- package/dist/adapter/types.d.ts.map +1 -0
- package/dist/brand/ComponentBrand.d.ts +25 -0
- package/dist/brand/ComponentBrand.d.ts.map +1 -0
- package/dist/contember/index.d.ts +10 -0
- package/dist/contember/index.d.ts.map +1 -0
- package/dist/core/ActionDispatcher.d.ts +64 -0
- package/dist/core/ActionDispatcher.d.ts.map +1 -0
- package/dist/core/Disposable.d.ts +57 -0
- package/dist/core/Disposable.d.ts.map +1 -0
- package/dist/core/EntityLoader.d.ts +80 -0
- package/dist/core/EntityLoader.d.ts.map +1 -0
- package/dist/core/PersistenceManager.d.ts +126 -0
- package/dist/core/PersistenceManager.d.ts.map +1 -0
- package/dist/core/SelectionResolver.d.ts +21 -0
- package/dist/core/SelectionResolver.d.ts.map +1 -0
- package/dist/core/actionClassification.d.ts +48 -0
- package/dist/core/actionClassification.d.ts.map +1 -0
- package/dist/core/actions.d.ts +301 -0
- package/dist/core/actions.d.ts.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/dataview/filterHandlers.d.ts +18 -0
- package/dist/dataview/filterHandlers.d.ts.map +1 -0
- package/dist/dataview/index.d.ts +3 -0
- package/dist/dataview/index.d.ts.map +1 -0
- package/dist/dataview/types.d.ts +164 -0
- package/dist/dataview/types.d.ts.map +1 -0
- package/dist/errors/UnfetchedFieldError.d.ts +11 -0
- package/dist/errors/UnfetchedFieldError.d.ts.map +1 -0
- package/dist/errors/errorPathResolver.d.ts +52 -0
- package/dist/errors/errorPathResolver.d.ts.map +1 -0
- package/dist/errors/index.d.ts +5 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/pathMapper.d.ts +42 -0
- package/dist/errors/pathMapper.d.ts.map +1 -0
- package/dist/errors/types.d.ts +131 -0
- package/dist/errors/types.d.ts.map +1 -0
- package/dist/events/EventEmitter.d.ts +97 -0
- package/dist/events/EventEmitter.d.ts.map +1 -0
- package/dist/events/eventFactory.d.ts +40 -0
- package/dist/events/eventFactory.d.ts.map +1 -0
- package/dist/events/index.d.ts +15 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/types.d.ts +264 -0
- package/dist/events/types.d.ts.map +1 -0
- package/dist/handles/BaseHandle.d.ts +64 -0
- package/dist/handles/BaseHandle.d.ts.map +1 -0
- package/dist/handles/EntityHandle.d.ts +208 -0
- package/dist/handles/EntityHandle.d.ts.map +1 -0
- package/dist/handles/FieldHandle.d.ts +111 -0
- package/dist/handles/FieldHandle.d.ts.map +1 -0
- package/dist/handles/HasManyListHandle.d.ts +166 -0
- package/dist/handles/HasManyListHandle.d.ts.map +1 -0
- package/dist/handles/HasOneHandle.d.ts +168 -0
- package/dist/handles/HasOneHandle.d.ts.map +1 -0
- package/dist/handles/PlaceholderHandle.d.ts +117 -0
- package/dist/handles/PlaceholderHandle.d.ts.map +1 -0
- package/dist/handles/index.d.ts +8 -0
- package/dist/handles/index.d.ts.map +1 -0
- package/dist/handles/proxyFactory.d.ts +66 -0
- package/dist/handles/proxyFactory.d.ts.map +1 -0
- package/dist/handles/types.d.ts +430 -0
- package/dist/handles/types.d.ts.map +1 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/internal.d.ts +11 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/persistence/BatchPersister.d.ts +142 -0
- package/dist/persistence/BatchPersister.d.ts.map +1 -0
- package/dist/persistence/ChangeRegistry.d.ts +87 -0
- package/dist/persistence/ChangeRegistry.d.ts.map +1 -0
- package/dist/persistence/ContemberSchemaMutationAdapter.d.ts +16 -0
- package/dist/persistence/ContemberSchemaMutationAdapter.d.ts.map +1 -0
- package/dist/persistence/MutationCollector.d.ts +96 -0
- package/dist/persistence/MutationCollector.d.ts.map +1 -0
- package/dist/persistence/MutationSchemaProvider.d.ts +30 -0
- package/dist/persistence/MutationSchemaProvider.d.ts.map +1 -0
- package/dist/persistence/index.d.ts +7 -0
- package/dist/persistence/index.d.ts.map +1 -0
- package/dist/persistence/types.d.ts +189 -0
- package/dist/persistence/types.d.ts.map +1 -0
- package/dist/roles/RoleSchemaRegistry.d.ts +77 -0
- package/dist/roles/RoleSchemaRegistry.d.ts.map +1 -0
- package/dist/roles/index.d.ts +11 -0
- package/dist/roles/index.d.ts.map +1 -0
- package/dist/roles/types.d.ts +242 -0
- package/dist/roles/types.d.ts.map +1 -0
- package/dist/schema/ContemberSchema.d.ts +98 -0
- package/dist/schema/ContemberSchema.d.ts.map +1 -0
- package/dist/schema/SchemaLoader.d.ts +28 -0
- package/dist/schema/SchemaLoader.d.ts.map +1 -0
- package/dist/schema/SchemaRegistry.d.ts +95 -0
- package/dist/schema/SchemaRegistry.d.ts.map +1 -0
- package/dist/schema/index.d.ts +6 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/roles.d.ts +62 -0
- package/dist/schema/roles.d.ts.map +1 -0
- package/dist/schema/types.d.ts +179 -0
- package/dist/schema/types.d.ts.map +1 -0
- package/dist/selection/SelectionMetaCollector.d.ts +32 -0
- package/dist/selection/SelectionMetaCollector.d.ts.map +1 -0
- package/dist/selection/SelectionScope.d.ts +77 -0
- package/dist/selection/SelectionScope.d.ts.map +1 -0
- package/dist/selection/buildQuery.d.ts +45 -0
- package/dist/selection/buildQuery.d.ts.map +1 -0
- package/dist/selection/createFragment.d.ts +29 -0
- package/dist/selection/createFragment.d.ts.map +1 -0
- package/dist/selection/createSelectionBuilder.d.ts +18 -0
- package/dist/selection/createSelectionBuilder.d.ts.map +1 -0
- package/dist/selection/index.d.ts +8 -0
- package/dist/selection/index.d.ts.map +1 -0
- package/dist/selection/queryTypes.d.ts +84 -0
- package/dist/selection/queryTypes.d.ts.map +1 -0
- package/dist/selection/types.d.ts +238 -0
- package/dist/selection/types.d.ts.map +1 -0
- package/dist/store/DirtyTracker.d.ts +26 -0
- package/dist/store/DirtyTracker.d.ts.map +1 -0
- package/dist/store/EntityMetaStore.d.ts +52 -0
- package/dist/store/EntityMetaStore.d.ts.map +1 -0
- package/dist/store/EntitySnapshotStore.d.ts +63 -0
- package/dist/store/EntitySnapshotStore.d.ts.map +1 -0
- package/dist/store/ErrorStore.d.ts +82 -0
- package/dist/store/ErrorStore.d.ts.map +1 -0
- package/dist/store/RelationStore.d.ts +175 -0
- package/dist/store/RelationStore.d.ts.map +1 -0
- package/dist/store/SnapshotStore.d.ts +143 -0
- package/dist/store/SnapshotStore.d.ts.map +1 -0
- package/dist/store/SubscriptionManager.d.ts +90 -0
- package/dist/store/SubscriptionManager.d.ts.map +1 -0
- package/dist/store/TouchedStore.d.ts +24 -0
- package/dist/store/TouchedStore.d.ts.map +1 -0
- package/dist/store/entityId.d.ts +29 -0
- package/dist/store/entityId.d.ts.map +1 -0
- package/dist/store/index.d.ts +1 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/snapshots.d.ts +144 -0
- package/dist/store/snapshots.d.ts.map +1 -0
- package/dist/undo/UndoManager.d.ts +120 -0
- package/dist/undo/UndoManager.d.ts.map +1 -0
- package/dist/undo/index.d.ts +3 -0
- package/dist/undo/index.d.ts.map +1 -0
- package/dist/undo/types.d.ts +74 -0
- package/dist/undo/types.d.ts.map +1 -0
- package/dist/utils/aliasGenerator.d.ts +25 -0
- package/dist/utils/aliasGenerator.d.ts.map +1 -0
- package/dist/utils/deepEqual.d.ts +6 -0
- package/dist/utils/deepEqual.d.ts.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/package.json +29 -0
- package/src/adapter/ContemberAdapter.ts +239 -0
- package/src/adapter/MockAdapter.ts +394 -0
- package/src/adapter/MockQueryEngine.ts +236 -0
- package/src/adapter/index.ts +21 -0
- package/src/adapter/types.ts +199 -0
- package/src/brand/ComponentBrand.ts +28 -0
- package/src/contember/index.ts +17 -0
- package/src/core/ActionDispatcher.ts +450 -0
- package/src/core/Disposable.ts +126 -0
- package/src/core/EntityLoader.ts +169 -0
- package/src/core/SelectionResolver.ts +78 -0
- package/src/core/actionClassification.ts +196 -0
- package/src/core/actions.ts +491 -0
- package/src/core/index.ts +20 -0
- package/src/dataview/filterHandlers.ts +443 -0
- package/src/dataview/index.ts +36 -0
- package/src/dataview/types.ts +220 -0
- package/src/errors/UnfetchedFieldError.ts +18 -0
- package/src/errors/errorPathResolver.ts +239 -0
- package/src/errors/index.ts +40 -0
- package/src/errors/pathMapper.ts +40 -0
- package/src/errors/types.ts +223 -0
- package/src/events/EventEmitter.ts +447 -0
- package/src/events/eventFactory.ts +430 -0
- package/src/events/index.ts +89 -0
- package/src/events/types.ts +374 -0
- package/src/handles/BaseHandle.ts +100 -0
- package/src/handles/EntityHandle.ts +538 -0
- package/src/handles/FieldHandle.ts +268 -0
- package/src/handles/HasManyListHandle.ts +500 -0
- package/src/handles/HasOneHandle.ts +500 -0
- package/src/handles/PlaceholderHandle.ts +321 -0
- package/src/handles/index.ts +37 -0
- package/src/handles/proxyFactory.ts +218 -0
- package/src/handles/types.ts +743 -0
- package/src/index.ts +384 -0
- package/src/internal.ts +19 -0
- package/src/persistence/BatchPersister.ts +911 -0
- package/src/persistence/ChangeRegistry.ts +150 -0
- package/src/persistence/ContemberSchemaMutationAdapter.ts +57 -0
- package/src/persistence/MutationCollector.ts +567 -0
- package/src/persistence/MutationSchemaProvider.ts +33 -0
- package/src/persistence/index.ts +23 -0
- package/src/persistence/types.ts +220 -0
- package/src/schema/ContemberSchema.ts +132 -0
- package/src/schema/SchemaLoader.ts +93 -0
- package/src/schema/SchemaRegistry.ts +286 -0
- package/src/schema/index.ts +51 -0
- package/src/schema/roles.ts +83 -0
- package/src/schema/types.ts +238 -0
- package/src/selection/SelectionMetaCollector.ts +122 -0
- package/src/selection/SelectionScope.ts +208 -0
- package/src/selection/buildQuery.ts +134 -0
- package/src/selection/createFragment.ts +50 -0
- package/src/selection/createSelectionBuilder.ts +283 -0
- package/src/selection/index.ts +31 -0
- package/src/selection/queryTypes.ts +135 -0
- package/src/selection/types.ts +320 -0
- package/src/store/DirtyTracker.ts +117 -0
- package/src/store/EntityMetaStore.ts +143 -0
- package/src/store/EntitySnapshotStore.ts +260 -0
- package/src/store/ErrorStore.ts +251 -0
- package/src/store/RelationStore.ts +696 -0
- package/src/store/SnapshotStore.ts +765 -0
- package/src/store/SubscriptionManager.ts +241 -0
- package/src/store/TouchedStore.ts +42 -0
- package/src/store/entityId.ts +43 -0
- package/src/store/index.ts +2 -0
- package/src/store/snapshots.ts +203 -0
- package/src/undo/UndoManager.ts +418 -0
- package/src/undo/index.ts +9 -0
- package/src/undo/types.ts +84 -0
- package/src/utils/aliasGenerator.ts +56 -0
- package/src/utils/deepEqual.ts +33 -0
- package/src/utils/index.ts +2 -0
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory functions for creating events from actions.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { Action } from '../core/actions.js'
|
|
6
|
+
import type { SnapshotStore } from '../store/SnapshotStore.js'
|
|
7
|
+
import type {
|
|
8
|
+
BeforeEvent,
|
|
9
|
+
AfterEvent,
|
|
10
|
+
FieldChangingEvent,
|
|
11
|
+
FieldChangedEvent,
|
|
12
|
+
RelationConnectingEvent,
|
|
13
|
+
RelationConnectedEvent,
|
|
14
|
+
RelationDisconnectingEvent,
|
|
15
|
+
RelationDisconnectedEvent,
|
|
16
|
+
RelationDeletingEvent,
|
|
17
|
+
RelationDeletedEvent,
|
|
18
|
+
HasManyConnectingEvent,
|
|
19
|
+
HasManyConnectedEvent,
|
|
20
|
+
HasManyDisconnectingEvent,
|
|
21
|
+
HasManyDisconnectedEvent,
|
|
22
|
+
EntityResettingEvent,
|
|
23
|
+
EntityResetEvent,
|
|
24
|
+
ErrorAddedEvent,
|
|
25
|
+
ErrorsClearedEvent,
|
|
26
|
+
LoadStateChangedEvent,
|
|
27
|
+
} from './types.js'
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* State captured before action execution.
|
|
31
|
+
* Used to create after events with old values.
|
|
32
|
+
*/
|
|
33
|
+
export interface CapturedState {
|
|
34
|
+
oldValue?: unknown
|
|
35
|
+
previousId?: string | null
|
|
36
|
+
currentId?: string | null
|
|
37
|
+
previousStatus?: string
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Creates a before event from an action.
|
|
42
|
+
* Returns null for actions that don't have before events.
|
|
43
|
+
*/
|
|
44
|
+
export function createBeforeEvent(
|
|
45
|
+
action: Action,
|
|
46
|
+
store: SnapshotStore,
|
|
47
|
+
): BeforeEvent | null {
|
|
48
|
+
const timestamp = Date.now()
|
|
49
|
+
|
|
50
|
+
switch (action.type) {
|
|
51
|
+
case 'SET_FIELD': {
|
|
52
|
+
const snapshot = store.getEntitySnapshot(action.entityType, action.entityId)
|
|
53
|
+
const fieldName = action.fieldPath[action.fieldPath.length - 1] ?? action.fieldPath[0] ?? ''
|
|
54
|
+
const oldValue = getNestedValue(snapshot?.data, action.fieldPath)
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
type: 'field:changing',
|
|
58
|
+
timestamp,
|
|
59
|
+
entityType: action.entityType,
|
|
60
|
+
entityId: action.entityId,
|
|
61
|
+
fieldName,
|
|
62
|
+
fieldPath: action.fieldPath,
|
|
63
|
+
oldValue,
|
|
64
|
+
newValue: action.value,
|
|
65
|
+
} satisfies FieldChangingEvent
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
case 'CONNECT_RELATION': {
|
|
69
|
+
const relation = store.getRelation(
|
|
70
|
+
action.entityType,
|
|
71
|
+
action.entityId,
|
|
72
|
+
action.fieldName,
|
|
73
|
+
)
|
|
74
|
+
return {
|
|
75
|
+
type: 'relation:connecting',
|
|
76
|
+
timestamp,
|
|
77
|
+
entityType: action.entityType,
|
|
78
|
+
entityId: action.entityId,
|
|
79
|
+
fieldName: action.fieldName,
|
|
80
|
+
targetId: action.targetId,
|
|
81
|
+
previousId: relation?.currentId ?? null,
|
|
82
|
+
} satisfies RelationConnectingEvent
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
case 'DISCONNECT_RELATION': {
|
|
86
|
+
const relation = store.getRelation(
|
|
87
|
+
action.entityType,
|
|
88
|
+
action.entityId,
|
|
89
|
+
action.fieldName,
|
|
90
|
+
)
|
|
91
|
+
return {
|
|
92
|
+
type: 'relation:disconnecting',
|
|
93
|
+
timestamp,
|
|
94
|
+
entityType: action.entityType,
|
|
95
|
+
entityId: action.entityId,
|
|
96
|
+
fieldName: action.fieldName,
|
|
97
|
+
currentId: relation?.currentId ?? null,
|
|
98
|
+
} satisfies RelationDisconnectingEvent
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
case 'DELETE_RELATION': {
|
|
102
|
+
const relation = store.getRelation(
|
|
103
|
+
action.entityType,
|
|
104
|
+
action.entityId,
|
|
105
|
+
action.fieldName,
|
|
106
|
+
)
|
|
107
|
+
return {
|
|
108
|
+
type: 'relation:deleting',
|
|
109
|
+
timestamp,
|
|
110
|
+
entityType: action.entityType,
|
|
111
|
+
entityId: action.entityId,
|
|
112
|
+
fieldName: action.fieldName,
|
|
113
|
+
currentId: relation?.currentId ?? null,
|
|
114
|
+
} satisfies RelationDeletingEvent
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
case 'RESET_ENTITY': {
|
|
118
|
+
return {
|
|
119
|
+
type: 'entity:resetting',
|
|
120
|
+
timestamp,
|
|
121
|
+
entityType: action.entityType,
|
|
122
|
+
entityId: action.entityId,
|
|
123
|
+
} satisfies EntityResettingEvent
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// HasMany events - these would need to be created from the store's planned operations
|
|
127
|
+
// For now, we handle ADD_TO_LIST and REMOVE_FROM_LIST actions
|
|
128
|
+
// Note: The current actions don't have a direct "connect to hasMany" action,
|
|
129
|
+
// but the store has planHasManyConnection/planHasManyRemoval methods
|
|
130
|
+
|
|
131
|
+
default:
|
|
132
|
+
return null
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Captures relevant state before action execution.
|
|
138
|
+
* Used to create after events with accurate old values.
|
|
139
|
+
*/
|
|
140
|
+
export function captureStateBeforeAction(
|
|
141
|
+
action: Action,
|
|
142
|
+
store: SnapshotStore,
|
|
143
|
+
): CapturedState {
|
|
144
|
+
switch (action.type) {
|
|
145
|
+
case 'SET_FIELD': {
|
|
146
|
+
const snapshot = store.getEntitySnapshot(action.entityType, action.entityId)
|
|
147
|
+
return {
|
|
148
|
+
oldValue: getNestedValue(snapshot?.data, action.fieldPath),
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
case 'CONNECT_RELATION':
|
|
153
|
+
case 'DISCONNECT_RELATION':
|
|
154
|
+
case 'DELETE_RELATION': {
|
|
155
|
+
const relation = store.getRelation(
|
|
156
|
+
action.entityType,
|
|
157
|
+
action.entityId,
|
|
158
|
+
action.fieldName,
|
|
159
|
+
)
|
|
160
|
+
return {
|
|
161
|
+
previousId: relation?.currentId ?? null,
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
case 'SET_LOAD_STATE': {
|
|
166
|
+
const loadState = store.getLoadState(action.entityType, action.entityId)
|
|
167
|
+
return {
|
|
168
|
+
previousStatus: loadState?.status,
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
default:
|
|
173
|
+
return {}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Creates an after event from an action and captured state.
|
|
179
|
+
* Returns null for actions that don't have after events.
|
|
180
|
+
*/
|
|
181
|
+
export function createAfterEvent(
|
|
182
|
+
action: Action,
|
|
183
|
+
stateBefore: CapturedState,
|
|
184
|
+
store: SnapshotStore,
|
|
185
|
+
): AfterEvent | null {
|
|
186
|
+
const timestamp = Date.now()
|
|
187
|
+
|
|
188
|
+
switch (action.type) {
|
|
189
|
+
case 'SET_FIELD': {
|
|
190
|
+
const fieldName = action.fieldPath[action.fieldPath.length - 1] ?? action.fieldPath[0] ?? ''
|
|
191
|
+
return {
|
|
192
|
+
type: 'field:changed',
|
|
193
|
+
timestamp,
|
|
194
|
+
entityType: action.entityType,
|
|
195
|
+
entityId: action.entityId,
|
|
196
|
+
fieldName,
|
|
197
|
+
fieldPath: action.fieldPath,
|
|
198
|
+
oldValue: stateBefore.oldValue,
|
|
199
|
+
newValue: action.value,
|
|
200
|
+
} satisfies FieldChangedEvent
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
case 'CONNECT_RELATION': {
|
|
204
|
+
return {
|
|
205
|
+
type: 'relation:connected',
|
|
206
|
+
timestamp,
|
|
207
|
+
entityType: action.entityType,
|
|
208
|
+
entityId: action.entityId,
|
|
209
|
+
fieldName: action.fieldName,
|
|
210
|
+
targetId: action.targetId,
|
|
211
|
+
previousId: stateBefore.previousId ?? null,
|
|
212
|
+
} satisfies RelationConnectedEvent
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
case 'DISCONNECT_RELATION': {
|
|
216
|
+
return {
|
|
217
|
+
type: 'relation:disconnected',
|
|
218
|
+
timestamp,
|
|
219
|
+
entityType: action.entityType,
|
|
220
|
+
entityId: action.entityId,
|
|
221
|
+
fieldName: action.fieldName,
|
|
222
|
+
previousId: stateBefore.previousId ?? null,
|
|
223
|
+
} satisfies RelationDisconnectedEvent
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
case 'DELETE_RELATION': {
|
|
227
|
+
return {
|
|
228
|
+
type: 'relation:deleted',
|
|
229
|
+
timestamp,
|
|
230
|
+
entityType: action.entityType,
|
|
231
|
+
entityId: action.entityId,
|
|
232
|
+
fieldName: action.fieldName,
|
|
233
|
+
previousId: stateBefore.previousId ?? null,
|
|
234
|
+
} satisfies RelationDeletedEvent
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
case 'RESET_ENTITY': {
|
|
238
|
+
return {
|
|
239
|
+
type: 'entity:reset',
|
|
240
|
+
timestamp,
|
|
241
|
+
entityType: action.entityType,
|
|
242
|
+
entityId: action.entityId,
|
|
243
|
+
} satisfies EntityResetEvent
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
case 'ADD_FIELD_ERROR': {
|
|
247
|
+
return {
|
|
248
|
+
type: 'error:added',
|
|
249
|
+
timestamp,
|
|
250
|
+
entityType: action.entityType,
|
|
251
|
+
entityId: action.entityId,
|
|
252
|
+
target: 'field',
|
|
253
|
+
targetName: action.fieldName,
|
|
254
|
+
error: action.error,
|
|
255
|
+
} satisfies ErrorAddedEvent
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
case 'ADD_ENTITY_ERROR': {
|
|
259
|
+
return {
|
|
260
|
+
type: 'error:added',
|
|
261
|
+
timestamp,
|
|
262
|
+
entityType: action.entityType,
|
|
263
|
+
entityId: action.entityId,
|
|
264
|
+
target: 'entity',
|
|
265
|
+
targetName: null,
|
|
266
|
+
error: action.error,
|
|
267
|
+
} satisfies ErrorAddedEvent
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
case 'ADD_RELATION_ERROR': {
|
|
271
|
+
return {
|
|
272
|
+
type: 'error:added',
|
|
273
|
+
timestamp,
|
|
274
|
+
entityType: action.entityType,
|
|
275
|
+
entityId: action.entityId,
|
|
276
|
+
target: 'relation',
|
|
277
|
+
targetName: action.relationName,
|
|
278
|
+
error: action.error,
|
|
279
|
+
} satisfies ErrorAddedEvent
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
case 'CLEAR_FIELD_ERRORS': {
|
|
283
|
+
return {
|
|
284
|
+
type: 'errors:cleared',
|
|
285
|
+
timestamp,
|
|
286
|
+
entityType: action.entityType,
|
|
287
|
+
entityId: action.entityId,
|
|
288
|
+
target: 'field',
|
|
289
|
+
targetName: action.fieldName,
|
|
290
|
+
} satisfies ErrorsClearedEvent
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
case 'CLEAR_ENTITY_ERRORS': {
|
|
294
|
+
return {
|
|
295
|
+
type: 'errors:cleared',
|
|
296
|
+
timestamp,
|
|
297
|
+
entityType: action.entityType,
|
|
298
|
+
entityId: action.entityId,
|
|
299
|
+
target: 'entity',
|
|
300
|
+
targetName: null,
|
|
301
|
+
} satisfies ErrorsClearedEvent
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
case 'CLEAR_RELATION_ERRORS': {
|
|
305
|
+
return {
|
|
306
|
+
type: 'errors:cleared',
|
|
307
|
+
timestamp,
|
|
308
|
+
entityType: action.entityType,
|
|
309
|
+
entityId: action.entityId,
|
|
310
|
+
target: 'relation',
|
|
311
|
+
targetName: action.relationName,
|
|
312
|
+
} satisfies ErrorsClearedEvent
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
case 'CLEAR_ALL_ERRORS':
|
|
316
|
+
case 'CLEAR_ALL_SERVER_ERRORS': {
|
|
317
|
+
return {
|
|
318
|
+
type: 'errors:cleared',
|
|
319
|
+
timestamp,
|
|
320
|
+
entityType: action.entityType,
|
|
321
|
+
entityId: action.entityId,
|
|
322
|
+
target: 'all',
|
|
323
|
+
targetName: null,
|
|
324
|
+
} satisfies ErrorsClearedEvent
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
case 'SET_LOAD_STATE': {
|
|
328
|
+
return {
|
|
329
|
+
type: 'load:stateChanged',
|
|
330
|
+
timestamp,
|
|
331
|
+
entityType: action.entityType,
|
|
332
|
+
entityId: action.entityId,
|
|
333
|
+
previousStatus: stateBefore.previousStatus,
|
|
334
|
+
newStatus: action.status,
|
|
335
|
+
error: action.error,
|
|
336
|
+
} satisfies LoadStateChangedEvent
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
default:
|
|
340
|
+
return null
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Creates hasMany connection events.
|
|
346
|
+
* These are separate since hasMany operations may not go through standard actions.
|
|
347
|
+
*/
|
|
348
|
+
export function createHasManyConnectingEvent(
|
|
349
|
+
entityType: string,
|
|
350
|
+
entityId: string,
|
|
351
|
+
fieldName: string,
|
|
352
|
+
itemId: string,
|
|
353
|
+
): HasManyConnectingEvent {
|
|
354
|
+
return {
|
|
355
|
+
type: 'hasMany:connecting',
|
|
356
|
+
timestamp: Date.now(),
|
|
357
|
+
entityType,
|
|
358
|
+
entityId,
|
|
359
|
+
fieldName,
|
|
360
|
+
itemId,
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
export function createHasManyConnectedEvent(
|
|
365
|
+
entityType: string,
|
|
366
|
+
entityId: string,
|
|
367
|
+
fieldName: string,
|
|
368
|
+
itemId: string,
|
|
369
|
+
): HasManyConnectedEvent {
|
|
370
|
+
return {
|
|
371
|
+
type: 'hasMany:connected',
|
|
372
|
+
timestamp: Date.now(),
|
|
373
|
+
entityType,
|
|
374
|
+
entityId,
|
|
375
|
+
fieldName,
|
|
376
|
+
itemId,
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
export function createHasManyDisconnectingEvent(
|
|
381
|
+
entityType: string,
|
|
382
|
+
entityId: string,
|
|
383
|
+
fieldName: string,
|
|
384
|
+
itemId: string,
|
|
385
|
+
): HasManyDisconnectingEvent {
|
|
386
|
+
return {
|
|
387
|
+
type: 'hasMany:disconnecting',
|
|
388
|
+
timestamp: Date.now(),
|
|
389
|
+
entityType,
|
|
390
|
+
entityId,
|
|
391
|
+
fieldName,
|
|
392
|
+
itemId,
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
export function createHasManyDisconnectedEvent(
|
|
397
|
+
entityType: string,
|
|
398
|
+
entityId: string,
|
|
399
|
+
fieldName: string,
|
|
400
|
+
itemId: string,
|
|
401
|
+
): HasManyDisconnectedEvent {
|
|
402
|
+
return {
|
|
403
|
+
type: 'hasMany:disconnected',
|
|
404
|
+
timestamp: Date.now(),
|
|
405
|
+
entityType,
|
|
406
|
+
entityId,
|
|
407
|
+
fieldName,
|
|
408
|
+
itemId,
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// ============================================================================
|
|
413
|
+
// Helper Functions
|
|
414
|
+
// ============================================================================
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Gets a nested value from an object by path.
|
|
418
|
+
*/
|
|
419
|
+
function getNestedValue(obj: unknown, path: readonly string[]): unknown {
|
|
420
|
+
if (obj === null || obj === undefined) return undefined
|
|
421
|
+
if (path.length === 0) return obj
|
|
422
|
+
|
|
423
|
+
let current: unknown = obj
|
|
424
|
+
for (const key of path) {
|
|
425
|
+
if (current === null || current === undefined) return undefined
|
|
426
|
+
if (typeof current !== 'object') return undefined
|
|
427
|
+
current = (current as Record<string, unknown>)[key]
|
|
428
|
+
}
|
|
429
|
+
return current
|
|
430
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event system for bindx.
|
|
3
|
+
*
|
|
4
|
+
* Provides type-safe event subscriptions and interceptors for:
|
|
5
|
+
* - Field value changes
|
|
6
|
+
* - Relation changes (hasOne, hasMany)
|
|
7
|
+
* - Entity lifecycle (persist, reset, delete)
|
|
8
|
+
* - Errors
|
|
9
|
+
* - Load state changes
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export { EventEmitter } from './EventEmitter.js'
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
createBeforeEvent,
|
|
16
|
+
createAfterEvent,
|
|
17
|
+
captureStateBeforeAction,
|
|
18
|
+
createHasManyConnectingEvent,
|
|
19
|
+
createHasManyConnectedEvent,
|
|
20
|
+
createHasManyDisconnectingEvent,
|
|
21
|
+
createHasManyDisconnectedEvent,
|
|
22
|
+
} from './eventFactory.js'
|
|
23
|
+
|
|
24
|
+
export type {
|
|
25
|
+
// Base types
|
|
26
|
+
BindxEvent,
|
|
27
|
+
FieldScopedEvent,
|
|
28
|
+
|
|
29
|
+
// Field events
|
|
30
|
+
FieldChangingEvent,
|
|
31
|
+
FieldChangedEvent,
|
|
32
|
+
|
|
33
|
+
// HasOne relation events
|
|
34
|
+
RelationConnectingEvent,
|
|
35
|
+
RelationConnectedEvent,
|
|
36
|
+
RelationDisconnectingEvent,
|
|
37
|
+
RelationDisconnectedEvent,
|
|
38
|
+
RelationDeletingEvent,
|
|
39
|
+
RelationDeletedEvent,
|
|
40
|
+
|
|
41
|
+
// HasMany relation events
|
|
42
|
+
HasManyConnectingEvent,
|
|
43
|
+
HasManyConnectedEvent,
|
|
44
|
+
HasManyDisconnectingEvent,
|
|
45
|
+
HasManyDisconnectedEvent,
|
|
46
|
+
|
|
47
|
+
// Entity lifecycle events
|
|
48
|
+
EntityPersistingEvent,
|
|
49
|
+
EntityPersistedEvent,
|
|
50
|
+
EntityPersistFailedEvent,
|
|
51
|
+
EntityResettingEvent,
|
|
52
|
+
EntityResetEvent,
|
|
53
|
+
EntityDeletingEvent,
|
|
54
|
+
EntityDeletedEvent,
|
|
55
|
+
|
|
56
|
+
// Error events
|
|
57
|
+
ErrorAddedEvent,
|
|
58
|
+
ErrorsClearedEvent,
|
|
59
|
+
|
|
60
|
+
// Load state events
|
|
61
|
+
LoadStateChangedEvent,
|
|
62
|
+
|
|
63
|
+
// Union types
|
|
64
|
+
BeforeEvent,
|
|
65
|
+
AfterEvent,
|
|
66
|
+
AnyBindxEvent,
|
|
67
|
+
|
|
68
|
+
// Event type strings
|
|
69
|
+
BeforeEventType,
|
|
70
|
+
AfterEventType,
|
|
71
|
+
AnyEventType,
|
|
72
|
+
|
|
73
|
+
// Type map
|
|
74
|
+
EventTypeMap,
|
|
75
|
+
EventByType,
|
|
76
|
+
|
|
77
|
+
// Interceptor types
|
|
78
|
+
InterceptorResult,
|
|
79
|
+
Interceptor,
|
|
80
|
+
EventListener,
|
|
81
|
+
Unsubscribe,
|
|
82
|
+
|
|
83
|
+
// Helper types
|
|
84
|
+
BeforeEventTypes,
|
|
85
|
+
AfterEventTypes,
|
|
86
|
+
FieldScopedEventTypes,
|
|
87
|
+
} from './types.js'
|
|
88
|
+
|
|
89
|
+
export type { CapturedState } from './eventFactory.js'
|