@powersync/service-core 0.0.0-dev-20250304151813 → 0.0.0-dev-20250306152715

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 (107) hide show
  1. package/CHANGELOG.md +18 -4
  2. package/dist/api/api-index.d.ts +1 -0
  3. package/dist/api/api-index.js +1 -0
  4. package/dist/api/api-index.js.map +1 -1
  5. package/dist/api/api-metrics.d.ts +11 -0
  6. package/dist/api/api-metrics.js +30 -0
  7. package/dist/api/api-metrics.js.map +1 -0
  8. package/dist/index.d.ts +2 -2
  9. package/dist/index.js +2 -2
  10. package/dist/index.js.map +1 -1
  11. package/dist/metrics/MetricsEngine.d.ts +21 -0
  12. package/dist/metrics/MetricsEngine.js +79 -0
  13. package/dist/metrics/MetricsEngine.js.map +1 -0
  14. package/dist/metrics/metrics-index.d.ts +4 -0
  15. package/dist/metrics/metrics-index.js +5 -0
  16. package/dist/metrics/metrics-index.js.map +1 -0
  17. package/dist/metrics/metrics-interfaces.d.ts +36 -0
  18. package/dist/metrics/metrics-interfaces.js +6 -0
  19. package/dist/metrics/metrics-interfaces.js.map +1 -0
  20. package/dist/metrics/open-telemetry/OpenTelemetryMetricsFactory.d.ts +10 -0
  21. package/dist/metrics/open-telemetry/OpenTelemetryMetricsFactory.js +51 -0
  22. package/dist/metrics/open-telemetry/OpenTelemetryMetricsFactory.js.map +1 -0
  23. package/dist/metrics/open-telemetry/util.d.ts +6 -0
  24. package/dist/metrics/open-telemetry/util.js +56 -0
  25. package/dist/metrics/open-telemetry/util.js.map +1 -0
  26. package/dist/replication/AbstractReplicationJob.d.ts +2 -0
  27. package/dist/replication/AbstractReplicationJob.js.map +1 -1
  28. package/dist/replication/AbstractReplicator.d.ts +3 -0
  29. package/dist/replication/AbstractReplicator.js +3 -0
  30. package/dist/replication/AbstractReplicator.js.map +1 -1
  31. package/dist/replication/ReplicationModule.d.ts +7 -0
  32. package/dist/replication/ReplicationModule.js +1 -0
  33. package/dist/replication/ReplicationModule.js.map +1 -1
  34. package/dist/replication/replication-index.d.ts +1 -0
  35. package/dist/replication/replication-index.js +1 -0
  36. package/dist/replication/replication-index.js.map +1 -1
  37. package/dist/replication/replication-metrics.d.ts +11 -0
  38. package/dist/replication/replication-metrics.js +39 -0
  39. package/dist/replication/replication-metrics.js.map +1 -0
  40. package/dist/routes/configure-fastify.d.ts +3 -3
  41. package/dist/routes/endpoints/checkpointing.d.ts +6 -6
  42. package/dist/routes/endpoints/socket-route.js +5 -5
  43. package/dist/routes/endpoints/socket-route.js.map +1 -1
  44. package/dist/routes/endpoints/sync-stream.js +6 -6
  45. package/dist/routes/endpoints/sync-stream.js.map +1 -1
  46. package/dist/storage/BucketStorageBatch.d.ts +2 -1
  47. package/dist/storage/BucketStorageBatch.js.map +1 -1
  48. package/dist/storage/ChecksumCache.d.ts +6 -6
  49. package/dist/storage/ChecksumCache.js +5 -6
  50. package/dist/storage/ChecksumCache.js.map +1 -1
  51. package/dist/storage/SyncRulesBucketStorage.d.ts +9 -9
  52. package/dist/storage/storage-index.d.ts +1 -0
  53. package/dist/storage/storage-index.js +1 -0
  54. package/dist/storage/storage-index.js.map +1 -1
  55. package/dist/storage/storage-metrics.d.ts +4 -0
  56. package/dist/storage/storage-metrics.js +56 -0
  57. package/dist/storage/storage-metrics.js.map +1 -0
  58. package/dist/sync/BucketChecksumState.d.ts +3 -3
  59. package/dist/sync/BucketChecksumState.js +3 -3
  60. package/dist/sync/BucketChecksumState.js.map +1 -1
  61. package/dist/sync/RequestTracker.d.ts +3 -0
  62. package/dist/sync/RequestTracker.js +8 -3
  63. package/dist/sync/RequestTracker.js.map +1 -1
  64. package/dist/sync/sync.d.ts +1 -1
  65. package/dist/sync/sync.js +8 -6
  66. package/dist/sync/sync.js.map +1 -1
  67. package/dist/system/ServiceContext.d.ts +3 -3
  68. package/dist/system/ServiceContext.js +7 -3
  69. package/dist/system/ServiceContext.js.map +1 -1
  70. package/dist/util/protocol-types.d.ts +10 -10
  71. package/dist/util/utils.d.ts +12 -2
  72. package/dist/util/utils.js +5 -1
  73. package/dist/util/utils.js.map +1 -1
  74. package/package.json +8 -8
  75. package/src/api/api-index.ts +1 -0
  76. package/src/api/api-metrics.ts +35 -0
  77. package/src/index.ts +2 -2
  78. package/src/metrics/MetricsEngine.ts +98 -0
  79. package/src/metrics/metrics-index.ts +4 -0
  80. package/src/metrics/metrics-interfaces.ts +41 -0
  81. package/src/metrics/open-telemetry/OpenTelemetryMetricsFactory.ts +66 -0
  82. package/src/metrics/open-telemetry/util.ts +74 -0
  83. package/src/replication/AbstractReplicationJob.ts +2 -0
  84. package/src/replication/AbstractReplicator.ts +7 -0
  85. package/src/replication/ReplicationModule.ts +10 -0
  86. package/src/replication/replication-index.ts +1 -0
  87. package/src/replication/replication-metrics.ts +45 -0
  88. package/src/routes/endpoints/socket-route.ts +6 -5
  89. package/src/routes/endpoints/sync-stream.ts +7 -6
  90. package/src/storage/BucketStorageBatch.ts +2 -1
  91. package/src/storage/ChecksumCache.ts +13 -14
  92. package/src/storage/SyncRulesBucketStorage.ts +10 -10
  93. package/src/storage/storage-index.ts +1 -0
  94. package/src/storage/storage-metrics.ts +67 -0
  95. package/src/sync/BucketChecksumState.ts +7 -7
  96. package/src/sync/RequestTracker.ts +9 -3
  97. package/src/sync/sync.ts +10 -8
  98. package/src/system/ServiceContext.ts +9 -4
  99. package/src/util/protocol-types.ts +10 -10
  100. package/src/util/utils.ts +13 -2
  101. package/test/src/checksum_cache.test.ts +83 -84
  102. package/test/src/sync/BucketChecksumState.test.ts +47 -41
  103. package/tsconfig.tsbuildinfo +1 -1
  104. package/dist/metrics/Metrics.d.ts +0 -30
  105. package/dist/metrics/Metrics.js +0 -202
  106. package/dist/metrics/Metrics.js.map +0 -1
  107. package/src/metrics/Metrics.ts +0 -255
