@party-stack/foundry-ontology 0.17.0 → 0.18.1

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 (253) hide show
  1. package/lib/adapter/convertLoadSubsetOptions.d.ts +2 -0
  2. package/lib/adapter/convertLoadSubsetOptions.d.ts.map +1 -1
  3. package/lib/adapter/convertLoadSubsetOptions.js +158 -191
  4. package/lib/adapter/convertLoadSubsetOptions.js.map +1 -1
  5. package/lib/adapter/createFoundryOntologyBackendAdapter.d.ts +17 -15
  6. package/lib/adapter/createFoundryOntologyBackendAdapter.d.ts.map +1 -1
  7. package/lib/adapter/createFoundryOntologyBackendAdapter.js +288 -400
  8. package/lib/adapter/createFoundryOntologyBackendAdapter.js.map +1 -1
  9. package/lib/adapter/foundryActionValidation.d.ts +17 -15
  10. package/lib/adapter/foundryActionValidation.d.ts.map +1 -1
  11. package/lib/adapter/foundryActionValidation.js +206 -305
  12. package/lib/adapter/foundryActionValidation.js.map +1 -1
  13. package/lib/adapter/foundryCodec.d.ts +10 -9
  14. package/lib/adapter/foundryCodec.d.ts.map +1 -1
  15. package/lib/adapter/foundryCodec.js +180 -287
  16. package/lib/adapter/foundryCodec.js.map +1 -1
  17. package/lib/adapter/foundryMediaId.d.ts +6 -4
  18. package/lib/adapter/foundryMediaId.d.ts.map +1 -1
  19. package/lib/adapter/foundryMediaId.js +31 -32
  20. package/lib/adapter/foundryMediaId.js.map +1 -1
  21. package/lib/adapter/index.d.ts +4 -4
  22. package/lib/adapter/index.js +4 -4
  23. package/lib/adapter/objectCollectionOptions.d.ts +17 -18
  24. package/lib/adapter/objectCollectionOptions.d.ts.map +1 -1
  25. package/lib/adapter/objectCollectionOptions.js +417 -538
  26. package/lib/adapter/objectCollectionOptions.js.map +1 -1
  27. package/lib/config/applyAttachmentConstraintOverrides.d.ts +6 -4
  28. package/lib/config/applyAttachmentConstraintOverrides.d.ts.map +1 -1
  29. package/lib/config/applyAttachmentConstraintOverrides.js +45 -49
  30. package/lib/config/applyAttachmentConstraintOverrides.js.map +1 -1
  31. package/lib/config/index.d.ts +17 -15
  32. package/lib/config/index.d.ts.map +1 -1
  33. package/lib/config/index.js +56 -81
  34. package/lib/config/index.js.map +1 -1
  35. package/lib/connection.d.ts +28 -26
  36. package/lib/connection.d.ts.map +1 -1
  37. package/lib/connection.js +183 -215
  38. package/lib/connection.js.map +1 -1
  39. package/lib/index.d.ts +9 -5
  40. package/lib/index.js +9 -5
  41. package/lib/installation/createFoundryBackendInstallation.d.ts +21 -20
  42. package/lib/installation/createFoundryBackendInstallation.d.ts.map +1 -1
  43. package/lib/installation/createFoundryBackendInstallation.js +52 -62
  44. package/lib/installation/createFoundryBackendInstallation.js.map +1 -1
  45. package/lib/installation/index.d.ts +2 -2
  46. package/lib/installation/index.js +2 -2
  47. package/lib/meta/actionTypeCollectionOptions.d.ts +8 -6
  48. package/lib/meta/actionTypeCollectionOptions.d.ts.map +1 -1
  49. package/lib/meta/actionTypeCollectionOptions.js +49 -49
  50. package/lib/meta/actionTypeCollectionOptions.js.map +1 -1
  51. package/lib/meta/convertActionTypeLoadSubsetOptions.d.ts +3 -1
  52. package/lib/meta/convertActionTypeLoadSubsetOptions.d.ts.map +1 -1
  53. package/lib/meta/convertActionTypeLoadSubsetOptions.js +69 -75
  54. package/lib/meta/convertActionTypeLoadSubsetOptions.js.map +1 -1
  55. package/lib/meta/convertMetaActionType.d.ts +7 -5
  56. package/lib/meta/convertMetaActionType.d.ts.map +1 -1
  57. package/lib/meta/convertMetaActionType.js +458 -581
  58. package/lib/meta/convertMetaActionType.js.map +1 -1
  59. package/lib/meta/convertMetaLinkType.d.ts +4 -2
  60. package/lib/meta/convertMetaLinkType.d.ts.map +1 -1
  61. package/lib/meta/convertMetaLinkType.js +37 -43
  62. package/lib/meta/convertMetaLinkType.js.map +1 -1
  63. package/lib/meta/convertMetaObjectType.d.ts +4 -2
  64. package/lib/meta/convertMetaObjectType.d.ts.map +1 -1
  65. package/lib/meta/convertMetaObjectType.js +34 -35
  66. package/lib/meta/convertMetaObjectType.js.map +1 -1
  67. package/lib/meta/convertMetaQueryFunctionType.d.ts +4 -2
  68. package/lib/meta/convertMetaQueryFunctionType.d.ts.map +1 -1
  69. package/lib/meta/convertMetaQueryFunctionType.js +113 -94
  70. package/lib/meta/convertMetaQueryFunctionType.js.map +1 -1
  71. package/lib/meta/convertMetaTypeDef.d.ts +4 -2
  72. package/lib/meta/convertMetaTypeDef.d.ts.map +1 -1
  73. package/lib/meta/convertMetaTypeDef.js +178 -176
  74. package/lib/meta/convertMetaTypeDef.js.map +1 -1
  75. package/lib/meta/convertMetaValueType.d.ts +4 -2
  76. package/lib/meta/convertMetaValueType.d.ts.map +1 -1
  77. package/lib/meta/convertMetaValueType.js +11 -7
  78. package/lib/meta/convertMetaValueType.js.map +1 -1
  79. package/lib/meta/convertOmsActionParameterMetadata.d.ts +4 -2
  80. package/lib/meta/convertOmsActionParameterMetadata.d.ts.map +1 -1
  81. package/lib/meta/convertOmsActionParameterMetadata.js +107 -163
  82. package/lib/meta/convertOmsActionParameterMetadata.js.map +1 -1
  83. package/lib/meta/createFoundryMetaOntologyBackendAdapter.d.ts +7 -5
  84. package/lib/meta/createFoundryMetaOntologyBackendAdapter.d.ts.map +1 -1
  85. package/lib/meta/createFoundryMetaOntologyBackendAdapter.js +39 -41
  86. package/lib/meta/createFoundryMetaOntologyBackendAdapter.js.map +1 -1
  87. package/lib/meta/entityCollectionOptions.d.ts +12 -11
  88. package/lib/meta/entityCollectionOptions.d.ts.map +1 -1
  89. package/lib/meta/entityCollectionOptions.js +59 -62
  90. package/lib/meta/entityCollectionOptions.js.map +1 -1
  91. package/lib/meta/foundryAttachmentMetadata.d.ts +2 -0
  92. package/lib/meta/foundryAttachmentMetadata.d.ts.map +1 -1
  93. package/lib/meta/foundryAttachmentMetadata.js +13 -14
  94. package/lib/meta/foundryAttachmentMetadata.js.map +1 -1
  95. package/lib/meta/index.d.ts +5 -5
  96. package/lib/meta/index.js +5 -5
  97. package/lib/meta/loadActionTypeOmsMetadata.d.ts +5 -4
  98. package/lib/meta/loadActionTypeOmsMetadata.d.ts.map +1 -1
  99. package/lib/meta/loadActionTypeOmsMetadata.js +102 -139
  100. package/lib/meta/loadActionTypeOmsMetadata.js.map +1 -1
  101. package/lib/meta/queryFunctionTypeCollectionOptions.d.ts +7 -5
  102. package/lib/meta/queryFunctionTypeCollectionOptions.d.ts.map +1 -1
  103. package/lib/meta/queryFunctionTypeCollectionOptions.js +47 -49
  104. package/lib/meta/queryFunctionTypeCollectionOptions.js.map +1 -1
  105. package/lib/stagedWrites.d.ts +26 -24
  106. package/lib/stagedWrites.d.ts.map +1 -1
  107. package/lib/stagedWrites.js +55 -66
  108. package/lib/stagedWrites.js.map +1 -1
  109. package/lib/users/createFoundryAdminOntologyRoute.d.ts +47 -17366
  110. package/lib/users/createFoundryAdminOntologyRoute.d.ts.map +1 -1
  111. package/lib/users/createFoundryAdminOntologyRoute.js +29 -37
  112. package/lib/users/createFoundryAdminOntologyRoute.js.map +1 -1
  113. package/lib/users/createFoundryUsersIntegration.d.ts +6 -4
  114. package/lib/users/createFoundryUsersIntegration.d.ts.map +1 -1
  115. package/lib/users/createFoundryUsersIntegration.js +28 -30
  116. package/lib/users/createFoundryUsersIntegration.js.map +1 -1
  117. package/lib/users/foundryUser.d.ts +4 -2
  118. package/lib/users/foundryUser.d.ts.map +1 -1
  119. package/lib/users/foundryUser.js +69 -74
  120. package/lib/users/foundryUser.js.map +1 -1
  121. package/lib/users/index.d.ts +5 -5
  122. package/lib/users/index.js +5 -5
  123. package/lib/users/userCollectionOptions.d.ts +13 -12
  124. package/lib/users/userCollectionOptions.d.ts.map +1 -1
  125. package/lib/users/userCollectionOptions.js +82 -100
  126. package/lib/users/userCollectionOptions.js.map +1 -1
  127. package/lib/utils/AsyncIterable.d.ts +2 -0
  128. package/lib/utils/AsyncIterable.d.ts.map +1 -1
  129. package/lib/utils/AsyncIterable.js +26 -34
  130. package/lib/utils/AsyncIterable.js.map +1 -1
  131. package/lib/utils/actionTypeName.d.ts +2 -0
  132. package/lib/utils/actionTypeName.d.ts.map +1 -1
  133. package/lib/utils/actionTypeName.js +9 -7
  134. package/lib/utils/actionTypeName.js.map +1 -1
  135. package/lib/utils/chunk.d.ts +2 -0
  136. package/lib/utils/chunk.d.ts.map +1 -1
  137. package/lib/utils/chunk.js +8 -6
  138. package/lib/utils/chunk.js.map +1 -1
  139. package/package.json +21 -27
  140. package/lib/adapter/convertLoadSubsetOptions.test.d.ts +0 -2
  141. package/lib/adapter/convertLoadSubsetOptions.test.d.ts.map +0 -1
  142. package/lib/adapter/convertLoadSubsetOptions.test.js +0 -213
  143. package/lib/adapter/convertLoadSubsetOptions.test.js.map +0 -1
  144. package/lib/adapter/createFoundryOntologyBackendAdapter.test.d.ts +0 -2
  145. package/lib/adapter/createFoundryOntologyBackendAdapter.test.d.ts.map +0 -1
  146. package/lib/adapter/createFoundryOntologyBackendAdapter.test.js +0 -628
  147. package/lib/adapter/createFoundryOntologyBackendAdapter.test.js.map +0 -1
  148. package/lib/adapter/foundryActionValidation.test.d.ts +0 -2
  149. package/lib/adapter/foundryActionValidation.test.d.ts.map +0 -1
  150. package/lib/adapter/foundryActionValidation.test.js +0 -243
  151. package/lib/adapter/foundryActionValidation.test.js.map +0 -1
  152. package/lib/adapter/foundryCodec.test.d.ts +0 -2
  153. package/lib/adapter/foundryCodec.test.d.ts.map +0 -1
  154. package/lib/adapter/foundryCodec.test.js +0 -137
  155. package/lib/adapter/foundryCodec.test.js.map +0 -1
  156. package/lib/adapter/foundryMediaId.test.d.ts +0 -2
  157. package/lib/adapter/foundryMediaId.test.d.ts.map +0 -1
  158. package/lib/adapter/foundryMediaId.test.js +0 -23
  159. package/lib/adapter/foundryMediaId.test.js.map +0 -1
  160. package/lib/adapter/index.d.ts.map +0 -1
  161. package/lib/adapter/index.js.map +0 -1
  162. package/lib/adapter/objectCollectionOptions.test.d.ts +0 -2
  163. package/lib/adapter/objectCollectionOptions.test.d.ts.map +0 -1
  164. package/lib/adapter/objectCollectionOptions.test.js +0 -1289
  165. package/lib/adapter/objectCollectionOptions.test.js.map +0 -1
  166. package/lib/config/connectionPull.test.d.ts +0 -2
  167. package/lib/config/connectionPull.test.d.ts.map +0 -1
  168. package/lib/config/connectionPull.test.js +0 -151
  169. package/lib/config/connectionPull.test.js.map +0 -1
  170. package/lib/config/index.test.d.ts +0 -2
  171. package/lib/config/index.test.d.ts.map +0 -1
  172. package/lib/config/index.test.js +0 -182
  173. package/lib/config/index.test.js.map +0 -1
  174. package/lib/connection.test.d.ts +0 -2
  175. package/lib/connection.test.d.ts.map +0 -1
  176. package/lib/connection.test.js +0 -162
  177. package/lib/connection.test.js.map +0 -1
  178. package/lib/index.d.ts.map +0 -1
  179. package/lib/index.js.map +0 -1
  180. package/lib/installation/createFoundryBackendInstallation.test.d.ts +0 -2
  181. package/lib/installation/createFoundryBackendInstallation.test.d.ts.map +0 -1
  182. package/lib/installation/createFoundryBackendInstallation.test.js +0 -83
  183. package/lib/installation/createFoundryBackendInstallation.test.js.map +0 -1
  184. package/lib/installation/index.d.ts.map +0 -1
  185. package/lib/installation/index.js.map +0 -1
  186. package/lib/meta/actionTypeCollectionOptions.test.d.ts +0 -2
  187. package/lib/meta/actionTypeCollectionOptions.test.d.ts.map +0 -1
  188. package/lib/meta/actionTypeCollectionOptions.test.js +0 -24
  189. package/lib/meta/actionTypeCollectionOptions.test.js.map +0 -1
  190. package/lib/meta/actionTypeIdQuery.test.d.ts +0 -2
  191. package/lib/meta/actionTypeIdQuery.test.d.ts.map +0 -1
  192. package/lib/meta/actionTypeIdQuery.test.js +0 -131
  193. package/lib/meta/actionTypeIdQuery.test.js.map +0 -1
  194. package/lib/meta/convertActionTypeLoadSubsetOptions.test.d.ts +0 -2
  195. package/lib/meta/convertActionTypeLoadSubsetOptions.test.d.ts.map +0 -1
  196. package/lib/meta/convertActionTypeLoadSubsetOptions.test.js +0 -138
  197. package/lib/meta/convertActionTypeLoadSubsetOptions.test.js.map +0 -1
  198. package/lib/meta/convertMetaActionType.test.d.ts +0 -2
  199. package/lib/meta/convertMetaActionType.test.d.ts.map +0 -1
  200. package/lib/meta/convertMetaActionType.test.js +0 -1565
  201. package/lib/meta/convertMetaActionType.test.js.map +0 -1
  202. package/lib/meta/convertMetaLinkType.test.d.ts +0 -2
  203. package/lib/meta/convertMetaLinkType.test.d.ts.map +0 -1
  204. package/lib/meta/convertMetaLinkType.test.js +0 -110
  205. package/lib/meta/convertMetaLinkType.test.js.map +0 -1
  206. package/lib/meta/convertMetaObjectType.test.d.ts +0 -2
  207. package/lib/meta/convertMetaObjectType.test.d.ts.map +0 -1
  208. package/lib/meta/convertMetaObjectType.test.js +0 -250
  209. package/lib/meta/convertMetaObjectType.test.js.map +0 -1
  210. package/lib/meta/convertMetaQueryFunctionType.test.d.ts +0 -2
  211. package/lib/meta/convertMetaQueryFunctionType.test.d.ts.map +0 -1
  212. package/lib/meta/convertMetaQueryFunctionType.test.js +0 -134
  213. package/lib/meta/convertMetaQueryFunctionType.test.js.map +0 -1
  214. package/lib/meta/createFoundryMetaOntologyBackendAdapter.test.d.ts +0 -2
  215. package/lib/meta/createFoundryMetaOntologyBackendAdapter.test.d.ts.map +0 -1
  216. package/lib/meta/createFoundryMetaOntologyBackendAdapter.test.js +0 -49
  217. package/lib/meta/createFoundryMetaOntologyBackendAdapter.test.js.map +0 -1
  218. package/lib/meta/entityCollectionOptions.test.d.ts +0 -2
  219. package/lib/meta/entityCollectionOptions.test.d.ts.map +0 -1
  220. package/lib/meta/entityCollectionOptions.test.js +0 -98
  221. package/lib/meta/entityCollectionOptions.test.js.map +0 -1
  222. package/lib/meta/index.d.ts.map +0 -1
  223. package/lib/meta/index.js.map +0 -1
  224. package/lib/meta/loadActionTypeOmsMetadata.test.d.ts +0 -2
  225. package/lib/meta/loadActionTypeOmsMetadata.test.d.ts.map +0 -1
  226. package/lib/meta/loadActionTypeOmsMetadata.test.js +0 -218
  227. package/lib/meta/loadActionTypeOmsMetadata.test.js.map +0 -1
  228. package/lib/stagedWrites.test.d.ts +0 -2
  229. package/lib/stagedWrites.test.d.ts.map +0 -1
  230. package/lib/stagedWrites.test.js +0 -71
  231. package/lib/stagedWrites.test.js.map +0 -1
  232. package/lib/users/createFoundryUsersIntegration.test.d.ts +0 -2
  233. package/lib/users/createFoundryUsersIntegration.test.d.ts.map +0 -1
  234. package/lib/users/createFoundryUsersIntegration.test.js +0 -32
  235. package/lib/users/createFoundryUsersIntegration.test.js.map +0 -1
  236. package/lib/users/foundryUser.test.d.ts +0 -2
  237. package/lib/users/foundryUser.test.d.ts.map +0 -1
  238. package/lib/users/foundryUser.test.js +0 -45
  239. package/lib/users/foundryUser.test.js.map +0 -1
  240. package/lib/users/index.d.ts.map +0 -1
  241. package/lib/users/index.js.map +0 -1
  242. package/lib/users/userCollectionOptions.test.d.ts +0 -2
  243. package/lib/users/userCollectionOptions.test.d.ts.map +0 -1
  244. package/lib/users/userCollectionOptions.test.js +0 -18
  245. package/lib/users/userCollectionOptions.test.js.map +0 -1
  246. package/lib/utils/AsyncIterable.test.d.ts +0 -2
  247. package/lib/utils/AsyncIterable.test.d.ts.map +0 -1
  248. package/lib/utils/AsyncIterable.test.js +0 -17
  249. package/lib/utils/AsyncIterable.test.js.map +0 -1
  250. package/lib/utils/actionTypeName.test.d.ts +0 -2
  251. package/lib/utils/actionTypeName.test.d.ts.map +0 -1
  252. package/lib/utils/actionTypeName.test.js +0 -30
  253. package/lib/utils/actionTypeName.test.js.map +0 -1
