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

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 (140) hide show
  1. package/CHANGELOG.md +52 -6
  2. package/dist/storage/MongoBucketStorage.d.ts +11 -2
  3. package/dist/storage/MongoBucketStorage.js +43 -13
  4. package/dist/storage/MongoBucketStorage.js.map +1 -1
  5. package/dist/storage/implementation/MongoBucketBatch.d.ts +24 -10
  6. package/dist/storage/implementation/MongoBucketBatch.js +134 -89
  7. package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
  8. package/dist/storage/implementation/MongoCompactor.d.ts +2 -0
  9. package/dist/storage/implementation/MongoCompactor.js.map +1 -1
  10. package/dist/storage/implementation/MongoIdSequence.d.ts +10 -1
  11. package/dist/storage/implementation/MongoIdSequence.js +14 -1
  12. package/dist/storage/implementation/MongoIdSequence.js.map +1 -1
  13. package/dist/storage/implementation/MongoOpIdAllocator.d.ts +27 -0
  14. package/dist/storage/implementation/MongoOpIdAllocator.js +97 -0
  15. package/dist/storage/implementation/MongoOpIdAllocator.js.map +1 -0
  16. package/dist/storage/implementation/MongoParsedSyncConfigSet.js +6 -2
  17. package/dist/storage/implementation/MongoParsedSyncConfigSet.js.map +1 -1
  18. package/dist/storage/implementation/MongoPersistedReplicationStream.d.ts +2 -1
  19. package/dist/storage/implementation/MongoPersistedReplicationStream.js +7 -4
  20. package/dist/storage/implementation/MongoPersistedReplicationStream.js.map +1 -1
  21. package/dist/storage/implementation/MongoPersistedSyncConfigContent.d.ts +3 -3
  22. package/dist/storage/implementation/MongoPersistedSyncConfigContent.js +6 -6
  23. package/dist/storage/implementation/MongoPersistedSyncConfigContent.js.map +1 -1
  24. package/dist/storage/implementation/MongoStorageProvider.js +5 -3
  25. package/dist/storage/implementation/MongoStorageProvider.js.map +1 -1
  26. package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +5 -0
  27. package/dist/storage/implementation/MongoSyncBucketStorage.js +17 -0
  28. package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
  29. package/dist/storage/implementation/MongoSyncRulesLock.d.ts +26 -2
  30. package/dist/storage/implementation/MongoSyncRulesLock.js +38 -1
  31. package/dist/storage/implementation/MongoSyncRulesLock.js.map +1 -1
  32. package/dist/storage/implementation/MongoWriteBatch.d.ts +49 -0
  33. package/dist/storage/implementation/MongoWriteBatch.js +149 -0
  34. package/dist/storage/implementation/MongoWriteBatch.js.map +1 -0
  35. package/dist/storage/implementation/MongoWriteCheckpointAPI.js +2 -2
  36. package/dist/storage/implementation/MongoWriteCheckpointAPI.js.map +1 -1
  37. package/dist/storage/implementation/common/PersistedBatch.d.ts +5 -4
  38. package/dist/storage/implementation/common/PersistedBatch.js +6 -4
  39. package/dist/storage/implementation/common/PersistedBatch.js.map +1 -1
  40. package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.d.ts +3 -0
  41. package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js +3 -0
  42. package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js.map +1 -1
  43. package/dist/storage/implementation/db.d.ts +5 -0
  44. package/dist/storage/implementation/db.js +14 -0
  45. package/dist/storage/implementation/db.js.map +1 -1
  46. package/dist/storage/implementation/v1/MongoBucketBatchV1.d.ts +5 -0
  47. package/dist/storage/implementation/v1/MongoBucketBatchV1.js +149 -139
  48. package/dist/storage/implementation/v1/MongoBucketBatchV1.js.map +1 -1
  49. package/dist/storage/implementation/v1/MongoCompactorV1.d.ts +2 -1
  50. package/dist/storage/implementation/v1/MongoCompactorV1.js +23 -17
  51. package/dist/storage/implementation/v1/MongoCompactorV1.js.map +1 -1
  52. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js +1 -1
  53. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js.map +1 -1
  54. package/dist/storage/implementation/v1/PersistedBatchV1.d.ts +7 -5
  55. package/dist/storage/implementation/v1/PersistedBatchV1.js +22 -28
  56. package/dist/storage/implementation/v1/PersistedBatchV1.js.map +1 -1
  57. package/dist/storage/implementation/v3/MongoBucketBatchV3.d.ts +6 -1
  58. package/dist/storage/implementation/v3/MongoBucketBatchV3.js +148 -162
  59. package/dist/storage/implementation/v3/MongoBucketBatchV3.js.map +1 -1
  60. package/dist/storage/implementation/v3/MongoCompactorV3.d.ts +10 -4
  61. package/dist/storage/implementation/v3/MongoCompactorV3.js +175 -76
  62. package/dist/storage/implementation/v3/MongoCompactorV3.js.map +1 -1
  63. package/dist/storage/implementation/v3/PersistedBatchV3.d.ts +12 -8
  64. package/dist/storage/implementation/v3/PersistedBatchV3.js +25 -32
  65. package/dist/storage/implementation/v3/PersistedBatchV3.js.map +1 -1
  66. package/dist/storage/implementation/v3/compact-utils.d.ts +3 -2
  67. package/dist/storage/implementation/v3/compact-utils.js +12 -5
  68. package/dist/storage/implementation/v3/compact-utils.js.map +1 -1
  69. package/dist/storage/implementation/v3/models.d.ts +1 -1
  70. package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js +8 -1
  71. package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js.map +1 -1
  72. package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.d.ts +3 -3
  73. package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js +7 -9
  74. package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js.map +1 -1
  75. package/dist/storage/implementation/v3/object-storage/ObjectStorageUsage.d.ts +3 -2
  76. package/dist/storage/implementation/v3/object-storage/ObjectStorageUsage.js +4 -7
  77. package/dist/storage/implementation/v3/object-storage/ObjectStorageUsage.js.map +1 -1
  78. package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.js +21 -3
  79. package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.js.map +1 -1
  80. package/dist/types/types.d.ts +5 -0
  81. package/dist/types/types.js +12 -0
  82. package/dist/types/types.js.map +1 -1
  83. package/dist/utils/test-utils.d.ts +4 -2
  84. package/dist/utils/test-utils.js +7 -4
  85. package/dist/utils/test-utils.js.map +1 -1
  86. package/package.json +6 -6
  87. package/src/storage/MongoBucketStorage.ts +54 -13
  88. package/src/storage/implementation/MongoBucketBatch.ts +205 -111
  89. package/src/storage/implementation/MongoCompactor.ts +2 -0
  90. package/src/storage/implementation/MongoIdSequence.ts +21 -1
  91. package/src/storage/implementation/MongoOpIdAllocator.ts +105 -0
  92. package/src/storage/implementation/MongoParsedSyncConfigSet.ts +12 -1
  93. package/src/storage/implementation/MongoPersistedReplicationStream.ts +12 -4
  94. package/src/storage/implementation/MongoPersistedSyncConfigContent.ts +48 -31
  95. package/src/storage/implementation/MongoStorageProvider.ts +13 -3
  96. package/src/storage/implementation/MongoSyncBucketStorage.ts +19 -0
  97. package/src/storage/implementation/MongoSyncRulesLock.ts +56 -3
  98. package/src/storage/implementation/MongoWriteBatch.ts +172 -0
  99. package/src/storage/implementation/MongoWriteCheckpointAPI.ts +4 -2
  100. package/src/storage/implementation/common/PersistedBatch.ts +12 -8
  101. package/src/storage/implementation/common/VersionedPowerSyncMongoBase.ts +4 -0
  102. package/src/storage/implementation/db.ts +15 -0
  103. package/src/storage/implementation/models.ts +1 -0
  104. package/src/storage/implementation/v1/MongoBucketBatchV1.ts +167 -160
  105. package/src/storage/implementation/v1/MongoCompactorV1.ts +29 -26
  106. package/src/storage/implementation/v1/MongoSyncBucketStorageV1.ts +1 -1
  107. package/src/storage/implementation/v1/PersistedBatchV1.ts +25 -30
  108. package/src/storage/implementation/v3/MongoBucketBatchV3.ts +217 -242
  109. package/src/storage/implementation/v3/MongoCompactorV3.ts +284 -108
  110. package/src/storage/implementation/v3/PersistedBatchV3.ts +36 -36
  111. package/src/storage/implementation/v3/compact-utils.ts +16 -7
  112. package/src/storage/implementation/v3/models.ts +1 -1
  113. package/src/storage/implementation/v3/object-storage/BucketDataObjectStorage.ts +8 -1
  114. package/src/storage/implementation/v3/object-storage/ObjectStorageLifecycle.ts +11 -10
  115. package/src/storage/implementation/v3/object-storage/ObjectStorageUsage.ts +8 -9
  116. package/src/storage/implementation/v3/object-storage/S3ObjectStorage.ts +23 -3
  117. package/src/types/types.ts +18 -0
  118. package/src/utils/test-utils.ts +9 -5
  119. package/test/src/__snapshots__/storage_sync.test.ts.snap +12 -12
  120. package/test/src/chunk_compaction_config.test.ts +38 -0
  121. package/test/src/cleanup-stopped-sync-configs.test.ts +19 -13
  122. package/test/src/compact-utils.test.ts +33 -8
  123. package/test/src/concurrent_writers.test.ts +599 -0
  124. package/test/src/connection_config.test.ts +159 -0
  125. package/test/src/helpers/concurrentWriter.mjs +29 -0
  126. package/test/src/helpers/s3TestFactory.ts +12 -12
  127. package/test/src/object_storage_usage.test.ts +18 -5
  128. package/test/src/parameter_compacting_v1.test.ts +2 -2
  129. package/test/src/parameter_compacting_v3.test.ts +2 -2
  130. package/test/src/parameter_compaction_fence.test.ts +3 -3
  131. package/test/src/storage.test.ts +15 -10
  132. package/test/src/storage_compacting.test.ts +397 -23
  133. package/test/src/storage_object_storage_inline_threshold.test.ts +3 -3
  134. package/test/src/storage_s3_checksums.test.ts +4 -4
  135. package/test/src/storage_s3_compaction_lifecycle.test.ts +8 -8
  136. package/test/src/storage_s3_reading.test.ts +51 -5
  137. package/test/src/storage_s3_writing.test.ts +3 -3
  138. package/test/src/storage_sync.test.ts +55 -47
  139. package/test/src/storeCurrentData.test.ts +5 -5
  140. package/tsconfig.tsbuildinfo +1 -1