@@ -4,7 +4,7 @@ import {
4
4
  BucketChecksumStateStorage,
5
5
  CHECKPOINT_INVALIDATE_ALL,
6
6
  ChecksumMap,
7
- OpId,
7
+ InternalOpId,
8
8
  SyncContext,
9
9
  WatchFilterEvent
10
10
  } from '@/index.js';
@@ -66,7 +66,7 @@ bucket_definitions:
66
66
  });
67
67
 
68
68
  const line = (await state.buildNextCheckpointLine({
69
- base: { checkpoint: '1', lsn: '1' },
69
+ base: { checkpoint: 1n, lsn: '1' },
70
70
  writeCheckpoint: null,
71
71
  update: CHECKPOINT_INVALIDATE_ALL
72
72
  }))!;
@@ -84,17 +84,17 @@ bucket_definitions:
84
84
  }
85
85
  ]);
86
86
  // This is the bucket data to be fetched
87
- expect(state.getFilteredBucketPositions(line.bucketsToFetch)).toEqual(new Map([['global[]', '0']]));
87
+ expect(state.getFilteredBucketPositions(line.bucketsToFetch)).toEqual(new Map([['global[]', 0n]]));
88
88
 
89
89
  // This similuates the bucket data being sent
90
- state.updateBucketPosition({ bucket: 'global[]', nextAfter: '1', hasMore: false });
90
+ state.updateBucketPosition({ bucket: 'global[]', nextAfter: 1n, hasMore: false });
91
91
 
92
92
  // Update bucket storage state
93
93
  storage.updateTestChecksum({ bucket: 'global[]', checksum: 2, count: 2 });
94
94
 
95
95
  // Now we get a new line