@@ -1,569 +1,448 @@
1
- import { OntologyObjectsV2, ObjectTypesV2, } from "@osdk/foundry.ontologies";
1
+ import { fromPagination, toArray } from "../utils/AsyncIterable.js";
2
+ import { convertLoadSubsetFilter, convertLoadSubsetOrderBy, isAlwaysFalseFilter } from "./convertLoadSubsetOptions.js";
3
+ import { ObjectTypesV2, OntologyObjectsV2 } from "@osdk/foundry.ontologies";
2
4
  import { getObjectSetWatcherManager } from "@party-stack/foundry-object-set-watcher";
3
- import { BasicIndex, DeduplicatedLoadSubset, } from "@tanstack/db";
5
+ import { BasicIndex, DeduplicatedLoadSubset } from "@tanstack/db";
4
6
  import { Store } from "@tanstack/store";
5
- import * as AsyncIterable from "../utils/AsyncIterable.js";
6
- import { convertLoadSubsetFilter, convertLoadSubsetOrderBy, isAlwaysFalseFilter, } from "./convertLoadSubsetOptions.js";
7
- const COLLECTION_SYNC_TIMEOUT_MS = 5_000;
8
- class TimeoutWaitingForOperationIdError extends Error {
9
- constructor(operationId, objectType) {
10
- super(`Timed out waiting for Foundry operation ${operationId} to sync for ${objectType}.`);
11
- this.name = "TimeoutWaitingForOperationIdError";
12
- }
13
- }
14
- class ObjectCollectionSyncAbortedError extends Error {
15
- constructor(objectType) {
16
- super(`Foundry sync for ${objectType} stopped before the operation was observed.`);
17
- this.name = "ObjectCollectionSyncAbortedError";
18
- }
19
- }
20
- // ---------------------------------------------------------------------------
21
- // Edit history helpers
22
- // ---------------------------------------------------------------------------
23
- const EDIT_HISTORY_PAGE_SIZE = 1_000;
7
+ //#region src/adapter/objectCollectionOptions.ts
8
+ const COLLECTION_SYNC_TIMEOUT_MS = 5e3;
9
+ var TimeoutWaitingForOperationIdError = class extends Error {
10
+ constructor(operationId, objectType) {
11
+ super(`Timed out waiting for Foundry operation ${operationId} to sync for ${objectType}.`);
12
+ this.name = "TimeoutWaitingForOperationIdError";
13
+ }
14
+ };
15
+ var ObjectCollectionSyncAbortedError = class extends Error {
16
+ constructor(objectType) {
17
+ super(`Foundry sync for ${objectType} stopped before the operation was observed.`);
18
+ this.name = "ObjectCollectionSyncAbortedError";
19
+ }
20
+ };
21
+ const EDIT_HISTORY_PAGE_SIZE = 1e3;
24
22
  const EDIT_HISTORY_CURSOR_METADATA_KEY = "foundry.editHistoryCursor";
