@powersync/service-module-mongodb-storage 0.0.0-dev-20260602073133 → 0.0.0-dev-20260909133214

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 (275) hide show
  1. package/CHANGELOG.md +177 -5
  2. package/dist/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.d.ts +3 -0
  3. package/dist/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.js +41 -0
  4. package/dist/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.js.map +1 -0
  5. package/dist/storage/MongoBucketStorage.d.ts +71 -18
  6. package/dist/storage/MongoBucketStorage.js +516 -202
  7. package/dist/storage/MongoBucketStorage.js.map +1 -1
  8. package/dist/storage/implementation/MongoBucketBatch.d.ts +71 -29
  9. package/dist/storage/implementation/MongoBucketBatch.js +140 -66
  10. package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
  11. package/dist/storage/implementation/MongoChecksums.d.ts +41 -13
  12. package/dist/storage/implementation/MongoChecksums.js +36 -121
  13. package/dist/storage/implementation/MongoChecksums.js.map +1 -1
  14. package/dist/storage/implementation/MongoCompactor.d.ts +28 -90
  15. package/dist/storage/implementation/MongoCompactor.js +87 -481
  16. package/dist/storage/implementation/MongoCompactor.js.map +1 -1
  17. package/dist/storage/implementation/MongoHydrationState.d.ts +11 -0
  18. package/dist/storage/implementation/MongoHydrationState.js +49 -0
  19. package/dist/storage/implementation/MongoHydrationState.js.map +1 -0
  20. package/dist/storage/implementation/MongoParameterCompactor.d.ts +82 -8
  21. package/dist/storage/implementation/MongoParameterCompactor.js +312 -76
  22. package/dist/storage/implementation/MongoParameterCompactor.js.map +1 -1
  23. package/dist/storage/implementation/MongoParsedSyncConfigSet.d.ts +21 -0
  24. package/dist/storage/implementation/MongoParsedSyncConfigSet.js +93 -0
  25. package/dist/storage/implementation/MongoParsedSyncConfigSet.js.map +1 -0
  26. package/dist/storage/implementation/MongoPersistedReplicationStream.d.ts +36 -0
  27. package/dist/storage/implementation/MongoPersistedReplicationStream.js +90 -0
  28. package/dist/storage/implementation/MongoPersistedReplicationStream.js.map +1 -0
  29. package/dist/storage/implementation/MongoPersistedSyncConfigContent.d.ts +25 -0
  30. package/dist/storage/implementation/MongoPersistedSyncConfigContent.js +125 -0
  31. package/dist/storage/implementation/MongoPersistedSyncConfigContent.js.map +1 -0
  32. package/dist/storage/implementation/MongoStorageProvider.js +41 -4
  33. package/dist/storage/implementation/MongoStorageProvider.js.map +1 -1
  34. package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +81 -37
  35. package/dist/storage/implementation/MongoSyncBucketStorage.js +159 -86
  36. package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
  37. package/dist/storage/implementation/MongoSyncRulesLock.d.ts +1 -1
  38. package/dist/storage/implementation/MongoSyncRulesLock.js +23 -11
  39. package/dist/storage/implementation/MongoSyncRulesLock.js.map +1 -1
  40. package/dist/storage/implementation/MongoWriteCheckpointAPI.d.ts +11 -8
  41. package/dist/storage/implementation/MongoWriteCheckpointAPI.js +159 -33
  42. package/dist/storage/implementation/MongoWriteCheckpointAPI.js.map +1 -1
  43. package/dist/storage/implementation/SyncRuleStateUpdate.d.ts +11 -5
  44. package/dist/storage/implementation/SyncRuleStateUpdate.js +14 -6
  45. package/dist/storage/implementation/SyncRuleStateUpdate.js.map +1 -1
  46. package/dist/storage/implementation/common/MongoSyncBucketStorageCheckpoint.d.ts +28 -0
  47. package/dist/storage/implementation/common/MongoSyncBucketStorageCheckpoint.js +2 -0
  48. package/dist/storage/implementation/common/MongoSyncBucketStorageCheckpoint.js.map +1 -0
  49. package/dist/storage/implementation/common/PersistedBatch.d.ts +34 -2
  50. package/dist/storage/implementation/common/PersistedBatch.js +63 -10
  51. package/dist/storage/implementation/common/PersistedBatch.js.map +1 -1
  52. package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js +1 -1
  53. package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js.map +1 -1
  54. package/dist/storage/implementation/createMongoSyncBucketStorage.d.ts +2 -2
  55. package/dist/storage/implementation/createMongoSyncBucketStorage.js +4 -4
  56. package/dist/storage/implementation/createMongoSyncBucketStorage.js.map +1 -1
  57. package/dist/storage/implementation/db.d.ts +4 -1
  58. package/dist/storage/implementation/db.js +31 -16
  59. package/dist/storage/implementation/db.js.map +1 -1
  60. package/dist/storage/implementation/models.d.ts +55 -13
  61. package/dist/storage/implementation/models.js.map +1 -1
  62. package/dist/storage/implementation/v1/MongoBucketBatchV1.d.ts +15 -1
  63. package/dist/storage/implementation/v1/MongoBucketBatchV1.js +135 -107
  64. package/dist/storage/implementation/v1/MongoBucketBatchV1.js.map +1 -1
  65. package/dist/storage/implementation/v1/MongoChecksumsV1.d.ts +4 -4
  66. package/dist/storage/implementation/v1/MongoChecksumsV1.js +119 -7
  67. package/dist/storage/implementation/v1/MongoChecksumsV1.js.map +1 -1
  68. package/dist/storage/implementation/v1/MongoCompactorV1.d.ts +47 -7
  69. package/dist/storage/implementation/v1/MongoCompactorV1.js +478 -8
  70. package/dist/storage/implementation/v1/MongoCompactorV1.js.map +1 -1
  71. package/dist/storage/implementation/v1/MongoParameterCompactorV1.d.ts +16 -2
  72. package/dist/storage/implementation/v1/MongoParameterCompactorV1.js +20 -9
  73. package/dist/storage/implementation/v1/MongoParameterCompactorV1.js.map +1 -1
  74. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.d.ts +33 -27
  75. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js +146 -73
  76. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js.map +1 -1
  77. package/dist/storage/implementation/v1/SingleBucketStoreV1.d.ts +9 -10
  78. package/dist/storage/implementation/v1/SingleBucketStoreV1.js +2 -8
  79. package/dist/storage/implementation/v1/SingleBucketStoreV1.js.map +1 -1
  80. package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.d.ts +2 -1
  81. package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.js +3 -0
  82. package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.js.map +1 -1
  83. package/dist/storage/implementation/v1/models.d.ts +10 -1
  84. package/dist/storage/implementation/v1/models.js +1 -0
  85. package/dist/storage/implementation/v1/models.js.map +1 -1
  86. package/dist/storage/implementation/v3/BucketDataContextV3.d.ts +13 -0
  87. package/dist/storage/implementation/v3/BucketDataContextV3.js +23 -0
  88. package/dist/storage/implementation/v3/BucketDataContextV3.js.map +1 -0
  89. package/dist/storage/implementation/v3/CompactionLease.d.ts +50 -0
  90. package/dist/storage/implementation/v3/CompactionLease.js +131 -0
  91. package/dist/storage/implementation/v3/CompactionLease.js.map +1 -0
  92. package/dist/storage/implementation/v3/MongoBucketBatchV3.d.ts +16 -5
  93. package/dist/storage/implementation/v3/MongoBucketBatchV3.js +393 -262
  94. package/dist/storage/implementation/v3/MongoBucketBatchV3.js.map +1 -1
  95. package/dist/storage/implementation/v3/MongoChecksumsV3.d.ts +30 -9
  96. package/dist/storage/implementation/v3/MongoChecksumsV3.js +161 -20
  97. package/dist/storage/implementation/v3/MongoChecksumsV3.js.map +1 -1
  98. package/dist/storage/implementation/v3/MongoCompactorV3.d.ts +108 -18
  99. package/dist/storage/implementation/v3/MongoCompactorV3.js +1115 -47
  100. package/dist/storage/implementation/v3/MongoCompactorV3.js.map +1 -1
  101. package/dist/storage/implementation/v3/MongoParameterCompactorV3.d.ts +12 -3
  102. package/dist/storage/implementation/v3/MongoParameterCompactorV3.js +13 -8
  103. package/dist/storage/implementation/v3/MongoParameterCompactorV3.js.map +1 -1
  104. package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.d.ts +54 -0
  105. package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.js +319 -0
  106. package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.js.map +1 -0
  107. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.d.ts +61 -36
  108. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js +353 -161
  109. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js.map +1 -1
  110. package/dist/storage/implementation/v3/MongoWriteCheckpointAPIV3.d.ts +26 -0
  111. package/dist/storage/implementation/v3/MongoWriteCheckpointAPIV3.js +82 -0
  112. package/dist/storage/implementation/v3/MongoWriteCheckpointAPIV3.js.map +1 -0
  113. package/dist/storage/implementation/v3/PersistedBatchV3.d.ts +8 -3
  114. package/dist/storage/implementation/v3/PersistedBatchV3.js +131 -29
  115. package/dist/storage/implementation/v3/PersistedBatchV3.js.map +1 -1
  116. package/dist/storage/implementation/v3/SourceRecordStoreV3.d.ts +3 -3
  117. package/dist/storage/implementation/v3/SourceRecordStoreV3.js +13 -11
  118. package/dist/storage/implementation/v3/SourceRecordStoreV3.js.map +1 -1
  119. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.d.ts +26 -14
  120. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js +73 -29
  121. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js.map +1 -1
  122. package/dist/storage/implementation/v3/bucket-format.d.ts +13 -0
  123. package/dist/storage/implementation/v3/bucket-format.js +79 -0
  124. package/dist/storage/implementation/v3/bucket-format.js.map +1 -0
  125. package/dist/storage/implementation/v3/chunking.d.ts +10 -0
  126. package/dist/storage/implementation/v3/chunking.js +30 -0
  127. package/dist/storage/implementation/v3/chunking.js.map +1 -0
  128. package/dist/storage/implementation/v3/compact-utils.d.ts +107 -0
  129. package/dist/storage/implementation/v3/compact-utils.js +216 -0
  130. package/dist/storage/implementation/v3/compact-utils.js.map +1 -0
  131. package/dist/storage/implementation/v3/compaction-constants.d.ts +5 -0
  132. package/dist/storage/implementation/v3/compaction-constants.js +6 -0
  133. package/dist/storage/implementation/v3/compaction-constants.js.map +1 -0
  134. package/dist/storage/implementation/v3/models.d.ts +187 -23
  135. package/dist/storage/implementation/v3/models.js +11 -28
  136. package/dist/storage/implementation/v3/models.js.map +1 -1
  137. package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.d.ts +20 -0
  138. package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js +48 -0
  139. package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js.map +1 -0
  140. package/dist/storage/implementation/v3/object-storage/ObjectStorage.d.ts +33 -0
  141. package/dist/storage/implementation/v3/object-storage/ObjectStorage.js +12 -0
  142. package/dist/storage/implementation/v3/object-storage/ObjectStorage.js.map +1 -0
  143. package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.d.ts +68 -0
  144. package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js +154 -0
  145. package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js.map +1 -0
  146. package/dist/storage/implementation/v3/object-storage/ObjectStorageUsage.d.ts +37 -0
  147. package/dist/storage/implementation/v3/object-storage/ObjectStorageUsage.js +167 -0
  148. package/dist/storage/implementation/v3/object-storage/ObjectStorageUsage.js.map +1 -0
  149. package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.d.ts +67 -0
  150. package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.js +439 -0
  151. package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.js.map +1 -0
  152. package/dist/storage/implementation/v3/source-table-utils.d.ts +63 -0
  153. package/dist/storage/implementation/v3/source-table-utils.js +206 -0
  154. package/dist/storage/implementation/v3/source-table-utils.js.map +1 -0
  155. package/dist/storage/storage-index.d.ts +5 -4
  156. package/dist/storage/storage-index.js +5 -4
  157. package/dist/storage/storage-index.js.map +1 -1
  158. package/dist/types/types.d.ts +71 -3
  159. package/dist/types/types.js +58 -2
  160. package/dist/types/types.js.map +1 -1
  161. package/dist/utils/test-utils.d.ts +1 -2
  162. package/dist/utils/test-utils.js +7 -1
  163. package/dist/utils/test-utils.js.map +1 -1
  164. package/dist/utils/util.d.ts +9 -2
  165. package/dist/utils/util.js +131 -5
  166. package/dist/utils/util.js.map +1 -1
  167. package/package.json +13 -19
  168. package/src/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.ts +55 -0
  169. package/src/storage/MongoBucketStorage.ts +728 -242
  170. package/src/storage/implementation/MongoBucketBatch.ts +196 -91
  171. package/src/storage/implementation/MongoChecksums.ts +93 -153
  172. package/src/storage/implementation/MongoCompactor.ts +106 -631
  173. package/src/storage/implementation/MongoHydrationState.ts +61 -0
  174. package/src/storage/implementation/MongoParameterCompactor.ts +392 -87
  175. package/src/storage/implementation/MongoParsedSyncConfigSet.ts +122 -0
  176. package/src/storage/implementation/MongoPersistedReplicationStream.ts +118 -0
  177. package/src/storage/implementation/MongoPersistedSyncConfigContent.ts +156 -0
  178. package/src/storage/implementation/MongoStorageProvider.ts +48 -4
  179. package/src/storage/implementation/MongoSyncBucketStorage.ts +226 -118
  180. package/src/storage/implementation/MongoSyncRulesLock.ts +28 -12
  181. package/src/storage/implementation/MongoWriteCheckpointAPI.ts +194 -52
  182. package/src/storage/implementation/SyncRuleStateUpdate.ts +13 -6
  183. package/src/storage/implementation/common/MongoSyncBucketStorageCheckpoint.ts +31 -0
  184. package/src/storage/implementation/common/PersistedBatch.ts +83 -15
  185. package/src/storage/implementation/common/VersionedPowerSyncMongoBase.ts +1 -1
  186. package/src/storage/implementation/createMongoSyncBucketStorage.ts +21 -7
  187. package/src/storage/implementation/db.ts +40 -22
  188. package/src/storage/implementation/models.ts +58 -14
  189. package/src/storage/implementation/v1/MongoBucketBatchV1.ts +174 -125
  190. package/src/storage/implementation/v1/MongoChecksumsV1.ts +154 -12
  191. package/src/storage/implementation/v1/MongoCompactorV1.ts +594 -25
  192. package/src/storage/implementation/v1/MongoParameterCompactorV1.ts +25 -9
  193. package/src/storage/implementation/v1/MongoSyncBucketStorageV1.ts +226 -129
  194. package/src/storage/implementation/v1/SingleBucketStoreV1.ts +18 -27
  195. package/src/storage/implementation/v1/VersionedPowerSyncMongoV1.ts +11 -1
  196. package/src/storage/implementation/v1/models.ts +12 -1
  197. package/src/storage/implementation/v3/BucketDataContextV3.ts +32 -0
  198. package/src/storage/implementation/v3/CompactionLease.ts +152 -0
  199. package/src/storage/implementation/v3/MongoBucketBatchV3.ts +502 -324
  200. package/src/storage/implementation/v3/MongoChecksumsV3.ts +250 -32
  201. package/src/storage/implementation/v3/MongoCompactorV3.ts +1439 -70
  202. package/src/storage/implementation/v3/MongoParameterCompactorV3.ts +19 -9
  203. package/src/storage/implementation/v3/MongoStoppedSyncConfigCleanup.ts +473 -0
  204. package/src/storage/implementation/v3/MongoSyncBucketStorageV3.ts +453 -211
  205. package/src/storage/implementation/v3/MongoWriteCheckpointAPIV3.ts +111 -0
  206. package/src/storage/implementation/v3/PersistedBatchV3.ts +169 -45
  207. package/src/storage/implementation/v3/SourceRecordStoreV3.ts +12 -12
  208. package/src/storage/implementation/v3/VersionedPowerSyncMongoV3.ts +99 -38
  209. package/src/storage/implementation/v3/bucket-format.ts +99 -0
  210. package/src/storage/implementation/v3/chunking.ts +40 -0
  211. package/src/storage/implementation/v3/compact-utils.ts +320 -0
  212. package/src/storage/implementation/v3/compaction-constants.ts +5 -0
  213. package/src/storage/implementation/v3/models.ts +228 -58
  214. package/src/storage/implementation/v3/object-storage/BucketDataObjectStorage.ts +62 -0
  215. package/src/storage/implementation/v3/object-storage/ObjectStorage.ts +44 -0
  216. package/src/storage/implementation/v3/object-storage/ObjectStorageLifecycle.ts +182 -0
  217. package/src/storage/implementation/v3/object-storage/ObjectStorageUsage.ts +230 -0
  218. package/src/storage/implementation/v3/object-storage/S3ObjectStorage.ts +573 -0
  219. package/src/storage/implementation/v3/source-table-utils.ts +398 -0
  220. package/src/storage/storage-index.ts +14 -4
  221. package/src/types/types.ts +76 -2
  222. package/src/utils/test-utils.ts +8 -3
  223. package/src/utils/util.ts +188 -7
  224. package/test/src/__snapshots__/storage.test.ts.snap +4 -54
  225. package/test/src/__snapshots__/storage_sync.test.ts.snap +652 -645
  226. package/test/src/cleanup-stopped-sync-configs.test.ts +698 -0
  227. package/test/src/compact-utils.test.ts +226 -0
  228. package/test/src/helpers/MemoryObjectStorage.ts +61 -0
  229. package/test/src/helpers/s3TestFactory.ts +69 -0
  230. package/test/src/object_storage_lifecycle.test.ts +59 -0
  231. package/test/src/object_storage_usage.test.ts +255 -0
  232. package/test/src/parameter_compacting_v1.test.ts +120 -0
  233. package/test/src/parameter_compacting_v3.test.ts +192 -0
  234. package/test/src/parameter_compaction_fence.test.ts +276 -0
  235. package/test/src/setup.ts +6 -1
  236. package/test/src/storage.test.ts +478 -13
  237. package/test/src/storage_compacting.test.ts +2516 -107
  238. package/test/src/storage_object_storage_inline_threshold.test.ts +116 -0
  239. package/test/src/storage_s3_checksums.test.ts +190 -0
  240. package/test/src/storage_s3_compaction_lifecycle.test.ts +543 -0
  241. package/test/src/storage_s3_reading.test.ts +768 -0
  242. package/test/src/storage_s3_writing.test.ts +136 -0
  243. package/test/src/storage_sync.test.ts +1507 -76
  244. package/test/src/storeCurrentData.test.ts +227 -0
  245. package/test/src/util.ts +3 -2
  246. package/tsconfig.json +1 -4
  247. package/tsconfig.tsbuildinfo +1 -1
  248. package/dist/storage/implementation/BucketDefinitionMapping.d.ts +0 -15
  249. package/dist/storage/implementation/BucketDefinitionMapping.js +0 -58
  250. package/dist/storage/implementation/BucketDefinitionMapping.js.map +0 -1
  251. package/dist/storage/implementation/MongoPersistedSyncRules.d.ts +0 -14
  252. package/dist/storage/implementation/MongoPersistedSyncRules.js +0 -67
  253. package/dist/storage/implementation/MongoPersistedSyncRules.js.map +0 -1
  254. package/dist/storage/implementation/MongoPersistedSyncRulesContent.d.ts +0 -29
  255. package/dist/storage/implementation/MongoPersistedSyncRulesContent.js +0 -76
  256. package/dist/storage/implementation/MongoPersistedSyncRulesContent.js.map +0 -1
  257. package/dist/storage/implementation/common/MongoSyncBucketStorageContext.d.ts +0 -13
  258. package/dist/storage/implementation/common/MongoSyncBucketStorageContext.js +0 -2
  259. package/dist/storage/implementation/common/MongoSyncBucketStorageContext.js.map +0 -1
  260. package/dist/storage/implementation/common/SingleBucketStore.d.ts +0 -54
  261. package/dist/storage/implementation/common/SingleBucketStore.js +0 -3
  262. package/dist/storage/implementation/common/SingleBucketStore.js.map +0 -1
  263. package/dist/storage/implementation/v3/MongoParameterLookupV3.d.ts +0 -4
  264. package/dist/storage/implementation/v3/MongoParameterLookupV3.js +0 -9
  265. package/dist/storage/implementation/v3/MongoParameterLookupV3.js.map +0 -1
  266. package/dist/storage/implementation/v3/SingleBucketStoreV3.d.ts +0 -18
  267. package/dist/storage/implementation/v3/SingleBucketStoreV3.js +0 -48
  268. package/dist/storage/implementation/v3/SingleBucketStoreV3.js.map +0 -1
  269. package/src/storage/implementation/BucketDefinitionMapping.ts +0 -75
  270. package/src/storage/implementation/MongoPersistedSyncRules.ts +0 -82
  271. package/src/storage/implementation/MongoPersistedSyncRulesContent.ts +0 -101
  272. package/src/storage/implementation/common/MongoSyncBucketStorageContext.ts +0 -15
  273. package/src/storage/implementation/common/SingleBucketStore.ts +0 -63
  274. package/src/storage/implementation/v3/MongoParameterLookupV3.ts +0 -11
  275. package/src/storage/implementation/v3/SingleBucketStoreV3.ts +0 -68
