@powersync/service-core 0.0.0-dev-20241001150444 → 0.0.0-dev-20241002180742

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 (112) hide show
  1. package/CHANGELOG.md +10 -5
  2. package/dist/api/RouteAPI.d.ts +1 -4
  3. package/dist/api/diagnostics.js.map +1 -1
  4. package/dist/api/schema.js +6 -2
  5. package/dist/api/schema.js.map +1 -1
  6. package/dist/auth/CachedKeyCollector.js.map +1 -1
  7. package/dist/auth/KeySpec.js.map +1 -1
  8. package/dist/auth/KeyStore.js.map +1 -1
  9. package/dist/auth/LeakyBucket.js.map +1 -1
  10. package/dist/auth/RemoteJWKSCollector.d.ts +0 -2
  11. package/dist/auth/RemoteJWKSCollector.js.map +1 -1
  12. package/dist/db/mongo.js.map +1 -1
  13. package/dist/entry/cli-entry.js.map +1 -1
  14. package/dist/entry/commands/compact-action.js.map +1 -1
  15. package/dist/entry/commands/migrate-action.js.map +1 -1
  16. package/dist/entry/commands/teardown-action.js.map +1 -1
  17. package/dist/locks/MongoLocks.js.map +1 -1
  18. package/dist/metrics/Metrics.js.map +1 -1
  19. package/dist/migrations/db/migrations/1684951997326-init.js.map +1 -1
  20. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +1 -1
  21. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js.map +1 -1
  22. package/dist/migrations/executor.js.map +1 -1
  23. package/dist/migrations/migrations.js.map +1 -1
  24. package/dist/migrations/store/migration-store.js.map +1 -1
  25. package/dist/modules/ModuleManager.js.map +1 -1
  26. package/dist/replication/AbstractReplicationJob.d.ts +0 -1
  27. package/dist/replication/AbstractReplicator.js.map +1 -1
  28. package/dist/replication/ErrorRateLimiter.d.ts +0 -1
  29. package/dist/replication/ReplicationEngine.js.map +1 -1
  30. package/dist/replication/ReplicationModule.js.map +1 -1
  31. package/dist/routes/RouterEngine.js.map +1 -1
  32. package/dist/routes/auth.js.map +1 -1
  33. package/dist/routes/configure-fastify.d.ts +21 -7
  34. package/dist/routes/configure-rsocket.d.ts +0 -1
  35. package/dist/routes/configure-rsocket.js.map +1 -1
  36. package/dist/routes/endpoints/admin.d.ts +42 -12
  37. package/dist/routes/endpoints/admin.js.map +1 -1
  38. package/dist/routes/endpoints/checkpointing.js.map +1 -1
  39. package/dist/routes/endpoints/socket-route.js.map +1 -1
  40. package/dist/routes/endpoints/sync-rules.js.map +1 -1
  41. package/dist/routes/endpoints/sync-stream.d.ts +0 -1
  42. package/dist/routes/endpoints/sync-stream.js.map +1 -1
  43. package/dist/routes/hooks.js.map +1 -1
  44. package/dist/routes/route-register.js.map +1 -1
  45. package/dist/runner/teardown.js.map +1 -1
  46. package/dist/storage/BucketStorage.d.ts +0 -1
  47. package/dist/storage/BucketStorage.js.map +1 -1
  48. package/dist/storage/ChecksumCache.d.ts +19 -1
  49. package/dist/storage/ChecksumCache.js +8 -1
  50. package/dist/storage/ChecksumCache.js.map +1 -1
  51. package/dist/storage/MongoBucketStorage.d.ts +0 -1
  52. package/dist/storage/MongoBucketStorage.js +1 -1
  53. package/dist/storage/MongoBucketStorage.js.map +1 -1
  54. package/dist/storage/StorageEngine.js.map +1 -1
  55. package/dist/storage/mongo/MongoBucketBatch.js.map +1 -1
  56. package/dist/storage/mongo/MongoCompactor.js.map +1 -1
  57. package/dist/storage/mongo/MongoIdSequence.js.map +1 -1
  58. package/dist/storage/mongo/MongoPersistedSyncRulesContent.js.map +1 -1
  59. package/dist/storage/mongo/MongoSyncBucketStorage.js +14 -4
  60. package/dist/storage/mongo/MongoSyncBucketStorage.js.map +1 -1
  61. package/dist/storage/mongo/MongoSyncRulesLock.js.map +1 -1
  62. package/dist/storage/mongo/OperationBatch.js.map +1 -1
  63. package/dist/storage/mongo/PersistedBatch.js.map +1 -1
  64. package/dist/storage/mongo/config.js.map +1 -1
  65. package/dist/storage/mongo/util.js.map +1 -1
  66. package/dist/sync/BroadcastIterable.d.ts +0 -1
  67. package/dist/sync/BroadcastIterable.js.map +1 -1
  68. package/dist/sync/LastValueSink.d.ts +0 -1
  69. package/dist/sync/LastValueSink.js.map +1 -1
  70. package/dist/sync/merge.d.ts +0 -1
  71. package/dist/sync/merge.js.map +1 -1
  72. package/dist/sync/safeRace.js.map +1 -1
  73. package/dist/sync/sync.d.ts +0 -1
  74. package/dist/sync/sync.js.map +1 -1
  75. package/dist/sync/util.d.ts +0 -2
  76. package/dist/sync/util.js.map +1 -1
  77. package/dist/util/Mutex.js.map +1 -1
  78. package/dist/util/config/collectors/config-collector.js.map +1 -1
  79. package/dist/util/config/collectors/impl/base64-config-collector.js.map +1 -1
  80. package/dist/util/config/collectors/impl/filesystem-config-collector.js.map +1 -1
  81. package/dist/util/config/compound-config-collector.js +1 -1
  82. package/dist/util/config/compound-config-collector.js.map +1 -1
  83. package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.js.map +1 -1
  84. package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.js.map +1 -1
  85. package/dist/util/config/sync-rules/impl/inline-sync-rules-collector.js.map +1 -1
  86. package/dist/util/config/sync-rules/sync-rules-provider.js.map +1 -1
  87. package/dist/util/config.js.map +1 -1
  88. package/dist/util/memory-tracking.js.map +1 -1
  89. package/dist/util/protocol-types.d.ts +0 -65
  90. package/dist/util/protocol-types.js +0 -7
  91. package/dist/util/protocol-types.js.map +1 -1
  92. package/dist/util/secs.js.map +1 -1
  93. package/dist/util/utils.d.ts +2 -1
  94. package/dist/util/utils.js +9 -2
  95. package/dist/util/utils.js.map +1 -1
  96. package/package.json +8 -8
  97. package/src/api/RouteAPI.ts +1 -4
  98. package/src/api/schema.ts +6 -2
  99. package/src/auth/RemoteJWKSCollector.ts +4 -1
  100. package/src/storage/ChecksumCache.ts +32 -2
  101. package/src/storage/mongo/MongoCompactor.ts +5 -1
  102. package/src/storage/mongo/MongoPersistedSyncRulesContent.ts +4 -1
  103. package/src/storage/mongo/MongoSyncBucketStorage.ts +18 -8
  104. package/src/storage/mongo/MongoSyncRulesLock.ts +6 -2
  105. package/src/storage/mongo/PersistedBatch.ts +4 -1
  106. package/src/util/protocol-types.ts +0 -89
  107. package/src/util/utils.ts +11 -3
  108. package/test/src/__snapshots__/sync.test.ts.snap +7 -7
  109. package/test/src/checksum_cache.test.ts +26 -19
  110. package/test/src/compacting.test.ts +81 -0
  111. package/tsconfig.tsbuildinfo +1 -1
  112. package/vitest.config.ts +7 -1