@@ -2,7 +2,7 @@ import { MongoSyncBucketStorageV3 } from '@module/storage/implementation/v3/Mong
2
2
  import { ObjectStorageLifecycle } from '@module/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js';
3
3
  import { mongoTestStorageFactoryGenerator } from '@module/utils/test-utils.js';
4
4
  import { storage, updateSyncRulesFromYaml } from '@powersync/service-core';
5
- import { test_utils } from '@powersync/service-core-tests';
5
+ import { getTestStorage, test_utils } from '@powersync/service-core-tests';
6
6
  import * as bson from 'bson';
7
7
  import { describe, expect, test } from 'vitest';
8
8
  import { VersionedPowerSyncMongoV3 } from '../../src/storage/implementation/v3/VersionedPowerSyncMongoV3.js';
@@ -78,7 +78,7 @@ streams:
78
78
  { storageVersion: 3 }
79
79
  )
80
80
  );
81
- const firstStorage = factory.getInstance(first) as MongoSyncBucketStorageV3;
81
+ const firstStorage = (await getTestStorage(factory, first)) as MongoSyncBucketStorageV3;
82
82
  const db = firstStorage.db as VersionedPowerSyncMongoV3;
83
83
  await using firstWriter = await firstStorage.createWriter(test_utils.BATCH_OPTIONS);