25
23
  const EDIT_HISTORY_CURSOR_VERSION = 1;
26
- function createEditHistoryCursor(timestamp = new Date().toISOString()) {
27
- return { timestamp, seenEntryKeysAtTimestamp: new Set() };
24
+ function createEditHistoryCursor(timestamp = (/* @__PURE__ */ new Date()).toISOString()) {
25
+ return {
26
+ timestamp,
27
+ seenEntryKeysAtTimestamp: /* @__PURE__ */ new Set()
28
+ };
28
29
  }
29
30
  function cloneEditHistoryCursor(cursor) {
30
- return {
31
- timestamp: cursor.timestamp,
32
- seenEntryKeysAtTimestamp: new Set(cursor.seenEntryKeysAtTimestamp),
33
- };
31
+ return {
32
+ timestamp: cursor.timestamp,
33
+ seenEntryKeysAtTimestamp: new Set(cursor.seenEntryKeysAtTimestamp)
34
+ };
34
35
  }
35
36
  function serializeEditHistoryCursor(cursor) {
36
- return {
37
- version: EDIT_HISTORY_CURSOR_VERSION,
38
- timestamp: cursor.timestamp,
39
- seenEntryKeysAtTimestamp: [...cursor.seenEntryKeysAtTimestamp].sort(),
40
- };
37
+ return {
38
+ version: EDIT_HISTORY_CURSOR_VERSION,
39
+ timestamp: cursor.timestamp,
40
+ seenEntryKeysAtTimestamp: [...cursor.seenEntryKeysAtTimestamp].sort()
41
+ };
41
42
  }
42
43
  function deserializeEditHistoryCursor(value) {
43
- if (!isPlainObject(value) ||
44
- value.version !== EDIT_HISTORY_CURSOR_VERSION ||
45
- typeof value.timestamp !== "string" ||
46
- !Array.isArray(value.seenEntryKeysAtTimestamp) ||
47
- !value.seenEntryKeysAtTimestamp.every((key) => typeof key === "string")) {
48
- return undefined;
49
- }
50
- return {
51
- timestamp: value.timestamp,
52
- seenEntryKeysAtTimestamp: new Set(value.seenEntryKeysAtTimestamp),
53
- };
44
+ if (!isPlainObject(value) || value.version !== EDIT_HISTORY_CURSOR_VERSION || typeof value.timestamp !== "string" || !Array.isArray(value.seenEntryKeysAtTimestamp) || !value.seenEntryKeysAtTimestamp.every((key) => typeof key === "string")) return;
45
+ return {
46
+ timestamp: value.timestamp,
47
+ seenEntryKeysAtTimestamp: new Set(value.seenEntryKeysAtTimestamp)
48
+ };
54
49
  }
55
50
  function editHistoryCursorsEqual(left, right) {
56
- return (left.timestamp === right.timestamp &&
57
- left.seenEntryKeysAtTimestamp.size === right.seenEntryKeysAtTimestamp.size &&
58
- [...left.seenEntryKeysAtTimestamp].every((key) => right.seenEntryKeysAtTimestamp.has(key)));
51
+ return left.timestamp === right.timestamp && left.seenEntryKeysAtTimestamp.size === right.seenEntryKeysAtTimestamp.size && [...left.seenEntryKeysAtTimestamp].every((key) => right.seenEntryKeysAtTimestamp.has(key));
59
52
  }
60
53
  function canonicalizeJsonValue(value) {
61
- if (Array.isArray(value))
62
- return value.map(canonicalizeJsonValue);
63
- if (isPlainObject(value)) {
64
- return Object.fromEntries(Object.keys(value)
65
- .sort()
66
- .map((key) => [key, canonicalizeJsonValue(value[key])]));
67
- }
68
- return value;
54
+ if (Array.isArray(value)) return value.map(canonicalizeJsonValue);
55
+ if (isPlainObject(value)) return Object.fromEntries(Object.keys(value).sort().map((key) => [key, canonicalizeJsonValue(value[key])]));
56
+ return value;
69
57
  }
70
58
  function getEditHistoryEntryKey(entry) {
71
- return JSON.stringify(canonicalizeJsonValue({
72
- objectPrimaryKey: entry.objectPrimaryKey,
73
- operationId: entry.operationId,
74
- timestamp: entry.timestamp,
75
- edit: entry.edit,
76
- }));
59
+ return JSON.stringify(canonicalizeJsonValue({
60
+ objectPrimaryKey: entry.objectPrimaryKey,
61
+ operationId: entry.operationId,
62
+ timestamp: entry.timestamp,
63
+ edit: entry.edit
64
+ }));
77
65
  }
78
66
  function shouldProcessEditHistoryEntry(cursor, entry) {
79
- if (entry.timestamp < cursor.timestamp)
80
- return false;
81
- if (entry.timestamp === cursor.timestamp) {
82
- return !cursor.seenEntryKeysAtTimestamp.has(getEditHistoryEntryKey(entry));
83
- }
84
- return true;
67
+ if (entry.timestamp < cursor.timestamp) return false;
68
+ if (entry.timestamp === cursor.timestamp) return !cursor.seenEntryKeysAtTimestamp.has(getEditHistoryEntryKey(entry));
69
+ return true;
85
70
  }
86
71
  function advanceEditHistoryCursor(cursor, entry) {
87
- const entryKey = getEditHistoryEntryKey(entry);
88
- if (entry.timestamp > cursor.timestamp) {
89
- cursor.timestamp = entry.timestamp;
90
- cursor.seenEntryKeysAtTimestamp.clear();
91
- }
92
- cursor.seenEntryKeysAtTimestamp.add(entryKey);
72
+ const entryKey = getEditHistoryEntryKey(entry);
73
+ if (entry.timestamp > cursor.timestamp) {
74
+ cursor.timestamp = entry.timestamp;
75
+ cursor.seenEntryKeysAtTimestamp.clear();
76
+ }
77
+ cursor.seenEntryKeysAtTimestamp.add(entryKey);
93
78
  }
94
79
  function getPrimaryKeyValue(primaryKey, primaryKeyProperty, decodeEditObject) {
95
- const values = Object.values(primaryKey);
96
- if (values.length !== 1) {
97
- throw new Error("Foundry object collections currently only support single-field primary keys.");
98
- }
99
- const value = decodeEditObject({
100
- [primaryKeyProperty]: values[0],
101
- })[primaryKeyProperty];
102
- if (typeof value !== "string" && typeof value !== "number") {
103
- throw new Error("Foundry object collections currently only support string or number primary keys.");
104
- }
105
- return value;
80
+ const values = Object.values(primaryKey);
81
+ if (values.length !== 1) throw new Error("Foundry object collections currently only support single-field primary keys.");
82
+ const value = decodeEditObject({ [primaryKeyProperty]: values[0] })[primaryKeyProperty];
83
+ if (typeof value !== "string" && typeof value !== "number") throw new Error("Foundry object collections currently only support string or number primary keys.");
84
+ return value;
106
85
  }
107
86
  function isPlainObject(value) {
108
- return typeof value === "object" && value !== null && !Array.isArray(value);
87
+ return typeof value === "object" && value !== null && !Array.isArray(value);
109
88
  }
110
- // ---------------------------------------------------------------------------
111
- // Foundry object fetching
112
- // ---------------------------------------------------------------------------
113
89
  async function fetchFoundryObjects(client, objectType, selectedProperties, opts, decodeObject = (object) => object) {
114
- opts.signal?.throwIfAborted();
115
- const offset = Math.max(0, Math.trunc(opts.offset ?? 0));
116
- const limit = opts.limit === undefined ? undefined : Math.max(0, Math.trunc(opts.limit));
117
- if (limit === 0)
118
- return [];
119
- let where = convertLoadSubsetFilter(opts.where);
120
- if (isAlwaysFalseFilter(where) || (where?.type === "in" && where.value.length === 0)) {
121
- return [];
122
- }
123
- if (opts.cursor?.whereFrom) {
124
- const cursorWhere = convertLoadSubsetFilter(opts.cursor.whereFrom);
125
- if (isAlwaysFalseFilter(cursorWhere)) {
126
- return [];
127
- }
128
- if (cursorWhere) {
129
- where = where ? { type: "and", value: [where, cursorWhere] } : cursorWhere;
130
- }
131
- }
132
- const requestClient = opts.signal
133
- ? {
134
- ...client,
135
- fetch: (input, init) => client.fetch(input, {
136
- ...init,
137
- signal: opts.signal,
138
- }),
139
- }
140
- : client;
141
- const results = await AsyncIterable.toArray(AsyncIterable.fromPagination((pageSize, pageToken) => OntologyObjectsV2.search(requestClient, client.ontologyRid, objectType, {
142
- snapshot: true,
143
- where,
144
- excludeRid: true,
145
- select: selectedProperties,
146
- selectV2: [],
147
- pageSize,
148
- pageToken,
149
- orderBy: convertLoadSubsetOrderBy(opts.orderBy),
150
- }), (page) => page.nextPageToken, (page) => page.data, 10_000, limit === undefined ? undefined : offset + limit));
151
- opts.signal?.throwIfAborted();
152
- return results
153
- .slice(offset, limit === undefined ? undefined : offset + limit)
154
- .map(decodeObject);
90
+ opts.signal?.throwIfAborted();
91
+ const offset = Math.max(0, Math.trunc(opts.offset ?? 0));
92
+ const limit = opts.limit === void 0 ? void 0 : Math.max(0, Math.trunc(opts.limit));
93
+ if (limit === 0) return [];
94
+ let where = convertLoadSubsetFilter(opts.where);
95
+ if (isAlwaysFalseFilter(where) || where?.type === "in" && where.value.length === 0) return [];
96
+ if (opts.cursor?.whereFrom) {
97
+ const cursorWhere = convertLoadSubsetFilter(opts.cursor.whereFrom);
98
+ if (isAlwaysFalseFilter(cursorWhere)) return [];
99
+ if (cursorWhere) where = where ? {
100
+ type: "and",
101
+ value: [where, cursorWhere]
102
+ } : cursorWhere;
103
+ }
104
+ const requestClient = opts.signal ? {
105
+ ...client,
106
+ fetch: (input, init) => client.fetch(input, {
107
+ ...init,
108
+ signal: opts.signal
109
+ })
110
+ } : client;
111
+ const results = await toArray(fromPagination((pageSize, pageToken) => OntologyObjectsV2.search(requestClient, client.ontologyRid, objectType, {
112
+ snapshot: true,
113
+ where,
114
+ excludeRid: true,
115
+ select: selectedProperties,
116
+ selectV2: [],
117
+ pageSize,
118
+ pageToken,
119
+ orderBy: convertLoadSubsetOrderBy(opts.orderBy)
120
+ }), (page) => page.nextPageToken, (page) => page.data, 1e4, limit === void 0 ? void 0 : offset + limit));
121
+ opts.signal?.throwIfAborted();
122
+ return results.slice(offset, limit === void 0 ? void 0 : offset + limit).map(decodeObject);
155
123
  }
156
124
  function createSyncConfig(client, objectType, primaryKeyProperty, selectedProperties, decodeObject = (object) => object, decodeEditObject = decodeObject, live = true) {
157
- const seenOperationIds = new Store(new Set());
158
- const syncDisposed = new Store(false);
159
- const directWebsocketSyncVersion = new Store(0);
160
- let editHistoryUnavailable = false;
161
- let requestFullRefresh;
162
- let requestEditHistoryCatchUp;
163
- const awaitOperationId = async (operationId, timeout = COLLECTION_SYNC_TIMEOUT_MS) => {
164
- if (typeof operationId !== "string" || operationId.length === 0) {
165
- throw new Error("Foundry operationId must be a non-empty string.");
166
- }
167
- if (seenOperationIds.state.has(operationId)) {
168
- return;
169
- }
170
- if (syncDisposed.state) {
171
- throw new ObjectCollectionSyncAbortedError(objectType);
172
- }
173
- if (!requestEditHistoryCatchUp) {
174
- // An on-demand collection has no local state to confirm until its sync starts.
175
- // TODO: Track sync activity and edit-history availability separately. If sync is
176
- // active but edit-history catch-up is unavailable, request and await a full refresh.
177
- return;
178
- }
179
- const directSyncVersionAtStart = directWebsocketSyncVersion.state;
180
- requestEditHistoryCatchUp();
181
- return new Promise((resolve, reject) => {
182
- const cleanup = () => {
183
- clearTimeout(timeoutId);
184
- seenOperationIdsSubscription.unsubscribe();
185
- directWebsocketSyncVersionSubscription.unsubscribe();
186
- disposedSubscription.unsubscribe();
187
- };
188
- const timeoutId = setTimeout(() => {
189
- cleanup();
190
- reject(new TimeoutWaitingForOperationIdError(operationId, objectType));
191
- }, timeout);
192
- const seenOperationIdsSubscription = seenOperationIds.subscribe(() => {
193
- if (seenOperationIds.state.has(operationId)) {
194
- cleanup();
195
- resolve();
196
- }
197
- });
198
- const directWebsocketSyncVersionSubscription = directWebsocketSyncVersion.subscribe(() => {
199
- if (editHistoryUnavailable &&
200
- directWebsocketSyncVersion.state >
201
- directSyncVersionAtStart) {
202
- cleanup();
203
- resolve();
204
- }
205
- });
206
- const disposedSubscription = syncDisposed.subscribe(() => {
207
- if (syncDisposed.state) {
208
- cleanup();
209
- reject(new ObjectCollectionSyncAbortedError(objectType));
210
- }
211
- });
212
- });
213
- };
214
- const utils = { awaitOperationId };
215
- const sync = {
216
- sync: (params) => {
217
- const { begin, write, commit, markError, markReady, truncate, } = params;
218
- const collectionMetadata = params.metadata?.collection;
219
- syncDisposed.setState(() => false);
220
- let disposed = false;
221
- const restoredEditHistoryCursor = deserializeEditHistoryCursor(collectionMetadata?.get(EDIT_HISTORY_CURSOR_METADATA_KEY));
222
- let editHistoryCursor = restoredEditHistoryCursor ?? createEditHistoryCursor();
223
- let initialCommit = true;
224
- if (!restoredEditHistoryCursor) {
225
- if (collectionMetadata) {
226
- begin();
227
- collectionMetadata.set(EDIT_HISTORY_CURSOR_METADATA_KEY, serializeEditHistoryCursor(editHistoryCursor));
228
- initialCommit = commit();
229
- }
230
- }
231
- let catchUpRequested = false;
232
- let catchUpTask;
233
- let pendingDirectWatcherUpdates = [];
234
- let fullRefreshRequested = false;
235
- let fullRefreshTask;
236
- const getObjectKey = (object) => object[primaryKeyProperty];
237
- const getWatcherObjectKey = (object) => {
238
- const key = object[primaryKeyProperty] ?? object.__primaryKey;
239
- if (typeof key !== "string" && typeof key !== "number") {
240
- throw new Error(`Foundry websocket update for ${objectType} did not include a supported primary key.`);
241
- }
242
- return key;
243
- };
244
- const upsertObject = (object) => {
245
- const key = getObjectKey(object);
246
- const exists = params.collection.has(key);
247
- const existing = exists ? params.collection.get(key) : undefined;
248
- write({
249
- type: exists ? "update" : "insert",
250
- value: existing
251
- ? {
252
- ...existing,
253
- ...object,
254
- }
255
- : object,
256
- });
257
- };
258
- const deleteObjectByKey = (key) => {
259
- write({ type: "delete", key });
260
- return true;
261
- };
262
- const fetchEditHistoryPage = (body) => ObjectTypesV2.getEditsHistory(client, client.ontologyRid, objectType, body,
263
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
264
- {
265
- preview: true,
266
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
267
- });
268
- const decodeEditProperties = (properties, primaryKey) => decodeEditObject({
269
- ...properties,
270
- [primaryKeyProperty]: primaryKey,
271
- });
272
- const decodeWatcherObject = (object, primaryKey) => decodeObject({
273
- ...object,
274
- [primaryKeyProperty]: primaryKey,
275
- });
276
- const applyDirectWatcherUpdates = async (updates) => {
277
- const pendingMutations = new Map();
278
- let observedObjectUpdate = false;
279
- for (const update of updates) {
280
- if (update.type !== "object")
281
- continue;
282
- observedObjectUpdate = true;
283
- const object = update.object;
284
- const primaryKey = getWatcherObjectKey(object);
285
- switch (update.state) {
286
- case "ADDED_OR_UPDATED":
287
- pendingMutations.set(primaryKey, {
288
- type: "upsert",
289
- object: decodeWatcherObject(object, primaryKey),
290
- });
291
- break;
292
- case "REMOVED":
293
- pendingMutations.set(primaryKey, { type: "delete" });
294
- break;
295
- }
296
- }
297
- let transactionStarted = false;
298
- for (const [primaryKey, mutation] of pendingMutations) {
299
- if (!transactionStarted) {
300
- begin();
301
- transactionStarted = true;
302
- }
303
- if (mutation.type === "delete") {
304
- deleteObjectByKey(primaryKey);
305
- }
306
- else {
307
- upsertObject(mutation.object);
308
- }
309
- }
310
- const receipt = transactionStarted ? commit() : true;
311
- if (observedObjectUpdate) {
312
- directWebsocketSyncVersion.setState((version) => version + 1);
313
- }
314
- if (receipt !== true)
315
- await receipt;
316
- };
317
- const switchToDirectWebsocketMode = (error) => {
318
- if (!editHistoryUnavailable) {
319
- const errorMessage = error instanceof Error ? error.message : error;
320
- console.warn(`Edit history catch-up failed for ${objectType}; falling back to direct websocket updates.`, errorMessage);
321
- editHistoryUnavailable = true;
322
- }
323
- if (pendingDirectWatcherUpdates.length >
324
- 0) {
325
- const updates = pendingDirectWatcherUpdates;
326
- pendingDirectWatcherUpdates = [];
327
- void applyDirectWatcherUpdates(updates).catch((applyError) => {
328
- console.warn(`Failed to apply direct Foundry updates for ${objectType}.`, applyError);
329
- });
330
- }
331
- requestFullRefresh?.();
332
- };
333
- const catchUpFromEditHistory = async () => {
334
- const nextEditHistoryCursor = cloneEditHistoryCursor(editHistoryCursor);
335
- const pendingMutations = new Map();
336
- const newOperationIds = new Set();
337
- for await (const entry of AsyncIterable.fromPagination((pageSize, pageToken) => fetchEditHistoryPage({
338
- filters: {
339
- type: "timestampFilter",
340
- startTime: nextEditHistoryCursor.timestamp,
341
- },
342
- includeAllPreviousProperties: true,
343
- pageSize,
344
- pageToken,
345
- sortOrder: "oldest_first",
346
- }), (page) => page.nextPageToken, (page) => page.data, EDIT_HISTORY_PAGE_SIZE)) {
347
- if (disposed)
348
- break;
349
- if (!shouldProcessEditHistoryEntry(nextEditHistoryCursor, entry))
350
- continue;
351
- advanceEditHistoryCursor(nextEditHistoryCursor, entry);
352
- newOperationIds.add(entry.operationId);
353
- const primaryKey = getPrimaryKeyValue(entry.objectPrimaryKey, primaryKeyProperty, decodeEditObject);
354
- switch (entry.edit.type) {
355
- case "createEdit":
356
- case "modifyEdit":
357
- pendingMutations.set(primaryKey, {
358
- type: "upsert",
359
- object: decodeEditProperties(entry.edit.properties, primaryKey),
360
- });
361
- break;
362
- case "deleteEdit":
363
- pendingMutations.set(primaryKey, { type: "delete" });
364
- break;
365
- }
366
- }
367
- if (disposed)
368
- return;
369
- const checkpointChanged = !editHistoryCursorsEqual(editHistoryCursor, nextEditHistoryCursor);
370
- let transactionStarted = false;
371
- const ensureTransaction = () => {
372
- if (transactionStarted)
373
- return;
374
- begin();
375
- transactionStarted = true;
376
- };
377
- for (const [primaryKey, mutation] of pendingMutations) {
378
- ensureTransaction();
379
- if (mutation.type === "delete") {
380
- deleteObjectByKey(primaryKey);
381
- }
382
- else {
383
- upsertObject(mutation.object);
384
- }
385
- }
386
- if (checkpointChanged && collectionMetadata) {
387
- ensureTransaction();
388
- collectionMetadata.set(EDIT_HISTORY_CURSOR_METADATA_KEY, serializeEditHistoryCursor(nextEditHistoryCursor));
389
- }
390
- const receipt = transactionStarted ? commit() : true;
391
- if (checkpointChanged) {
392
- editHistoryCursor = nextEditHistoryCursor;
393
- }
394
- if (newOperationIds.size > 0) {
395
- seenOperationIds.setState((current) => new Set([
396
- ...current,
397
- ...newOperationIds,
398
- ]));
399
- }
400
- pendingDirectWatcherUpdates = [];
401
- if (receipt !== true)
402
- await receipt;
403
- };
404
- const refreshAllFromSource = async () => {
405
- const objects = await fetchFoundryObjects(client, objectType, selectedProperties, {}, decodeObject);
406
- if (disposed)
407
- return;
408
- begin();
409
- truncate();
410
- for (const object of objects) {
411
- write({
412
- type: "insert",
413
- value: object,
414
- });
415
- }
416
- const receipt = commit();
417
- if (pendingDirectWatcherUpdates.length > 0) {
418
- const updates = pendingDirectWatcherUpdates;
419
- pendingDirectWatcherUpdates = [];
420
- await applyDirectWatcherUpdates(updates);
421
- }
422
- directWebsocketSyncVersion.setState((version) => version + 1);
423
- if (receipt !== true)
424
- await receipt;
425
- };
426
- requestFullRefresh = () => {
427
- fullRefreshRequested = true;
428
- if (fullRefreshTask)
429
- return;
430
- fullRefreshTask = (async () => {
431
- while (fullRefreshRequested && !disposed) {
432
- fullRefreshRequested = false;
433
- await refreshAllFromSource();
434
- }
435
- })()
436
- .catch((error) => {
437
- console.warn(`Failed full Foundry refresh for ${objectType}.`, error);
438
- })
439
- .finally(() => {
440
- fullRefreshTask = undefined;
441
- if (fullRefreshRequested && !disposed) {
442
- requestFullRefresh?.();
443
- }
444
- });
445
- };
446
- requestEditHistoryCatchUp = () => {
447
- if (editHistoryUnavailable) {
448
- return;
449
- }
450
- catchUpRequested = true;
451
- if (catchUpTask)
452
- return;
453
- catchUpTask = (async () => {
454
- while (catchUpRequested && !disposed) {
455
- catchUpRequested = false;
456
- await catchUpFromEditHistory();
457
- }
458
- })()
459
- .catch((error) => {
460
- switchToDirectWebsocketMode(error);
461
- })
462
- .finally(() => {
463
- catchUpTask = undefined;
464
- if (catchUpRequested && !disposed) {
465
- requestEditHistoryCatchUp?.();
466
- }
467
- });
468
- };
469
- const loadSubset = async (opts) => {
470
- const objects = await fetchFoundryObjects(client, objectType, selectedProperties, opts, decodeObject);
471
- if (objects.length > 0) {
472
- begin();
473
- for (const object of objects) {
474
- upsertObject(object);
475
- }
476
- const receipt = commit(opts.signal);
477
- if (receipt !== true)
478
- await receipt;
479
- }
480
- };
481
- const loadSubsetDedupe = new DeduplicatedLoadSubset({ loadSubset });
482
- const unsubscribe = live
483
- ? getObjectSetWatcherManager(client).subscribe({ type: "base", objectType }, (message) => {
484
- switch (message.type) {
485
- case "change": {
486
- if (editHistoryUnavailable) {
487
- if (fullRefreshTask) {
488
- pendingDirectWatcherUpdates.push(...message.updates);
489
- }
490
- else {
491
- void applyDirectWatcherUpdates(message.updates).catch((error) => {
492
- console.warn(`Failed to apply direct Foundry updates for ${objectType}.`, error);
493
- requestFullRefresh?.();
494
- });
495
- }
496
- }
497
- else {
498
- pendingDirectWatcherUpdates.push(...message.updates);
499
- requestEditHistoryCatchUp?.();
500
- }
501
- break;
502
- }
503
- case "refresh": {
504
- if (editHistoryUnavailable) {
505
- requestFullRefresh?.();
506
- }
507
- else {
508
- requestEditHistoryCatchUp?.();
509
- }
510
- break;
511
- }
512
- case "state": {
513
- if (message.status !== "open")
514
- break;
515
- if (editHistoryUnavailable) {
516
- requestFullRefresh?.();
517
- }
518
- else {
519
- requestEditHistoryCatchUp?.();
520
- }
521
- break;
522
- }
523
- }
524
- })
525
- : () => { };
526
- // start task here, cleanup can stop it
527
- // in that task:
528
- // - spawn object set subscription, which sends messages to catch up
529
- // - actions sends messages to catch up
530
- if (initialCommit === true) {
531
- markReady();
532
- }
533
- else {
534
- void initialCommit.then(markReady, markError);
535
- }
536
- return {
537
- loadSubset: loadSubsetDedupe.loadSubset,
538
- cleanup: () => {
539
- disposed = true;
540
- requestEditHistoryCatchUp = undefined;
541
- requestFullRefresh = undefined;
542
- syncDisposed.setState(() => true);
543
- unsubscribe();
544
- loadSubsetDedupe.reset();
545
- },
546
- };
547
- },
548
- };
549
- return { sync, utils };
125
+ const seenOperationIds = new Store(/* @__PURE__ */ new Set());
126
+ const syncDisposed = new Store(false);
127
+ const directWebsocketSyncVersion = new Store(0);
128
+ let editHistoryUnavailable = false;
129
+ let requestFullRefresh;
130
+ let requestEditHistoryCatchUp;
131
+ const awaitOperationId = async (operationId, timeout = COLLECTION_SYNC_TIMEOUT_MS) => {
132
+ if (typeof operationId !== "string" || operationId.length === 0) throw new Error("Foundry operationId must be a non-empty string.");
133
+ if (seenOperationIds.state.has(operationId)) return;
134
+ if (syncDisposed.state) throw new ObjectCollectionSyncAbortedError(objectType);
135
+ if (!requestEditHistoryCatchUp) return;
136
+ const directSyncVersionAtStart = directWebsocketSyncVersion.state;
137
+ requestEditHistoryCatchUp();
138
+ return new Promise((resolve, reject) => {
139
+ const cleanup = () => {
140
+ clearTimeout(timeoutId);
141
+ seenOperationIdsSubscription.unsubscribe();
142
+ directWebsocketSyncVersionSubscription.unsubscribe();
143
+ disposedSubscription.unsubscribe();
144
+ };
145
+ const timeoutId = setTimeout(() => {
146
+ cleanup();
147
+ reject(new TimeoutWaitingForOperationIdError(operationId, objectType));
148
+ }, timeout);
149
+ const seenOperationIdsSubscription = seenOperationIds.subscribe(() => {
150
+ if (seenOperationIds.state.has(operationId)) {
151
+ cleanup();
152
+ resolve();
153
+ }
154
+ });
155
+ const directWebsocketSyncVersionSubscription = directWebsocketSyncVersion.subscribe(() => {
156
+ if (editHistoryUnavailable && directWebsocketSyncVersion.state > directSyncVersionAtStart) {
157
+ cleanup();
158
+ resolve();
159
+ }
160
+ });
161
+ const disposedSubscription = syncDisposed.subscribe(() => {
162
+ if (syncDisposed.state) {
163
+ cleanup();
164
+ reject(new ObjectCollectionSyncAbortedError(objectType));
165
+ }
166
+ });
167
+ });
168
+ };
169
+ return {
170
+ sync: { sync: (params) => {
171
+ const { begin, write, commit, markError, markReady, truncate } = params;
172
+ const collectionMetadata = params.metadata?.collection;
173
+ syncDisposed.setState(() => false);
174
+ let disposed = false;
175
+ const restoredEditHistoryCursor = deserializeEditHistoryCursor(collectionMetadata?.get(EDIT_HISTORY_CURSOR_METADATA_KEY));
176
+ let editHistoryCursor = restoredEditHistoryCursor ?? createEditHistoryCursor();
177
+ let initialCommit = true;
178
+ if (!restoredEditHistoryCursor) {
179
+ if (collectionMetadata) {
180
+ begin();
181
+ collectionMetadata.set(EDIT_HISTORY_CURSOR_METADATA_KEY, serializeEditHistoryCursor(editHistoryCursor));
182
+ initialCommit = commit();
183
+ }
184
+ }
185
+ let catchUpRequested = false;
186
+ let catchUpTask;
187
+ let pendingDirectWatcherUpdates = [];
188
+ let fullRefreshRequested = false;
189
+ let fullRefreshTask;
190
+ const getObjectKey = (object) => object[primaryKeyProperty];
191
+ const getWatcherObjectKey = (object) => {
192
+ const key = object[primaryKeyProperty] ?? object.__primaryKey;
193
+ if (typeof key !== "string" && typeof key !== "number") throw new Error(`Foundry websocket update for ${objectType} did not include a supported primary key.`);
194
+ return key;
195
+ };
196
+ const upsertObject = (object) => {
197
+ const key = getObjectKey(object);
198
+ const exists = params.collection.has(key);
199
+ const existing = exists ? params.collection.get(key) : void 0;
200
+ write({
201
+ type: exists ? "update" : "insert",
202
+ value: existing ? {
203
+ ...existing,
204
+ ...object
205
+ } : object
206
+ });
207
+ };
208
+ const deleteObjectByKey = (key) => {
209
+ write({
210
+ type: "delete",
211
+ key
212
+ });
213
+ return true;
214
+ };
215
+ const fetchEditHistoryPage = (body) => ObjectTypesV2.getEditsHistory(client, client.ontologyRid, objectType, body, { preview: true });
216
+ const decodeEditProperties = (properties, primaryKey) => decodeEditObject({
217
+ ...properties,
218
+ [primaryKeyProperty]: primaryKey
219
+ });
220
+ const decodeWatcherObject = (object, primaryKey) => decodeObject({
221
+ ...object,
222
+ [primaryKeyProperty]: primaryKey
223
+ });
224
+ const applyDirectWatcherUpdates = async (updates) => {
225
+ const pendingMutations = /* @__PURE__ */ new Map();
226
+ let observedObjectUpdate = false;
227
+ for (const update of updates) {
228
+ if (update.type !== "object") continue;
229
+ observedObjectUpdate = true;
230
+ const object = update.object;
231
+ const primaryKey = getWatcherObjectKey(object);
232
+ switch (update.state) {
233
+ case "ADDED_OR_UPDATED":
234
+ pendingMutations.set(primaryKey, {
235
+ type: "upsert",
236
+ object: decodeWatcherObject(object, primaryKey)
237
+ });
238
+ break;
239
+ case "REMOVED": pendingMutations.set(primaryKey, { type: "delete" });
240
+ }
241
+ }
242
+ let transactionStarted = false;
243
+ for (const [primaryKey, mutation] of pendingMutations) {
244
+ if (!transactionStarted) {
245
+ begin();
246
+ transactionStarted = true;
247
+ }
248
+ if (mutation.type === "delete") deleteObjectByKey(primaryKey);
249
+ else upsertObject(mutation.object);
250
+ }
251
+ const receipt = transactionStarted ? commit() : true;
252
+ if (observedObjectUpdate) directWebsocketSyncVersion.setState((version) => version + 1);
253
+ if (receipt !== true) await receipt;
254
+ };
255
+ const switchToDirectWebsocketMode = (error) => {
256
+ if (!editHistoryUnavailable) {
257
+ const errorMessage = error instanceof Error ? error.message : error;
258
+ console.warn(`Edit history catch-up failed for ${objectType}; falling back to direct websocket updates.`, errorMessage);
259
+ editHistoryUnavailable = true;
260
+ }
261
+ if (pendingDirectWatcherUpdates.length > 0) {
262
+ const updates = pendingDirectWatcherUpdates;
263
+ pendingDirectWatcherUpdates = [];
264
+ applyDirectWatcherUpdates(updates).catch((applyError) => {
265
+ console.warn(`Failed to apply direct Foundry updates for ${objectType}.`, applyError);
266
+ });
267
+ }
268
+ requestFullRefresh?.();
269
+ };
270
+ const catchUpFromEditHistory = async () => {
271
+ const nextEditHistoryCursor = cloneEditHistoryCursor(editHistoryCursor);
272
+ const pendingMutations = /* @__PURE__ */ new Map();
273
+ const newOperationIds = /* @__PURE__ */ new Set();
274
+ for await (const entry of fromPagination((pageSize, pageToken) => fetchEditHistoryPage({
275
+ filters: {
276
+ type: "timestampFilter",
277
+ startTime: nextEditHistoryCursor.timestamp
278
+ },
279
+ includeAllPreviousProperties: true,
280
+ pageSize,
281
+ pageToken,
282
+ sortOrder: "oldest_first"
283
+ }), (page) => page.nextPageToken, (page) => page.data, EDIT_HISTORY_PAGE_SIZE)) {
284
+ if (disposed) break;
285
+ if (!shouldProcessEditHistoryEntry(nextEditHistoryCursor, entry)) continue;
286
+ advanceEditHistoryCursor(nextEditHistoryCursor, entry);
287
+ newOperationIds.add(entry.operationId);
288
+ const primaryKey = getPrimaryKeyValue(entry.objectPrimaryKey, primaryKeyProperty, decodeEditObject);
289
+ switch (entry.edit.type) {
290
+ case "createEdit":
291
+ case "modifyEdit":
292
+ pendingMutations.set(primaryKey, {
293
+ type: "upsert",
294
+ object: decodeEditProperties(entry.edit.properties, primaryKey)
295
+ });
296
+ break;
297
+ case "deleteEdit": pendingMutations.set(primaryKey, { type: "delete" });
298
+ }
299
+ }
300
+ if (disposed) return;
301
+ const checkpointChanged = !editHistoryCursorsEqual(editHistoryCursor, nextEditHistoryCursor);
302
+ let transactionStarted = false;
303
+ const ensureTransaction = () => {
304
+ if (transactionStarted) return;
305
+ begin();
306
+ transactionStarted = true;
307
+ };
308
+ for (const [primaryKey, mutation] of pendingMutations) {
309
+ ensureTransaction();
310
+ if (mutation.type === "delete") deleteObjectByKey(primaryKey);
311
+ else upsertObject(mutation.object);
312
+ }
313
+ if (checkpointChanged && collectionMetadata) {
314
+ ensureTransaction();
315
+ collectionMetadata.set(EDIT_HISTORY_CURSOR_METADATA_KEY, serializeEditHistoryCursor(nextEditHistoryCursor));
316
+ }
317
+ const receipt = transactionStarted ? commit() : true;
318
+ if (checkpointChanged) editHistoryCursor = nextEditHistoryCursor;
319
+ if (newOperationIds.size > 0) seenOperationIds.setState((current) => /* @__PURE__ */ new Set([...current, ...newOperationIds]));
320
+ pendingDirectWatcherUpdates = [];
321
+ if (receipt !== true) await receipt;
322
+ };
323
+ const refreshAllFromSource = async () => {
324
+ const objects = await fetchFoundryObjects(client, objectType, selectedProperties, {}, decodeObject);
325
+ if (disposed) return;
326
+ begin();
327
+ truncate();
328
+ for (const object of objects) write({
329
+ type: "insert",
330
+ value: object
331
+ });
332
+ const receipt = commit();
333
+ if (pendingDirectWatcherUpdates.length > 0) {
334
+ const updates = pendingDirectWatcherUpdates;
335
+ pendingDirectWatcherUpdates = [];
336
+ await applyDirectWatcherUpdates(updates);
337
+ }
338
+ directWebsocketSyncVersion.setState((version) => version + 1);
339
+ if (receipt !== true) await receipt;
340
+ };
341
+ requestFullRefresh = () => {
342
+ fullRefreshRequested = true;
343
+ if (fullRefreshTask) return;
344
+ fullRefreshTask = (async () => {
345
+ while (fullRefreshRequested && !disposed) {
346
+ fullRefreshRequested = false;
347
+ await refreshAllFromSource();
348
+ }
349
+ })().catch((error) => {
350
+ console.warn(`Failed full Foundry refresh for ${objectType}.`, error);
351
+ }).finally(() => {
352
+ fullRefreshTask = void 0;
353
+ if (fullRefreshRequested && !disposed) requestFullRefresh?.();
354
+ });
355
+ };
356
+ requestEditHistoryCatchUp = () => {
357
+ if (editHistoryUnavailable) return;
358
+ catchUpRequested = true;
359
+ if (catchUpTask) return;
360
+ catchUpTask = (async () => {
361
+ while (catchUpRequested && !disposed) {
362
+ catchUpRequested = false;
363
+ await catchUpFromEditHistory();
364
+ }
365
+ })().catch((error) => {
366
+ switchToDirectWebsocketMode(error);
367
+ }).finally(() => {
368
+ catchUpTask = void 0;
369
+ if (catchUpRequested && !disposed) requestEditHistoryCatchUp?.();
370
+ });
371
+ };
372
+ const loadSubset = async (opts) => {
373
+ const objects = await fetchFoundryObjects(client, objectType, selectedProperties, opts, decodeObject);
374
+ if (objects.length > 0) {
375
+ begin();
376
+ for (const object of objects) upsertObject(object);
377
+ const receipt = commit(opts.signal);
378
+ if (receipt !== true) await receipt;
379
+ }
380
+ };
381
+ const loadSubsetDedupe = new DeduplicatedLoadSubset({ loadSubset });
382
+ const unsubscribe = live ? getObjectSetWatcherManager(client).subscribe({
383
+ type: "base",
384
+ objectType
385
+ }, (message) => {
386
+ switch (message.type) {
387
+ case "change":
388
+ if (editHistoryUnavailable) {
389
+ if (fullRefreshTask) pendingDirectWatcherUpdates.push(...message.updates);
390
+ else applyDirectWatcherUpdates(message.updates).catch((error) => {
391
+ console.warn(`Failed to apply direct Foundry updates for ${objectType}.`, error);
392
+ requestFullRefresh?.();
393
+ });
394
+ } else {
395
+ pendingDirectWatcherUpdates.push(...message.updates);
396
+ requestEditHistoryCatchUp?.();
397
+ }
398
+ break;
399
+ case "refresh":
400
+ if (editHistoryUnavailable) requestFullRefresh?.();
401
+ else requestEditHistoryCatchUp?.();
402
+ break;
403
+ case "state":
404
+ if (message.status !== "open") break;
405
+ if (editHistoryUnavailable) requestFullRefresh?.();
406
+ else requestEditHistoryCatchUp?.();
407
+ }
408
+ }) : () => {};
409
+ if (initialCommit === true) markReady();
410
+ else initialCommit.then(markReady, markError);
411
+ return {
412
+ loadSubset: loadSubsetDedupe.loadSubset,
413
+ cleanup: () => {
414
+ disposed = true;
415
+ requestEditHistoryCatchUp = void 0;
416
+ requestFullRefresh = void 0;
417
+ syncDisposed.setState(() => true);
418
+ unsubscribe();
419
+ loadSubsetDedupe.reset();
420
+ }
421
+ };
422
+ } },
423
+ utils: { awaitOperationId }
424
+ };
550
425
  }
551
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
552
- export function objectCollectionOptions(config) {
553
- const { client, objectType, primaryKeyProperty, selectedProperties, live, decodeObject, decodeEditObject, schema, ...rest } = config;
554
- const { sync, utils } = createSyncConfig(client, objectType, primaryKeyProperty, selectedProperties, decodeObject, decodeEditObject, live);
555
- if (schema === undefined) {
556
- return { syncMode: "on-demand", sync, utils };
557
- }
558
- return {
559
- ...rest,
560
- schema,
561
- defaultIndexType: BasicIndex,
562
- autoIndex: "eager",
563
- syncMode: "on-demand",
564
- getKey: (object) => object[primaryKeyProperty],
565
- sync,
566
- utils,
567
- };
426
+ function objectCollectionOptions(config) {
427
+ const { client, objectType, primaryKeyProperty, selectedProperties, live, decodeObject, decodeEditObject, schema, ...rest } = config;
428
+ const { sync, utils } = createSyncConfig(client, objectType, primaryKeyProperty, selectedProperties, decodeObject, decodeEditObject, live);
429
+ if (schema === void 0) return {
430
+ syncMode: "on-demand",
431
+ sync,
432
+ utils
433
+ };
434
+ return {
435
+ ...rest,
436
+ schema,
437
+ defaultIndexType: BasicIndex,
438
+ autoIndex: "eager",
439
+ syncMode: "on-demand",
440
+ getKey: (object) => object[primaryKeyProperty],
441
+ sync,
442
+ utils
443
+ };
568
444
  }
445
+ //#endregion
446
+ export { objectCollectionOptions };
447
+
569
448
  //# sourceMappingURL=objectCollectionOptions.js.map