@@ -1,6 +1,6 @@
1
- import { ChecksumCache, FetchChecksums, FetchPartialBucketChecksum } from '@/storage/ChecksumCache.js';
2
- import { BucketChecksum, OpId } from '@/util/protocol-types.js';
3
- import { addBucketChecksums } from '@/util/util-index.js';
1
+ import { ChecksumCache, FetchChecksums, FetchPartialBucketChecksum, PartialChecksum } from '@/storage/ChecksumCache.js';
2
+ import { OpId } from '@/util/protocol-types.js';
3
+ import { addChecksums } from '@/util/util-index.js';
4
4
  import * as crypto from 'node:crypto';
5
5
  import { describe, expect, it } from 'vitest';
6
6
 
@@ -13,28 +13,22 @@ function testHash(bucket: string, checkpoint: OpId) {
13
13
  return hash;
14
14
  }
15
15
 
16
- function testPartialHash(request: FetchPartialBucketChecksum): BucketChecksum {
16
+ function testPartialHash(request: FetchPartialBucketChecksum): PartialChecksum {
17
17
  if (request.start) {
18
18
  const a = testHash(request.bucket, request.start);
19
19
  const b = testHash(request.bucket, request.end);
20
- return addBucketChecksums(
21
- {
22
- bucket: request.bucket,
23
- checksum: b,
24
- count: Number(request.end)
25
- },
26
- {
27
- // Subtract a
28
- bucket: request.bucket,
29
- checksum: -a,
30
- count: -Number(request.start)
31
- }
32
- );
20
+ return {
21
+ bucket: request.bucket,
22
+ partialCount: Number(request.end) - Number(request.start),
23
+ partialChecksum: addChecksums(b, -a),
24
+ isFullChecksum: false
25
+ };
33
26
  } else {
34
27
  return {
35
28
  bucket: request.bucket,
36
- checksum: testHash(request.bucket, request.end),
37
- count: Number(request.end)
29
+ partialChecksum: testHash(request.bucket, request.end),
30
+ partialCount: Number(request.end),
31
+ isFullChecksum: true
38
32
  };
39
33
  }
40
34
  }
@@ -433,4 +427,17 @@ describe('checksum cache', function () {
433
427
  [{ bucket: 'test2', end: '123' }]
434
428
  ]);
435
429
  });