96
96
  const line2 = (await state.buildNextCheckpointLine({
97
- base: { checkpoint: '2', lsn: '2' },
97
+ base: { checkpoint: 2n, lsn: '2' },
98
98
  writeCheckpoint: null,
99
99
  update: {
100
100
  updatedDataBuckets: ['global[]'],
@@ -111,7 +111,7 @@ bucket_definitions:
111
111
  write_checkpoint: undefined
112
112
  }
113
113
  });
114
- expect(state.getFilteredBucketPositions(line2.bucketsToFetch)).toEqual(new Map([['global[]', '1']]));
114
+ expect(state.getFilteredBucketPositions(line2.bucketsToFetch)).toEqual(new Map([['global[]', 1n]]));
115
115
  });
116
116
 
117
117
  test('global bucket with initial state', async () => {
@@ -125,14 +125,14 @@ bucket_definitions:
125
125
  const state = new BucketChecksumState({
126
126
  syncContext,
127
127
  // Client sets the initial state here
128
- initialBucketPositions: [{ name: 'global[]', after: '1' }],
128
+ initialBucketPositions: [{ name: 'global[]', after: 1n }],
129
129
  syncParams: new RequestParameters({ sub: '' }, {}),
130
130
  syncRules: SYNC_RULES_GLOBAL,
131
131
  bucketStorage: storage
132
132
  });
133
133
 
134
134
  const line = (await state.buildNextCheckpointLine({
135
- base: { checkpoint: '1', lsn: '1' },
135
+ base: { checkpoint: 1n, lsn: '1' },
136
136
  writeCheckpoint: null,
137
137
  update: CHECKPOINT_INVALIDATE_ALL
138
138
  }))!;
@@ -150,7 +150,7 @@ bucket_definitions:
150
150
  }
151
151
  ]);
152
152
  // This is the main difference between this and the previous test
153
- expect(state.getFilteredBucketPositions(line.bucketsToFetch)).toEqual(new Map([['global[]', '1']]));
153
+ expect(state.getFilteredBucketPositions(line.bucketsToFetch)).toEqual(new Map([['global[]', 1n]]));
154
154
  });
155
155
 
156
156
  test('multiple static buckets', async () => {
@@ -167,7 +167,7 @@ bucket_definitions:
167
167
  });
168
168
 
169
169
  const line = (await state.buildNextCheckpointLine({
170
- base: { checkpoint: '1', lsn: '1' },
170
+ base: { checkpoint: 1n, lsn: '1' },
171
171
  writeCheckpoint: null,
172
172
  update: CHECKPOINT_INVALIDATE_ALL
173
173
  }))!;
@@ -196,7 +196,7 @@ bucket_definitions:
196
196
  storage.updateTestChecksum({ bucket: 'global[2]', checksum: 2, count: 2 });
197
197
 
