@verdant-web/store 2.8.5 → 3.0.0-next.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 (307) hide show
  1. package/dist/bundle/index.js +9 -10
  2. package/dist/bundle/index.js.map +4 -4
  3. package/dist/cjs/DocumentManager.d.ts +6 -5
  4. package/dist/cjs/DocumentManager.js +2 -2
  5. package/dist/cjs/DocumentManager.js.map +1 -1
  6. package/dist/cjs/IDBService.d.ts +28 -7
  7. package/dist/cjs/IDBService.js +50 -13
  8. package/dist/cjs/IDBService.js.map +1 -1
  9. package/dist/cjs/UndoHistory.d.ts +1 -1
  10. package/dist/cjs/UndoHistory.js +6 -2
  11. package/dist/cjs/UndoHistory.js.map +1 -1
  12. package/dist/cjs/__tests__/batching.test.js +3 -1
  13. package/dist/cjs/__tests__/batching.test.js.map +1 -1
  14. package/dist/cjs/__tests__/documents.test.js +37 -6
  15. package/dist/cjs/__tests__/documents.test.js.map +1 -1
  16. package/dist/cjs/__tests__/fixtures/testStorage.d.ts +2 -2
  17. package/dist/cjs/__tests__/fixtures/testStorage.js +2 -1
  18. package/dist/cjs/__tests__/fixtures/testStorage.js.map +1 -1
  19. package/dist/cjs/__tests__/legacyOids.test.js +50 -17
  20. package/dist/cjs/__tests__/legacyOids.test.js.map +1 -1
  21. package/dist/cjs/__tests__/mutations.test.js +9 -3
  22. package/dist/cjs/__tests__/mutations.test.js.map +1 -1
  23. package/dist/cjs/__tests__/queries.test.js +6 -2
  24. package/dist/cjs/__tests__/queries.test.js.map +1 -1
  25. package/dist/cjs/__tests__/setup/indexedDB.d.ts +1 -1
  26. package/dist/cjs/__tests__/setup/indexedDB.js +8 -1
  27. package/dist/cjs/__tests__/setup/indexedDB.js.map +1 -1
  28. package/dist/cjs/__tests__/undo.test.js +16 -9
  29. package/dist/cjs/__tests__/undo.test.js.map +1 -1
  30. package/dist/cjs/client/Client.d.ts +2 -3
  31. package/dist/cjs/client/Client.js +8 -4
  32. package/dist/cjs/client/Client.js.map +1 -1
  33. package/dist/cjs/client/ClientDescriptor.js +21 -6
  34. package/dist/cjs/client/ClientDescriptor.js.map +1 -1
  35. package/dist/cjs/context.d.ts +10 -1
  36. package/dist/cjs/entities/2/Entity.d.ts +148 -0
  37. package/dist/cjs/entities/2/Entity.js +711 -0
  38. package/dist/cjs/entities/2/Entity.js.map +1 -0
  39. package/dist/cjs/entities/2/Entity.test.d.ts +1 -0
  40. package/dist/cjs/entities/2/Entity.test.js +194 -0
  41. package/dist/cjs/entities/2/Entity.test.js.map +1 -0
  42. package/dist/cjs/entities/2/EntityCache.d.ts +15 -0
  43. package/dist/cjs/entities/2/EntityCache.js +39 -0
  44. package/dist/cjs/entities/2/EntityCache.js.map +1 -0
  45. package/dist/cjs/entities/2/EntityMetadata.d.ts +68 -0
  46. package/dist/cjs/entities/2/EntityMetadata.js +261 -0
  47. package/dist/cjs/entities/2/EntityMetadata.js.map +1 -0
  48. package/dist/cjs/entities/2/EntityStore.d.ts +78 -0
  49. package/dist/cjs/entities/2/EntityStore.js +352 -0
  50. package/dist/cjs/entities/2/EntityStore.js.map +1 -0
  51. package/dist/cjs/entities/2/OperationBatcher.d.ts +52 -0
  52. package/dist/cjs/entities/2/OperationBatcher.js +165 -0
  53. package/dist/cjs/entities/2/OperationBatcher.js.map +1 -0
  54. package/dist/cjs/entities/2/types.d.ts +84 -0
  55. package/dist/cjs/entities/2/types.js +3 -0
  56. package/dist/cjs/entities/2/types.js.map +1 -0
  57. package/dist/cjs/entities/Entity.d.ts +0 -7
  58. package/dist/cjs/entities/Entity.js +7 -0
  59. package/dist/cjs/entities/Entity.js.map +1 -1
  60. package/dist/cjs/entities/EntityStore.js +4 -20
  61. package/dist/cjs/entities/EntityStore.js.map +1 -1
  62. package/dist/cjs/entities/FakeWeakRef.d.ts +11 -0
  63. package/dist/cjs/entities/FakeWeakRef.js +19 -0
  64. package/dist/cjs/entities/FakeWeakRef.js.map +1 -0
  65. package/dist/cjs/files/EntityFile.d.ts +5 -2
  66. package/dist/cjs/files/EntityFile.js +8 -4
  67. package/dist/cjs/files/EntityFile.js.map +1 -1
  68. package/dist/cjs/files/FileManager.d.ts +3 -1
  69. package/dist/cjs/files/FileManager.js +5 -3
  70. package/dist/cjs/files/FileManager.js.map +1 -1
  71. package/dist/cjs/files/FileStorage.js +7 -7
  72. package/dist/cjs/files/FileStorage.js.map +1 -1
  73. package/dist/cjs/files/utils.d.ts +2 -0
  74. package/dist/cjs/files/utils.js +5 -2
  75. package/dist/cjs/files/utils.js.map +1 -1
  76. package/dist/cjs/idb.d.ts +2 -0
  77. package/dist/cjs/idb.js +50 -4
  78. package/dist/cjs/idb.js.map +1 -1
  79. package/dist/cjs/index.d.ts +2 -2
  80. package/dist/cjs/index.js +1 -1
  81. package/dist/cjs/index.js.map +1 -1
  82. package/dist/cjs/indexes.d.ts +3 -0
  83. package/dist/cjs/indexes.js +20 -0
  84. package/dist/cjs/indexes.js.map +1 -0
  85. package/dist/cjs/metadata/AckInfoStore.js +1 -1
  86. package/dist/cjs/metadata/AckInfoStore.js.map +1 -1
  87. package/dist/cjs/metadata/BaselinesStore.d.ts +4 -1
  88. package/dist/cjs/metadata/BaselinesStore.js +19 -10
  89. package/dist/cjs/metadata/BaselinesStore.js.map +1 -1
  90. package/dist/cjs/metadata/LocalReplicaStore.d.ts +1 -1
  91. package/dist/cjs/metadata/LocalReplicaStore.js +11 -5
  92. package/dist/cjs/metadata/LocalReplicaStore.js.map +1 -1
  93. package/dist/cjs/metadata/Metadata.d.ts +26 -5
  94. package/dist/cjs/metadata/Metadata.js +55 -18
  95. package/dist/cjs/metadata/Metadata.js.map +1 -1
  96. package/dist/cjs/metadata/OperationsStore.d.ts +3 -0
  97. package/dist/cjs/metadata/OperationsStore.js +35 -15
  98. package/dist/cjs/metadata/OperationsStore.js.map +1 -1
  99. package/dist/cjs/migration/openDatabase.js +31 -10
  100. package/dist/cjs/migration/openDatabase.js.map +1 -1
  101. package/dist/cjs/queries/BaseQuery.js +14 -2
  102. package/dist/cjs/queries/BaseQuery.js.map +1 -1
  103. package/dist/cjs/queries/CollectionQueries.d.ts +2 -4
  104. package/dist/cjs/queries/CollectionQueries.js +1 -1
  105. package/dist/cjs/queries/CollectionQueries.js.map +1 -1
  106. package/dist/cjs/queries/FindAllQuery.js +1 -0
  107. package/dist/cjs/queries/FindAllQuery.js.map +1 -1
  108. package/dist/cjs/queries/QueryCache.d.ts +1 -0
  109. package/dist/cjs/queries/QueryCache.js +4 -0
  110. package/dist/cjs/queries/QueryCache.js.map +1 -1
  111. package/dist/cjs/queries/QueryableStorage.d.ts +20 -0
  112. package/dist/cjs/queries/QueryableStorage.js +84 -0
  113. package/dist/cjs/queries/QueryableStorage.js.map +1 -0
  114. package/dist/cjs/queries/dbQueries.js +13 -3
  115. package/dist/cjs/queries/dbQueries.js.map +1 -1
  116. package/dist/cjs/queries/utils.js +1 -1
  117. package/dist/cjs/queries/utils.js.map +1 -1
  118. package/dist/cjs/sync/FileSync.d.ts +1 -0
  119. package/dist/cjs/sync/FileSync.js +1 -0
  120. package/dist/cjs/sync/FileSync.js.map +1 -1
  121. package/dist/cjs/sync/PushPullSync.d.ts +2 -1
  122. package/dist/cjs/sync/PushPullSync.js +7 -1
  123. package/dist/cjs/sync/PushPullSync.js.map +1 -1
  124. package/dist/cjs/sync/Sync.d.ts +6 -3
  125. package/dist/cjs/sync/Sync.js +9 -4
  126. package/dist/cjs/sync/Sync.js.map +1 -1
  127. package/dist/cjs/sync/WebSocketSync.d.ts +4 -1
  128. package/dist/cjs/sync/WebSocketSync.js +41 -11
  129. package/dist/cjs/sync/WebSocketSync.js.map +1 -1
  130. package/dist/esm/DocumentManager.d.ts +6 -5
  131. package/dist/esm/DocumentManager.js +2 -2
  132. package/dist/esm/DocumentManager.js.map +1 -1
  133. package/dist/esm/IDBService.d.ts +28 -7
  134. package/dist/esm/IDBService.js +51 -14
  135. package/dist/esm/IDBService.js.map +1 -1
  136. package/dist/esm/UndoHistory.d.ts +1 -1
  137. package/dist/esm/UndoHistory.js +6 -2
  138. package/dist/esm/UndoHistory.js.map +1 -1
  139. package/dist/esm/__tests__/batching.test.js +3 -1
  140. package/dist/esm/__tests__/batching.test.js.map +1 -1
  141. package/dist/esm/__tests__/documents.test.js +37 -6
  142. package/dist/esm/__tests__/documents.test.js.map +1 -1
  143. package/dist/esm/__tests__/fixtures/testStorage.d.ts +2 -2
  144. package/dist/esm/__tests__/fixtures/testStorage.js +2 -1
  145. package/dist/esm/__tests__/fixtures/testStorage.js.map +1 -1
  146. package/dist/esm/__tests__/legacyOids.test.js +50 -17
  147. package/dist/esm/__tests__/legacyOids.test.js.map +1 -1
  148. package/dist/esm/__tests__/mutations.test.js +9 -3
  149. package/dist/esm/__tests__/mutations.test.js.map +1 -1
  150. package/dist/esm/__tests__/queries.test.js +6 -2
  151. package/dist/esm/__tests__/queries.test.js.map +1 -1
  152. package/dist/esm/__tests__/setup/indexedDB.d.ts +1 -1
  153. package/dist/esm/__tests__/setup/indexedDB.js +8 -1
  154. package/dist/esm/__tests__/setup/indexedDB.js.map +1 -1
  155. package/dist/esm/__tests__/undo.test.js +16 -9
  156. package/dist/esm/__tests__/undo.test.js.map +1 -1
  157. package/dist/esm/client/Client.d.ts +2 -3
  158. package/dist/esm/client/Client.js +8 -4
  159. package/dist/esm/client/Client.js.map +1 -1
  160. package/dist/esm/client/ClientDescriptor.js +21 -6
  161. package/dist/esm/client/ClientDescriptor.js.map +1 -1
  162. package/dist/esm/context.d.ts +10 -1
  163. package/dist/esm/entities/2/Entity.d.ts +148 -0
  164. package/dist/esm/entities/2/Entity.js +707 -0
  165. package/dist/esm/entities/2/Entity.js.map +1 -0
  166. package/dist/esm/entities/2/Entity.test.d.ts +1 -0
  167. package/dist/esm/entities/2/Entity.test.js +192 -0
  168. package/dist/esm/entities/2/Entity.test.js.map +1 -0
  169. package/dist/esm/entities/2/EntityCache.d.ts +15 -0
  170. package/dist/esm/entities/2/EntityCache.js +35 -0
  171. package/dist/esm/entities/2/EntityCache.js.map +1 -0
  172. package/dist/esm/entities/2/EntityMetadata.d.ts +68 -0
  173. package/dist/esm/entities/2/EntityMetadata.js +256 -0
  174. package/dist/esm/entities/2/EntityMetadata.js.map +1 -0
  175. package/dist/esm/entities/2/EntityStore.d.ts +78 -0
  176. package/dist/esm/entities/2/EntityStore.js +348 -0
  177. package/dist/esm/entities/2/EntityStore.js.map +1 -0
  178. package/dist/esm/entities/2/OperationBatcher.d.ts +52 -0
  179. package/dist/esm/entities/2/OperationBatcher.js +161 -0
  180. package/dist/esm/entities/2/OperationBatcher.js.map +1 -0
  181. package/dist/esm/entities/2/types.d.ts +84 -0
  182. package/dist/esm/entities/2/types.js +2 -0
  183. package/dist/esm/entities/2/types.js.map +1 -0
  184. package/dist/esm/entities/Entity.d.ts +0 -7
  185. package/dist/esm/entities/Entity.js +7 -0
  186. package/dist/esm/entities/Entity.js.map +1 -1
  187. package/dist/esm/entities/EntityStore.js +4 -20
  188. package/dist/esm/entities/EntityStore.js.map +1 -1
  189. package/dist/esm/entities/FakeWeakRef.d.ts +11 -0
  190. package/dist/esm/entities/FakeWeakRef.js +15 -0
  191. package/dist/esm/entities/FakeWeakRef.js.map +1 -0
  192. package/dist/esm/files/EntityFile.d.ts +5 -2
  193. package/dist/esm/files/EntityFile.js +8 -4
  194. package/dist/esm/files/EntityFile.js.map +1 -1
  195. package/dist/esm/files/FileManager.d.ts +3 -1
  196. package/dist/esm/files/FileManager.js +5 -3
  197. package/dist/esm/files/FileManager.js.map +1 -1
  198. package/dist/esm/files/FileStorage.js +7 -7
  199. package/dist/esm/files/FileStorage.js.map +1 -1
  200. package/dist/esm/files/utils.d.ts +2 -0
  201. package/dist/esm/files/utils.js +4 -2
  202. package/dist/esm/files/utils.js.map +1 -1
  203. package/dist/esm/idb.d.ts +2 -0
  204. package/dist/esm/idb.js +47 -3
  205. package/dist/esm/idb.js.map +1 -1
  206. package/dist/esm/index.d.ts +2 -2
  207. package/dist/esm/index.js +1 -1
  208. package/dist/esm/index.js.map +1 -1
  209. package/dist/esm/indexes.d.ts +3 -0
  210. package/dist/esm/indexes.js +15 -0
  211. package/dist/esm/indexes.js.map +1 -0
  212. package/dist/esm/metadata/AckInfoStore.js +1 -1
  213. package/dist/esm/metadata/AckInfoStore.js.map +1 -1
  214. package/dist/esm/metadata/BaselinesStore.d.ts +4 -1
  215. package/dist/esm/metadata/BaselinesStore.js +19 -10
  216. package/dist/esm/metadata/BaselinesStore.js.map +1 -1
  217. package/dist/esm/metadata/LocalReplicaStore.d.ts +1 -1
  218. package/dist/esm/metadata/LocalReplicaStore.js +11 -5
  219. package/dist/esm/metadata/LocalReplicaStore.js.map +1 -1
  220. package/dist/esm/metadata/Metadata.d.ts +26 -5
  221. package/dist/esm/metadata/Metadata.js +56 -19
  222. package/dist/esm/metadata/Metadata.js.map +1 -1
  223. package/dist/esm/metadata/OperationsStore.d.ts +3 -0
  224. package/dist/esm/metadata/OperationsStore.js +35 -15
  225. package/dist/esm/metadata/OperationsStore.js.map +1 -1
  226. package/dist/esm/migration/openDatabase.js +32 -11
  227. package/dist/esm/migration/openDatabase.js.map +1 -1
  228. package/dist/esm/queries/BaseQuery.js +14 -2
  229. package/dist/esm/queries/BaseQuery.js.map +1 -1
  230. package/dist/esm/queries/CollectionQueries.d.ts +2 -4
  231. package/dist/esm/queries/CollectionQueries.js +1 -1
  232. package/dist/esm/queries/CollectionQueries.js.map +1 -1
  233. package/dist/esm/queries/FindAllQuery.js +1 -0
  234. package/dist/esm/queries/FindAllQuery.js.map +1 -1
  235. package/dist/esm/queries/QueryCache.d.ts +1 -0
  236. package/dist/esm/queries/QueryCache.js +4 -0
  237. package/dist/esm/queries/QueryCache.js.map +1 -1
  238. package/dist/esm/queries/QueryableStorage.d.ts +20 -0
  239. package/dist/esm/queries/QueryableStorage.js +80 -0
  240. package/dist/esm/queries/QueryableStorage.js.map +1 -0
  241. package/dist/esm/queries/dbQueries.js +13 -3
  242. package/dist/esm/queries/dbQueries.js.map +1 -1
  243. package/dist/esm/queries/utils.js +1 -1
  244. package/dist/esm/queries/utils.js.map +1 -1
  245. package/dist/esm/sync/FileSync.d.ts +1 -0
  246. package/dist/esm/sync/FileSync.js +1 -0
  247. package/dist/esm/sync/FileSync.js.map +1 -1
  248. package/dist/esm/sync/PushPullSync.d.ts +2 -1
  249. package/dist/esm/sync/PushPullSync.js +7 -1
  250. package/dist/esm/sync/PushPullSync.js.map +1 -1
  251. package/dist/esm/sync/Sync.d.ts +6 -3
  252. package/dist/esm/sync/Sync.js +9 -4
  253. package/dist/esm/sync/Sync.js.map +1 -1
  254. package/dist/esm/sync/WebSocketSync.d.ts +4 -1
  255. package/dist/esm/sync/WebSocketSync.js +41 -11
  256. package/dist/esm/sync/WebSocketSync.js.map +1 -1
  257. package/dist/tsconfig-cjs.tsbuildinfo +1 -1
  258. package/dist/tsconfig.tsbuildinfo +1 -1
  259. package/package.json +8 -7
  260. package/src/DocumentManager.ts +3 -7
  261. package/src/IDBService.ts +78 -17
  262. package/src/UndoHistory.ts +5 -3
  263. package/src/__tests__/batching.test.ts +5 -2
  264. package/src/__tests__/documents.test.ts +44 -6
  265. package/src/__tests__/fixtures/testStorage.ts +3 -0
  266. package/src/__tests__/legacyOids.test.ts +53 -17
  267. package/src/__tests__/mutations.test.ts +9 -3
  268. package/src/__tests__/queries.test.ts +6 -2
  269. package/src/__tests__/setup/indexedDB.ts +8 -1
  270. package/src/__tests__/undo.test.ts +17 -9
  271. package/src/client/Client.ts +8 -4
  272. package/src/client/ClientDescriptor.ts +24 -8
  273. package/src/context.ts +16 -1
  274. package/src/entities/2/Entity.test.ts +218 -0
  275. package/src/entities/2/Entity.ts +954 -0
  276. package/src/entities/2/EntityCache.ts +41 -0
  277. package/src/entities/2/EntityMetadata.ts +364 -0
  278. package/src/entities/2/EntityStore.ts +490 -0
  279. package/src/entities/2/NOTES.md +22 -0
  280. package/src/entities/2/OperationBatcher.ts +251 -0
  281. package/src/entities/2/types.ts +154 -0
  282. package/src/files/EntityFile.ts +9 -4
  283. package/src/files/FileManager.ts +5 -3
  284. package/src/files/FileStorage.ts +7 -13
  285. package/src/files/utils.ts +6 -2
  286. package/src/idb.ts +51 -3
  287. package/src/index.ts +2 -2
  288. package/src/metadata/AckInfoStore.ts +1 -1
  289. package/src/metadata/BaselinesStore.ts +16 -24
  290. package/src/metadata/LocalReplicaStore.ts +13 -6
  291. package/src/metadata/Metadata.ts +109 -24
  292. package/src/metadata/OperationsStore.ts +37 -16
  293. package/src/migration/openDatabase.ts +32 -10
  294. package/src/queries/BaseQuery.ts +15 -2
  295. package/src/queries/CollectionQueries.ts +3 -3
  296. package/src/queries/FindAllQuery.ts +4 -0
  297. package/src/queries/QueryCache.ts +5 -0
  298. package/src/queries/QueryableStorage.ts +107 -0
  299. package/src/queries/dbQueries.ts +10 -3
  300. package/src/queries/utils.ts +1 -1
  301. package/src/sync/FileSync.ts +2 -0
  302. package/src/sync/PushPullSync.ts +8 -1
  303. package/src/sync/Sync.ts +14 -6
  304. package/src/sync/WebSocketSync.ts +47 -10
  305. package/src/entities/DocumentFamiliyCache.ts +0 -426
  306. package/src/entities/Entity.ts +0 -874
  307. package/src/entities/EntityStore.ts +0 -731
