@powersync/service-core 0.0.0-dev-20250820110726 → 0.0.0-dev-20250827072023
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.
- package/CHANGELOG.md +10 -6
- package/dist/events/EventsEngine.d.ts +4 -1
- package/dist/events/EventsEngine.js +4 -3
- package/dist/events/EventsEngine.js.map +1 -1
- package/dist/routes/configure-fastify.d.ts +0 -5
- package/dist/routes/configure-fastify.js.map +1 -1
- package/dist/routes/endpoints/socket-route.js +6 -5
- package/dist/routes/endpoints/socket-route.js.map +1 -1
- package/dist/routes/endpoints/sync-stream.d.ts +0 -10
- package/dist/routes/endpoints/sync-stream.js +8 -5
- package/dist/routes/endpoints/sync-stream.js.map +1 -1
- package/dist/routes/router.d.ts +3 -3
- package/dist/storage/BucketStorageBatch.d.ts +4 -4
- package/dist/storage/BucketStorageBatch.js.map +1 -1
- package/dist/storage/BucketStorageFactory.d.ts +2 -0
- package/dist/storage/ReplicationEventPayload.d.ts +2 -2
- package/dist/storage/ReportStorage.d.ts +30 -2
- package/dist/sync/sync.d.ts +1 -0
- package/dist/sync/sync.js +18 -35
- package/dist/sync/sync.js.map +1 -1
- package/dist/util/protocol-types.d.ts +0 -4
- package/dist/util/protocol-types.js +0 -4
- package/dist/util/protocol-types.js.map +1 -1
- package/dist/util/utils.d.ts +1 -1
- package/dist/util/utils.js.map +1 -1
- package/package.json +6 -6
- package/src/events/EventsEngine.ts +4 -4
- package/src/routes/configure-fastify.ts +0 -1
- package/src/routes/endpoints/socket-route.ts +6 -5
- package/src/routes/endpoints/sync-stream.ts +8 -6
- package/src/routes/router.ts +3 -3
- package/src/storage/BucketStorageBatch.ts +10 -4
- package/src/storage/BucketStorageFactory.ts +2 -0
- package/src/storage/ReplicationEventPayload.ts +2 -2
- package/src/storage/ReportStorage.ts +30 -2
- package/src/sync/sync.ts +36 -36
- package/src/util/protocol-types.ts +0 -5
- package/src/util/utils.ts +4 -1
- package/test/src/sync/BucketChecksumState.test.ts +36 -92
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -607,11 +607,23 @@ bucket_definitions:
|
|
|
607
607
|
describe('streams', () => {
|
|
608
608
|
let source: { -readonly [P in keyof BucketSource]: BucketSource[P] };
|
|
609
609
|
let storage: MockBucketChecksumStateStorage;
|
|
610
|
-
let staticBucketIds = ['stream|0[]'];
|
|
611
610
|
|
|
612
|
-
function checksumState(options?: Partial<BucketChecksumStateOptions>) {
|
|
613
|
-
|
|
614
|
-
|
|
611
|
+
function checksumState(source: string | boolean, options?: Partial<BucketChecksumStateOptions>) {
|
|
612
|
+
if (typeof source == 'boolean') {
|
|
613
|
+
source = `
|
|
614
|
+
streams:
|
|
615
|
+
stream:
|
|
616
|
+
auto_subscribe: ${source}
|
|
617
|
+
query: SELECT * FROM assets WHERE id IN ifnull(subscription.parameter('ids'), '["default"]');
|
|
618
|
+
|
|
619
|
+
config:
|
|
620
|
+
edition: 2
|
|
621
|
+
`;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
const rules = SqlSyncRules.fromYaml(source, {
|
|
625
|
+
defaultSchema: 'public'
|
|
626
|
+
});
|
|
615
627
|
|
|
616
628
|
return new BucketChecksumState({
|
|
617
629
|
syncContext,
|
|
@@ -623,77 +635,15 @@ bucket_definitions:
|
|
|
623
635
|
});
|
|
624
636
|
}
|
|
625
637
|
|
|
626
|
-
function createQuerier(ids: string[], subscription: number | null): BucketParameterQuerier {
|
|
627
|
-
return {
|
|
628
|
-
staticBuckets: ids.map((bucket) => ({
|
|
629
|
-
definition: 'stream',
|
|
630
|
-
inclusion_reasons: subscription == null ? ['default'] : [{ subscription }],
|
|
631
|
-
bucket,
|
|
632
|
-
priority: 3
|
|
633
|
-
})),
|
|
634
|
-
hasDynamicBuckets: false,
|
|
635
|
-
parameterQueryLookups: [],
|
|
636
|
-
queryDynamicBucketDescriptions: function (): never {
|
|
637
|
-
throw new Error('no dynamic buckets.');
|
|
638
|
-
}
|
|
639
|
-
};
|
|
640
|
-
}
|
|
641
|
-
|
|
642
638
|
beforeEach(() => {
|
|
643
|
-
// Currently using mocked streams before streams are actually implemented as parsable rules.
|
|
644
|
-
source = {
|
|
645
|
-
name: 'stream',
|
|
646
|
-
type: BucketSourceType.SYNC_STREAM,
|
|
647
|
-
subscribedToByDefault: false,
|
|
648
|
-
pushBucketParameterQueriers(result, options) {
|
|
649
|
-
// Create a fake querier that resolves the global stream["default"] bucket by default and allows extracting
|
|
650
|
-
// additional buckets from parameters.
|
|
651
|
-
const subscriptions = options.streams['stream'] ?? [];
|
|
652
|
-
if (!this.subscribedToByDefault && !subscriptions.length) {
|
|
653
|
-
return;
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
let hasExplicitDefaultSubscription = false;
|
|
657
|
-
for (const subscription of subscriptions) {
|
|
658
|
-
try {
|
|
659
|
-
let subscriptionParameters = [];
|
|
660
|
-
|
|
661
|
-
if (subscription.parameters != null) {
|
|
662
|
-
subscriptionParameters = JSON.parse(subscription.parameters['ids'] as string).map(
|
|
663
|
-
(e: string) => `stream["${e}"]`
|
|
664
|
-
);
|
|
665
|
-
} else {
|
|
666
|
-
hasExplicitDefaultSubscription = true;
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
result.queriers.push(createQuerier([...subscriptionParameters], subscription.opaque_id));
|
|
670
|
-
} catch (e) {
|
|
671
|
-
result.errors.push({
|
|
672
|
-
descriptor: 'stream',
|
|
673
|
-
subscription,
|
|
674
|
-
message: `Error evaluating bucket ids: ${e.message}`
|
|
675
|
-
});
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
// If the stream is subscribed to by default and there is no explicit subscription that would match the default
|
|
680
|
-
// subscription, also include the default querier.
|
|
681
|
-
if (this.subscribedToByDefault && !hasExplicitDefaultSubscription) {
|
|
682
|
-
result.queriers.push(createQuerier(['stream["default"]'], null));
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
} satisfies Partial<BucketSource> as any;
|
|
686
|
-
|
|
687
639
|
storage = new MockBucketChecksumStateStorage();
|
|
688
|
-
storage.updateTestChecksum({ bucket: 'stream["default"]', checksum: 1, count: 1 });
|
|
689
|
-
storage.updateTestChecksum({ bucket: 'stream["a"]', checksum: 1, count: 1 });
|
|
690
|
-
storage.updateTestChecksum({ bucket: 'stream["b"]', checksum: 1, count: 1 });
|
|
640
|
+
storage.updateTestChecksum({ bucket: 'stream|0["default"]', checksum: 1, count: 1 });
|
|
641
|
+
storage.updateTestChecksum({ bucket: 'stream|0["a"]', checksum: 1, count: 1 });
|
|
642
|
+
storage.updateTestChecksum({ bucket: 'stream|0["b"]', checksum: 1, count: 1 });
|
|
691
643
|
});
|
|
692
644
|
|
|
693
645
|
test('includes defaults', async () => {
|
|
694
|
-
|
|
695
|
-
const state = checksumState();
|
|
696
|
-
|
|
646
|
+
const state = checksumState(true);
|
|
697
647
|
const line = await state.buildNextCheckpointLine({
|
|
698
648
|
base: storage.makeCheckpoint(1n),
|
|
699
649
|
writeCheckpoint: null,
|
|
@@ -703,7 +653,7 @@ bucket_definitions:
|
|
|
703
653
|
expect(line?.checkpointLine).toEqual({
|
|
704
654
|
checkpoint: {
|
|
705
655
|
buckets: [
|
|
706
|
-
{ bucket: 'stream["default"]', checksum: 1, count: 1, priority: 3, subscriptions: [{ default: 0 }] }
|
|
656
|
+
{ bucket: 'stream|0["default"]', checksum: 1, count: 1, priority: 3, subscriptions: [{ default: 0 }] }
|
|
707
657
|
],
|
|
708
658
|
last_op_id: '1',
|
|
709
659
|
write_checkpoint: undefined,
|
|
@@ -713,8 +663,7 @@ bucket_definitions:
|
|
|
713
663
|
});
|
|
714
664
|
|
|
715
665
|
test('can exclude defaults', async () => {
|
|
716
|
-
|
|
717
|
-
const state = checksumState({ syncRequest: { streams: { include_defaults: false, subscriptions: [] } } });
|
|
666
|
+
const state = checksumState(true, { syncRequest: { streams: { include_defaults: false, subscriptions: [] } } });
|
|
718
667
|
|
|
719
668
|
const line = await state.buildNextCheckpointLine({
|
|
720
669
|
base: storage.makeCheckpoint(1n),
|
|
@@ -733,9 +682,7 @@ bucket_definitions:
|
|
|
733
682
|
});
|
|
734
683
|
|
|
735
684
|
test('custom subscriptions', async () => {
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
const state = checksumState({
|
|
685
|
+
const state = checksumState(true, {
|
|
739
686
|
syncRequest: {
|
|
740
687
|
streams: {
|
|
741
688
|
subscriptions: [
|
|
@@ -755,9 +702,9 @@ bucket_definitions:
|
|
|
755
702
|
expect(line?.checkpointLine).toEqual({
|
|
756
703
|
checkpoint: {
|
|
757
704
|
buckets: [
|
|
758
|
-
{ bucket: 'stream["a"]', checksum: 1, count: 1, priority: 3, subscriptions: [{ sub: 0 }] },
|
|
759
|
-
{ bucket: 'stream["b"]', checksum: 1, count: 1, priority: 1, subscriptions: [{ sub: 1 }] },
|
|
760
|
-
{ bucket: 'stream["default"]', checksum: 1, count: 1, priority: 3, subscriptions: [{ default: 0 }] }
|
|
705
|
+
{ bucket: 'stream|0["a"]', checksum: 1, count: 1, priority: 3, subscriptions: [{ sub: 0 }] },
|
|
706
|
+
{ bucket: 'stream|0["b"]', checksum: 1, count: 1, priority: 1, subscriptions: [{ sub: 1 }] },
|
|
707
|
+
{ bucket: 'stream|0["default"]', checksum: 1, count: 1, priority: 3, subscriptions: [{ default: 0 }] }
|
|
761
708
|
],
|
|
762
709
|
last_op_id: '1',
|
|
763
710
|
write_checkpoint: undefined,
|
|
@@ -767,7 +714,7 @@ bucket_definitions:
|
|
|
767
714
|
});
|
|
768
715
|
|
|
769
716
|
test('overlap between custom subscriptions', async () => {
|
|
770
|
-
const state = checksumState({
|
|
717
|
+
const state = checksumState(false, {
|
|
771
718
|
syncRequest: {
|
|
772
719
|
streams: {
|
|
773
720
|
subscriptions: [
|
|
@@ -787,8 +734,8 @@ bucket_definitions:
|
|
|
787
734
|
expect(line?.checkpointLine).toEqual({
|
|
788
735
|
checkpoint: {
|
|
789
736
|
buckets: [
|
|
790
|
-
{ bucket: 'stream["a"]', checksum: 1, count: 1, priority: 3, subscriptions: [{ sub: 0 }] },
|
|
791
|
-
{ bucket: 'stream["b"]', checksum: 1, count: 1, priority: 1, subscriptions: [{ sub: 0 }, { sub: 1 }] }
|
|
737
|
+
{ bucket: 'stream|0["a"]', checksum: 1, count: 1, priority: 3, subscriptions: [{ sub: 0 }] },
|
|
738
|
+
{ bucket: 'stream|0["b"]', checksum: 1, count: 1, priority: 1, subscriptions: [{ sub: 0 }, { sub: 1 }] }
|
|
792
739
|
],
|
|
793
740
|
last_op_id: '1',
|
|
794
741
|
write_checkpoint: undefined,
|
|
@@ -798,8 +745,7 @@ bucket_definitions:
|
|
|
798
745
|
});
|
|
799
746
|
|
|
800
747
|
test('overlap between default and custom subscription', async () => {
|
|
801
|
-
|
|
802
|
-
const state = checksumState({
|
|
748
|
+
const state = checksumState(true, {
|
|
803
749
|
syncRequest: {
|
|
804
750
|
streams: {
|
|
805
751
|
subscriptions: [{ stream: 'stream', parameters: { ids: '["a", "default"]' }, override_priority: 1 }]
|
|
@@ -816,9 +762,9 @@ bucket_definitions:
|
|
|
816
762
|
expect(line?.checkpointLine).toEqual({
|
|
817
763
|
checkpoint: {
|
|
818
764
|
buckets: [
|
|
819
|
-
{ bucket: 'stream["a"]', checksum: 1, count: 1, priority: 1, subscriptions: [{ sub: 0 }] },
|
|
765
|
+
{ bucket: 'stream|0["a"]', checksum: 1, count: 1, priority: 1, subscriptions: [{ sub: 0 }] },
|
|
820
766
|
{
|
|
821
|
-
bucket: 'stream["default"]',
|
|
767
|
+
bucket: 'stream|0["default"]',
|
|
822
768
|
checksum: 1,
|
|
823
769
|
count: 1,
|
|
824
770
|
priority: 1,
|
|
@@ -833,9 +779,7 @@ bucket_definitions:
|
|
|
833
779
|
});
|
|
834
780
|
|
|
835
781
|
test('reports errors', async () => {
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
const state = checksumState({
|
|
782
|
+
const state = checksumState(true, {
|
|
839
783
|
syncRequest: {
|
|
840
784
|
streams: {
|
|
841
785
|
subscriptions: [
|
|
@@ -855,10 +799,10 @@ bucket_definitions:
|
|
|
855
799
|
expect(line?.checkpointLine).toEqual({
|
|
856
800
|
checkpoint: {
|
|
857
801
|
buckets: [
|
|
858
|
-
{ bucket: 'stream["a"]', checksum: 1, count: 1, priority: 1, subscriptions: [{ sub: 0 }] },
|
|
859
|
-
{ bucket: 'stream["b"]', checksum: 1, count: 1, priority: 1, subscriptions: [{ sub: 0 }] },
|
|
802
|
+
{ bucket: 'stream|0["a"]', checksum: 1, count: 1, priority: 1, subscriptions: [{ sub: 0 }] },
|
|
803
|
+
{ bucket: 'stream|0["b"]', checksum: 1, count: 1, priority: 1, subscriptions: [{ sub: 0 }] },
|
|
860
804
|
{
|
|
861
|
-
bucket: 'stream["default"]',
|
|
805
|
+
bucket: 'stream|0["default"]',
|
|
862
806
|
checksum: 1,
|
|
863
807
|
count: 1,
|
|
864
808
|
priority: 3,
|