@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,268 @@
1
+ import { EntityRelatedHandle } from './BaseHandle.js'
2
+ import type { ActionDispatcher } from '../core/ActionDispatcher.js'
3
+ import type { SnapshotStore } from '../store/SnapshotStore.js'
4
+ import { addFieldError, clearFieldErrors, setField } from '../core/actions.js'
5
+ import { FIELD_REF_META, type FieldRef, type FieldRefMeta, type InputProps, type Unsubscribe } from './types.js'
6
+ import { deepEqual } from '../utils/deepEqual.js'
7
+ import { createClientError, type ErrorInput, type FieldError } from '../errors/types.js'
8
+ import type {
9
+ FieldChangedEvent,
10
+ FieldChangingEvent,
11
+ EventListener,
12
+ Interceptor,
13
+ } from '../events/types.js'
14
+ import { createAliasProxy } from './proxyFactory.js'
15
+
16
+ /**
17
+ * FieldHandle provides stable access to a scalar field.
18
+ *
19
+ * Key characteristics:
20
+ * - Stable identity (same instance across renders)
21
+ * - Reads data from SnapshotStore snapshots
22
+ * - Dispatches actions for mutations
23
+ * - Provides inputProps for form integration
24
+ * - Implements FieldRef interface for JSX compatibility
25
+ */
26
+ export class FieldHandle<T = unknown> extends EntityRelatedHandle implements FieldRef<T> {
27
+ private _cachedInputProps: InputProps<T> | null = null
28
+ private _cachedInputPropsValue: T | null | undefined = undefined
29
+
30
+ private readonly _boundSetValue = (value: T | null): void => this.setValue(value)
31
+
32
+ private constructor(
33
+ entityType: string,
34
+ entityId: string,
35
+ private readonly fieldPath: string[],
36
+ store: SnapshotStore,
37
+ dispatcher: ActionDispatcher,
38
+ private readonly _enumName?: string,
39
+ private readonly _columnType?: string,
40
+ ) {
41
+ super(entityType, entityId, store, dispatcher)
42
+ }
43
+
44
+ static create<T = unknown>(
45
+ entityType: string,
46
+ entityId: string,
47
+ fieldPath: string[],
48
+ store: SnapshotStore,
49
+ dispatcher: ActionDispatcher,
50
+ enumName?: string,
51
+ columnType?: string,
52
+ ): FieldHandle<T> {
53
+ return createAliasProxy(new FieldHandle<T>(entityType, entityId, fieldPath, store, dispatcher, enumName, columnType))
54
+ }
55
+
56
+ /**
57
+ * JSX field reference metadata for collection phase.
58
+ * Implements FieldRef interface.
59
+ */
60
+ get [FIELD_REF_META](): FieldRefMeta {
61
+ return {
62
+ entityType: this.entityType,
63
+ entityId: this.entityId,
64
+ path: this.fieldPath,
65
+ fieldName: this.fieldName,
66
+ isArray: false,
67
+ isRelation: false,
68
+ enumName: this._enumName,
69
+ columnType: this._columnType,
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Gets the current field value.
75
+ */
76
+ get value(): T | null {
77
+ const data = this.getEntityData()
78
+ if (!data) return null
79
+ return getNestedValue(data, this.fieldPath) as T | null
80
+ }
81
+
82
+ /**
83
+ * Gets the server value (for dirty tracking).
84
+ */
85
+ get serverValue(): T | null {
86
+ const serverData = this.getServerData()
87
+ if (!serverData) return null
88
+ return getNestedValue(serverData, this.fieldPath) as T | null
89
+ }
90
+
91
+ /**
92
+ * Checks if the field has been modified.
93
+ */
94
+ get isDirty(): boolean {
95
+ return !deepEqual(this.value, this.serverValue)
96
+ }
97
+
98
+ /**
99
+ * Checks if the field has been touched (interacted with by the user).
100
+ * Useful for showing errors only after user interaction.
101
+ */
102
+ get isTouched(): boolean {
103
+ return this.store.isFieldTouched(this.entityType, this.entityId, this.fieldName)
104
+ }
105
+
106
+ /**
107
+ * Marks the field as touched.
108
+ * Call this on blur or other interaction events.
109
+ */
110
+ touch(): void {
111
+ this.assertNotDisposed()
112
+ this.store.setFieldTouched(this.entityType, this.entityId, this.fieldName, true)
113
+ }
114
+
115
+ /**
116
+ * Sets the field value.
117
+ * Also clears non-sticky client errors.
118
+ */
119
+ setValue(value: T | null): void {
120
+ this.assertNotDisposed()
121
+ // Clear non-sticky errors when value changes
122
+ this.store.clearNonStickyFieldErrors(this.entityType, this.entityId, this.fieldName)
123
+ this.dispatcher.dispatch(
124
+ setField(this.entityType, this.entityId, this.fieldPath, value),
125
+ )
126
+ }
127
+
128
+ /**
129
+ * Gets the list of errors on this field.
130
+ */
131
+ get errors(): readonly FieldError[] {
132
+ return this.store.getFieldErrors(this.entityType, this.entityId, this.fieldName)
133
+ }
134
+
135
+ /**
136
+ * Checks if this field has any errors.
137
+ */
138
+ get hasError(): boolean {
139
+ return this.errors.length > 0
140
+ }
141
+
142
+ /**
143
+ * Adds a client-side error to this field.
144
+ */
145
+ addError(error: ErrorInput): void {
146
+ this.assertNotDisposed()
147
+ this.dispatcher.dispatch(
148
+ addFieldError(this.entityType, this.entityId, this.fieldName, createClientError(error)),
149
+ )
150
+ }
151
+
152
+ /**
153
+ * Clears all errors from this field.
154
+ */
155
+ clearErrors(): void {
156
+ this.assertNotDisposed()
157
+ this.dispatcher.dispatch(
158
+ clearFieldErrors(this.entityType, this.entityId, this.fieldName),
159
+ )
160
+ }
161
+
162
+ /**
163
+ * Gets input binding props for form integration.
164
+ *
165
+ * @example
166
+ * ```tsx
167
+ * <input {...field.inputProps} />
168
+ * // or with custom handler
169
+ * <input
170
+ * value={field.inputProps.value ?? ''}
171
+ * onChange={e => field.inputProps.onChange(e.target.value)}
172
+ * />
173
+ * ```
174
+ */
175
+ get inputProps(): InputProps<T> {
176
+ const currentValue = this.value
177
+ if (this._cachedInputProps === null || currentValue !== this._cachedInputPropsValue) {
178
+ this._cachedInputPropsValue = currentValue
179
+ this._cachedInputProps = {
180
+ value: currentValue,
181
+ setValue: this._boundSetValue,
182
+ onChange: this._boundSetValue,
183
+ }
184
+ }
185
+ return this._cachedInputProps
186
+ }
187
+
188
+ /**
189
+ * Gets the field path.
190
+ */
191
+ get path(): readonly string[] {
192
+ return this.fieldPath
193
+ }
194
+
195
+ /**
196
+ * Gets the field name (last segment of path).
197
+ */
198
+ get fieldName(): string {
199
+ return this.fieldPath[this.fieldPath.length - 1] ?? ''
200
+ }
201
+
202
+ /**
203
+ * Creates a nested field handle for a subfield.
204
+ */
205
+ nested<K extends keyof NonNullable<T>>(
206
+ key: K,
207
+ ): FieldHandle<NonNullable<T>[K]> {
208
+ return FieldHandle.create<NonNullable<T>[K]>(
209
+ this.entityType,
210
+ this.entityId,
211
+ [...this.fieldPath, key as string],
212
+ this.store,
213
+ this.dispatcher,
214
+ )
215
+ }
216
+
217
+ // ==================== Event Subscriptions ====================
218
+
219
+ /**
220
+ * Subscribe to field value changes.
221
+ * The listener is called after the value has changed.
222
+ */
223
+ onChange(listener: EventListener<FieldChangedEvent>): Unsubscribe {
224
+ const emitter = this.dispatcher.getEventEmitter()
225
+ return emitter.onField(
226
+ 'field:changed',
227
+ this.entityType,
228
+ this.entityId,
229
+ this.fieldName,
230
+ listener,
231
+ )
232
+ }
233
+
234
+ /**
235
+ * Intercept field value changes.
236
+ * The interceptor can cancel or modify the change.
237
+ */
238
+ onChanging(interceptor: Interceptor<FieldChangingEvent>): Unsubscribe {
239
+ const emitter = this.dispatcher.getEventEmitter()
240
+ return emitter.interceptField(
241
+ 'field:changing',
242
+ this.entityType,
243
+ this.entityId,
244
+ this.fieldName,
245
+ interceptor,
246
+ )
247
+ }
248
+
249
+ }
250
+
251
+ // ==================== Helper Functions ====================
252
+
253
+ /**
254
+ * Gets a nested value from an object using a path array.
255
+ */
256
+ function getNestedValue(obj: Record<string, unknown>, path: string[]): unknown {
257
+ let current: unknown = obj
258
+
259
+ for (const key of path) {
260
+ if (current === null || current === undefined || typeof current !== 'object') {
261
+ return undefined
262
+ }
263
+ current = (current as Record<string, unknown>)[key]
264
+ }
265
+
266
+ return current
267
+ }
268
+