@@ -0,0 +1,398 @@
1
+ import { ReplicationAssertionError } from '@powersync/lib-services-framework';
2
+ import { BucketDefinitionMapping, ColumnDescriptor, JsonValue, storage } from '@powersync/service-core';
3
+ import {
4
+ BucketDataSource,
5
+ BucketDefinitionId,
6
+ EventDefinitionId,
7
+ HydratedEventDescriptor,
8
+ HydratedSyncConfig,
9
+ MatchingSources,
10
+ ParameterIndexId,
11
+ ParameterIndexLookupCreator,
12
+ SourceTableRef
13
+ } from '@powersync/service-sync-rules';
14
+ import * as bson from 'bson';
15
+ import { ReplicaIdColumn, SourceTableDocumentV3 } from './models.js';
16
+
17
+ export interface SourceTableIdentity {
18
+ schema: string;
19
+ name: string;
20
+ objectId: number | string | undefined;
21
+ replicaIdColumns: ReplicaIdColumn[];
22
+ }
23
+
24
+ export interface SourceTableMembershipIds {
25
+ bucketDataSourceIds: BucketDefinitionId[];
26
+ parameterLookupSourceIds: ParameterIndexId[];
27
+ eventDefinitionIds: EventDefinitionId[];
28
+ }
29
+
30
+ export interface SourceTableDesiredResolution {
31
+ bucketSourceById: Map<BucketDefinitionId, BucketDataSource>;
32
+ parameterLookupSourceById: Map<ParameterIndexId, ParameterIndexLookupCreator>;
33
+ eventDefinitionById: Map<EventDefinitionId, HydratedEventDescriptor>;
34
+ }
35
+
36
+ export interface SourceTableReconciliationContext {
37
+ connectionId: number;
38
+ connectionTag: string;
39
+ identity: SourceTableIdentity;
40
+ storeCurrentData: boolean;
41
+ syncConfig: HydratedSyncConfig;
42
+ mapping: BucketDefinitionMapping;
43
+ desired: SourceTableDesiredResolution;
44
+ /**
45
+ * Candidates the source connector considers safe to reuse.
46
+ */
47
+ sourceCompatibleTables: readonly storage.SourceTableCandidate[];
48
+ /**
49
+ * Source metadata for records created by this resolution.
50
+ */
51
+ newTableSourceMetadata: JsonValue;
52
+ }
53
+
54
+ export interface SourceTableReconciliationPlan {
55
+ /** Retained source tables, with memberships narrowed to the desired set. */
56
+ tables: storage.SourceTable[];
57
+ /** Membership narrowing to persist for retained snapshot-incomplete docs. */
58
+ narrowingUpdates: SourceTableMembershipUpdate[];
59
+ /**
60
+ * Memberships for a new source-table doc covering desired ids no existing doc covers,
61
+ * or null if no new doc is needed.
62
+ */
63
+ newTableMemberships: SourceTableMembershipIds | null;
64
+ /** Identity-overlapping docs that conflict with the current identity and must be dropped. */
65
+ dropDocs: SourceTableDocumentV3[];
66
+ }
67
+
68
+ export interface SourceTableMembershipUpdate {
69
+ id: bson.ObjectId;
70
+ memberships: SourceTableMembershipIds;
71
+ }
72
+
73
+ export interface NewSourceTable {
74
+ doc: SourceTableDocumentV3;
75
+ table: storage.SourceTable;
76
+ }
77
+
78
+ export function sourceTableDesiredResolution(
79
+ syncConfig: HydratedSyncConfig,
80
+ ref: SourceTableRef,
81
+ mapping: BucketDefinitionMapping,
82
+ eventById: ReadonlyMap<EventDefinitionId, HydratedEventDescriptor>
83
+ ): SourceTableDesiredResolution {
84
+ const matchingSources = syncConfig.getMatchingSources(ref);
85
+ return {
86
+ bucketSourceById: new Map(
87
+ matchingSources.bucketDataSources.map((source) => [mapping.bucketSourceId(source), source] as const)
88
+ ),
89
+ parameterLookupSourceById: new Map(
90
+ matchingSources.parameterLookupSources.map((source) => [mapping.parameterLookupId(source), source] as const)
91
+ ),
92
+ eventDefinitionById: new Map([...eventById].filter(([, event]) => event.tableTriggersEvent(ref)))
93
+ };
94
+ }
95
+
96
+ export function planSourceTableReconciliation(
97
+ candidateDocs: SourceTableDocumentV3[],
98
+ context: SourceTableReconciliationContext
99
+ ): SourceTableReconciliationPlan {
100
+ return new SourceTableReconciliationPlanner(context).plan(candidateDocs);
101
+ }
102
+
103
+ function sameStringArray(left: string[], right: string[]) {
104
+ return left.length == right.length && left.every((value, index) => value == right[index]);
105
+ }
106
+
107
+ function matchingSourcesFor(
108
+ desired: SourceTableDesiredResolution,
109
+ memberships: SourceTableMembershipIds
110
+ ): MatchingSources {
111
+ return {
112
+ bucketDataSources: memberships.bucketDataSourceIds.map((id) => desired.bucketSourceById.get(id)!),
113
+ parameterLookupSources: memberships.parameterLookupSourceIds.map((id) => desired.parameterLookupSourceById.get(id)!)
114
+ };
115
+ }
116
+
117
+ function intersectMembershipIds(
118
+ doc: SourceTableDocumentV3,
119
+ desired: SourceTableDesiredResolution
120
+ ): SourceTableMembershipIds {
121
+ return {
122
+ bucketDataSourceIds: doc.bucket_data_source_ids.filter((id) => desired.bucketSourceById.has(id)),
123
+ parameterLookupSourceIds: doc.parameter_lookup_source_ids.filter((id) => desired.parameterLookupSourceById.has(id)),
124
+ eventDefinitionIds: doc.event_definition_ids.filter((id) => desired.eventDefinitionById.has(id))
125
+ };
126
+ }
127
+
128
+ function hasMembershipIds(memberships: SourceTableMembershipIds) {
129
+ return (
130
+ memberships.bucketDataSourceIds.length > 0 ||
131
+ memberships.parameterLookupSourceIds.length > 0 ||
132
+ memberships.eventDefinitionIds.length > 0
133
+ );
134
+ }
135
+
136
+ function sameMembershipIds(doc: SourceTableDocumentV3, memberships: SourceTableMembershipIds) {
137
+ return (
138
+ sameStringArray(doc.bucket_data_source_ids, memberships.bucketDataSourceIds) &&
139
+ sameStringArray(doc.parameter_lookup_source_ids, memberships.parameterLookupSourceIds) &&
140
+ sameStringArray(doc.event_definition_ids, memberships.eventDefinitionIds)
141
+ );
142
+ }
143
+
144
+ class SourceTableReconciliationPlanner {
145
+ private readonly coveredBucketDataSourceIds = new Set<string>();
146
+ private readonly coveredParameterLookupSourceIds = new Set<string>();
147
+ private readonly coveredEventDefinitionIds = new Set<string>();
148
+ private readonly tables: storage.SourceTable[] = [];
149
+ private readonly narrowingUpdates: SourceTableMembershipUpdate[] = [];
150
+
151
+ constructor(private readonly context: SourceTableReconciliationContext) {}
152
+
153
+ plan(candidateDocs: SourceTableDocumentV3[]): SourceTableReconciliationPlan {
154
+ for (const doc of candidateDocs) {
155
+ if (this.isCompatible(doc)) {
156
+ this.retainDoc(doc);
157
+ }
158
+ }
159
+
160
+ return {
161
+ tables: this.tables,
162
+ narrowingUpdates: this.narrowingUpdates,
163
+ newTableMemberships: this.newTableMemberships(),
164
+ // Compatible records remain available for reuse even when not needed by this config.
165
+ dropDocs: candidateDocs.filter((doc) => !this.isCompatible(doc))
166
+ };
167
+ }
168
+
169
+ private isCompatible(doc: SourceTableDocumentV3) {
170
+ return this.compatibleTableFor(doc) != null;
171
+ }
172
+
173
+ private compatibleTableFor(doc: SourceTableDocumentV3): storage.SourceTableCandidate | undefined {
174
+ return this.context.sourceCompatibleTables.find((table) => storage.sourceTableIdEquals(table.id, doc._id));
175
+ }
176
+
177
+ private retainDoc(doc: SourceTableDocumentV3) {
178
+ const memberships = intersectMembershipIds(doc, this.context.desired);
179
+ const coversDesiredMembership = hasMembershipIds(memberships);
180
+
181
+ this.recordCoverage(doc, memberships);
182
+ this.planNarrowingUpdate(doc, memberships, coversDesiredMembership);
183
+
184
+ if (coversDesiredMembership) {
185
+ this.tables.push(this.sourceTableFor(doc, memberships));
186
+ }
187
+ }
188
+
189
+ private recordCoverage(doc: SourceTableDocumentV3, memberships: SourceTableMembershipIds) {
190
+ this.addCoverage(doc, 'bucket data source', this.coveredBucketDataSourceIds, memberships.bucketDataSourceIds);
191
+ this.addCoverage(
192
+ doc,
193
+ 'parameter lookup source',
194
+ this.coveredParameterLookupSourceIds,
195
+ memberships.parameterLookupSourceIds
196
+ );
197
+ this.addCoverage(doc, 'event definition', this.coveredEventDefinitionIds, memberships.eventDefinitionIds);
198
+ }
199
+
200
+ // Membership sets must be pairwise disjoint across the docs of one physical table:
201
+ // each desired id is covered by exactly one doc, so each definition is evaluated through
202
+ // only one SourceTable for a physical row. Different docs may own different event ids.
203
+ // The algorithm maintains this (new docs only get uncovered ids, narrowing only removes ids) -
204
+ // overlap means the persisted state is corrupt.
205
+ private addCoverage(doc: SourceTableDocumentV3, kind: string, covered: Set<string>, ids: string[]) {
206
+ const { schema, name } = this.context.identity;
207
+ for (const id of ids) {
208
+ if (covered.has(id)) {
209
+ throw new ReplicationAssertionError(
210
+ `Source table ${doc._id} duplicates coverage of ${kind} ${id} for ${schema}.${name}`
211
+ );
212
+ }
213
+ covered.add(id);
214
+ }
215
+ }
216
+
217
+ private planNarrowingUpdate(
218
+ doc: SourceTableDocumentV3,
219
+ memberships: SourceTableMembershipIds,
220
+ coversDesiredMembership: boolean
221
+ ) {
222
+ const shouldNarrow = coversDesiredMembership && !doc.snapshot_done && !sameMembershipIds(doc, memberships);
223
+
224
+ if (!shouldNarrow) {
225
+ return;
226
+ }
227
+
228
+ this.narrowingUpdates.push({
229
+ id: doc._id,
230
+ memberships
231
+ });
232
+ }
233
+
234
+ private newTableMemberships(): SourceTableMembershipIds | null {
235
+ const { desired } = this.context;
236
+ const uncovered: SourceTableMembershipIds = {
237
+ bucketDataSourceIds: [...desired.bucketSourceById.keys()].filter(
238
+ (id) => !this.coveredBucketDataSourceIds.has(id)
239
+ ),
240
+ parameterLookupSourceIds: [...desired.parameterLookupSourceById.keys()].filter(
241
+ (id) => !this.coveredParameterLookupSourceIds.has(id)
242
+ ),
243
+ eventDefinitionIds: [...desired.eventDefinitionById.keys()].filter(
244
+ (id) => !this.coveredEventDefinitionIds.has(id)
245
+ )
246
+ };
247
+ if (hasMembershipIds(uncovered)) {
248
+ return uncovered;
249
+ }
250
+ return null;
251
+ }
252
+
253
+ private sourceTableFor(doc: SourceTableDocumentV3, memberships: SourceTableMembershipIds): storage.SourceTable {
254
+ const { connectionTag, syncConfig, mapping, desired, storeCurrentData } = this.context;
255
+ const built = sourceTableFromDocument(
256
+ doc,
257
+ connectionTag,
258
+ syncConfig,
259
+ mapping,
260
+ desired.eventDefinitionById,
261
+ matchingSourcesFor(desired, memberships),
262
+ memberships
263
+ );
264
+ // Use any metadata update returned by the reconciler.
265
+ const resolved = this.compatibleTableFor(doc);
266
+ const table = resolved == null ? built : built.withSourceMetadata(resolved.sourceMetadata);
267
+ table.storeCurrentData = storeCurrentData;
268
+ return table;
269
+ }
270
+ }
271
+
272
+ export function overlappingSourceTableFilter(
273
+ connectionId: number,
274
+ identity: Pick<SourceTableIdentity, 'schema' | 'name' | 'objectId'>
275
+ ): Record<string, unknown> {
276
+ const clauses = [{ schema_name: identity.schema, table_name: identity.name }] as Record<string, unknown>[];
277
+ if (identity.objectId != null) {
278
+ clauses.push({ relation_id: identity.objectId });
279
+ }
280
+
281
+ return {
282
+ connection_id: connectionId,
283
+ $or: clauses
284
+ };
285
+ }
286
+
287
+ export function createNewSourceTable(
288
+ id: bson.ObjectId,
289
+ memberships: SourceTableMembershipIds,
290
+ context: SourceTableReconciliationContext
291
+ ): NewSourceTable {
292
+ const {
293
+ connectionId,
294
+ connectionTag,
295
+ identity,
296
+ syncConfig,
297
+ mapping,
298
+ desired,
299
+ storeCurrentData,
300
+ newTableSourceMetadata
301
+ } = context;
302
+ const doc: SourceTableDocumentV3 = {
303
+ _id: id,
304
+ connection_id: connectionId,
305
+ relation_id: identity.objectId,
306
+ schema_name: identity.schema,
307
+ table_name: identity.name,
308
+ replica_id_columns: identity.replicaIdColumns,
309
+ snapshot_done: false,
310
+ snapshot_status: undefined,
311
+ bucket_data_source_ids: memberships.bucketDataSourceIds,
312
+ parameter_lookup_source_ids: memberships.parameterLookupSourceIds,
313
+ event_definition_ids: memberships.eventDefinitionIds,
314
+ // Records created together share the same source metadata.
315
+ source_metadata: newTableSourceMetadata
316
+ };
317
+ const table = sourceTableFromDocument(
318
+ doc,
319
+ connectionTag,
320
+ syncConfig,
321
+ mapping,
322
+ desired.eventDefinitionById,
323
+ matchingSourcesFor(desired, memberships),
324
+ memberships
325
+ );
326
+ table.storeCurrentData = storeCurrentData;
327
+
328
+ return { doc, table };
329
+ }
330
+
331
+ function sourceTableMembershipsFromDocument(
332
+ doc: SourceTableDocumentV3,
333
+ syncConfig: HydratedSyncConfig,
334
+ mapping: BucketDefinitionMapping
335
+ ): MatchingSources {
336
+ const bucketDataSourceIds = new Set(doc.bucket_data_source_ids);
337
+ const parameterLookupSourceIds = new Set(doc.parameter_lookup_source_ids);
338
+
339
+ return {
340
+ bucketDataSources: syncConfig.bucketDataSources.filter((source) =>
341
+ bucketDataSourceIds.has(mapping.bucketSourceId(source))
342
+ ),
343
+ parameterLookupSources: syncConfig.bucketParameterLookupSources.filter((source) =>
344
+ parameterLookupSourceIds.has(mapping.parameterLookupId(source))
345
+ )
346
+ };
347
+ }
348
+
349
+ export function sourceTableFromDocument(
350
+ doc: SourceTableDocumentV3,
351
+ connectionTag: string,
352
+ syncConfig: HydratedSyncConfig,
353
+ mapping: BucketDefinitionMapping,
354
+ eventById: ReadonlyMap<EventDefinitionId, HydratedEventDescriptor>,
355
+ memberships?: MatchingSources,
356
+ membershipIds?: SourceTableMembershipIds
357
+ ): storage.SourceTable {
358
+ const resolvedMemberships = memberships ?? sourceTableMembershipsFromDocument(doc, syncConfig, mapping);
359
+ const resolvedMembershipIds = membershipIds ?? {
360
+ bucketDataSourceIds: resolvedMemberships.bucketDataSources.map((source) => mapping.bucketSourceId(source)),
361
+ parameterLookupSourceIds: resolvedMemberships.parameterLookupSources.map((source) =>
362
+ mapping.parameterLookupId(source)
363
+ ),
364
+ eventDefinitionIds: doc.event_definition_ids.filter((id) => eventById.has(id))
365
+ };
366
+ const table = new storage.SourceTable({
367
+ id: doc._id,
368
+ ref: {
369
+ connectionTag,
370
+ schema: doc.schema_name,
371
+ name: doc.table_name
372
+ },
373
+ objectId: doc.relation_id,
374
+ replicaIdColumns:
375
+ doc.replica_id_columns?.map(
376
+ (column) => ({ name: column.name, typeId: column.type_oid, type: column.type }) satisfies ColumnDescriptor
377
+ ) ?? [],
378
+ snapshotComplete: doc.snapshot_done,
379
+ bucketDataSources: resolvedMemberships.bucketDataSources,
380
+ parameterLookupSources: resolvedMemberships.parameterLookupSources,
381
+ bucketDataSourceIds: new Set(resolvedMembershipIds.bucketDataSourceIds),
382
+ parameterLookupSourceIds: new Set(resolvedMembershipIds.parameterLookupSourceIds),
383
+ eventDefinitionIds: new Set(resolvedMembershipIds.eventDefinitionIds),
384
+ sourceMetadata: doc.source_metadata ?? null
385
+ });
386
+ table.syncData = table.bucketDataSources.length > 0;
387
+ table.syncParameters = table.parameterLookupSources.length > 0;
388
+ table.syncEvent = table.eventDefinitionIds!.size > 0;
389
+ table.snapshotStatus =
390
+ doc.snapshot_status == null
391
+ ? undefined
392
+ : {
393
+ lastKey: doc.snapshot_status.last_key?.buffer ?? null,
394
+ totalEstimatedCount: doc.snapshot_status.total_estimated_count,
395
+ replicatedCount: doc.snapshot_status.replicated_count
396
+ };
397
+ return table;
398
+ }
@@ -1,17 +1,27 @@
1
1
  export * as test_utils from '../utils/test-utils.js';