430
+
431
+ it('should handle CLEAR/isFullChecksum checksums', async function () {
432
+ let lookups: FetchPartialBucketChecksum[][] = [];
433
+ const cache = factory(async (batch) => {
434
+ lookups.push(batch);
435
+ // This forces a `isFullChecksum: true` result
436
+ delete batch[0].start;
437
+ return fetchTestChecksums(batch);
438
+ });
439
+
440
+ expect(await cache.getChecksums('123', ['test'])).toEqual([TEST_123]);
441
+ expect(await cache.getChecksums('1234', ['test'])).toEqual([TEST_1234]);
442
+ });
436
443
  });
@@ -61,6 +61,7 @@ bucket_definitions:
61
61
 
62
62
  const batchBefore = await oneFromAsync(storage.getBucketDataBatch(checkpoint, new Map([['global[]', '0']])));
63
63
  const dataBefore = batchBefore.batch.data;
64
+ const checksumBefore = await storage.getChecksums(checkpoint, ['global[]']);
64
65
 
65
66
  expect(dataBefore).toMatchObject([
66
67
  {
@@ -87,6 +88,7 @@ bucket_definitions:
87
88
 
88
89
  const batchAfter = await oneFromAsync(storage.getBucketDataBatch(checkpoint, new Map([['global[]', '0']])));
89
90
  const dataAfter = batchAfter.batch.data;
91
+ const checksumAfter = await storage.getChecksums(checkpoint, ['global[]']);
90
92
 
91
93
  expect(batchAfter.targetOp).toEqual(3n);
92
94
  expect(dataAfter).toMatchObject([
@@ -109,6 +111,8 @@ bucket_definitions:
109
111
  }
110
112
  ]);
111
113
 
114
+ expect(checksumBefore.get('global[]')).toEqual(checksumAfter.get('global[]'));
115
+
112
116
  validateCompactedBucket(dataBefore, dataAfter);
113
117
  });