84
84
 
@@ -155,7 +155,7 @@ streams:
155
155
  );
156
156
  expect(second.replicationStreamId).toBe(first.replicationStreamId);
157
157
  const replicatingStreams = await factory.getReplicatingReplicationStreams();
158
- const secondStorage = factory.getInstance(replicatingStreams[0]) as MongoSyncBucketStorageV3;
158
+ const secondStorage = (await getTestStorage(factory, replicatingStreams[0])) as MongoSyncBucketStorageV3;
159
159
  await using secondWriter = await secondStorage.createWriter(test_utils.BATCH_OPTIONS);
160
160
  await secondWriter.markAllSnapshotDone('2/1');
161
161
  await secondWriter.commit('2/1');
@@ -218,7 +218,7 @@ streams:
218
218
  { storageVersion: 3 }
219
219
  )
220
220
  );
221
- const firstStorage = factory.getInstance(first) as MongoSyncBucketStorageV3;
221
+ const firstStorage = (await getTestStorage(factory, first)) as MongoSyncBucketStorageV3;
222
222
  const db = firstStorage.db as VersionedPowerSyncMongoV3;
223
223
  await using firstWriter = await firstStorage.createWriter(test_utils.BATCH_OPTIONS);
224
224
  const resolved = await firstWriter.resolveTables({
@@ -266,7 +266,7 @@ streams:
266
266
  expect(secondDefinitionId).toBe(projectDefinitionId);
267
267
 
268
268
  const replicatingStreams = await factory.getReplicatingReplicationStreams();
269
- const secondStorage = factory.getInstance(replicatingStreams[0]) as MongoSyncBucketStorageV3;
269
+ const secondStorage = (await getTestStorage(factory, replicatingStreams[0])) as MongoSyncBucketStorageV3;
270
270
  await using secondWriter = await secondStorage.createWriter(test_utils.BATCH_OPTIONS);
271
271
  await secondWriter.markAllSnapshotDone('2/1');
272
272
  await secondWriter.commit('2/1');
@@ -289,7 +289,10 @@ streams:
289
289
  expect(await collectionExists(db, ownerBucketDataCollection)).toBe(false);
290
290
  expect(await collectionExists(db, sourceRecordsCollection)).toBe(true);
291
291
 
292
- const activeStorage = (await factory.getActiveSyncConfig())!.storage as MongoSyncBucketStorageV3;
292
+ const activeStorage = (await getTestStorage(
293
+ factory,
294
+ (await factory.getActiveSyncConfig())!.replicationStream
295
+ )) as MongoSyncBucketStorageV3;
293
296
  await using activeWriter = await activeStorage.createWriter(test_utils.BATCH_OPTIONS);
294
297
  const activeTable = (
295
298
  await activeWriter.resolveTables({
@@ -343,7 +346,7 @@ event_definitions:
343
346
  { storageVersion: 3 }
344
347
  )
345
348
  );
346
- const firstStorage = factory.getInstance(first) as MongoSyncBucketStorageV3;
349
+ const firstStorage = (await getTestStorage(factory, first)) as MongoSyncBucketStorageV3;
347
350
  const db = firstStorage.db as VersionedPowerSyncMongoV3;
348
351
  await using firstWriter = await firstStorage.createWriter(test_utils.BATCH_OPTIONS);
349
352
  const resolved = await firstWriter.resolveTables({
@@ -402,7 +405,7 @@ event_definitions:
402
405
  expect(second.replicationStreamId).toBe(first.replicationStreamId);
403
406
 
404
407
  const replicatingStreams = await factory.getReplicatingReplicationStreams();
405
- const secondStorage = factory.getInstance(replicatingStreams[0]) as MongoSyncBucketStorageV3;
408
+ const secondStorage = (await getTestStorage(factory, replicatingStreams[0])) as MongoSyncBucketStorageV3;
406
409
  await using secondWriter = await secondStorage.createWriter(test_utils.BATCH_OPTIONS);
407
410
  await secondWriter.markAllSnapshotDone('2/1');
408
411
  await secondWriter.commit('2/1');
@@ -466,7 +469,7 @@ event_definitions:
466
469
  { storageVersion: 3 }
467
470
  )
468
471
  );
469
- const firstStorage = factory.getInstance(first) as MongoSyncBucketStorageV3;
472
+ const firstStorage = (await getTestStorage(factory, first)) as MongoSyncBucketStorageV3;
470
473
  const db = firstStorage.db as VersionedPowerSyncMongoV3;
471
474
  await using firstWriter = await firstStorage.createWriter(test_utils.BATCH_OPTIONS);
472
475
 
@@ -538,7 +541,7 @@ streams:
538
541
  expect(second.replicationStreamId).toBe(first.replicationStreamId);
539
542
 
540
543
  const replicatingStreams = await factory.getReplicatingReplicationStreams();
541
- const secondStorage = factory.getInstance(replicatingStreams[0]) as MongoSyncBucketStorageV3;
544
+ const secondStorage = (await getTestStorage(factory, replicatingStreams[0])) as MongoSyncBucketStorageV3;
542
545
  await using secondWriter = await secondStorage.createWriter(test_utils.BATCH_OPTIONS);
543
546
  await secondWriter.markAllSnapshotDone('2/1');
544
547
  await secondWriter.commit('2/1');
@@ -599,7 +602,7 @@ streams:
599
602
  { storageVersion: 3 }
600
603
  )
601
604
  );
602
- const firstStorage = factory.getInstance(first) as MongoSyncBucketStorageV3;
605
+ const firstStorage = (await getTestStorage(factory, first)) as MongoSyncBucketStorageV3;
603
606
  const db = firstStorage.db as VersionedPowerSyncMongoV3;
604
607
  await using firstWriter = await firstStorage.createWriter(test_utils.BATCH_OPTIONS);
605
608
  const resolved = await firstWriter.resolveTables({
@@ -652,7 +655,7 @@ streams:
652
655
  expect(secondIndexId).toBe(roleIndexId);
653
656
 
654
657
  const replicatingStreams = await factory.getReplicatingReplicationStreams();
655
- const secondStorage = factory.getInstance(replicatingStreams[0]) as MongoSyncBucketStorageV3;
658
+ const secondStorage = (await getTestStorage(factory, replicatingStreams[0])) as MongoSyncBucketStorageV3;
656
659
  await using secondWriter = await secondStorage.createWriter(test_utils.BATCH_OPTIONS);
657
660
  await secondWriter.markAllSnapshotDone('2/1');
658
661
  await secondWriter.commit('2/1');
@@ -664,7 +667,10 @@ streams:
664
667
  expect(await collectionExists(db, orgParameterIndexCollection)).toBe(false);
665
668
  expect(await collectionExists(db, sourceRecordsCollection)).toBe(true);
666
669
 
667
- const activeStorage = (await factory.getActiveSyncConfig())!.storage as MongoSyncBucketStorageV3;
670
+ const activeStorage = (await getTestStorage(
671
+ factory,
672
+ (await factory.getActiveSyncConfig())!.replicationStream
673
+ )) as MongoSyncBucketStorageV3;
668
674
  await using activeWriter = await activeStorage.createWriter(test_utils.BATCH_OPTIONS);
669
675
  const activeTable = (
670
676
  await activeWriter.resolveTables({
@@ -3,12 +3,12 @@ import {
3
3
  applyStatsReplacement,
4
4
  bucketStats,
5
5
  chooseCompactionKind,
6
+ chooseRequestedCompactionKind,
6
7
  combineAdjacentStats,
7
8
  combineChunkStats,
8
9
  CompactIntervalConfig,
9
10
  CompactionKind,
10
11
  emptyBucketStats,
11
- forcedCompactionKind,
12
12
  fullCompactionCheckAt,
13
13
  statsForDocument,
14
14
  statsForDocuments
@@ -130,44 +130,69 @@ describe('V3 compact utilities', () => {
130
130
  test.each([
131
131
  {
132
132
  name: 'does not force an unspecified kind',
133
- forceKind: undefined,
133
+ requestedKind: undefined,
134
134
  compactedOpId: undefined,
135
135
  maxOpIdCap: undefined,
136
136
  expected: null
137
137
  },
138
138
  {
139
139
  name: 'forces work without previous compacted state',
140
- forceKind: CompactionKind.Chunks,
140
+ requestedKind: CompactionKind.Chunks,
141
141
  compactedOpId: undefined,
142
142
  maxOpIdCap: undefined,
143
143
  expected: CompactionKind.Chunks
144
144
  },
145
145
  {
146
146
  name: 'skips work already compacted through the cap',
147
- forceKind: CompactionKind.Chunks,
147
+ requestedKind: CompactionKind.Chunks,
148
148
  compactedOpId: 5n,
149
149
  maxOpIdCap: 5n,
150
150
  expected: null
151
151
  },
152
152
  {
153
153
  name: 'skips work already compacted through the bucket head',
154
- forceKind: CompactionKind.Chunks,
154
+ requestedKind: CompactionKind.Chunks,
155
155
  compactedOpId: 10n,
156
156
  maxOpIdCap: undefined,
157
157
  expected: null
158
158
  },
159
159
  {
160
160
  name: 'forces work beyond the compacted state',
161
- forceKind: CompactionKind.Chunks,
161
+ requestedKind: CompactionKind.Chunks,
162
162
  compactedOpId: 5n,
163
163
  maxOpIdCap: 6n,
164
164
  expected: CompactionKind.Chunks
165
165
  }
166
- ])('$name', ({ forceKind, compactedOpId, maxOpIdCap, expected }) => {
166
+ ])('$name', ({ requestedKind, compactedOpId, maxOpIdCap, expected }) => {
167
167
  const state = bucketState({
168
+ bucket_stats: { count: 10, bytes: 100n, chunks: 9 },
168
169
  compacted_state: compactedOpId == null ? undefined : compactedState({ op_id: compactedOpId })
169
170
  });
170
- expect(forcedCompactionKind(state, forceKind, { maxOpIdCap })).toBe(expected);
171
+ expect(chooseRequestedCompactionKind(state, requestedKind, { maxOpIdCap })).toBe(expected);
172
+ });
173
+
174
+ test.each([undefined, compactedState({ at: new Date() })])(
175
+ 'initial chunk compaction requires eight new chunks, regardless of the interval: %o',
176
+ (compacted) => {
177
+ for (const newChunks of [1, 7, 8]) {
178
+ const state = bucketState({
179
+ bucket_stats: { count: 10, bytes: 100n, chunks: (compacted?.chunks ?? 0) + newChunks },
180
+ compacted_state: compacted
181
+ });
182
+ expect(chooseRequestedCompactionKind(state, CompactionKind.Chunks, { maxOpIdCap: undefined })).toBe(
183
+ newChunks < 8 ? null : CompactionKind.Chunks
184
+ );
185
+ }
186
+ }
187
+ );
188
+
189
+ test('the testing override bypasses the chunk threshold but preserves the compaction watermark', () => {
190
+ const state = bucketState();
191
+ const config = { maxOpIdCap: undefined, forceChunkCompaction: true };
192
+ expect(chooseRequestedCompactionKind(state, CompactionKind.Chunks, config)).toBe(CompactionKind.Chunks);
193
+ expect(chooseRequestedCompactionKind(state, undefined, config)).toBeNull();
194
+ state.compacted_state = compactedState({ op_id: state.last_op });
195
+ expect(chooseRequestedCompactionKind(state, CompactionKind.Chunks, config)).toBeNull();
171
196
  });
172
197
 
173
198
  test('derives and combines bucket statistics', () => {