@powersync/service-core 1.20.4 → 1.21.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 +53 -0
- 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/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/metrics-index.d.ts +3 -3
- package/dist/metrics/metrics-index.js +3 -3
- 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 +1 -1
- package/dist/replication/AbstractReplicationJob.js +1 -1
- package/dist/replication/AbstractReplicationJob.js.map +1 -1
- package/dist/replication/AbstractReplicator.d.ts +6 -6
- package/dist/replication/AbstractReplicator.js +21 -21
- package/dist/replication/AbstractReplicator.js.map +1 -1
- package/dist/replication/replication-index.d.ts +3 -3
- package/dist/replication/replication-index.js +3 -3
- 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 +7 -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 +2 -2
- 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 +1 -1
- package/dist/storage/BucketStorageFactory.d.ts +27 -20
- package/dist/storage/BucketStorageFactory.js +19 -16
- package/dist/storage/BucketStorageFactory.js.map +1 -1
- package/dist/storage/ChecksumCache.js.map +1 -1
- package/dist/storage/PersistedSyncRulesContent.d.ts +3 -1
- package/dist/storage/PersistedSyncRulesContent.js +24 -5
- package/dist/storage/PersistedSyncRulesContent.js.map +1 -1
- package/dist/storage/ReplicationEventPayload.d.ts +1 -1
- package/dist/storage/SourceTable.d.ts +4 -4
- package/dist/storage/SourceTable.js +3 -3
- package/dist/storage/SourceTable.js.map +1 -1
- package/dist/storage/StorageVersionConfig.d.ts +1 -1
- package/dist/storage/StorageVersionConfig.js +1 -1
- package/dist/storage/SyncRulesBucketStorage.d.ts +38 -6
- 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 +2 -5
- package/dist/sync/BucketChecksumState.js +119 -75
- 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.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/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/metrics-index.ts +3 -3
- 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 +2 -2
- package/src/replication/AbstractReplicator.ts +23 -23
- package/src/replication/replication-index.ts +3 -3
- package/src/replication/replication-metrics.ts +1 -1
- package/src/routes/endpoints/admin.ts +7 -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 +2 -2
- 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 +1 -1
- package/src/storage/BucketStorageFactory.ts +45 -34
- package/src/storage/ChecksumCache.ts +1 -1
- package/src/storage/PersistedSyncRulesContent.ts +30 -6
- package/src/storage/ReplicationEventPayload.ts +1 -1
- package/src/storage/SourceTable.ts +4 -4
- package/src/storage/StorageVersionConfig.ts +1 -1
- package/src/storage/SyncRulesBucketStorage.ts +46 -7
- 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 +141 -93
- package/src/sync/RequestTracker.ts +1 -1
- package/src/sync/sync-index.ts +2 -2
- package/src/sync/sync.ts +2 -8
- package/src/sync/util.ts +1 -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/auth.test.ts +115 -7
- 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 +223 -67
- package/test/src/util/protocol_types.test.ts +1 -1
- package/test/tsconfig.json +0 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/vitest.config.ts +1 -1
|
@@ -4,9 +4,9 @@ import type { FastifyPluginAsync } from 'fastify';
|
|
|
4
4
|
import * as t from 'ts-codec';
|
|
5
5
|
|
|
6
6
|
import { RouteAPI } from '../../api/RouteAPI.js';
|
|
7
|
+
import { updateSyncRulesFromConfig, updateSyncRulesFromYaml } from '../../storage/BucketStorageFactory.js';
|
|
7
8
|
import { authApi } from '../auth.js';
|
|
8
9
|
import { routeDefinition } from '../router.js';
|
|
9
|
-
import { updateSyncRulesFromConfig, updateSyncRulesFromYaml } from '../../storage/BucketStorageFactory.js';
|
|
10
10
|
|
|
11
11
|
const DeploySyncRulesRequest = t.object({
|
|
12
12
|
content: t.string
|
|
@@ -43,12 +43,12 @@ export const deploySyncRules = routeDefinition({
|
|
|
43
43
|
const { storageEngine } = service_context;
|
|
44
44
|
|
|
45
45
|
if (service_context.configuration.sync_rules.present) {
|
|
46
|
-
// If sync
|
|
46
|
+
// If sync config is configured via the service config, disable deploy via the API.
|
|
47
47
|
throw new errors.ServiceError({
|
|
48
48
|
status: 422,
|
|
49
49
|
code: ErrorCode.PSYNC_S4105,
|
|
50
|
-
description: 'Sync
|
|
51
|
-
details: '
|
|
50
|
+
description: 'Sync config API disabled',
|
|
51
|
+
details: 'Update sync config in the service configuration'
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
54
|
const content = payload.params.content;
|
|
@@ -56,7 +56,7 @@ export const deploySyncRules = routeDefinition({
|
|
|
56
56
|
|
|
57
57
|
try {
|
|
58
58
|
const apiHandler = service_context.routerEngine.getAPI();
|
|
59
|
-
syncConfig = SqlSyncRules.fromYaml(
|
|
59
|
+
syncConfig = SqlSyncRules.fromYaml(content, {
|
|
60
60
|
...apiHandler.getParseSyncRulesOptions(),
|
|
61
61
|
// We don't do any schema-level validation at this point
|
|
62
62
|
schema: undefined
|
|
@@ -65,14 +65,12 @@ export const deploySyncRules = routeDefinition({
|
|
|
65
65
|
throw new errors.ServiceError({
|
|
66
66
|
status: 422,
|
|
67
67
|
code: ErrorCode.PSYNC_R0001,
|
|
68
|
-
description: 'Sync
|
|
68
|
+
description: 'Sync config parsing failed',
|
|
69
69
|
details: e.message
|
|
70
70
|
});
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
const sync_rules = await storageEngine.activeBucketStorage.updateSyncRules(
|
|
74
|
-
updateSyncRulesFromConfig(syncConfig.config)
|
|
75
|
-
);
|
|
73
|
+
const sync_rules = await storageEngine.activeBucketStorage.updateSyncRules(updateSyncRulesFromConfig(syncConfig));
|
|
76
74
|
|
|
77
75
|
return {
|
|
78
76
|
slot_name: sync_rules.slot_name
|
|
@@ -117,7 +115,7 @@ export const currentSyncRules = routeDefinition({
|
|
|
117
115
|
throw new errors.ServiceError({
|
|
118
116
|
status: 422,
|
|
119
117
|
code: ErrorCode.PSYNC_S4104,
|
|
120
|
-
description: 'No active sync
|
|
118
|
+
description: 'No active sync config'
|
|
121
119
|
});
|
|
122
120
|
}
|
|
123
121
|
|
|
@@ -164,13 +162,13 @@ export const reprocessSyncRules = routeDefinition({
|
|
|
164
162
|
throw new errors.ServiceError({
|
|
165
163
|
status: 422,
|
|
166
164
|
code: ErrorCode.PSYNC_S4104,
|
|
167
|
-
description: 'No active sync
|
|
165
|
+
description: 'No active sync config'
|
|
168
166
|
});
|
|
169
167
|
}
|
|
170
168
|
|
|
171
169
|
const new_rules = await activeBucketStorage.updateSyncRules(
|
|
172
170
|
updateSyncRulesFromYaml(sync_rules.sync_rules.config.content, {
|
|
173
|
-
//
|
|
171
|
+
// This sync config already passed validation. But if the rules are not valid anymore due
|
|
174
172
|
// to a service change, we do want to report the error here.
|
|
175
173
|
validate: true
|
|
176
174
|
})
|
|
@@ -68,7 +68,7 @@ export const syncStreamed = routeDefinition({
|
|
|
68
68
|
throw new errors.ServiceError({
|
|
69
69
|
status: 500,
|
|
70
70
|
code: ErrorCode.PSYNC_S2302,
|
|
71
|
-
description: 'No sync
|
|
71
|
+
description: 'No sync config available'
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
74
|
|
|
@@ -121,7 +121,7 @@ export const syncStreamed = routeDefinition({
|
|
|
121
121
|
});
|
|
122
122
|
|
|
123
123
|
stream.on('end', () => {
|
|
124
|
-
// Auth failure or switch to new sync
|
|
124
|
+
// Auth failure or switch to new sync config
|
|
125
125
|
closeReason ??= 'service closing stream';
|
|
126
126
|
});
|
|
127
127
|
|
package/src/routes/hooks.ts
CHANGED
|
@@ -1,17 +1,9 @@
|
|
|
1
1
|
import type fastify from 'fastify';
|
|
2
2
|
import * as uuid from 'uuid';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
ErrorCode,
|
|
6
|
-
errors,
|
|
7
|
-
HTTPMethod,
|
|
8
|
-
logger,
|
|
9
|
-
RouteNotFound,
|
|
10
|
-
router,
|
|
11
|
-
ServiceError
|
|
12
|
-
} from '@powersync/lib-services-framework';
|
|
13
|
-
import { Context, ContextProvider, RequestEndpoint, RequestEndpointHandlerPayload } from './router.js';
|
|
4
|
+
import { errors, HTTPMethod, logger, RouteNotFound, router, ServiceError } from '@powersync/lib-services-framework';
|
|
14
5
|
import { FastifyReply } from 'fastify';
|
|
6
|
+
import { Context, ContextProvider, RequestEndpoint, RequestEndpointHandlerPayload } from './router.js';
|
|
15
7
|
|
|
16
8
|
export type FastifyEndpoint<I, O, C> = RequestEndpoint<I, O, C> & {
|
|
17
9
|
parse?: boolean;
|
package/src/runner/teardown.ts
CHANGED
|
@@ -35,13 +35,13 @@ export async function teardown(runnerConfig: utils.RunnerConfig) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
async function terminateSyncRules(storageFactory: storage.BucketStorageFactory, moduleManager: modules.ModuleManager) {
|
|
38
|
-
logger.info(`Terminating
|
|
38
|
+
logger.info(`Terminating replication stream...`);
|
|
39
39
|
const start = Date.now();
|
|
40
40
|
const locks: storage.ReplicationLock[] = [];
|
|
41
41
|
while (Date.now() - start < 120_000) {
|
|
42
42
|
let retry = false;
|
|
43
43
|
const replicatingSyncRules = await storageFactory.getReplicatingSyncRules();
|
|
44
|
-
// Lock all the replicating
|
|
44
|
+
// Lock all the replicating replication streams
|
|
45
45
|
for (const replicatingSyncRule of replicatingSyncRules) {
|
|
46
46
|
const lock = await replicatingSyncRule.lock();
|
|
47
47
|
locks.push(lock);
|
|
@@ -50,10 +50,10 @@ async function terminateSyncRules(storageFactory: storage.BucketStorageFactory,
|
|
|
50
50
|
const stoppedSyncRules = await storageFactory.getStoppedSyncRules();
|
|
51
51
|
const combinedSyncRules = [...replicatingSyncRules, ...stoppedSyncRules];
|
|
52
52
|
try {
|
|
53
|
-
// Clean up any module specific configuration for the
|
|
53
|
+
// Clean up any module specific configuration for the replication stream
|
|
54
54
|
await moduleManager.tearDown({ syncRules: combinedSyncRules });
|
|
55
55
|
|
|
56
|
-
// Mark the
|
|
56
|
+
// Mark the replication stream as terminated
|
|
57
57
|
for (let syncRules of combinedSyncRules) {
|
|
58
58
|
const syncRulesStorage = storageFactory.getInstance(syncRules);
|
|
59
59
|
// The storage will be dropped at the end of the teardown, so we don't need to clear it here
|
|
@@ -2,36 +2,36 @@ import { ToastableSqliteRow } from '@powersync/service-sync-rules';
|
|
|
2
2
|
|
|
3
3
|
export enum SyncRuleState {
|
|
4
4
|
/**
|
|
5
|
-
* New
|
|
5
|
+
* New replication stream - needs to be processed (initial replication).
|
|
6
6
|
*
|
|
7
|
-
* While multiple
|
|
7
|
+
* While multiple replication streams _can_ be in PROCESSING,
|
|
8
8
|
* it's generally pointless, so we only keep one in that state.
|
|
9
9
|
*/
|
|
10
10
|
PROCESSING = 'PROCESSING',
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* Intial processing is done, and can be used for sync.
|
|
14
14
|
*
|
|
15
|
-
* Only one
|
|
15
|
+
* Only one replication stream should be in ACTIVE or ERRORED state.
|
|
16
16
|
*/
|
|
17
17
|
ACTIVE = 'ACTIVE',
|
|
18
18
|
/**
|
|
19
|
-
* This state is used when the
|
|
19
|
+
* This state is used when the replication stream has been replaced,
|
|
20
20
|
* and replication is or should be stopped.
|
|
21
21
|
*/
|
|
22
22
|
STOP = 'STOP',
|
|
23
23
|
/**
|
|
24
|
-
* After
|
|
24
|
+
* After replication stream has been stopped, the data needs to be
|
|
25
25
|
* deleted. Once deleted, the state is TERMINATED.
|
|
26
26
|
*/
|
|
27
27
|
TERMINATED = 'TERMINATED',
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
*
|
|
31
|
-
* is still the "active"
|
|
30
|
+
* Replication stream has run into a permanent replication error. It
|
|
31
|
+
* is still the "active" replication stram for syncing to users,
|
|
32
32
|
* but should not replicate anymore.
|
|
33
33
|
*
|
|
34
|
-
* It will transition to STOP when a new
|
|
34
|
+
* It will transition to STOP when a new replication stream is activated.
|
|
35
35
|
*/
|
|
36
36
|
ERRORED = 'ERRORED'
|
|
37
37
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ObserverClient } from '@powersync/lib-services-framework';
|
|
2
2
|
import { EvaluatedParameters, EvaluatedRow, SqliteRow, ToastableSqliteRow } from '@powersync/service-sync-rules';
|
|
3
3
|
import { BSON } from 'bson';
|
|
4
|
+
import { InternalOpId } from '../util/utils.js';
|
|
4
5
|
import { ReplicationEventPayload } from './ReplicationEventPayload.js';
|
|
5
6
|
import { SourceTable, TableSnapshotStatus } from './SourceTable.js';
|
|
6
7
|
import { BatchedCustomWriteCheckpointOptions } from './storage-index.js';
|
|
7
|
-
import { InternalOpId } from '../util/utils.js';
|
|
8
8
|
|
|
9
9
|
export const DEFAULT_BUCKET_BATCH_COMMIT_OPTIONS: ResolvedBucketBatchCommitOptions = {
|
|
10
10
|
createEmptyCheckpoints: true,
|
|
@@ -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 {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { OrderedSet } from '@js-sdsl/ordered-set';
|
|
2
|
-
import { LRUCache } from 'lru-cache/min';
|
|
3
2
|
import { BucketDataSource } from '@powersync/service-sync-rules';
|
|
3
|
+
import { LRUCache } from 'lru-cache/min';
|
|
4
4
|
import { BucketChecksum } from '../util/protocol-types.js';
|
|
5
5
|
import { addBucketChecksums, ChecksumMap, InternalOpId, PartialChecksum } from '../util/utils.js';
|
|
6
6
|
import { BucketChecksumRequest } from './SyncRulesBucketStorage.js';
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { ErrorCode, ServiceError } from '@powersync/lib-services-framework';
|
|
1
|
+
import { logger as defaultLogger, ErrorCode, Logger, ServiceError } from '@powersync/lib-services-framework';
|
|
2
2
|
import {
|
|
3
3
|
CompatibilityContext,
|
|
4
4
|
CompatibilityOption,
|
|
5
5
|
DEFAULT_HYDRATION_STATE,
|
|
6
6
|
deserializeSyncPlan,
|
|
7
|
+
ErrorLocation,
|
|
7
8
|
HydratedSyncRules,
|
|
8
9
|
HydrationState,
|
|
9
10
|
javaScriptExpressionEngine,
|
|
@@ -11,7 +12,8 @@ import {
|
|
|
11
12
|
SqlEventDescriptor,
|
|
12
13
|
SqlSyncRules,
|
|
13
14
|
SyncConfigWithErrors,
|
|
14
|
-
versionedHydrationState
|
|
15
|
+
versionedHydrationState,
|
|
16
|
+
YamlError
|
|
15
17
|
} from '@powersync/service-sync-rules';
|
|
16
18
|
import { SerializedSyncPlan, UpdateSyncRulesOptions } from './BucketStorageFactory.js';
|
|
17
19
|
import { ReplicationLock } from './ReplicationLock.js';
|
|
@@ -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
|
}
|
|
@@ -128,8 +150,10 @@ export abstract class PersistedSyncRulesContent implements PersistedSyncRulesCon
|
|
|
128
150
|
}
|
|
129
151
|
|
|
130
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' });
|
|
131
155
|
return {
|
|
132
|
-
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 },
|
|
133
157
|
...options
|
|
134
158
|
};
|
|
135
159
|
}
|
|
@@ -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,7 +1,7 @@
|
|
|
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
|
-
import { bson } from '../index.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Format of the id depends on the bucket storage module. It should be consistent within the module.
|
|
@@ -28,7 +28,7 @@ export class SourceTable implements SourceEntityDescriptor {
|
|
|
28
28
|
static readonly DEFAULT_TAG = DEFAULT_TAG;
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
* True if the table is used in sync
|
|
31
|
+
* True if the table is used in sync config for data queries.
|
|
32
32
|
*
|
|
33
33
|
* This value is resolved externally, and cached here.
|
|
34
34
|
*
|
|
@@ -37,7 +37,7 @@ export class SourceTable implements SourceEntityDescriptor {
|
|
|
37
37
|
public syncData = true;
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* True if the table is used in sync
|
|
40
|
+
* True if the table is used in sync config for data queries.
|
|
41
41
|
*
|
|
42
42
|
* This value is resolved externally, and cached here.
|
|
43
43
|
*
|
|
@@ -46,7 +46,7 @@ export class SourceTable implements SourceEntityDescriptor {
|
|
|
46
46
|
public syncParameters = true;
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
* True if the table is used in sync
|
|
49
|
+
* True if the table is used in sync config for events.
|
|
50
50
|
*
|
|
51
51
|
* This value is resolved externally, and cached here.
|
|
52
52
|
*
|
|
@@ -45,7 +45,7 @@ export const STORAGE_VERSION_3 = 3;
|
|
|
45
45
|
export const LEGACY_STORAGE_VERSION = STORAGE_VERSION_1;
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
|
-
* Default storage version for newly persisted
|
|
48
|
+
* Default storage version for newly persisted replication streams.
|
|
49
49
|
*/
|
|
50
50
|
export const CURRENT_STORAGE_VERSION = STORAGE_VERSION_2;
|
|
51
51
|
|