@@ -1,874 +0,0 @@
1
- import {
2
- assert,
3
- assignOid,
4
- cloneDeep,
5
- createRef,
6
- decomposeOid,
7
- EventSubscriber,
8
- FileData,
9
- FileRef,
10
- isFileRef,
11
- isObjectRef,
12
- maybeGetOid,
13
- ObjectIdentifier,
14
- Operation,
15
- PatchCreator,
16
- StorageFieldSchema,
17
- StorageFieldsSchema,
18
- TimestampProvider,
19
- traverseCollectionFieldsAndApplyDefaults,
20
- validateEntityField,
21
- } from '@verdant-web/common';
22
- import { EntityFile } from '../files/EntityFile.js';
23
- import { processValueFiles } from '../files/utils.js';
24
-
25
- export const ADD_OPERATIONS = '@@addOperations';
26
- export const DELETE = '@@delete';
27
- export const REBASE = '@@rebase';
28
- const REFRESH = '@@refresh';
29
- export const DEEP_CHANGE = '@@deepChange';
30
-
31
- export interface CacheTools {
32
- computeView(oid: ObjectIdentifier): {
33
- view: any;
34
- deleted: boolean;
35
- lastTimestamp: number | null;
36
- };
37
- getEntity(params: {
38
- oid: ObjectIdentifier;
39
- fieldSchema: StorageFieldSchema;
40
- parent?: Entity;
41
- fieldKey?: string | number;
42
- }): Entity;
43
- hasOid(oid: ObjectIdentifier): boolean;
44
- weakRef<T extends object>(value: T): WeakRef<T>;
45
- }
46
-
47
- export interface StoreTools {
48
- addLocalOperations(operations: Operation[]): void;
49
- patchCreator: PatchCreator;
50
- addFile: (file: FileData) => void;
51
- getFile: (id: string) => EntityFile;
52
- time: TimestampProvider;
53
- now: string;
54
- }
55
-
56
- export type AccessibleEntityProperty<T> = T extends Array<any>
57
- ? number
58
- : T extends object
59
- ? keyof T
60
- : never;
61
-
62
- type DataFromInit<Init> = Init extends { [key: string]: any }
63
- ? {
64
- [Key in keyof Init]: Init[Key];
65
- }
66
- : Init extends Array<any>
67
- ? Init
68
- : any;
69
-
70
- export type EntityShape<E extends Entity<any, any>> = E extends Entity<
71
- infer Value,
72
- any
73
- >
74
- ? Value
75
- : never;
76
-
77
- // reduces keys of an object to only ones with an optional
78
- // value
79
- type DeletableKeys<T> = keyof {
80
- [Key in keyof T as IfNullableThen<T[Key], Key>]: Key;
81
- };
82
- type IfNullableThen<T, Out> = undefined extends T
83
- ? Out
84
- : null extends T
85
- ? Out
86
- : never;
87
-
88
- export function refreshEntity(
89
- entity: Entity<any, any>,
90
- info: EntityChangeInfo,
91
- ) {
92
- return entity[REFRESH](info);
93
- }
94
-
95
- export interface EntityChangeInfo {
96
- isLocal?: boolean;
97
- }
98
-
99
- type EntityEvents = {
100
- change: (info: EntityChangeInfo) => void;
101
- changeDeep: (target: Entity<any, any>, info: EntityChangeInfo) => void;
102
- delete: (info: EntityChangeInfo) => void;
103
- restore: (info: EntityChangeInfo) => void;
104
- };
105
-
106
- type BaseEntityValue = { [Key: string]: any } | any[];
107
-
108
- export class Entity<
109
- Init = any,
110
- KeyValue extends BaseEntityValue = any,
111
- Snapshot extends any = DataFromInit<Init>,
112
- >
113
- implements
114
- ObjectEntity<Init, KeyValue, Snapshot>,
115
- ListEntity<Init, KeyValue, Snapshot>
116
- {
117
- // if current is null, the entity was deleted.
118
- protected _current: any | null = null;
119
-
120
- readonly oid: ObjectIdentifier;
121
- readonly fieldPath: string[];
122
- readonly collection: string;
123
- protected readonly store: StoreTools;
124
- protected readonly fieldSchema;
125
- protected readonly cache: CacheTools;
126
- protected _deleted = false;
127
- protected parent: WeakRef<Entity<any, any>> | undefined;
128
- protected readonly readonlyKeys: (keyof Init)[];
129
-
130
- private cachedSnapshot: any = null;
131
- private cachedDestructure: KeyValue | null = null;
132
- private cachedDeepUpdatedAt: number | null = null;
133
-
134
- private _updatedAt: number | null = null;
135
-
136
- protected events;
137
-
138
- protected hasSubscribersToDeepChanges() {
139
- return this.events.subscriberCount('changeDeep') > 0;
140
- }
141
-
142
- get hasSubscribers() {
143
- if (this.events.totalSubscriberCount() > 0) {
144
- return true;
145
- }
146
-
147
- // even if nobody subscribes directly to this entity, if a parent
148
- // has a deep subscription that counts.
149
- let parent = this.parent?.deref();
150
- while (parent) {
151
- if (parent.hasSubscribersToDeepChanges()) {
152
- return true;
153
- }
154
- parent = parent.parent?.deref();
155
- }
156
-
157
- return false;
158
- }
159
-
160
- get deleted() {
161
- return this._deleted;
162
- }
163
-
164
- protected get value() {
165
- return this._current;
166
- }
167
-
168
- get isList() {
169
- return Array.isArray(this._current) as any;
170
- }
171
-
172
- get updatedAt() {
173
- return this._updatedAt;
174
- }
175
-
176
- get deepUpdatedAt() {
177
- if (this.cachedDeepUpdatedAt) return this.cachedDeepUpdatedAt;
178
- // iterate over all children and take the latest timestamp
179
- let latest: number | null = this._updatedAt;
180
- if (this.isList) {
181
- this.forEach((child) => {
182
- if ((child as any) instanceof Entity) {
183
- const childTimestamp = child.deepUpdatedAt;
184
- if (childTimestamp && (!latest || childTimestamp > latest)) {
185
- latest = childTimestamp;
186
- }
187
- }
188
- });
189
- } else {
190
- this.values().forEach((child) => {
191
- if ((child as any) instanceof Entity) {
192
- const childTimestamp = child.deepUpdatedAt;
193
- if (childTimestamp && (!latest || childTimestamp > latest)) {
194
- latest = childTimestamp;
195
- }
196
- }
197
- });
198
- }
199
- this.cachedDeepUpdatedAt = latest;
200
- return latest;
201
- }
202
-
203
- get uid() {
204
- return this.oid;
205
- }
206
-
207
- constructor({
208
- oid,
209
- store,
210
- fieldSchema,
211
- cache,
212
- parent,
213
- onAllUnsubscribed,
214
- readonlyKeys = [],
215
- fieldPath = [],
216
- }: {
217
- oid: ObjectIdentifier;
218
- store: StoreTools;
219
- fieldSchema: StorageFieldSchema | StorageFieldsSchema;
220
- cache: CacheTools;
221
- parent?: Entity<any, any>;
222
- onAllUnsubscribed?: () => void;
223
- readonlyKeys?: (keyof Init)[];
224
- fieldPath?: string[];
225
- }) {
226
- this.oid = oid;
227
- const { collection } = decomposeOid(oid);
228
- this.collection = collection;
229
- this.store = store;
230
- this.fieldSchema = fieldSchema;
231
- this.fieldPath = fieldPath;
232
- this.readonlyKeys = readonlyKeys;
233
- this.cache = cache;
234
- this.parent = parent && this.cache.weakRef(parent);
235
- const { view, deleted, lastTimestamp } = this.cache.computeView(oid);
236
- this._current = view;
237
- this._deleted = deleted;
238
- this._updatedAt = lastTimestamp ? lastTimestamp : null;
239
- this.cachedDeepUpdatedAt = null;
240
- this.events = new EventSubscriber<EntityEvents>(() => {
241
- if (!this.hasSubscribers) {
242
- onAllUnsubscribed?.();
243
- }
244
- });
245
-
246
- if (this.oid.includes('.') && !this.parent) {
247
- throw new Error('Parent must be provided for sub entities');
248
- }
249
- assert(!!fieldSchema, 'Field schema must be provided');
250
- }
251
-
252
- private [REFRESH] = (info: EntityChangeInfo) => {
253
- const { view, deleted, lastTimestamp } = this.cache.computeView(this.oid);
254
- this._current = view;
255
- const restored = this._deleted && !deleted;
256
- this._deleted = deleted;
257
- this.cachedDestructure = null;
258
- this._updatedAt = lastTimestamp ? lastTimestamp : null;
259
- this.cachedDeepUpdatedAt = null;
260
-
261
- if (this._deleted) {
262
- this.events.emit('delete', info);
263
- } else {
264
- this.events.emit('change', info);
265
- this[DEEP_CHANGE](this as unknown as Entity<any, any>, info);
266
- }
267
- if (restored) {
268
- this.cachedSnapshot = null;
269
- this.events.emit('restore', info);
270
- }
271
- };
272
-
273
- private [DEEP_CHANGE] = (
274
- source: Entity<any, any>,
275
- info: EntityChangeInfo,
276
- ) => {
277
- this.cachedSnapshot = null;
278
- this.cachedDeepUpdatedAt = null;
279
- this.events.emit('changeDeep', source, info);
280
- const parent = this.parent?.deref();
281
- if (parent) {
282
- parent[DEEP_CHANGE](source, info);
283
- }
284
- };
285
-
286
- protected getChildFieldSchema = (key: any) => {
287
- if (this.fieldSchema.type === 'object') {
288
- return this.fieldSchema.properties[key];
289
- } else if (this.fieldSchema.type === 'array') {
290
- return this.fieldSchema.items;
291
- } else if (this.fieldSchema.type === 'map') {
292
- return this.fieldSchema.values;
293
- } else if (this.fieldSchema.type === 'any') {
294
- return this.fieldSchema;
295
- }
296
- throw new Error('Invalid field schema');
297
- };
298
-
299
- dispose = () => {
300
- this.events.dispose();
301
- };
302
-
303
- subscribe = <EventName extends keyof EntityEvents>(
304
- event: EventName,
305
- callback: EntityEvents[EventName],
306
- ) => {
307
- const unsubscribe = this.events.subscribe(event, callback);
308
-
309
- return unsubscribe;
310
- };
311
-
312
- protected addPatches = (patches: Operation[]) => {
313
- this.store.addLocalOperations(patches);
314
- };
315
-
316
- protected cloneCurrent = () => {
317
- if (this._current === undefined) {
318
- return undefined;
319
- }
320
- return cloneDeep(this._current);
321
- };
322
-
323
- protected getSubObject = (
324
- oid: ObjectIdentifier,
325
- key: any,
326
- ): Entity<any, any> => {
327
- const fieldSchema = this.getChildFieldSchema(key);
328
- // this is a failure case, but trying to be graceful about it...
329
- // @ts-ignore
330
- // if (!fieldSchema) return null;
331
- return this.cache.getEntity({
332
- oid,
333
- fieldSchema,
334
- parent: this,
335
- fieldKey: key,
336
- });
337
- };
338
-
339
- protected wrapValue = <Key extends keyof KeyValue>(
340
- value: any,
341
- key: Key,
342
- ): KeyValue[Key] => {
343
- if (isObjectRef(value)) {
344
- const oid = value.id;
345
- const subObject = this.getSubObject(oid, key);
346
- if (subObject) {
347
- return subObject as any;
348
- }
349
- throw new Error(
350
- `CACHE MISS: Subobject ${oid} does not exist on ${this.oid}`,
351
- );
352
- } else if (isFileRef(value)) {
353
- const file = this.store.getFile(value.id);
354
- if (file) {
355
- file.subscribe('change', () => {
356
- this[DEEP_CHANGE](this, {
357
- isLocal: false,
358
- });
359
- });
360
- return file as any;
361
- }
362
- }
363
- return value;
364
- };
365
-
366
- protected processInputValue = (value: any, key: any) => {
367
- // disassociate incoming OIDs on values and generally break object
368
- // references. cloning doesn't work on files so those are
369
- // filtered out.
370
- // The goal here is to be safe about a bunch of cases that could
371
- // result in corrupt data, like...
372
- // ent1.set('objField', ent2.get('objField'))
373
- // or
374
- // var shared = { foo: 'bar' };
375
- // ent1.set('objField', shared);
376
- // ent2.set('objField', shared);
377
- // ... each of these would result in the same object being
378
- // referenced in multiple entities, which could mean introduction
379
- // of foreign OIDs, or one object being assigned different OIDs
380
- // with unexpected results.
381
- if (!(value instanceof File)) {
382
- value = cloneDeep(value, false);
383
- }
384
- const fieldSchema = this.getChildFieldSchema(key);
385
- if (fieldSchema) {
386
- traverseCollectionFieldsAndApplyDefaults(value, fieldSchema);
387
- }
388
- const validationError = validateEntityField(fieldSchema, value, [
389
- ...this.fieldPath,
390
- key,
391
- ]);
392
- if (validationError) {
393
- // TODO: is it a good idea to throw an error here? a runtime error won't be that helpful,
394
- // but also we don't really want invalid data supplied.
395
- throw new Error(validationError);
396
- }
397
- return processValueFiles(value, this.store.addFile);
398
- };
399
-
400
- get = <Key extends keyof KeyValue>(key: Key): KeyValue[Key] => {
401
- if (this.value === undefined || this.value === null) {
402
- throw new Error('Cannot access deleted entity');
403
- }
404
-
405
- const value = this.value[key];
406
- return this.wrapValue(value, key);
407
- };
408
-
409
- getAll = (): KeyValue => {
410
- if (this.value === undefined || this.value === null) {
411
- throw new Error('Cannot access deleted entity');
412
- }
413
-
414
- if (this.cachedDestructure) return this.cachedDestructure;
415
-
416
- let result: any;
417
- if (Array.isArray(this.value)) {
418
- result = this.value.map((value, index) =>
419
- this.wrapValue(value, index as any),
420
- ) as any;
421
- } else {
422
- result = {} as any;
423
- for (const key in this.value) {
424
- result[key as any] = this.get(key as any);
425
- }
426
- }
427
- this.cachedDestructure = result;
428
- return result;
429
- };
430
-
431
- private getFileSnapshot(item: FileRef) {
432
- const file = this.store.getFile(item.id);
433
- if (file.url) {
434
- return { id: item.id, url: file.url };
435
- } else if (file.loading || file.failed) {
436
- return { id: item.id, url: undefined };
437
- } else {
438
- return { id: item.id, url: null };
439
- }
440
- }
441
-
442
- /**
443
- * Returns a copy of the entity and all sub-objects as
444
- * a plain object or array.
445
- */
446
- getSnapshot = (): any => {
447
- if (!this.value) {
448
- return null;
449
- }
450
- if (this.deleted) {
451
- return null;
452
- }
453
- if (this.cachedSnapshot) {
454
- return this.cachedSnapshot;
455
- }
456
- let snapshot;
457
- if (Array.isArray(this.value)) {
458
- snapshot = this.value.map((item, idx) => {
459
- if (isObjectRef(item)) {
460
- return this.getSubObject(item.id, idx)?.getSnapshot();
461
- } else if (isFileRef(item)) {
462
- return this.getFileSnapshot(item);
463
- }
464
- return item;
465
- }) as Snapshot;
466
- } else {
467
- snapshot = { ...this.value };
468
- for (const [key, value] of Object.entries(snapshot)) {
469
- if (isObjectRef(value)) {
470
- snapshot[key] = this.getSubObject(value.id, key)?.getSnapshot();
471
- } else if (isFileRef(value)) {
472
- snapshot[key] = this.getFileSnapshot(value);
473
- }
474
- }
475
- }
476
-
477
- assignOid(snapshot, this.oid);
478
- this.cachedSnapshot = snapshot;
479
- return snapshot;
480
- };
481
-
482
- /**
483
- * Object methods
484
- */
485
- keys = () => {
486
- return Object.keys(this.value || {});
487
- };
488
- entries = () => {
489
- return Object.entries(this.getAll());
490
- };
491
- values = () => {
492
- return Object.values(this.getAll());
493
- };
494
- set = <Key extends keyof Init>(key: Key, value: Init[Key]) => {
495
- if (this.readonlyKeys.includes(key)) {
496
- throw new Error(`Cannot set readonly key ${key.toString()}`);
497
- }
498
- this.addPatches(
499
- this.store.patchCreator.createSet(
500
- this.oid,
501
- key as string | number,
502
- this.processInputValue(value, key),
503
- ),
504
- );
505
- };
506
- delete = (key: any) => {
507
- if (Array.isArray(this.value)) {
508
- this.addPatches(
509
- this.store.patchCreator.createListDelete(this.oid, key as number, 1),
510
- );
511
- } else {
512
- // the key must be deletable - i.e. optional in the schema
513
- const deleteMode = this.getDeleteMode(key);
514
- if (!deleteMode) {
515
- throw new Error(
516
- `Cannot delete key ${key} - the property is not marked as optional in the schema`,
517
- );
518
- }
519
- if (deleteMode === 'delete') {
520
- this.addPatches(this.store.patchCreator.createRemove(this.oid, key));
521
- } else {
522
- this.addPatches(this.store.patchCreator.createSet(this.oid, key, null));
523
- }
524
- }
525
- };
526
- private getDeleteMode = (key: any) => {
527
- if (this.readonlyKeys.includes(key)) {
528
- return false;
529
- }
530
- // 'any' is always deletable, and map values can be removed completely
531
- if (this.fieldSchema.type === 'any' || this.fieldSchema.type === 'map') {
532
- return 'delete';
533
- }
534
-
535
- if (this.fieldSchema.type === 'object') {
536
- const property = this.fieldSchema.properties[key];
537
- if (!property) {
538
- // huh, trying to delete a field that isn't specified
539
- // in the schema. we should use 'delete' mode.
540
- return 'delete';
541
- }
542
- if (property.type === 'any') return 'delete';
543
- // map can't be nullable
544
- // TODO: should it be?
545
- if (property.type === 'map') return false;
546
- // nullable properties can only be set null
547
- if (property.nullable) return 'null';
548
- }
549
- // no other parent objects support deleting
550
- return false;
551
- };
552
- /** @deprecated - renamed to delete */
553
- remove = this.delete.bind(this);
554
-
555
- update = (
556
- value: DeepPartial<Init>,
557
- {
558
- replaceSubObjects = false,
559
- merge = true,
560
- }: {
561
- /**
562
- * If true, merged sub-objects will be replaced entirely if there's
563
- * ambiguity about their identity.
564
- */
565
- replaceSubObjects?: boolean;
566
- /**
567
- * If false, omitted keys will erase their respective fields.
568
- */
569
- merge?: boolean;
570
- } = {
571
- replaceSubObjects: false,
572
- merge: true,
573
- },
574
- ) => {
575
- if (
576
- !merge &&
577
- this.fieldSchema.type !== 'any' &&
578
- this.fieldSchema.type !== 'map'
579
- ) {
580
- throw new Error(
581
- 'Cannot use .update without merge if the field has a strict schema type. merge: false is only available on "any" or "map" types.',
582
- );
583
- }
584
- for (const [key, field] of Object.entries(value)) {
585
- if (this.readonlyKeys.includes(key as any)) {
586
- throw new Error(`Cannot set readonly key ${key.toString()}`);
587
- }
588
- const fieldSchema = this.getChildFieldSchema(key);
589
- if (fieldSchema) {
590
- traverseCollectionFieldsAndApplyDefaults(field, fieldSchema);
591
- }
592
- }
593
- const withoutFiles = processValueFiles(value, this.store.addFile);
594
- this.addPatches(
595
- this.store.patchCreator.createDiff(
596
- this.getSnapshot(),
597
- assignOid(withoutFiles, this.oid),
598
- {
599
- mergeUnknownObjects: !replaceSubObjects,
600
- defaultUndefined: merge,
601
- },
602
- ),
603
- );
604
- };
605
-
606
- /**
607
- * List methods
608
- */
609
-
610
- /**
611
- * Returns the referent value of an item in the list, used for
612
- * operations which act on items. if the item is an object,
613
- * it will attempt to create an OID reference to it. If it
614
- * is a primitive, it will return the primitive.
615
- */
616
- private getItemRefValue = (item: ListItemValue<KeyValue>) => {
617
- if (typeof item === 'object') {
618
- const itemOid = maybeGetOid(item);
619
- if (!itemOid || !this.cache.hasOid(itemOid)) {
620
- throw new Error(
621
- `Cannot move object ${JSON.stringify(
622
- item,
623
- )} which does not exist in this list`,
624
- );
625
- }
626
- return itemOid;
627
- } else {
628
- return item;
629
- }
630
- };
631
-
632
- get length() {
633
- return this.value.length;
634
- }
635
-
636
- push = (value: ListItemInit<Init>) => {
637
- this.addPatches(
638
- this.store.patchCreator.createListPush(
639
- this.oid,
640
- this.processInputValue(value, this.value.length),
641
- ),
642
- );
643
- };
644
- insert = (index: number, value: ListItemInit<Init>) => {
645
- this.addPatches(
646
- this.store.patchCreator.createListInsert(
647
- this.oid,
648
- index,
649
- this.processInputValue(value, index),
650
- ),
651
- );
652
- };
653
- move = (from: number, to: number) => {
654
- this.addPatches(
655
- this.store.patchCreator.createListMoveByIndex(this.oid, from, to),
656
- );
657
- };
658
- moveItem = (item: ListItemValue<KeyValue>, to: number) => {
659
- const itemRef = this.getItemRefValue(item);
660
- if (isObjectRef(itemRef)) {
661
- this.addPatches(
662
- this.store.patchCreator.createListMoveByRef(this.oid, itemRef, to),
663
- );
664
- } else {
665
- const index = this.value.indexOf(itemRef);
666
- this.addPatches(
667
- this.store.patchCreator.createListMoveByIndex(this.oid, index, to),
668
- );
669
- }
670
- };
671
- removeAll = (item: ListItemValue<KeyValue>) => {
672
- this.addPatches(
673
- this.store.patchCreator.createListRemove(
674
- this.oid,
675
- this.getItemRefValue(item),
676
- ),
677
- );
678
- };
679
- removeFirst = (item: ListItemValue<KeyValue>) => {
680
- this.addPatches(
681
- this.store.patchCreator.createListRemove(
682
- this.oid,
683
- this.getItemRefValue(item),
684
- 'first',
685
- ),
686
- );
687
- };
688
- removeLast = (item: ListItemValue<KeyValue>) => {
689
- this.addPatches(
690
- this.store.patchCreator.createListRemove(
691
- this.oid,
692
- this.getItemRefValue(item),
693
- 'last',
694
- ),
695
- );
696
- };
697
- add = (item: ListItemValue<KeyValue>) => {
698
- this.addPatches(
699
- this.store.patchCreator.createListAdd(
700
- this.oid,
701
- this.processInputValue(item, this.value.length),
702
- ),
703
- );
704
- };
705
- has = (item: ListItemValue<KeyValue>) => {
706
- if (typeof item === 'object') {
707
- return this.value.some((val: unknown) => {
708
- if (isObjectRef(val)) return val.id === maybeGetOid(item);
709
- // Sets of files don't work right now, there's no way to compare them
710
- // effectively.
711
- if (isFileRef(val)) return false;
712
- return false;
713
- });
714
- }
715
- return this.value.includes(item);
716
- };
717
-
718
- // list implements an iterator which maps items to wrapped
719
- // versions
720
- [Symbol.iterator]() {
721
- let index = 0;
722
- return {
723
- next: () => {
724
- if (index < this.value.length) {
725
- return {
726
- value: this.get(index++) as ListItemValue<KeyValue>,
727
- done: false,
728
- } as const;
729
- }
730
- return {
731
- value: undefined,
732
- done: true,
733
- } as const;
734
- },
735
- };
736
- }
737
-
738
- // additional access methods
739
-
740
- private getAsWrapped = (): ListItemValue<KeyValue>[] => {
741
- if (!this.isList) throw new Error('Cannot map items of a non-list');
742
- return this.value.map(this.wrapValue);
743
- };
744
-
745
- map = <U>(callback: (value: ListItemValue<KeyValue>, index: number) => U) => {
746
- return this.getAsWrapped().map(callback);
747
- };
748
-
749
- filter = (
750
- callback: (value: ListItemValue<KeyValue>, index: number) => boolean,
751
- ) => {
752
- return this.getAsWrapped().filter((val, index) => {
753
- return callback(val, index);
754
- });
755
- };
756
-
757
- forEach = (
758
- callback: (value: ListItemValue<KeyValue>, index: number) => void,
759
- ) => {
760
- this.getAsWrapped().forEach(callback);
761
- };
762
-
763
- some = (predicate: (value: ListItemValue<KeyValue>) => boolean) => {
764
- return this.getAsWrapped().some(predicate);
765
- };
766
-
767
- every = (predicate: (value: ListItemValue<KeyValue>) => boolean) => {
768
- return this.getAsWrapped().every(predicate);
769
- };
770
-
771
- find = (predicate: (value: ListItemValue<KeyValue>) => boolean) => {
772
- return this.getAsWrapped().find(predicate);
773
- };
774
-
775
- includes = (item: ListItemValue<KeyValue>) => {
776
- return this.has(item);
777
- };
778
- }
779
-
780
- export interface BaseEntity<
781
- Init,
782
- Value extends BaseEntityValue,
783
- Snapshot = DataFromInit<Init>,
784
- > {
785
- dispose: () => void;
786
- subscribe<EventName extends keyof EntityEvents>(
787
- event: EventName,
788
- callback: EntityEvents[EventName],
789
- ): () => void;
790
- get<Key extends keyof Value>(key: Key): Value[Key];
791
- getAll(): Value;
792
- getSnapshot(): Snapshot;
793
- readonly deleted: boolean;
794
- readonly hasSubscribers: boolean;
795
- }
796
-
797
- type DeepPartial<T> = {
798
- [P in keyof T]?: T[P] extends Array<infer U>
799
- ? Array<DeepPartial<U>>
800
- : T[P] extends ReadonlyArray<infer U>
801
- ? ReadonlyArray<DeepPartial<U>>
802
- : DeepPartial<T[P]>;
803
- };
804
-
805
- export interface ObjectEntity<
806
- Init,
807
- Value extends BaseEntityValue,
808
- Snapshot = DataFromInit<Init>,
809
- > extends BaseEntity<Init, Value, Snapshot> {
810
- keys(): string[];
811
- entries(): [string, Exclude<Value[keyof Value], undefined>][];
812
- values(): Exclude<Value[keyof Value], undefined>[];
813
- set<Key extends keyof Init>(key: Key, value: Init[Key]): void;
814
- delete(key: DeletableKeys<Value>): void;
815
- update(
816
- value: DeepPartial<Init>,
817
- options?: { replaceSubObjects?: boolean; merge?: boolean },
818
- ): void;
819
- readonly isList: false;
820
- }
821
-
822
- export interface ListEntity<
823
- Init,
824
- Value extends BaseEntityValue,
825
- Snapshot = DataFromInit<Init>,
826
- > extends Iterable<ListItemValue<Value>>,
827
- BaseEntity<Init, Value, Snapshot> {
828
- readonly isList: true;
829
- readonly length: number;
830
- push(value: ListItemInit<Init>): void;
831
- insert(index: number, value: ListItemInit<Init>): void;
832
- move(from: number, to: number): void;
833
- moveItem(item: ListItemValue<Value>, to: number): void;
834
- /**
835
- * A Set operation which adds a value if an equivalent value is not already present.
836
- * Object values are never the same.
837
- */
838
- add(value: ListItemValue<Value>): void;
839
- removeAll(item: ListItemValue<Value>): void;
840
- removeFirst(item: ListItemValue<Value>): void;
841
- removeLast(item: ListItemValue<Value>): void;
842
- map<U>(callback: (value: ListItemValue<Value>, index: number) => U): U[];
843
- filter(
844
- callback: (value: ListItemValue<Value>, index: number) => boolean,
845
- ): ListItemValue<Value>[];
846
- delete(index: number): void;
847
- has(value: ListItemValue<Value>): boolean;
848
- forEach(callback: (value: ListItemValue<Value>, index: number) => void): void;
849
- some(predicate: (value: ListItemValue<Value>) => boolean): boolean;
850
- every(predicate: (value: ListItemValue<Value>) => boolean): boolean;
851
- find(
852
- predicate: (value: ListItemValue<Value>) => boolean,
853
- ): ListItemValue<Value> | undefined;
854
- includes(value: ListItemValue<Value>): boolean;
855
- }
856
-
857
- export type AnyEntity<
858
- Init,
859
- KeyValue extends BaseEntityValue,
860
- Snapshot extends any,
861
- > =
862
- | ListEntity<Init, KeyValue, Snapshot>
863
- | ObjectEntity<Init, KeyValue, Snapshot>;
864
-
865
- type ListItemValue<KeyValue> = KeyValue extends Array<infer T> ? T : never;
866
- type ListItemInit<Init> = Init extends Array<infer T> ? T : never;
867
-
868
- export type EntityDestructured<T extends AnyEntity<any, any, any> | null> =
869
- | (T extends ListEntity<any, infer KeyValue, any>
870
- ? KeyValue
871
- : T extends ObjectEntity<any, infer KeyValue, any>
872
- ? KeyValue
873
- : never)
874
- | (T extends null ? null : never);