2
2
  export * from '../utils/util.js';
3
- export * from './implementation/BucketDefinitionMapping.js';
4
3
  export * from './implementation/common/PersistedBatch.js';
5
4
  export * from './implementation/createMongoSyncBucketStorage.js';
6
5
  export * from './implementation/db.js';
7
6
  export * from './implementation/models.js';
8
7
  export * from './implementation/MongoIdSequence.js';
9
- export * from './implementation/MongoPersistedSyncRules.js';
10
- export * from './implementation/MongoPersistedSyncRulesContent.js';
8
+ export * from './implementation/MongoParsedSyncConfigSet.js';
9
+ export * from './implementation/MongoPersistedReplicationStream.js';
11
10
  export * from './implementation/MongoStorageProvider.js';
12
11
  export * from './implementation/MongoSyncRulesLock.js';
13
12
  export * from './implementation/OperationBatch.js';
14
13
  export * from './implementation/v1/models.js';
15
- export * from './implementation/v3/models.js';
14
+ export { loadBucketDataDocument, serializeBucketData } from './implementation/v3/bucket-format.js';
15
+ export {
16
+ BucketDataDocumentV3,
17
+ BucketOperation,
18
+ ObjectStorageUsageDocument,
19
+ RecordedLookupV3,
20
+ ReplicationStreamDocumentV3,
21
+ SyncConfigDefinition,
22
+ SyncRuleConfigStateV3,
23
+ taggedBucketParameterDocumentToTagged
24
+ } from './implementation/v3/models.js';
25
+ export * from './implementation/v3/object-storage/ObjectStorageUsage.js';
16
26
  export * from './MongoBucketStorage.js';