114
118
 
@@ -163,6 +167,7 @@ bucket_definitions:
163
167
 
164
168
  const batchBefore = await oneFromAsync(storage.getBucketDataBatch(checkpoint, new Map([['global[]', '0']])));
165
169
  const dataBefore = batchBefore.batch.data;
170
+ const checksumBefore = await storage.getChecksums(checkpoint, ['global[]']);
166
171
 
167
172
  expect(dataBefore).toMatchObject([
168
173
  {
@@ -195,6 +200,7 @@ bucket_definitions:
195
200
 
196
201
  const batchAfter = await oneFromAsync(storage.getBucketDataBatch(checkpoint, new Map([['global[]', '0']])));
197
202
  const dataAfter = batchAfter.batch.data;
203
+ const checksumAfter = await storage.getChecksums(checkpoint, ['global[]']);
198
204
 
199
205
  expect(batchAfter.targetOp).toEqual(4n);
200
206
  expect(dataAfter).toMatchObject([
@@ -210,7 +216,82 @@ bucket_definitions:
210
216
  op_id: '4'
211
217
  }
212
218
  ]);
219
+ expect(checksumBefore.get('global[]')).toEqual(checksumAfter.get('global[]'));
213
220
 
214
221
  validateCompactedBucket(dataBefore, dataAfter);
215
222
  });
223
+
224
+ test('compacting (3)', async () => {
225
+ const sync_rules = testRules(`
226
+ bucket_definitions:
227
+ global:
228
+ data: [select * from test]
229
+ `);
230
+
231
+ const storage = (await factory()).getInstance(sync_rules);
232
+
233
+ const result = await storage.startBatch(BATCH_OPTIONS, async (batch) => {
234
+ await batch.save({
235
+ sourceTable: TEST_TABLE,
236
+ tag: 'insert',
237
+ after: {
238
+ id: 't1'
239
+ },
240
+ afterReplicaId: 't1'
241
+ });
242
+
243
+ await batch.save({
244
+ sourceTable: TEST_TABLE,
245
+ tag: 'insert',
246
+ after: {
247
+ id: 't2'
248
+ },
249
+ afterReplicaId: 't2'
250
+ });
251
+
252
+ await batch.save({
253
+ sourceTable: TEST_TABLE,
254
+ tag: 'delete',
255
+ before: {
256
+ id: 't1'
257
+ },
258
+ beforeReplicaId: 't1'
259
+ });
260
+ });
261
+
262
+ const checkpoint1 = result!.flushed_op;
263
+ const checksumBefore = await storage.getChecksums(checkpoint1, ['global[]']);
264
+
265
+ const result2 = await storage.startBatch(BATCH_OPTIONS, async (batch) => {
266
+ await batch.save({
267
+ sourceTable: TEST_TABLE,
268
+ tag: 'delete',
269
+ before: {
270
+ id: 't2'
271
+ },
272
+ beforeReplicaId: 't2'
273
+ });
274
+ });
275
+ const checkpoint2 = result2!.flushed_op;
276
+
277
+ await storage.compact(compactOptions);
278
+
279
+ const batchAfter = await oneFromAsync(storage.getBucketDataBatch(checkpoint2, new Map([['global[]', '0']])));
280
+ const dataAfter = batchAfter.batch.data;
281
+ const checksumAfter = await storage.getChecksums(checkpoint2, ['global[]']);
282
+
283
+ expect(batchAfter.targetOp).toEqual(4n);
284
+ expect(dataAfter).toMatchObject([
285
+ {
286
+ checksum: 1874612650,
287
+ op: 'CLEAR',
288
+ op_id: '4'
289
+ }
290
+ ]);
291
+ expect(checksumAfter.get('global[]')).toEqual({
292
+ bucket: 'global[]',
293
+ count: 1,
294
+ checksum: 1874612650
295
+ });
296
+ });
216
297
  }