198
198
  const line2 = (await state.buildNextCheckpointLine({
199
- base: { checkpoint: '2', lsn: '2' },
199
+ base: { checkpoint: 2n, lsn: '2' },
200
200
  writeCheckpoint: null,
201
201
  update: {
202
202
  ...CHECKPOINT_INVALIDATE_ALL,
@@ -226,7 +226,7 @@ bucket_definitions:
226
226
  const state = new BucketChecksumState({
227
227
  syncContext,
228
228
  // Client sets the initial state here
229
- initialBucketPositions: [{ name: 'something_here[]', after: '1' }],
229
+ initialBucketPositions: [{ name: 'something_here[]', after: 1n }],
230
230
  syncParams: new RequestParameters({ sub: '' }, {}),
231
231
  syncRules: SYNC_RULES_GLOBAL,
232
232
  bucketStorage: storage
@@ -235,7 +235,7 @@ bucket_definitions:
235
235
  storage.updateTestChecksum({ bucket: 'global[]', checksum: 1, count: 1 });
236
236
 
237
237
  const line = (await state.buildNextCheckpointLine({
238
- base: { checkpoint: '1', lsn: '1' },
238
+ base: { checkpoint: 1n, lsn: '1' },
239
239
  writeCheckpoint: null,
240
240
  update: CHECKPOINT_INVALIDATE_ALL
241
241
  }))!;
@@ -252,7 +252,7 @@ bucket_definitions:
252
252
  priority: 3
253
253
  }
254
254
  ]);
255
- expect(state.getFilteredBucketPositions(line.bucketsToFetch)).toEqual(new Map([['global[]', '0']]));
255
+ expect(state.getFilteredBucketPositions(line.bucketsToFetch)).toEqual(new Map([['global[]', 0n]]));
256
256
  });
257
257
 
258
258
  test('invalidating individual bucket', async () => {
@@ -274,19 +274,19 @@ bucket_definitions:
274
274
  // storage.filter = state.checkpointFilter;
275
275
 
276
276
  await state.buildNextCheckpointLine({
277
- base: { checkpoint: '1', lsn: '1' },
277
+ base: { checkpoint: 1n, lsn: '1' },
278
278
  writeCheckpoint: null,
279
279
  update: CHECKPOINT_INVALIDATE_ALL
280
280
  });
281
281
 
282
- state.updateBucketPosition({ bucket: 'global[1]', nextAfter: '1', hasMore: false });
283
- state.updateBucketPosition({ bucket: 'global[2]', nextAfter: '1', hasMore: false });
282
+ state.updateBucketPosition({ bucket: 'global[1]', nextAfter: 1n, hasMore: false });
283
+ state.updateBucketPosition({ bucket: 'global[2]', nextAfter: 1n, hasMore: false });
284
284
 
285
285
  storage.updateTestChecksum({ bucket: 'global[1]', checksum: 2, count: 2 });
286
286
  storage.updateTestChecksum({ bucket: 'global[2]', checksum: 2, count: 2 });
287
287
 
288
288
  const line2 = (await state.buildNextCheckpointLine({
289
- base: { checkpoint: '2', lsn: '2' },
289
+ base: { checkpoint: 2n, lsn: '2' },
290
290
  writeCheckpoint: null,
291
291
  update: {
292
292
  ...CHECKPOINT_INVALIDATE_ALL,
@@ -330,7 +330,7 @@ bucket_definitions:
330
330
  storage.updateTestChecksum({ bucket: 'global[2]', checksum: 1, count: 1 });
331
331
 
332
332
  await state.buildNextCheckpointLine({
333
- base: { checkpoint: '1', lsn: '1' },
333
+ base: { checkpoint: 1n, lsn: '1' },
334
334
  writeCheckpoint: null,
335
335
  update: CHECKPOINT_INVALIDATE_ALL
336
336
  });
@@ -339,7 +339,7 @@ bucket_definitions:
339
339
  storage.updateTestChecksum({ bucket: 'global[2]', checksum: 2, count: 2 });
340
340
 
341
341
  const line2 = (await state.buildNextCheckpointLine({
342
- base: { checkpoint: '2', lsn: '2' },
342
+ base: { checkpoint: 2n, lsn: '2' },
343
343
  writeCheckpoint: null,
344
344
  // Invalidate the state - will re-check all buckets
345
345
  update: CHECKPOINT_INVALIDATE_ALL
@@ -375,7 +375,7 @@ bucket_definitions:
375
375
  });
376
376
 
377
377
  const line = (await state.buildNextCheckpointLine({
378
- base: { checkpoint: '3', lsn: '3' },
378
+ base: { checkpoint: 3n, lsn: '3' },
379
379
  writeCheckpoint: null,
380
380
  update: CHECKPOINT_INVALIDATE_ALL
381
381
  }))!;
@@ -403,19 +403,19 @@ bucket_definitions:
403
403
  // This is the bucket data to be fetched
404
404
  expect(state.getFilteredBucketPositions(line.bucketsToFetch)).toEqual(
405
405
  new Map([
406
- ['global[1]', '0'],
407
- ['global[2]', '0']
406
+ ['global[1]', 0n],
407
+ ['global[2]', 0n]
408
408
  ])
409
409
  );
410
410
 
411
411
  // No data changes here.
412
412
  // We simulate partial data sent, before a checkpoint is interrupted.
413
- state.updateBucketPosition({ bucket: 'global[1]', nextAfter: '3', hasMore: false });
414
- state.updateBucketPosition({ bucket: 'global[2]', nextAfter: '1', hasMore: true });
413
+ state.updateBucketPosition({ bucket: 'global[1]', nextAfter: 3n, hasMore: false });
414
+ state.updateBucketPosition({ bucket: 'global[2]', nextAfter: 1n, hasMore: true });
415
415
  storage.updateTestChecksum({ bucket: 'global[1]', checksum: 4, count: 4 });
416
416
 
417
417
  const line2 = (await state.buildNextCheckpointLine({
418
- base: { checkpoint: '4', lsn: '4' },
418
+ base: { checkpoint: 4n, lsn: '4' },
419
419
  writeCheckpoint: null,
420
420
  update: {
421
421
  ...CHECKPOINT_INVALIDATE_ALL,
@@ -452,8 +452,8 @@ bucket_definitions:
452
452
 
453
453
  expect(state.getFilteredBucketPositions(line2.bucketsToFetch)).toEqual(
454
454
  new Map([
455
- ['global[1]', '3'],
456
- ['global[2]', '1']
455
+ ['global[1]', 3n],
456
+ ['global[2]', 1n]
457
457
  ])
458
458
  );
459
459
  });
@@ -472,14 +472,17 @@ bucket_definitions:
472
472
  bucketStorage: storage
473
473
  });
474
474
 
475
- storage.getParameterSets = async (checkpoint: OpId, lookups: SqliteJsonValue[][]): Promise<SqliteJsonRow[]> => {
476
- expect(checkpoint).toEqual('1');
475
+ storage.getParameterSets = async (
476
+ checkpoint: InternalOpId,
477
+ lookups: SqliteJsonValue[][]
478
+ ): Promise<SqliteJsonRow[]> => {
479
+ expect(checkpoint).toEqual(1n);
477
480
  expect(lookups).toEqual([['by_project', '1', 'u1']]);
478
481
  return [{ id: 1 }, { id: 2 }];
479
482
  };
480
483
 
481
484
  const line = (await state.buildNextCheckpointLine({
482
- base: { checkpoint: '1', lsn: '1' },
485
+ base: { checkpoint: 1n, lsn: '1' },
483
486
  writeCheckpoint: null,
484
487
  update: CHECKPOINT_INVALIDATE_ALL
485
488
  }))!;
@@ -506,23 +509,26 @@ bucket_definitions:
506
509
  // This is the bucket data to be fetched
507
510
  expect(state.getFilteredBucketPositions(line.bucketsToFetch)).toEqual(
508
511
  new Map([
509
- ['by_project[1]', '0'],
510
- ['by_project[2]', '0']
512
+ ['by_project[1]', 0n],
513
+ ['by_project[2]', 0n]
511
514
  ])
512
515
  );
513
516
 
514
- state.updateBucketPosition({ bucket: 'by_project[1]', nextAfter: '1', hasMore: false });
515
- state.updateBucketPosition({ bucket: 'by_project[2]', nextAfter: '1', hasMore: false });
517
+ state.updateBucketPosition({ bucket: 'by_project[1]', nextAfter: 1n, hasMore: false });
518
+ state.updateBucketPosition({ bucket: 'by_project[2]', nextAfter: 1n, hasMore: false });
516
519
 
517
- storage.getParameterSets = async (checkpoint: OpId, lookups: SqliteJsonValue[][]): Promise<SqliteJsonRow[]> => {
518
- expect(checkpoint).toEqual('2');
520
+ storage.getParameterSets = async (
521
+ checkpoint: InternalOpId,
522
+ lookups: SqliteJsonValue[][]
523
+ ): Promise<SqliteJsonRow[]> => {
524
+ expect(checkpoint).toEqual(2n);
519
525
  expect(lookups).toEqual([['by_project', '1', 'u1']]);
520
526
  return [{ id: 1 }, { id: 2 }, { id: 3 }];
521
527
  };
522
528
 
523
529
  // Now we get a new line
524
530
  const line2 = (await state.buildNextCheckpointLine({
525
- base: { checkpoint: '2', lsn: '2' },
531
+ base: { checkpoint: 2n, lsn: '2' },
526
532
  writeCheckpoint: null,
527
533
  update: {
528
534
  invalidateDataBuckets: false,
@@ -539,7 +545,7 @@ bucket_definitions:
539
545
  write_checkpoint: undefined
540
546
  }
541
547
  });
542
- expect(state.getFilteredBucketPositions(line2.bucketsToFetch)).toEqual(new Map([['by_project[3]', '0']]));
548
+ expect(state.getFilteredBucketPositions(line2.bucketsToFetch)).toEqual(new Map([['by_project[3]', 0n]]));
543
549
  });
544
550
  });
545
551
 
@@ -558,7 +564,7 @@ class MockBucketChecksumStateStorage implements BucketChecksumStateStorage {
558
564
  this.filter?.({ invalidate: true });
559
565
  }
560
566
 
561
- async getChecksums(checkpoint: OpId, buckets: string[]): Promise<ChecksumMap> {
567
+ async getChecksums(checkpoint: InternalOpId, buckets: string[]): Promise<ChecksumMap> {
562
568
  return new Map<string, BucketChecksum>(
563
569
  buckets.map((bucket) => {
564
570
  const checksum = this.state.get(bucket);
@@ -574,7 +580,7 @@ class MockBucketChecksumStateStorage implements BucketChecksumStateStorage {
574
580
  );
575
581
  }
576
582
 
577
- async getParameterSets(checkpoint: OpId, lookups: SqliteJsonValue[][]): Promise<SqliteJsonRow[]> {
583
+ async getParameterSets(checkpoint: InternalOpId, lookups: SqliteJsonValue[][]): Promise<SqliteJsonRow[]> {
578
584
  throw new Error('Method not implemented.');
579
585
  }
580
586
  }