@powersync/service-core 0.0.0-dev-20260225160713 → 0.0.0-dev-20260511080634
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 +102 -5
- package/dist/api/RouteAPI.d.ts +17 -3
- package/dist/api/api-index.d.ts +1 -1
- package/dist/api/api-index.js +1 -1
- package/dist/api/api-index.js.map +1 -1
- package/dist/api/api-metrics.js.map +1 -1
- package/dist/api/diagnostics.d.ts +1 -1
- package/dist/api/diagnostics.js +32 -14
- package/dist/api/diagnostics.js.map +1 -1
- package/dist/auth/CachedKeyCollector.js +1 -1
- package/dist/auth/CachedKeyCollector.js.map +1 -1
- package/dist/auth/CompoundKeyCollector.js.map +1 -1
- package/dist/auth/KeyStore.js.map +1 -1
- package/dist/auth/RemoteJWKSCollector.js.map +1 -1
- package/dist/auth/StaticKeyCollector.d.ts +1 -1
- package/dist/auth/StaticKeyCollector.js.map +1 -1
- package/dist/auth/StaticSupabaseKeyCollector.d.ts +1 -1
- package/dist/auth/StaticSupabaseKeyCollector.js.map +1 -1
- package/dist/auth/utils.d.ts +2 -1
- package/dist/auth/utils.js +1 -1
- package/dist/auth/utils.js.map +1 -1
- package/dist/entry/commands/compact-action.js +26 -5
- package/dist/entry/commands/compact-action.js.map +1 -1
- package/dist/entry/commands/teardown-action.js +2 -2
- package/dist/entry/commands/teardown-action.js.map +1 -1
- package/dist/entry/entry-index.d.ts +1 -1
- package/dist/entry/entry-index.js +1 -1
- package/dist/entry/entry-index.js.map +1 -1
- package/dist/events/EventsEngine.js +1 -1
- package/dist/events/EventsEngine.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/metrics/MetricsEngine.d.ts +1 -1
- package/dist/metrics/RollingBucketMax.d.ts +28 -0
- package/dist/metrics/RollingBucketMax.js +80 -0
- package/dist/metrics/RollingBucketMax.js.map +1 -0
- package/dist/metrics/metrics-index.d.ts +3 -2
- package/dist/metrics/metrics-index.js +3 -2
- package/dist/metrics/metrics-index.js.map +1 -1
- package/dist/metrics/open-telemetry/util.js +1 -1
- package/dist/metrics/open-telemetry/util.js.map +1 -1
- package/dist/metrics/register-metrics.js +2 -2
- package/dist/metrics/register-metrics.js.map +1 -1
- package/dist/modules/AbstractModule.d.ts +2 -2
- package/dist/modules/AbstractModule.js.map +1 -1
- package/dist/modules/modules-index.d.ts +1 -1
- package/dist/modules/modules-index.js +1 -1
- package/dist/modules/modules-index.js.map +1 -1
- package/dist/replication/AbstractReplicationJob.d.ts +2 -2
- package/dist/replication/AbstractReplicationJob.js +1 -1
- package/dist/replication/AbstractReplicationJob.js.map +1 -1
- package/dist/replication/AbstractReplicator.d.ts +7 -7
- package/dist/replication/AbstractReplicator.js +31 -28
- package/dist/replication/AbstractReplicator.js.map +1 -1
- package/dist/replication/ReplicationLagTracker.d.ts +50 -0
- package/dist/replication/ReplicationLagTracker.js +78 -0
- package/dist/replication/ReplicationLagTracker.js.map +1 -0
- package/dist/replication/replication-index.d.ts +3 -2
- package/dist/replication/replication-index.js +3 -2
- package/dist/replication/replication-index.js.map +1 -1
- package/dist/replication/replication-metrics.js.map +1 -1
- package/dist/routes/configure-fastify.d.ts +59 -32
- package/dist/routes/endpoints/admin.d.ts +108 -54
- package/dist/routes/endpoints/admin.js +8 -3
- package/dist/routes/endpoints/admin.js.map +1 -1
- package/dist/routes/endpoints/checkpointing.js +1 -1
- package/dist/routes/endpoints/checkpointing.js.map +1 -1
- package/dist/routes/endpoints/socket-route.js +1 -1
- package/dist/routes/endpoints/socket-route.js.map +1 -1
- package/dist/routes/endpoints/sync-rules.js +10 -10
- package/dist/routes/endpoints/sync-rules.js.map +1 -1
- package/dist/routes/endpoints/sync-stream.d.ts +10 -10
- package/dist/routes/endpoints/sync-stream.js +8 -3
- package/dist/routes/endpoints/sync-stream.js.map +1 -1
- package/dist/routes/hooks.js +1 -1
- package/dist/routes/hooks.js.map +1 -1
- package/dist/routes/route-register.js.map +1 -1
- package/dist/runner/teardown.js +4 -4
- package/dist/runner/teardown.js.map +1 -1
- package/dist/storage/BucketStorage.d.ts +9 -9
- package/dist/storage/BucketStorage.js +9 -9
- package/dist/storage/BucketStorageBatch.d.ts +30 -9
- package/dist/storage/BucketStorageBatch.js.map +1 -1
- package/dist/storage/BucketStorageFactory.d.ts +32 -20
- package/dist/storage/BucketStorageFactory.js +19 -16
- package/dist/storage/BucketStorageFactory.js.map +1 -1
- package/dist/storage/ChecksumCache.d.ts +5 -2
- package/dist/storage/ChecksumCache.js +8 -4
- package/dist/storage/ChecksumCache.js.map +1 -1
- package/dist/storage/PersistedSyncRulesContent.d.ts +9 -3
- package/dist/storage/PersistedSyncRulesContent.js +25 -5
- package/dist/storage/PersistedSyncRulesContent.js.map +1 -1
- package/dist/storage/ReplicationEventPayload.d.ts +1 -1
- package/dist/storage/SourceTable.d.ts +10 -5
- package/dist/storage/SourceTable.js +3 -3
- package/dist/storage/SourceTable.js.map +1 -1
- package/dist/storage/StorageVersionConfig.d.ts +34 -1
- package/dist/storage/StorageVersionConfig.js +40 -7
- package/dist/storage/StorageVersionConfig.js.map +1 -1
- package/dist/storage/SyncRulesBucketStorage.d.ts +63 -11
- package/dist/storage/SyncRulesBucketStorage.js +14 -0
- package/dist/storage/SyncRulesBucketStorage.js.map +1 -1
- package/dist/storage/WriteCheckpointAPI.d.ts +6 -6
- package/dist/storage/WriteCheckpointAPI.js +1 -1
- package/dist/storage/bson.d.ts +0 -1
- package/dist/storage/bson.js +0 -4
- package/dist/storage/bson.js.map +1 -1
- package/dist/storage/storage-index.d.ts +8 -8
- package/dist/storage/storage-index.js +8 -8
- package/dist/storage/storage-index.js.map +1 -1
- package/dist/storage/storage-metrics.js.map +1 -1
- package/dist/streams/streams-index.d.ts +2 -2
- package/dist/streams/streams-index.js +2 -2
- package/dist/streams/streams-index.js.map +1 -1
- package/dist/sync/BucketChecksumState.d.ts +5 -8
- package/dist/sync/BucketChecksumState.js +118 -116
- package/dist/sync/BucketChecksumState.js.map +1 -1
- package/dist/sync/RequestTracker.js +1 -1
- package/dist/sync/RequestTracker.js.map +1 -1
- package/dist/sync/sync-index.d.ts +2 -2
- package/dist/sync/sync-index.js +2 -2
- package/dist/sync/sync-index.js.map +1 -1
- package/dist/sync/sync.js.map +1 -1
- package/dist/sync/util.d.ts +1 -0
- package/dist/sync/util.js +10 -0
- package/dist/sync/util.js.map +1 -1
- package/dist/system/ServiceContext.d.ts +1 -1
- package/dist/system/ServiceContext.js +1 -1
- package/dist/system/ServiceContext.js.map +1 -1
- package/dist/tracing/PerformanceTracer.d.ts +44 -0
- package/dist/tracing/PerformanceTracer.js +102 -0
- package/dist/tracing/PerformanceTracer.js.map +1 -0
- package/dist/tracing/TraceWriter.d.ts +22 -0
- package/dist/tracing/TraceWriter.js +63 -0
- package/dist/tracing/TraceWriter.js.map +1 -0
- package/dist/util/checkpointing.js +1 -1
- package/dist/util/config/collectors/impl/base64-config-collector.d.ts +1 -1
- package/dist/util/config/collectors/impl/base64-config-collector.js.map +1 -1
- package/dist/util/config/collectors/impl/filesystem-config-collector.d.ts +1 -1
- package/dist/util/config/collectors/impl/filesystem-config-collector.js +1 -1
- package/dist/util/config/collectors/impl/filesystem-config-collector.js.map +1 -1
- package/dist/util/config/compound-config-collector.d.ts +1 -1
- package/dist/util/config/compound-config-collector.js +2 -2
- package/dist/util/config/compound-config-collector.js.map +1 -1
- package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.js +1 -1
- package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.js.map +1 -1
- package/dist/util/config/sync-rules/sync-rules-provider.js.map +1 -1
- package/dist/util/config.js +1 -1
- package/dist/util/config.js.map +1 -1
- package/dist/util/env.js +1 -1
- package/dist/util/errors.d.ts +3 -0
- package/dist/util/errors.js +15 -0
- package/dist/util/errors.js.map +1 -0
- package/dist/util/protocol-types.d.ts +3 -3
- package/dist/util/protocol-types.js +1 -1
- package/dist/util/util-index.d.ts +1 -1
- package/dist/util/util-index.js +1 -1
- package/dist/util/util-index.js.map +1 -1
- package/dist/util/utils.d.ts +1 -1
- package/package.json +11 -11
- package/src/api/RouteAPI.ts +20 -3
- package/src/api/api-index.ts +1 -1
- package/src/api/api-metrics.ts +1 -1
- package/src/api/diagnostics.ts +42 -20
- package/src/auth/CachedKeyCollector.ts +2 -3
- package/src/auth/CompoundKeyCollector.ts +2 -3
- package/src/auth/KeyStore.ts +1 -1
- package/src/auth/RemoteJWKSCollector.ts +0 -1
- package/src/auth/StaticKeyCollector.ts +1 -1
- package/src/auth/StaticSupabaseKeyCollector.ts +1 -1
- package/src/auth/utils.ts +5 -2
- package/src/entry/commands/compact-action.ts +29 -5
- package/src/entry/commands/teardown-action.ts +2 -2
- package/src/entry/entry-index.ts +1 -1
- package/src/events/EventsEngine.ts +1 -1
- package/src/index.ts +2 -0
- package/src/metrics/MetricsEngine.ts +1 -1
- package/src/metrics/RollingBucketMax.ts +109 -0
- package/src/metrics/metrics-index.ts +3 -2
- package/src/metrics/open-telemetry/util.ts +1 -1
- package/src/metrics/register-metrics.ts +3 -3
- package/src/modules/AbstractModule.ts +2 -2
- package/src/modules/modules-index.ts +1 -1
- package/src/replication/AbstractReplicationJob.ts +3 -3
- package/src/replication/AbstractReplicator.ts +32 -30
- package/src/replication/ReplicationLagTracker.ts +86 -0
- package/src/replication/replication-index.ts +3 -2
- package/src/replication/replication-metrics.ts +1 -1
- package/src/routes/endpoints/admin.ts +8 -3
- package/src/routes/endpoints/checkpointing.ts +1 -1
- package/src/routes/endpoints/socket-route.ts +1 -1
- package/src/routes/endpoints/sync-rules.ts +10 -12
- package/src/routes/endpoints/sync-stream.ts +8 -3
- package/src/routes/hooks.ts +2 -2
- package/src/routes/route-register.ts +2 -10
- package/src/runner/teardown.ts +4 -4
- package/src/storage/BucketStorage.ts +9 -9
- package/src/storage/BucketStorageBatch.ts +34 -10
- package/src/storage/BucketStorageFactory.ts +51 -34
- package/src/storage/ChecksumCache.ts +14 -6
- package/src/storage/PersistedSyncRulesContent.ts +36 -7
- package/src/storage/ReplicationEventPayload.ts +1 -1
- package/src/storage/SourceTable.ts +10 -4
- package/src/storage/StorageVersionConfig.ts +55 -7
- package/src/storage/SyncRulesBucketStorage.ts +77 -11
- package/src/storage/WriteCheckpointAPI.ts +6 -6
- package/src/storage/bson.ts +0 -5
- package/src/storage/storage-index.ts +8 -8
- package/src/storage/storage-metrics.ts +2 -2
- package/src/streams/streams-index.ts +2 -2
- package/src/sync/BucketChecksumState.ts +142 -139
- package/src/sync/RequestTracker.ts +1 -1
- package/src/sync/sync-index.ts +2 -2
- package/src/sync/sync.ts +4 -4
- package/src/sync/util.ts +11 -1
- package/src/system/ServiceContext.ts +1 -1
- package/src/tracing/PerformanceTracer.ts +126 -0
- package/src/tracing/TraceWriter.ts +67 -0
- package/src/util/checkpointing.ts +1 -1
- package/src/util/config/collectors/impl/base64-config-collector.ts +1 -1
- package/src/util/config/collectors/impl/filesystem-config-collector.ts +2 -2
- package/src/util/config/compound-config-collector.ts +3 -3
- package/src/util/config/sync-rules/impl/filesystem-sync-rules-collector.ts +1 -1
- package/src/util/config/sync-rules/sync-rules-provider.ts +1 -1
- package/src/util/config.ts +1 -1
- package/src/util/env.ts +1 -1
- package/src/util/errors.ts +21 -0
- package/src/util/protocol-types.ts +1 -1
- package/src/util/util-index.ts +1 -1
- package/src/util/utils.ts +1 -1
- package/test/src/ReplicationLagTracker.test.ts +53 -0
- package/test/src/RollingBucketMax.test.ts +106 -0
- package/test/src/auth.test.ts +26 -7
- package/test/src/checksum_cache.test.ts +102 -57
- package/test/src/config.test.ts +1 -0
- package/test/src/diagnostics.test.ts +151 -0
- package/test/src/module-loader.test.ts +1 -1
- package/test/src/routes/mocks.ts +1 -1
- package/test/src/routes/stream.test.ts +1 -2
- package/test/src/sync/BucketChecksumState.test.ts +209 -80
- package/test/src/util/protocol_types.test.ts +1 -1
- package/test/src/utils.ts +9 -0
- package/test/tsconfig.json +0 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/vitest.config.ts +1 -1
|
@@ -1,31 +1,33 @@
|
|
|
1
1
|
import { BaseObserver, logger } from '@powersync/lib-services-framework';
|
|
2
|
-
import { ParseSyncRulesOptions, PersistedSyncRules, PersistedSyncRulesContent } from './PersistedSyncRulesContent.js';
|
|
3
|
-
import { ReplicationEventPayload } from './ReplicationEventPayload.js';
|
|
4
|
-
import { ReplicationLock } from './ReplicationLock.js';
|
|
5
|
-
import { SyncRulesBucketStorage } from './SyncRulesBucketStorage.js';
|
|
6
|
-
import { ReportStorage } from './ReportStorage.js';
|
|
7
2
|
import {
|
|
8
3
|
PrecompiledSyncConfig,
|
|
9
4
|
SerializedCompatibilityContext,
|
|
10
5
|
serializeSyncPlan,
|
|
11
6
|
SqlSyncRules,
|
|
12
|
-
|
|
7
|
+
SyncConfigWithErrors
|
|
13
8
|
} from '@powersync/service-sync-rules';
|
|
9
|
+
import { ReplicationError } from '@powersync/service-types';
|
|
10
|
+
import { syncConfigYamlErrorToReplicationError } from '../util/errors.js';
|
|
11
|
+
import { ParseSyncRulesOptions, PersistedSyncRules, PersistedSyncRulesContent } from './PersistedSyncRulesContent.js';
|
|
12
|
+
import { ReplicationEventPayload } from './ReplicationEventPayload.js';
|
|
13
|
+
import { ReplicationLock } from './ReplicationLock.js';
|
|
14
|
+
import { ReportStorage } from './ReportStorage.js';
|
|
15
|
+
import { SyncRulesBucketStorage } from './SyncRulesBucketStorage.js';
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* Represents a configured storage provider.
|
|
17
19
|
*
|
|
18
|
-
* The provider can handle multiple
|
|
19
|
-
* This is to handle replication of a new version of sync
|
|
20
|
+
* The provider can handle multiple replication streams concurrently, each with their own storage.
|
|
21
|
+
* This is to handle replication of a new version of sync config, while the old replication stream is still active.
|
|
20
22
|
*
|
|
21
|
-
* Storage APIs for a specific
|
|
23
|
+
* Storage APIs for a specific replication stream are provided by the `SyncRulesBucketStorage` instances.
|
|
22
24
|
*/
|
|
23
25
|
export abstract class BucketStorageFactory
|
|
24
26
|
extends BaseObserver<BucketStorageFactoryListener>
|
|
25
27
|
implements AsyncDisposable
|
|
26
28
|
{
|
|
27
29
|
/**
|
|
28
|
-
* Update sync
|
|
30
|
+
* Update sync config from configuration, if changed.
|
|
29
31
|
*/
|
|
30
32
|
async configureSyncRules(
|
|
31
33
|
options: UpdateSyncRulesOptions
|
|
@@ -34,42 +36,42 @@ export abstract class BucketStorageFactory
|
|
|
34
36
|
const active = await this.getActiveSyncRulesContent();
|
|
35
37
|
|
|
36
38
|
if (next?.sync_rules_content == options.config.yaml) {
|
|
37
|
-
logger.info('Sync
|
|
39
|
+
logger.info('Sync config unchanged');
|
|
38
40
|
return { updated: false };
|
|
39
41
|
} else if (next == null && active?.sync_rules_content == options.config.yaml) {
|
|
40
|
-
logger.info('Sync
|
|
42
|
+
logger.info('Sync config unchanged');
|
|
41
43
|
return { updated: false };
|
|
42
44
|
} else {
|
|
43
|
-
logger.info('Sync
|
|
45
|
+
logger.info('Sync config updated');
|
|
44
46
|
const persisted_sync_rules = await this.updateSyncRules(options);
|
|
45
47
|
return { updated: true, persisted_sync_rules, lock: persisted_sync_rules.current_lock ?? undefined };
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
/**
|
|
50
|
-
* Get a storage instance to query sync data for specific sync
|
|
52
|
+
* Get a storage instance to query sync data for specific sync config.
|
|
51
53
|
*/
|
|
52
54
|
abstract getInstance(syncRules: PersistedSyncRulesContent, options?: GetIntanceOptions): SyncRulesBucketStorage;
|
|
53
55
|
|
|
54
56
|
/**
|
|
55
|
-
* Deploy new sync
|
|
57
|
+
* Deploy new sync config.
|
|
56
58
|
*/
|
|
57
59
|
abstract updateSyncRules(options: UpdateSyncRulesOptions): Promise<PersistedSyncRulesContent>;
|
|
58
60
|
|
|
59
61
|
/**
|
|
60
62
|
* Indicate that a slot was removed, and we should re-sync by creating
|
|
61
|
-
* a new
|
|
63
|
+
* a new replication stream.
|
|
62
64
|
*
|
|
63
65
|
* This is roughly the same as deploying a new version of the current sync
|
|
64
|
-
*
|
|
65
|
-
* the latest
|
|
66
|
+
* config, but also accounts for cases where the current sync config is not
|
|
67
|
+
* the latest one.
|
|
66
68
|
*
|
|
67
69
|
* Replication should be restarted after this.
|
|
68
70
|
*/
|
|
69
71
|
abstract restartReplication(sync_rules_group_id: number): Promise<void>;
|
|
70
72
|
|
|
71
73
|
/**
|
|
72
|
-
* Get the sync
|
|
74
|
+
* Get the sync config used for querying.
|
|
73
75
|
*/
|
|
74
76
|
async getActiveSyncRules(options: ParseSyncRulesOptions): Promise<PersistedSyncRules | null> {
|
|
75
77
|
const content = await this.getActiveSyncRulesContent();
|
|
@@ -77,12 +79,12 @@ export abstract class BucketStorageFactory
|
|
|
77
79
|
}
|
|
78
80
|
|
|
79
81
|
/**
|
|
80
|
-
* Get the sync
|
|
82
|
+
* Get the sync config used for querying.
|
|
81
83
|
*/
|
|
82
84
|
abstract getActiveSyncRulesContent(): Promise<PersistedSyncRulesContent | null>;
|
|
83
85
|
|
|
84
86
|
/**
|
|
85
|
-
* Get the sync
|
|
87
|
+
* Get the sync config that will be active next once done with initial replicatino.
|
|
86
88
|
*/
|
|
87
89
|
async getNextSyncRules(options: ParseSyncRulesOptions): Promise<PersistedSyncRules | null> {
|
|
88
90
|
const content = await this.getNextSyncRulesContent();
|
|
@@ -90,17 +92,17 @@ export abstract class BucketStorageFactory
|
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
/**
|
|
93
|
-
* Get the sync
|
|
95
|
+
* Get the sync config that will be active next once done with initial replicatino.
|
|
94
96
|
*/
|
|
95
97
|
abstract getNextSyncRulesContent(): Promise<PersistedSyncRulesContent | null>;
|
|
96
98
|
|
|
97
99
|
/**
|
|
98
|
-
* Get all sync
|
|
100
|
+
* Get all sync config currently replicating. Typically this is the "active" and "next" sync config.
|
|
99
101
|
*/
|
|
100
102
|
abstract getReplicatingSyncRules(): Promise<PersistedSyncRulesContent[]>;
|
|
101
103
|
|
|
102
104
|
/**
|
|
103
|
-
* Get all sync
|
|
105
|
+
* Get all sync config stopped but not terminated yet.
|
|
104
106
|
*/
|
|
105
107
|
abstract getStoppedSyncRules(): Promise<PersistedSyncRulesContent[]>;
|
|
106
108
|
|
|
@@ -110,12 +112,12 @@ export abstract class BucketStorageFactory
|
|
|
110
112
|
abstract getActiveStorage(): Promise<SyncRulesBucketStorage | null>;
|
|
111
113
|
|
|
112
114
|
/**
|
|
113
|
-
* Get storage size of active
|
|
115
|
+
* Get storage size of active replication stream.
|
|
114
116
|
*/
|
|
115
117
|
abstract getStorageMetrics(): Promise<StorageMetrics>;
|
|
116
118
|
|
|
117
119
|
/**
|
|
118
|
-
* Get the unique identifier for this instance of Powersync
|
|
120
|
+
* Get the unique identifier for this instance of Powersync.
|
|
119
121
|
*/
|
|
120
122
|
abstract getPowerSyncInstanceId(): Promise<string>;
|
|
121
123
|
|
|
@@ -159,6 +161,12 @@ export interface UpdateSyncRulesOptions {
|
|
|
159
161
|
* compiler.
|
|
160
162
|
*/
|
|
161
163
|
plan: SerializedSyncPlan | null;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Parsed sync config, primarily to generate a definition mapping.
|
|
167
|
+
* Not persisted, and the defaultSchema used for parsing is not relevant.
|
|
168
|
+
*/
|
|
169
|
+
parsed: SyncConfigWithErrors;
|
|
162
170
|
};
|
|
163
171
|
lock?: boolean;
|
|
164
172
|
storageVersion?: number;
|
|
@@ -178,13 +186,14 @@ export interface SerializedSyncPlan {
|
|
|
178
186
|
* them.
|
|
179
187
|
*/
|
|
180
188
|
eventDescriptors: Record<string, string[]>;
|
|
189
|
+
errors?: ReplicationError[];
|
|
181
190
|
}
|
|
182
191
|
|
|
183
192
|
export function updateSyncRulesFromYaml(
|
|
184
193
|
content: string,
|
|
185
194
|
options?: Omit<UpdateSyncRulesOptions, 'config'> & { validate?: boolean }
|
|
186
195
|
): UpdateSyncRulesOptions {
|
|
187
|
-
const
|
|
196
|
+
const config = SqlSyncRules.fromYaml(content, {
|
|
188
197
|
// No schema-based validation at this point
|
|
189
198
|
schema: undefined,
|
|
190
199
|
defaultSchema: 'not_applicable', // Not needed for validation
|
|
@@ -195,24 +204,26 @@ export function updateSyncRulesFromYaml(
|
|
|
195
204
|
}
|
|
196
205
|
|
|
197
206
|
export function updateSyncRulesFromConfig(
|
|
198
|
-
parsed:
|
|
207
|
+
parsed: SyncConfigWithErrors,
|
|
199
208
|
options?: Omit<UpdateSyncRulesOptions, 'config'>
|
|
200
209
|
): UpdateSyncRulesOptions {
|
|
201
210
|
let plan: SerializedSyncPlan | null = null;
|
|
202
|
-
|
|
211
|
+
const { config, errors } = parsed;
|
|
212
|
+
if (config instanceof PrecompiledSyncConfig) {
|
|
203
213
|
const eventDescriptors: Record<string, string[]> = {};
|
|
204
|
-
for (const event of
|
|
214
|
+
for (const event of config.eventDescriptors) {
|
|
205
215
|
eventDescriptors[event.name] = event.sourceQueries.map((q) => q.sql);
|
|
206
216
|
}
|
|
207
217
|
|
|
208
218
|
plan = {
|
|
209
|
-
compatibility:
|
|
210
|
-
plan: serializeSyncPlan(
|
|
211
|
-
eventDescriptors
|
|
219
|
+
compatibility: config.compatibility.serialize(),
|
|
220
|
+
plan: serializeSyncPlan(config.plan),
|
|
221
|
+
eventDescriptors,
|
|
222
|
+
errors: errors.map((e) => syncConfigYamlErrorToReplicationError(e))
|
|
212
223
|
};
|
|
213
224
|
}
|
|
214
225
|
|
|
215
|
-
return { config: { yaml:
|
|
226
|
+
return { config: { yaml: config.content, plan, parsed }, ...options };
|
|
216
227
|
}
|
|
217
228
|
|
|
218
229
|
export interface GetIntanceOptions {
|
|
@@ -257,3 +268,9 @@ export interface TestStorageOptions {
|
|
|
257
268
|
}
|
|
258
269
|
export type TestStorageFactory = (options?: TestStorageOptions) => Promise<BucketStorageFactory>;
|
|
259
270
|
export type TestReportStorageFactory = (options?: TestStorageOptions) => Promise<ReportStorage>;
|
|
271
|
+
|
|
272
|
+
export interface TestStorageConfig {
|
|
273
|
+
factory: TestStorageFactory;
|
|
274
|
+
tableIdStrings: boolean;
|
|
275
|
+
storageVersion?: number;
|
|
276
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { OrderedSet } from '@js-sdsl/ordered-set';
|
|
2
|
+
import { BucketDataSource } from '@powersync/service-sync-rules';
|
|
2
3
|
import { LRUCache } from 'lru-cache/min';
|
|
3
4
|
import { BucketChecksum } from '../util/protocol-types.js';
|
|
4
5
|
import { addBucketChecksums, ChecksumMap, InternalOpId, PartialChecksum } from '../util/utils.js';
|
|
6
|
+
import { BucketChecksumRequest } from './SyncRulesBucketStorage.js';
|
|
5
7
|
|
|
6
8
|
interface ChecksumFetchContext {
|
|
7
9
|
fetch(bucket: string): Promise<BucketChecksum>;
|
|
@@ -10,6 +12,7 @@ interface ChecksumFetchContext {
|
|
|
10
12
|
|
|
11
13
|
export interface FetchPartialBucketChecksum {
|
|
12
14
|
bucket: string;
|
|
15
|
+
source: BucketDataSource;
|
|
13
16
|
start?: InternalOpId;
|
|
14
17
|
end: InternalOpId;
|
|
15
18
|
}
|
|
@@ -113,10 +116,10 @@ export class ChecksumCache {
|
|
|
113
116
|
this.bucketCheckpoints.clear();
|
|
114
117
|
}
|
|
115
118
|
|
|
116
|
-
async getChecksums(checkpoint: InternalOpId, buckets:
|
|
119
|
+
async getChecksums(checkpoint: InternalOpId, buckets: BucketChecksumRequest[]): Promise<BucketChecksum[]> {
|
|
117
120
|
const checksums = await this.getChecksumMap(checkpoint, buckets);
|
|
118
121
|
// Return results in the same order as the request
|
|
119
|
-
return buckets.map((bucket) => checksums.get(bucket)!);
|
|
122
|
+
return buckets.map((bucket) => checksums.get(bucket.bucket)!);
|
|
120
123
|
}
|
|
121
124
|
|
|
122
125
|
/**
|
|
@@ -126,7 +129,7 @@ export class ChecksumCache {
|
|
|
126
129
|
*
|
|
127
130
|
* @returns a Map with exactly one entry for each bucket requested
|
|
128
131
|
*/
|
|
129
|
-
async getChecksumMap(checkpoint: InternalOpId, buckets:
|
|
132
|
+
async getChecksumMap(checkpoint: InternalOpId, buckets: BucketChecksumRequest[]): Promise<ChecksumMap> {
|
|
130
133
|
// Buckets that don't have a cached checksum for this checkpoint yet
|
|
131
134
|
let toFetch = new Set<string>();
|
|
132
135
|
|
|
@@ -164,19 +167,21 @@ export class ChecksumCache {
|
|
|
164
167
|
// One promise to await to ensure all fetch requests completed.
|
|
165
168
|
let settledPromise: Promise<PromiseSettledResult<void>[]> | null = null;
|
|
166
169
|
|
|
170
|
+
const sourceMap = new Map<string, BucketDataSource>();
|
|
171
|
+
|
|
167
172
|
try {
|
|
168
173
|
// Individual cache fetch promises
|
|
169
174
|
let cacheFetchPromises: Promise<void>[] = [];
|
|
170
175
|
|
|
171
176
|
for (let bucket of buckets) {
|
|
172
|
-
const cacheKey = makeCacheKey(checkpoint, bucket);
|
|
177
|
+
const cacheKey = makeCacheKey(checkpoint, bucket.bucket);
|
|
173
178
|
let status: LRUCache.Status<BucketChecksum> = {};
|
|
174
179
|
const p = this.cache.fetch(cacheKey, { context: context, status: status }).then((checksums) => {
|
|
175
180
|
if (checksums == null) {
|
|
176
181
|
// Should never happen
|
|
177
182
|
throw new Error(`Failed to get checksums for ${cacheKey}`);
|
|
178
183
|
}
|
|
179
|
-
finalResults.set(bucket, checksums);
|
|
184
|
+
finalResults.set(bucket.bucket, checksums);
|
|
180
185
|
});
|
|
181
186
|
cacheFetchPromises.push(p);
|
|
182
187
|
if (status.fetch == 'hit' || status.fetch == 'inflight') {
|
|
@@ -185,7 +190,8 @@ export class ChecksumCache {
|
|
|
185
190
|
// In either case, we don't need to fetch a new checksum.
|
|
186
191
|
} else {
|
|
187
192
|
// We need a new request for this checksum.
|
|
188
|
-
toFetch.add(bucket);
|
|
193
|
+
toFetch.add(bucket.bucket);
|
|
194
|
+
sourceMap.set(bucket.bucket, bucket.source);
|
|
189
195
|
}
|
|
190
196
|
}
|
|
191
197
|
// We do this directly after creating the promises, otherwise
|
|
@@ -220,6 +226,7 @@ export class ChecksumCache {
|
|
|
220
226
|
// Partial checksum found - make a partial checksum request
|
|
221
227
|
bucketRequest = {
|
|
222
228
|
bucket,
|
|
229
|
+
source: sourceMap.get(bucket)!,
|
|
223
230
|
start: cp,
|
|
224
231
|
end: checkpoint
|
|
225
232
|
};
|
|
@@ -240,6 +247,7 @@ export class ChecksumCache {
|
|
|
240
247
|
// No partial checksum found - make a new full checksum request
|
|
241
248
|
bucketRequest = {
|
|
242
249
|
bucket,
|
|
250
|
+
source: sourceMap.get(bucket)!,
|
|
243
251
|
end: checkpoint
|
|
244
252
|
};
|
|
245
253
|
add.set(bucket, {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { logger as defaultLogger, ErrorCode, Logger, ServiceError } from '@powersync/lib-services-framework';
|
|
1
2
|
import {
|
|
2
3
|
CompatibilityContext,
|
|
3
4
|
CompatibilityOption,
|
|
4
5
|
DEFAULT_HYDRATION_STATE,
|
|
5
6
|
deserializeSyncPlan,
|
|
7
|
+
ErrorLocation,
|
|
6
8
|
HydratedSyncRules,
|
|
7
9
|
HydrationState,
|
|
8
10
|
javaScriptExpressionEngine,
|
|
@@ -10,12 +12,12 @@ import {
|
|
|
10
12
|
SqlEventDescriptor,
|
|
11
13
|
SqlSyncRules,
|
|
12
14
|
SyncConfigWithErrors,
|
|
13
|
-
versionedHydrationState
|
|
15
|
+
versionedHydrationState,
|
|
16
|
+
YamlError
|
|
14
17
|
} from '@powersync/service-sync-rules';
|
|
18
|
+
import { SerializedSyncPlan, UpdateSyncRulesOptions } from './BucketStorageFactory.js';
|
|
15
19
|
import { ReplicationLock } from './ReplicationLock.js';
|
|
16
20
|
import { STORAGE_VERSION_CONFIG, StorageVersionConfig } from './StorageVersionConfig.js';
|
|
17
|
-
import { ErrorCode, ServiceError } from '@powersync/lib-services-framework';
|
|
18
|
-
import { SerializedSyncPlan, UpdateSyncRulesOptions } from './BucketStorageFactory.js';
|
|
19
21
|
|
|
20
22
|
export interface ParseSyncRulesOptions {
|
|
21
23
|
defaultSchema: string;
|
|
@@ -27,7 +29,7 @@ export interface PersistedSyncRulesContentData {
|
|
|
27
29
|
readonly compiled_plan: SerializedSyncPlan | null;
|
|
28
30
|
readonly slot_name: string;
|
|
29
31
|
/**
|
|
30
|
-
* True if this is the "active" copy of the sync
|
|
32
|
+
* True if this is the "active" copy of the sync config.
|
|
31
33
|
*/
|
|
32
34
|
readonly active: boolean;
|
|
33
35
|
readonly storageVersion: number;
|
|
@@ -47,6 +49,7 @@ export abstract class PersistedSyncRulesContent implements PersistedSyncRulesCon
|
|
|
47
49
|
readonly slot_name!: string;
|
|
48
50
|
readonly active!: boolean;
|
|
49
51
|
readonly storageVersion!: number;
|
|
52
|
+
readonly logger: Logger;
|
|
50
53
|
|
|
51
54
|
readonly last_checkpoint_lsn!: string | null;
|
|
52
55
|
|
|
@@ -59,6 +62,7 @@ export abstract class PersistedSyncRulesContent implements PersistedSyncRulesCon
|
|
|
59
62
|
|
|
60
63
|
constructor(data: PersistedSyncRulesContentData) {
|
|
61
64
|
Object.assign(this, data);
|
|
65
|
+
this.logger = defaultLogger.child({ prefix: `[${this.slot_name}] ` });
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
/**
|
|
@@ -71,7 +75,7 @@ export abstract class PersistedSyncRulesContent implements PersistedSyncRulesCon
|
|
|
71
75
|
if (storageConfig == null) {
|
|
72
76
|
throw new ServiceError(
|
|
73
77
|
ErrorCode.PSYNC_S1005,
|
|
74
|
-
`Unsupported storage version ${this.storageVersion} for
|
|
78
|
+
`Unsupported storage version ${this.storageVersion} for replication stream ${this.id}`
|
|
75
79
|
);
|
|
76
80
|
}
|
|
77
81
|
return storageConfig;
|
|
@@ -101,7 +105,25 @@ export abstract class PersistedSyncRulesContent implements PersistedSyncRulesCon
|
|
|
101
105
|
sourceText: this.sync_rules_content
|
|
102
106
|
});
|
|
103
107
|
|
|
104
|
-
|
|
108
|
+
// Note: If the original content did not define a storage version, this will still set the storage version.
|
|
109
|
+
// This means asUpdateOptions will not change the storage version, even if the default changes.
|
|
110
|
+
precompiled.storageVersion = this.storageVersion;
|
|
111
|
+
|
|
112
|
+
const errors: YamlError[] = [];
|
|
113
|
+
if (this.compiled_plan.errors) {
|
|
114
|
+
for (const error of this.compiled_plan.errors) {
|
|
115
|
+
const location: ErrorLocation | undefined = error.location && {
|
|
116
|
+
start: error.location.start_offset,
|
|
117
|
+
end: error.location.end_offset
|
|
118
|
+
};
|
|
119
|
+
const asYamlError = new YamlError(new Error(error.message), location);
|
|
120
|
+
asYamlError.type = error.level;
|
|
121
|
+
|
|
122
|
+
errors.push(asYamlError);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
config = { config: precompiled, errors };
|
|
105
127
|
} else {
|
|
106
128
|
config = SqlSyncRules.fromYaml(this.sync_rules_content, options);
|
|
107
129
|
}
|
|
@@ -120,6 +142,7 @@ export abstract class PersistedSyncRulesContent implements PersistedSyncRulesCon
|
|
|
120
142
|
id: this.id,
|
|
121
143
|
slot_name: this.slot_name,
|
|
122
144
|
sync_rules: config,
|
|
145
|
+
hydrationState,
|
|
123
146
|
hydratedSyncRules: () => {
|
|
124
147
|
return config.config.hydrate({ hydrationState });
|
|
125
148
|
}
|
|
@@ -127,8 +150,10 @@ export abstract class PersistedSyncRulesContent implements PersistedSyncRulesCon
|
|
|
127
150
|
}
|
|
128
151
|
|
|
129
152
|
asUpdateOptions(options?: Omit<UpdateSyncRulesOptions, 'config'>): UpdateSyncRulesOptions {
|
|
153
|
+
// defaultSchema is not relevant for the parsed version here
|
|
154
|
+
const parsed = this.parsed({ defaultSchema: 'not_applicable' });
|
|
130
155
|
return {
|
|
131
|
-
config: { yaml: this.sync_rules_content, plan: this.compiled_plan },
|
|
156
|
+
config: { yaml: this.sync_rules_content, plan: this.compiled_plan, parsed: parsed.sync_rules },
|
|
132
157
|
...options
|
|
133
158
|
};
|
|
134
159
|
}
|
|
@@ -140,6 +165,10 @@ export interface PersistedSyncRules {
|
|
|
140
165
|
readonly id: number;
|
|
141
166
|
readonly sync_rules: SyncConfigWithErrors;
|
|
142
167
|
readonly slot_name: string;
|
|
168
|
+
/**
|
|
169
|
+
* For testing only.
|
|
170
|
+
*/
|
|
171
|
+
readonly hydrationState: HydrationState;
|
|
143
172
|
|
|
144
173
|
hydratedSyncRules(): HydratedSyncRules;
|
|
145
174
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as sync_rules from '@powersync/service-sync-rules';
|
|
2
|
-
import { SourceTable } from './SourceTable.js';
|
|
3
2
|
import { BucketStorageBatch, SaveOp } from './BucketStorageBatch.js';
|
|
3
|
+
import { SourceTable } from './SourceTable.js';
|
|
4
4
|
|
|
5
5
|
export type EventData = {
|
|
6
6
|
op: SaveOp;
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { DEFAULT_TAG } from '@powersync/service-sync-rules';
|
|
2
|
+
import { bson } from '../index.js';
|
|
2
3
|
import * as util from '../util/util-index.js';
|
|
3
4
|
import { ColumnDescriptor, SourceEntityDescriptor } from './SourceEntity.js';
|
|
4
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Format of the id depends on the bucket storage module. It should be consistent within the module.
|
|
8
|
+
*/
|
|
9
|
+
export type SourceTableId = string | bson.ObjectId;
|
|
10
|
+
|
|
5
11
|
export interface SourceTableOptions {
|
|
6
|
-
id:
|
|
12
|
+
id: SourceTableId;
|
|
7
13
|
connectionTag: string;
|
|
8
14
|
objectId: number | string | undefined;
|
|
9
15
|
schema: string;
|
|
@@ -22,7 +28,7 @@ export class SourceTable implements SourceEntityDescriptor {
|
|
|
22
28
|
static readonly DEFAULT_TAG = DEFAULT_TAG;
|
|
23
29
|
|
|
24
30
|
/**
|
|
25
|
-
* True if the table is used in sync
|
|
31
|
+
* True if the table is used in sync config for data queries.
|
|
26
32
|
*
|
|
27
33
|
* This value is resolved externally, and cached here.
|
|
28
34
|
*
|
|
@@ -31,7 +37,7 @@ export class SourceTable implements SourceEntityDescriptor {
|
|
|
31
37
|
public syncData = true;
|
|
32
38
|
|
|
33
39
|
/**
|
|
34
|
-
* True if the table is used in sync
|
|
40
|
+
* True if the table is used in sync config for data queries.
|
|
35
41
|
*
|
|
36
42
|
* This value is resolved externally, and cached here.
|
|
37
43
|
*
|
|
@@ -40,7 +46,7 @@ export class SourceTable implements SourceEntityDescriptor {
|
|
|
40
46
|
public syncParameters = true;
|
|
41
47
|
|
|
42
48
|
/**
|
|
43
|
-
* True if the table is used in sync
|
|
49
|
+
* True if the table is used in sync config for events.
|
|
44
50
|
*
|
|
45
51
|
* This value is resolved externally, and cached here.
|
|
46
52
|
*
|
|
@@ -1,30 +1,78 @@
|
|
|
1
1
|
export interface StorageVersionConfig {
|
|
2
|
+
version: number;
|
|
3
|
+
|
|
2
4
|
/**
|
|
3
5
|
* Whether versioned bucket names are automatically enabled.
|
|
4
6
|
*
|
|
5
7
|
* If this is false, bucket names may still be versioned depending on the sync config.
|
|
8
|
+
*
|
|
9
|
+
* Introduced in STORAGE_VERSION_2.
|
|
6
10
|
*/
|
|
7
11
|
versionedBuckets: boolean;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Whether to use soft deletes for current_data, improving replication concurrency support.
|
|
15
|
+
*
|
|
16
|
+
* Introduced in STORAGE_VERSION_3.
|
|
17
|
+
*/
|
|
18
|
+
softDeleteCurrentData: boolean;
|
|
8
19
|
}
|
|
9
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Corresponds to the storage version initially used, before we started explicitly versioning storage.
|
|
23
|
+
*/
|
|
24
|
+
export const STORAGE_VERSION_1 = 1;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* First new storage version.
|
|
28
|
+
*
|
|
29
|
+
* Uses versioned bucket names.
|
|
30
|
+
*
|
|
31
|
+
* On MongoDB storage, this always uses Long for checksums.
|
|
32
|
+
*/
|
|
33
|
+
export const STORAGE_VERSION_2 = 2;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* This version is currently unstable, and not enabled by default yet.
|
|
37
|
+
*
|
|
38
|
+
* This is used to build towards incremental reprocessing.
|
|
39
|
+
*/
|
|
40
|
+
export const STORAGE_VERSION_3 = 3;
|
|
41
|
+
|
|
10
42
|
/**
|
|
11
43
|
* Oldest supported storage version.
|
|
12
44
|
*/
|
|
13
|
-
export const LEGACY_STORAGE_VERSION =
|
|
45
|
+
export const LEGACY_STORAGE_VERSION = STORAGE_VERSION_1;
|
|
14
46
|
|
|
15
47
|
/**
|
|
16
|
-
* Default storage version for newly persisted
|
|
48
|
+
* Default storage version for newly persisted replication streams.
|
|
17
49
|
*/
|
|
18
|
-
export const CURRENT_STORAGE_VERSION =
|
|
50
|
+
export const CURRENT_STORAGE_VERSION = STORAGE_VERSION_2;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* All versions that can be loaded.
|
|
54
|
+
*
|
|
55
|
+
* This includes unstable versions.
|
|
56
|
+
*/
|
|
57
|
+
export const SUPPORTED_STORAGE_VERSIONS = [STORAGE_VERSION_1, STORAGE_VERSION_2, STORAGE_VERSION_3];
|
|
19
58
|
|
|
20
59
|
/**
|
|
21
60
|
* Shared storage-version behavior across storage implementations.
|
|
22
61
|
*/
|
|
23
62
|
export const STORAGE_VERSION_CONFIG: Record<number, StorageVersionConfig | undefined> = {
|
|
24
|
-
[
|
|
25
|
-
|
|
63
|
+
[STORAGE_VERSION_1]: {
|
|
64
|
+
version: STORAGE_VERSION_1,
|
|
65
|
+
versionedBuckets: false,
|
|
66
|
+
softDeleteCurrentData: false
|
|
67
|
+
},
|
|
68
|
+
[STORAGE_VERSION_2]: {
|
|
69
|
+
version: STORAGE_VERSION_2,
|
|
70
|
+
versionedBuckets: true,
|
|
71
|
+
softDeleteCurrentData: false
|
|
26
72
|
},
|
|
27
|
-
[
|
|
28
|
-
|
|
73
|
+
[STORAGE_VERSION_3]: {
|
|
74
|
+
version: STORAGE_VERSION_3,
|
|
75
|
+
versionedBuckets: true,
|
|
76
|
+
softDeleteCurrentData: true
|
|
29
77
|
}
|
|
30
78
|
};
|