@powersync/service-core 0.18.1 → 1.7.1
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 +29 -0
- package/dist/api/RouteAPI.d.ts +1 -1
- package/dist/api/diagnostics.js +107 -169
- package/dist/api/diagnostics.js.map +1 -1
- package/dist/entry/commands/compact-action.js +10 -73
- package/dist/entry/commands/compact-action.js.map +1 -1
- package/dist/modules/AbstractModule.d.ts +1 -1
- package/dist/replication/AbstractReplicator.js +8 -76
- package/dist/replication/AbstractReplicator.js.map +1 -1
- package/dist/routes/endpoints/checkpointing.js +3 -2
- package/dist/routes/endpoints/checkpointing.js.map +1 -1
- package/dist/routes/endpoints/socket-route.js +5 -5
- package/dist/routes/endpoints/socket-route.js.map +1 -1
- package/dist/routes/endpoints/sync-stream.js +5 -5
- package/dist/routes/endpoints/sync-stream.js.map +1 -1
- package/dist/runner/teardown.js +3 -65
- package/dist/runner/teardown.js.map +1 -1
- package/dist/storage/BucketStorage.d.ts +8 -441
- package/dist/storage/BucketStorage.js +9 -10
- package/dist/storage/BucketStorage.js.map +1 -1
- package/dist/storage/BucketStorageBatch.d.ts +130 -0
- package/dist/storage/BucketStorageBatch.js +10 -0
- package/dist/storage/BucketStorageBatch.js.map +1 -0
- package/dist/storage/BucketStorageFactory.d.ts +145 -0
- package/dist/storage/BucketStorageFactory.js +2 -0
- package/dist/storage/BucketStorageFactory.js.map +1 -0
- package/dist/storage/ChecksumCache.js.map +1 -1
- package/dist/storage/PersistedSyncRulesContent.d.ts +20 -0
- package/dist/storage/PersistedSyncRulesContent.js +2 -0
- package/dist/storage/PersistedSyncRulesContent.js.map +1 -0
- package/dist/storage/ReplicationEventPayload.d.ts +1 -1
- package/dist/storage/ReplicationLock.d.ts +4 -0
- package/dist/storage/ReplicationLock.js +2 -0
- package/dist/storage/ReplicationLock.js.map +1 -0
- package/dist/storage/SourceEntity.d.ts +6 -2
- package/dist/storage/SourceTable.d.ts +2 -2
- package/dist/storage/SourceTable.js.map +1 -1
- package/dist/storage/StorageEngine.d.ts +4 -4
- package/dist/storage/StorageEngine.js +2 -2
- package/dist/storage/StorageEngine.js.map +1 -1
- package/dist/storage/StorageProvider.d.ts +4 -1
- package/dist/storage/SyncRulesBucketStorage.d.ts +207 -0
- package/dist/storage/SyncRulesBucketStorage.js +7 -0
- package/dist/storage/SyncRulesBucketStorage.js.map +1 -0
- package/dist/storage/bson.d.ts +14 -3
- package/dist/storage/bson.js +18 -2
- package/dist/storage/bson.js.map +1 -1
- package/dist/storage/storage-index.d.ts +5 -0
- package/dist/storage/storage-index.js +5 -0
- package/dist/storage/storage-index.js.map +1 -1
- package/dist/sync/BucketChecksumState.d.ts +91 -0
- package/dist/sync/BucketChecksumState.js +313 -0
- package/dist/sync/BucketChecksumState.js.map +1 -0
- package/dist/sync/sync-index.d.ts +1 -0
- package/dist/sync/sync-index.js +1 -0
- package/dist/sync/sync-index.js.map +1 -1
- package/dist/sync/sync.d.ts +7 -3
- package/dist/sync/sync.js +139 -135
- package/dist/sync/sync.js.map +1 -1
- package/dist/sync/util.d.ts +9 -0
- package/dist/sync/util.js +44 -0
- package/dist/sync/util.js.map +1 -1
- package/dist/util/checkpointing.d.ts +1 -1
- package/dist/util/checkpointing.js +15 -78
- package/dist/util/checkpointing.js.map +1 -1
- package/dist/util/protocol-types.d.ts +13 -4
- package/package.json +5 -5
- package/src/api/RouteAPI.ts +1 -1
- package/src/api/diagnostics.ts +1 -1
- package/src/entry/commands/compact-action.ts +2 -3
- package/src/modules/AbstractModule.ts +1 -1
- package/src/replication/AbstractReplicator.ts +7 -12
- package/src/routes/endpoints/checkpointing.ts +3 -3
- package/src/routes/endpoints/socket-route.ts +7 -5
- package/src/routes/endpoints/sync-stream.ts +8 -5
- package/src/runner/teardown.ts +1 -1
- package/src/storage/BucketStorage.ts +8 -550
- package/src/storage/BucketStorageBatch.ts +158 -0
- package/src/storage/BucketStorageFactory.ts +166 -0
- package/src/storage/ChecksumCache.ts +1 -0
- package/src/storage/PersistedSyncRulesContent.ts +26 -0
- package/src/storage/ReplicationEventPayload.ts +1 -1
- package/src/storage/ReplicationLock.ts +5 -0
- package/src/storage/SourceEntity.ts +6 -2
- package/src/storage/SourceTable.ts +1 -1
- package/src/storage/StorageEngine.ts +4 -4
- package/src/storage/StorageProvider.ts +4 -1
- package/src/storage/SyncRulesBucketStorage.ts +265 -0
- package/src/storage/bson.ts +22 -4
- package/src/storage/storage-index.ts +5 -0
- package/src/sync/BucketChecksumState.ts +392 -0
- package/src/sync/sync-index.ts +1 -0
- package/src/sync/sync.ts +182 -157
- package/src/sync/util.ts +54 -0
- package/src/util/checkpointing.ts +4 -6
- package/src/util/protocol-types.ts +16 -4
- package/test/src/auth.test.ts +5 -5
- package/test/src/sync/BucketChecksumState.test.ts +565 -0
- package/test/src/sync/util.test.ts +34 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as t from 'ts-codec';
|
|
2
|
-
import { SqliteJsonValue } from '@powersync/service-sync-rules';
|
|
2
|
+
import { BucketDescription, BucketPriority, SqliteJsonValue } from '@powersync/service-sync-rules';
|
|
3
3
|
export declare const BucketRequest: t.ObjectCodec<{
|
|
4
4
|
name: t.IdentityCodec<t.CodecType.String>;
|
|
5
5
|
/**
|
|
@@ -52,7 +52,7 @@ export interface StreamingSyncCheckpointDiff {
|
|
|
52
52
|
checkpoint_diff: {
|
|
53
53
|
last_op_id: OpId;
|
|
54
54
|
write_checkpoint?: OpId;
|
|
55
|
-
updated_buckets:
|
|
55
|
+
updated_buckets: BucketChecksumWithDescription[];
|
|
56
56
|
removed_buckets: string[];
|
|
57
57
|
};
|
|
58
58
|
}
|
|
@@ -64,9 +64,16 @@ export interface StreamingSyncCheckpointComplete {
|
|
|
64
64
|
last_op_id: OpId;
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
|
+
export interface StreamingSyncCheckpointPartiallyComplete {
|
|
68
|
+
partial_checkpoint_complete: {
|
|
69
|
+
last_op_id: OpId;
|
|
70
|
+
priority: BucketPriority;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
67
73
|
export interface StreamingSyncKeepalive {
|
|
74
|
+
token_expires_in: number;
|
|
68
75
|
}
|
|
69
|
-
export type StreamingSyncLine = StreamingSyncData | StreamingSyncCheckpoint | StreamingSyncCheckpointDiff | StreamingSyncCheckpointComplete | StreamingSyncKeepalive;
|
|
76
|
+
export type StreamingSyncLine = StreamingSyncData | StreamingSyncCheckpoint | StreamingSyncCheckpointDiff | StreamingSyncCheckpointComplete | StreamingSyncCheckpointPartiallyComplete | StreamingSyncKeepalive;
|
|
70
77
|
/**
|
|
71
78
|
* 64-bit unsigned number, as a base-10 string.
|
|
72
79
|
*/
|
|
@@ -74,7 +81,7 @@ export type OpId = string;
|
|
|
74
81
|
export interface Checkpoint {
|
|
75
82
|
last_op_id: OpId;
|
|
76
83
|
write_checkpoint?: OpId;
|
|
77
|
-
buckets:
|
|
84
|
+
buckets: BucketChecksumWithDescription[];
|
|
78
85
|
}
|
|
79
86
|
export interface BucketState {
|
|
80
87
|
bucket: string;
|
|
@@ -119,3 +126,5 @@ export interface BucketChecksum {
|
|
|
119
126
|
*/
|
|
120
127
|
count: number;
|
|
121
128
|
}
|
|
129
|
+
export interface BucketChecksumWithDescription extends BucketChecksum, BucketDescription {
|
|
130
|
+
}
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
8
|
-
"version": "
|
|
8
|
+
"version": "1.7.1",
|
|
9
9
|
"main": "dist/index.js",
|
|
10
10
|
"license": "FSL-1.1-Apache-2.0",
|
|
11
11
|
"type": "module",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"@opentelemetry/sdk-metrics": "1.24.1",
|
|
19
19
|
"async": "^3.2.4",
|
|
20
20
|
"async-mutex": "^0.5.0",
|
|
21
|
-
"bson": "^6.
|
|
21
|
+
"bson": "^6.10.3",
|
|
22
22
|
"commander": "^12.0.0",
|
|
23
23
|
"cors": "^2.8.5",
|
|
24
24
|
"ipaddr.js": "^2.1.0",
|
|
@@ -32,10 +32,10 @@
|
|
|
32
32
|
"uuid": "^9.0.1",
|
|
33
33
|
"winston": "^3.13.0",
|
|
34
34
|
"yaml": "^2.3.2",
|
|
35
|
-
"@powersync/lib-services-framework": "0.5.
|
|
35
|
+
"@powersync/lib-services-framework": "0.5.3",
|
|
36
36
|
"@powersync/service-jsonbig": "0.17.10",
|
|
37
|
-
"@powersync/service-rsocket-router": "0.0.
|
|
38
|
-
"@powersync/service-sync-rules": "0.
|
|
37
|
+
"@powersync/service-rsocket-router": "0.0.20",
|
|
38
|
+
"@powersync/service-sync-rules": "0.24.0",
|
|
39
39
|
"@powersync/service-types": "0.8.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
package/src/api/RouteAPI.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SqlSyncRules, TablePattern } from '@powersync/service-sync-rules';
|
|
2
2
|
import * as types from '@powersync/service-types';
|
|
3
|
-
import { ParseSyncRulesOptions, SyncRulesBucketStorage } from '../storage/
|
|
3
|
+
import { ParseSyncRulesOptions, SyncRulesBucketStorage } from '../storage/storage-index.js';
|
|
4
4
|
|
|
5
5
|
export interface PatternResult {
|
|
6
6
|
schema: string;
|
package/src/api/diagnostics.ts
CHANGED
|
@@ -57,7 +57,7 @@ export async function getSyncRulesStatus(
|
|
|
57
57
|
// This method can run under some situations if no connection is configured yet.
|
|
58
58
|
// It will return a default tag in such a case. This default tag is not module specific.
|
|
59
59
|
const tag = sourceConfig.tag ?? DEFAULT_TAG;
|
|
60
|
-
|
|
60
|
+
const systemStorage = live_status ? bucketStorage.getInstance(sync_rules) : undefined;
|
|
61
61
|
const status = await systemStorage?.getStatus();
|
|
62
62
|
let replication_lag_bytes: number | undefined = undefined;
|
|
63
63
|
|
|
@@ -50,14 +50,13 @@ export function registerCompactAction(program: Command) {
|
|
|
50
50
|
await serviceContext.lifeCycleEngine.start();
|
|
51
51
|
const bucketStorage = serviceContext.storageEngine.activeBucketStorage;
|
|
52
52
|
|
|
53
|
-
const active = await bucketStorage.
|
|
53
|
+
const active = await bucketStorage.getActiveStorage();
|
|
54
54
|
if (active == null) {
|
|
55
55
|
logger.info('No active instance to compact');
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
|
-
using p = bucketStorage.getInstance(active);
|
|
59
58
|
logger.info('Performing compaction...');
|
|
60
|
-
await
|
|
59
|
+
await active.compact({ memoryLimitMB: COMPACT_MEMORY_LIMIT_MB, compactBuckets: buckets });
|
|
61
60
|
logger.info('Successfully compacted storage.');
|
|
62
61
|
} catch (e) {
|
|
63
62
|
logger.error(`Failed to compact: ${e.toString()}`);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ServiceContextContainer } from '../system/ServiceContext.js';
|
|
2
2
|
import { logger } from '@powersync/lib-services-framework';
|
|
3
3
|
import winston from 'winston';
|
|
4
|
-
import { PersistedSyncRulesContent } from '../storage/
|
|
4
|
+
import { PersistedSyncRulesContent } from '../storage/storage-index.js';
|
|
5
5
|
|
|
6
6
|
export interface TearDownOptions {
|
|
7
7
|
/**
|
|
@@ -193,16 +193,15 @@ export abstract class AbstractReplicator<T extends AbstractReplicationJob = Abst
|
|
|
193
193
|
|
|
194
194
|
this.replicationJobs = newJobs;
|
|
195
195
|
|
|
196
|
-
//
|
|
196
|
+
// Stop any orphaned jobs that no longer have sync rules.
|
|
197
|
+
// Termination happens below
|
|
197
198
|
for (let job of existingJobs.values()) {
|
|
198
199
|
// Old - stop and clean up
|
|
199
200
|
try {
|
|
200
201
|
await job.stop();
|
|
201
|
-
await this.terminateSyncRules(job.storage);
|
|
202
|
-
job.storage[Symbol.dispose]();
|
|
203
202
|
} catch (e) {
|
|
204
203
|
// This will be retried
|
|
205
|
-
this.logger.warn('Failed to
|
|
204
|
+
this.logger.warn('Failed to stop old replication job}', e);
|
|
206
205
|
}
|
|
207
206
|
}
|
|
208
207
|
|
|
@@ -210,7 +209,7 @@ export abstract class AbstractReplicator<T extends AbstractReplicationJob = Abst
|
|
|
210
209
|
const stopped = await this.storage.getStoppedSyncRules();
|
|
211
210
|
for (let syncRules of stopped) {
|
|
212
211
|
try {
|
|
213
|
-
|
|
212
|
+
const syncRuleStorage = this.storage.getInstance(syncRules, { skipLifecycleHooks: true });
|
|
214
213
|
await this.terminateSyncRules(syncRuleStorage);
|
|
215
214
|
} catch (e) {
|
|
216
215
|
this.logger.warn(`Failed clean up replication config for sync rule: ${syncRules.id}`, e);
|
|
@@ -224,13 +223,9 @@ export abstract class AbstractReplicator<T extends AbstractReplicationJob = Abst
|
|
|
224
223
|
|
|
225
224
|
protected async terminateSyncRules(syncRuleStorage: storage.SyncRulesBucketStorage) {
|
|
226
225
|
this.logger.info(`Terminating sync rules: ${syncRuleStorage.group_id}...`);
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
this.logger.info(`Successfully terminated sync rules: ${syncRuleStorage.group_id}`);
|
|
231
|
-
} catch (e) {
|
|
232
|
-
this.logger.warn(`Failed clean up replication config for sync rules: ${syncRuleStorage.group_id}`, e);
|
|
233
|
-
}
|
|
226
|
+
await this.cleanUp(syncRuleStorage);
|
|
227
|
+
await syncRuleStorage.terminate();
|
|
228
|
+
this.logger.info(`Successfully terminated sync rules: ${syncRuleStorage.group_id}`);
|
|
234
229
|
}
|
|
235
230
|
|
|
236
231
|
abstract testConnection(): Promise<ConnectionTestResult>;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { logger, router, schema } from '@powersync/lib-services-framework';
|
|
2
2
|
import * as t from 'ts-codec';
|
|
3
3
|
|
|
4
|
-
import * as framework from '@powersync/lib-services-framework';
|
|
5
4
|
import * as util from '../../util/util-index.js';
|
|
6
5
|
import { authUser } from '../auth.js';
|
|
7
6
|
import { routeDefinition } from '../router.js';
|
|
@@ -31,8 +30,9 @@ export const writeCheckpoint = routeDefinition({
|
|
|
31
30
|
|
|
32
31
|
logger.info(`Waiting for LSN checkpoint: ${head}`);
|
|
33
32
|
while (Date.now() - start < timeout) {
|
|
34
|
-
const
|
|
35
|
-
|
|
33
|
+
const bucketStorage = await service_context.storageEngine.activeBucketStorage.getActiveStorage();
|
|
34
|
+
const cp = await bucketStorage?.getCheckpoint();
|
|
35
|
+
if (cp == null) {
|
|
36
36
|
throw new Error('No sync rules available');
|
|
37
37
|
}
|
|
38
38
|
if (cp.lsn && cp.lsn >= head) {
|
|
@@ -49,9 +49,9 @@ export const syncStreamReactive: SocketRouteGenerator = (router) =>
|
|
|
49
49
|
const {
|
|
50
50
|
storageEngine: { activeBucketStorage }
|
|
51
51
|
} = service_context;
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
if (
|
|
52
|
+
|
|
53
|
+
const bucketStorage = await activeBucketStorage.getActiveStorage();
|
|
54
|
+
if (bucketStorage == null) {
|
|
55
55
|
responder.onError(
|
|
56
56
|
new errors.ServiceError({
|
|
57
57
|
status: 500,
|
|
@@ -63,6 +63,8 @@ export const syncStreamReactive: SocketRouteGenerator = (router) =>
|
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
const syncRules = bucketStorage.getParsedSyncRules(routerEngine!.getAPI().getParseSyncRulesOptions());
|
|
67
|
+
|
|
66
68
|
const removeStopHandler = routerEngine!.addStopHandler(() => {
|
|
67
69
|
controller.abort();
|
|
68
70
|
});
|
|
@@ -71,8 +73,8 @@ export const syncStreamReactive: SocketRouteGenerator = (router) =>
|
|
|
71
73
|
const tracker = new sync.RequestTracker();
|
|
72
74
|
try {
|
|
73
75
|
for await (const data of sync.streamResponse({
|
|
74
|
-
|
|
75
|
-
|
|
76
|
+
bucketStorage: bucketStorage,
|
|
77
|
+
syncRules: syncRules,
|
|
76
78
|
params: {
|
|
77
79
|
...params,
|
|
78
80
|
binary_data: true // always true for web sockets
|
|
@@ -36,15 +36,18 @@ export const syncStreamed = routeDefinition({
|
|
|
36
36
|
const params: util.StreamingSyncRequest = payload.params;
|
|
37
37
|
const syncParams = new RequestParameters(payload.context.token_payload!, payload.params.parameters ?? {});
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (
|
|
39
|
+
const bucketStorage = await storageEngine.activeBucketStorage.getActiveStorage();
|
|
40
|
+
|
|
41
|
+
if (bucketStorage == null) {
|
|
42
42
|
throw new errors.ServiceError({
|
|
43
43
|
status: 500,
|
|
44
44
|
code: ErrorCode.PSYNC_S2302,
|
|
45
45
|
description: 'No sync rules available'
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
|
+
|
|
49
|
+
const syncRules = bucketStorage.getParsedSyncRules(routerEngine!.getAPI().getParseSyncRulesOptions());
|
|
50
|
+
|
|
48
51
|
const controller = new AbortController();
|
|
49
52
|
const tracker = new sync.RequestTracker();
|
|
50
53
|
try {
|
|
@@ -53,8 +56,8 @@ export const syncStreamed = routeDefinition({
|
|
|
53
56
|
sync.transformToBytesTracked(
|
|
54
57
|
sync.ndjson(
|
|
55
58
|
sync.streamResponse({
|
|
56
|
-
|
|
57
|
-
|
|
59
|
+
bucketStorage,
|
|
60
|
+
syncRules: syncRules,
|
|
58
61
|
params,
|
|
59
62
|
syncParams,
|
|
60
63
|
token: payload.context.token_payload!,
|
package/src/runner/teardown.ts
CHANGED
|
@@ -51,7 +51,7 @@ async function terminateSyncRules(storageFactory: storage.BucketStorageFactory,
|
|
|
51
51
|
|
|
52
52
|
// Mark the sync rules as terminated
|
|
53
53
|
for (let syncRules of combinedSyncRules) {
|
|
54
|
-
|
|
54
|
+
const syncRulesStorage = storageFactory.getInstance(syncRules);
|
|
55
55
|
// The storage will be dropped at the end of the teardown, so we don't need to clear it here
|
|
56
56
|
await syncRulesStorage.terminate({ clearStorage: false });
|
|
57
57
|
}
|