17
27
  export * from './MongoReportStorage.js';
@@ -1,16 +1,90 @@
1
1
  import * as lib_mongo from '@powersync/lib-service-mongodb';
2
+ import { ErrorCode, ServiceError } from '@powersync/lib-services-framework';
2
3
  import * as service_types from '@powersync/service-types';
3
4
  import * as t from 'ts-codec';
4
5
 
5
- export const MongoStorageConfig = lib_mongo.BaseMongoConfig.and(
6
+ /**
7
+ * AWS defaults mode, as used by the AWS SDK.
8
+ *
9
+ * This is the baseline for the object storage request timeouts, so that they do not each need to be
10
+ * configured individually.
11
+ *
12
+ * The SDK's `legacy` and `auto` modes are not selectable here: `legacy` defines no timeouts at all,
13
+ * and `auto` makes the timeouts depend on where the process happens to be running. Both are still
14
+ * handled when they come from the AWS environment, and are then treated as `standard`.
15
+ */
16
+ export const S3DefaultsMode = service_types.enumLiteral('standard', 'in-region', 'cross-region', 'mobile');
17
+
18
+ export type S3DefaultsMode = t.Encoded<typeof S3DefaultsMode>;
19
+
20
+ const S3ObjectStorageConfig = t.object({
21
+ type: t.literal('s3'),
22
+ bucket: t.string,
23
+ region: t.string.optional(),
24
+ prefix: t.string.optional(),
25
+ endpoint: t.string.optional(),
26
+ force_path_style: t.boolean.optional(),
27
+ access_key_id: t.string.optional(),
28
+ secret_access_key: t.string.optional(),
29
+ concurrency_limit: t.number.optional(),
30
+ // Defaults to the AWS_DEFAULTS_MODE environment variable.
31
+ defaults_mode: S3DefaultsMode.optional(),
32
+ // Chunks whose BSON-serialized size falls below this byte threshold
33
+ // stay inline in MongoDB instead of being offloaded to S3. Default 1024.
34
+ inline_threshold_bytes: t.number.optional()
35
+ });
36
+
37
+ export const MongoStorageReadPreference = service_types.enumLiteral(
38
+ 'primary',
39
+ 'primaryPreferred',
40
+ 'secondary',
41
+ 'secondaryPreferred',
42
+ 'nearest'
43
+ );
44
+
45
+ export type MongoStorageReadPreference = t.Encoded<typeof MongoStorageReadPreference>;
46
+
47
+ export const MongoStorageConfig = service_types.configFile.BaseStorageConfig.and(lib_mongo.BaseMongoConfig).and(
6
48
  t.object({
7
- // Add any mongo specific storage settings here in future
49
+ /**
50
+ * Read preference for bulk checksum and bucket data reads.
51
+ *
52
+ * If unset, MongoDB driver defaults are used for backwards compatibility.
53
+ *
54
+ * This is an experimental option, and may be removed in a future release.
55
+ */
56
+ bulk_read_preference: MongoStorageReadPreference.optional(),
57
+ /**
58
+ * Throttle clear operations after sync config deploys, by pausing between batches.
59
+ * The rate produces a pause proportional to the previous batch duration.
60
+ *
61
+ * Increase this to reduce impact of clear operations on the storage cluster.
62
+ * Use 0 to clear as fast as possible.
63
+ *
64
+ * Defaults to 0.2.
65
+ */
66
+ clear_batch_throttle_rate: t.number.optional(),
67
+
68
+ object_storage: S3ObjectStorageConfig.optional()
8
69
  })
9
70
  );
10
71
 
11
72
  export type MongoStorageConfig = t.Encoded<typeof MongoStorageConfig>;
12
73
  export type MongoStorageConfigDecoded = t.Decoded<typeof MongoStorageConfig>;
13
74
 
75
+ export const DEFAULT_CLEAR_BATCH_THROTTLE_RATE = 0.2;
76
+
77
+ export function normalizeClearBatchThrottleRate(value: number | undefined): number {
78
+ const rate = value ?? DEFAULT_CLEAR_BATCH_THROTTLE_RATE;
79
+ if (!Number.isFinite(rate) || rate < 0 || rate > 20) {
80
+ throw new ServiceError(
81
+ ErrorCode.PSYNC_S3201,
82
+ 'storage.clear_batch_throttle_rate must be a finite number between 0 and 20'
83
+ );
84
+ }
85
+ return rate;
86
+ }
87
+
14
88
  export function isMongoStorageConfig(
15
89
  config: service_types.configFile.GenericStorageConfig
16
90
  ): config is MongoStorageConfig {
@@ -7,8 +7,7 @@ import { PowerSyncMongo } from '../storage/implementation/db.js';
7
7
  export type MongoTestStorageOptions = {
8
8
  url: string;
9
9
  isCI: boolean;
10
- internalOptions?: MongoBucketStorageOptions;
11
- };
10
+ } & Omit<MongoBucketStorageOptions, 'replicationStreamNamePrefix'>;
12
11
 
13
12
  export function mongoTestStorageFactoryGenerator(factoryOptions: MongoTestStorageOptions) {
14
13
  return {
@@ -27,7 +26,13 @@ export function mongoTestStorageFactoryGenerator(factoryOptions: MongoTestStorag
27
26
  await db.clear();
28
27
  }
29
28
 
30
- return new MongoBucketStorage(db, { slot_name_prefix: 'test_' }, factoryOptions.internalOptions);
29
+ return new MongoBucketStorage(db, {
30
+ replicationStreamNamePrefix: 'test_',
31
+ checksumOptions: factoryOptions.checksumOptions,
32
+ supportsMultipleSyncConfigs: factoryOptions.supportsMultipleSyncConfigs,
33
+ objectStorage: factoryOptions.objectStorage,
34
+ inlineThresholdBytes: factoryOptions.inlineThresholdBytes
35
+ });
31
36
  },
32
37
  tableIdStrings: false
33
38
  };