@powersync/service-core 1.21.0 → 1.22.0
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 +31 -0
- package/dist/api/diagnostics.js +1 -1
- package/dist/api/diagnostics.js.map +1 -1
- package/dist/auth/RemoteJWKSCollector.js +3 -2
- package/dist/auth/RemoteJWKSCollector.js.map +1 -1
- package/dist/replication/RelationCache.d.ts +9 -2
- package/dist/replication/RelationCache.js +21 -2
- package/dist/replication/RelationCache.js.map +1 -1
- package/dist/routes/configure-fastify.js +3 -1
- package/dist/routes/configure-fastify.js.map +1 -1
- package/dist/routes/endpoints/admin.js +9 -5
- package/dist/routes/endpoints/admin.js.map +1 -1
- package/dist/routes/endpoints/sync-rules.js +1 -1
- package/dist/routes/endpoints/sync-rules.js.map +1 -1
- package/dist/routes/route-register.d.ts +2 -0
- package/dist/routes/route-register.js +65 -3
- package/dist/routes/route-register.js.map +1 -1
- package/dist/storage/BucketStorageBatch.d.ts +29 -0
- package/dist/storage/BucketStorageBatch.js.map +1 -1
- package/dist/storage/BucketStorageFactory.d.ts +4 -0
- package/dist/storage/BucketStorageFactory.js +1 -1
- package/dist/storage/BucketStorageFactory.js.map +1 -1
- package/dist/storage/PersistedSyncRulesContent.d.ts +3 -3
- package/dist/storage/PersistedSyncRulesContent.js +6 -6
- package/dist/storage/PersistedSyncRulesContent.js.map +1 -1
- package/dist/storage/SourceEntity.d.ts +8 -1
- package/dist/storage/SourceTable.d.ts +29 -8
- package/dist/storage/SourceTable.js +38 -12
- package/dist/storage/SourceTable.js.map +1 -1
- package/dist/storage/SyncRulesBucketStorage.d.ts +26 -13
- package/dist/storage/SyncRulesBucketStorage.js.map +1 -1
- package/dist/sync/BucketChecksumState.d.ts +4 -4
- package/dist/sync/BucketChecksumState.js +1 -1
- package/dist/sync/BucketChecksumState.js.map +1 -1
- package/dist/sync/sync.d.ts +2 -2
- package/dist/sync/sync.js.map +1 -1
- package/dist/tracing/PerformanceTracer.d.ts +17 -1
- package/dist/tracing/PerformanceTracer.js +3 -0
- package/dist/tracing/PerformanceTracer.js.map +1 -1
- package/dist/util/util-index.d.ts +1 -0
- package/dist/util/util-index.js +1 -0
- package/dist/util/util-index.js.map +1 -1
- package/dist/util/utils.d.ts +5 -0
- package/dist/util/utils.js +7 -0
- package/dist/util/utils.js.map +1 -1
- package/package.json +4 -4
- package/src/api/diagnostics.ts +3 -3
- package/src/auth/RemoteJWKSCollector.ts +3 -1
- package/src/replication/RelationCache.ts +23 -4
- package/src/routes/configure-fastify.ts +8 -1
- package/src/routes/endpoints/admin.ts +10 -5
- package/src/routes/endpoints/sync-rules.ts +1 -1
- package/src/routes/route-register.ts +73 -4
- package/src/storage/BucketStorageBatch.ts +32 -0
- package/src/storage/BucketStorageFactory.ts +6 -1
- package/src/storage/PersistedSyncRulesContent.ts +9 -9
- package/src/storage/SourceEntity.ts +9 -1
- package/src/storage/SourceTable.ts +53 -19
- package/src/storage/SyncRulesBucketStorage.ts +28 -15
- package/src/sync/BucketChecksumState.ts +5 -5
- package/src/sync/sync.ts +3 -3
- package/src/tracing/PerformanceTracer.ts +24 -1
- package/src/util/util-index.ts +1 -0
- package/src/util/utils.ts +8 -0
- package/test/src/auth.test.ts +11 -0
- package/test/src/diagnostics.test.ts +10 -6
- package/test/src/routes/error-handler.integration.test.ts +275 -0
- package/test/src/routes/stream.test.ts +15 -4
- package/test/src/storage/SourceTable.test.ts +89 -0
- package/test/src/sync/BucketChecksumState.test.ts +25 -17
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import * as storage from '../../../src/storage/storage-index.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Build a SourceTable with the current `ref`-based options shape.
|
|
6
|
+
* Data/parameter sources are not relevant to the storeCurrentData behaviour, so they default to empty.
|
|
7
|
+
*/
|
|
8
|
+
function makeTable(options: Partial<storage.SourceTableOptions> = {}): storage.SourceTable {
|
|
9
|
+
return new storage.SourceTable({
|
|
10
|
+
id: 'test-id',
|
|
11
|
+
ref: { connectionTag: 'test', schema: 'public', name: 'test_table' },
|
|
12
|
+
objectId: 123,
|
|
13
|
+
replicaIdColumns: [{ name: 'id' }],
|
|
14
|
+
snapshotComplete: true,
|
|
15
|
+
bucketDataSources: [],
|
|
16
|
+
parameterLookupSources: [],
|
|
17
|
+
...options
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe('SourceTable', () => {
|
|
22
|
+
describe('storeCurrentData property', () => {
|
|
23
|
+
test('defaults to true', () => {
|
|
24
|
+
const table = makeTable();
|
|
25
|
+
expect(table.storeCurrentData).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('can be set to false', () => {
|
|
29
|
+
const table = makeTable();
|
|
30
|
+
table.storeCurrentData = false;
|
|
31
|
+
expect(table.storeCurrentData).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('is preserved when cloning', () => {
|
|
35
|
+
const table = makeTable();
|
|
36
|
+
table.storeCurrentData = false;
|
|
37
|
+
const cloned = table.clone();
|
|
38
|
+
|
|
39
|
+
expect(cloned.storeCurrentData).toBe(false);
|
|
40
|
+
expect(cloned).not.toBe(table);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('clone preserves all properties including storeCurrentData', () => {
|
|
44
|
+
const table = makeTable({
|
|
45
|
+
replicaIdColumns: [{ name: 'id', type: 'int4' }],
|
|
46
|
+
snapshotComplete: false
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
table.syncData = false;
|
|
50
|
+
table.syncParameters = false;
|
|
51
|
+
table.syncEvent = false;
|
|
52
|
+
table.storeCurrentData = false;
|
|
53
|
+
table.snapshotStatus = {
|
|
54
|
+
totalEstimatedCount: 100,
|
|
55
|
+
replicatedCount: 50,
|
|
56
|
+
lastKey: Buffer.from('test')
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const cloned = table.clone();
|
|
60
|
+
|
|
61
|
+
expect(cloned.syncData).toBe(false);
|
|
62
|
+
expect(cloned.syncParameters).toBe(false);
|
|
63
|
+
expect(cloned.syncEvent).toBe(false);
|
|
64
|
+
expect(cloned.storeCurrentData).toBe(false);
|
|
65
|
+
expect(cloned.snapshotStatus).toEqual(table.snapshotStatus);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
describe('integration with other properties', () => {
|
|
70
|
+
test('storeCurrentData does not affect syncAny', () => {
|
|
71
|
+
const table = makeTable();
|
|
72
|
+
|
|
73
|
+
table.storeCurrentData = false;
|
|
74
|
+
table.syncData = true;
|
|
75
|
+
table.syncParameters = false;
|
|
76
|
+
table.syncEvent = false;
|
|
77
|
+
|
|
78
|
+
expect(table.syncAny).toBe(true); // Should still be true
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('storeCurrentData is independent of snapshot status', () => {
|
|
82
|
+
const table = makeTable({ snapshotComplete: false });
|
|
83
|
+
|
|
84
|
+
table.storeCurrentData = false;
|
|
85
|
+
expect(table.snapshotComplete).toBe(false);
|
|
86
|
+
expect(table.storeCurrentData).toBe(false);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
});
|
|
@@ -15,34 +15,39 @@ import {
|
|
|
15
15
|
} from '@/index.js';
|
|
16
16
|
import { JSONBig } from '@powersync/service-jsonbig';
|
|
17
17
|
import {
|
|
18
|
+
nodeSqlite,
|
|
18
19
|
ParameterIndexLookupCreator,
|
|
20
|
+
ParameterLookupDefinitionId,
|
|
19
21
|
ParameterLookupRows,
|
|
22
|
+
ParameterLookupScope,
|
|
20
23
|
ScopedParameterLookup,
|
|
21
|
-
|
|
22
|
-
SqliteRow,
|
|
24
|
+
SourceTableRef,
|
|
23
25
|
SqlSyncRules,
|
|
24
26
|
TablePattern,
|
|
25
27
|
versionedHydrationState
|
|
26
28
|
} from '@powersync/service-sync-rules';
|
|
27
|
-
import
|
|
29
|
+
import * as sqlite from 'node:sqlite';
|
|
28
30
|
import { beforeEach, describe, expect, test } from 'vitest';
|
|
29
31
|
|
|
30
32
|
describe('BucketChecksumState', () => {
|
|
31
33
|
const LOOKUP_SOURCE: ParameterIndexLookupCreator = {
|
|
32
|
-
get
|
|
34
|
+
get sourceId(): ParameterLookupDefinitionId {
|
|
33
35
|
return {
|
|
34
36
|
lookupName: 'lookup',
|
|
35
|
-
queryId: '0'
|
|
36
|
-
source: LOOKUP_SOURCE
|
|
37
|
+
queryId: '0'
|
|
37
38
|
};
|
|
38
39
|
},
|
|
39
40
|
getSourceTables(): Set<TablePattern> {
|
|
40
41
|
return new Set();
|
|
41
42
|
},
|
|
42
|
-
|
|
43
|
-
return
|
|
43
|
+
createEvaluator() {
|
|
44
|
+
return {
|
|
45
|
+
evaluateParameterRow() {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
};
|
|
44
49
|
},
|
|
45
|
-
tableSyncsParameters(_table:
|
|
50
|
+
tableSyncsParameters(_table: SourceTableRef): boolean {
|
|
46
51
|
return false;
|
|
47
52
|
}
|
|
48
53
|
};
|
|
@@ -60,7 +65,7 @@ bucket_definitions:
|
|
|
60
65
|
data: []
|
|
61
66
|
`,
|
|
62
67
|
{ defaultSchema: 'public' }
|
|
63
|
-
).config.hydrate({ hydrationState: versionedHydrationState(1) });
|
|
68
|
+
).config.hydrate({ hydrationState: versionedHydrationState(1), sqlite: nodeSqlite(sqlite) });
|
|
64
69
|
|
|
65
70
|
// global[1] and global[2]
|
|
66
71
|
const SYNC_RULES_GLOBAL_TWO = SqlSyncRules.fromYaml(
|
|
@@ -73,7 +78,7 @@ bucket_definitions:
|
|
|
73
78
|
data: []
|
|
74
79
|
`,
|
|
75
80
|
{ defaultSchema: 'public' }
|
|
76
|
-
).config.hydrate({ hydrationState: versionedHydrationState(2) });
|
|
81
|
+
).config.hydrate({ hydrationState: versionedHydrationState(2), sqlite: nodeSqlite(sqlite) });
|
|
77
82
|
|
|
78
83
|
// by_project[n]
|
|
79
84
|
const SYNC_RULES_DYNAMIC = SqlSyncRules.fromYaml(
|
|
@@ -84,7 +89,7 @@ bucket_definitions:
|
|
|
84
89
|
data: []
|
|
85
90
|
`,
|
|
86
91
|
{ defaultSchema: 'public' }
|
|
87
|
-
).config.hydrate({ hydrationState: versionedHydrationState(3) });
|
|
92
|
+
).config.hydrate({ hydrationState: versionedHydrationState(3), sqlite: nodeSqlite(sqlite) });
|
|
88
93
|
|
|
89
94
|
const syncContext = new SyncContext({
|
|
90
95
|
maxBuckets: 100,
|
|
@@ -655,7 +660,7 @@ config:
|
|
|
655
660
|
|
|
656
661
|
const rules = SqlSyncRules.fromYaml(source, {
|
|
657
662
|
defaultSchema: 'public'
|
|
658
|
-
}).config.hydrate({ hydrationState: versionedHydrationState(1) });
|
|
663
|
+
}).config.hydrate({ hydrationState: versionedHydrationState(1), sqlite: nodeSqlite(sqlite) });
|
|
659
664
|
|
|
660
665
|
return new BucketChecksumState({
|
|
661
666
|
syncContext,
|
|
@@ -921,7 +926,8 @@ streams:
|
|
|
921
926
|
`,
|
|
922
927
|
{ defaultSchema: 'public' }
|
|
923
928
|
).config.hydrate({
|
|
924
|
-
hydrationState: versionedHydrationState(1)
|
|
929
|
+
hydrationState: versionedHydrationState(1),
|
|
930
|
+
sqlite: nodeSqlite(sqlite)
|
|
925
931
|
});
|
|
926
932
|
|
|
927
933
|
const storage = new MockBucketChecksumStateStorage();
|
|
@@ -1018,7 +1024,8 @@ streams:
|
|
|
1018
1024
|
`,
|
|
1019
1025
|
{ defaultSchema: 'public' }
|
|
1020
1026
|
).config.hydrate({
|
|
1021
|
-
hydrationState: versionedHydrationState(1)
|
|
1027
|
+
hydrationState: versionedHydrationState(1),
|
|
1028
|
+
sqlite: nodeSqlite(sqlite)
|
|
1022
1029
|
});
|
|
1023
1030
|
|
|
1024
1031
|
const storage = new MockBucketChecksumStateStorage();
|
|
@@ -1090,7 +1097,7 @@ streams:
|
|
|
1090
1097
|
query: SELECT id FROM comments WHERE p IN auth.parameter('c')
|
|
1091
1098
|
`,
|
|
1092
1099
|
{ defaultSchema: 'public' }
|
|
1093
|
-
).config.hydrate({ hydrationState: versionedHydrationState(4) });
|
|
1100
|
+
).config.hydrate({ hydrationState: versionedHydrationState(4), sqlite: nodeSqlite(sqlite) });
|
|
1094
1101
|
|
|
1095
1102
|
const storage = new MockBucketChecksumStateStorage();
|
|
1096
1103
|
|
|
@@ -1165,7 +1172,8 @@ streams:
|
|
|
1165
1172
|
}
|
|
1166
1173
|
|
|
1167
1174
|
const SYNC_RULES_MANY = SqlSyncRules.fromYaml(yamlDefinitions, { defaultSchema: 'public' }).config.hydrate({
|
|
1168
|
-
hydrationState: versionedHydrationState(5)
|
|
1175
|
+
hydrationState: versionedHydrationState(5),
|
|
1176
|
+
sqlite: nodeSqlite(sqlite)
|
|
1169
1177
|
});
|
|
1170
1178
|
|
|
1171
1179
|
const storage = new MockBucketChecksumStateStorage();
|