@powersync/service-core 1.27.0 → 1.27.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 +43 -0
- package/dist/api/RouteAPI.d.ts +8 -1
- package/dist/api/api-index.d.ts +1 -0
- package/dist/api/api-index.js +1 -0
- package/dist/api/api-index.js.map +1 -1
- package/dist/api/diagnostics.js +33 -16
- package/dist/api/diagnostics.js.map +1 -1
- package/dist/api/source-capabilities.d.ts +7 -0
- package/dist/api/source-capabilities.js +23 -0
- package/dist/api/source-capabilities.js.map +1 -0
- package/dist/auth/JwtPayload.d.ts +2 -2
- package/dist/auth/JwtPayload.js +2 -2
- package/dist/auth/JwtPayload.js.map +1 -1
- package/dist/replication/AbstractReplicationJob.d.ts +4 -6
- package/dist/replication/AbstractReplicationJob.js.map +1 -1
- package/dist/replication/AbstractReplicator.d.ts +15 -0
- package/dist/replication/AbstractReplicator.js +35 -3
- package/dist/replication/AbstractReplicator.js.map +1 -1
- package/dist/replication/ReplicationModule.js +13 -2
- package/dist/replication/ReplicationModule.js.map +1 -1
- package/dist/routes/configure-fastify.d.ts +39 -27
- package/dist/routes/endpoints/admin.d.ts +78 -54
- package/dist/routes/endpoints/admin.js +23 -9
- package/dist/routes/endpoints/admin.js.map +1 -1
- package/dist/routes/endpoints/sync-rules.js +39 -6
- package/dist/routes/endpoints/sync-rules.js.map +1 -1
- package/dist/storage/BucketStorageFactory.d.ts +11 -1
- package/dist/storage/BucketStorageFactory.js +22 -2
- package/dist/storage/BucketStorageFactory.js.map +1 -1
- package/dist/storage/PersistedSyncConfigContent.d.ts +2 -1
- package/dist/storage/PersistedSyncConfigContent.js.map +1 -1
- package/dist/storage/StorageProvider.d.ts +3 -0
- package/dist/storage/SyncRulesBucketStorage.d.ts +1 -1
- package/dist/storage/implementation/IncrementalReprocessingCompatibility.js +5 -1
- package/dist/storage/implementation/IncrementalReprocessingCompatibility.js.map +1 -1
- package/package.json +11 -11
- package/src/api/RouteAPI.ts +9 -1
- package/src/api/api-index.ts +1 -0
- package/src/api/diagnostics.ts +30 -14
- package/src/api/source-capabilities.ts +24 -0
- package/src/auth/JwtPayload.ts +2 -2
- package/src/replication/AbstractReplicationJob.ts +2 -4
- package/src/replication/AbstractReplicator.ts +44 -3
- package/src/replication/ReplicationModule.ts +12 -2
- package/src/routes/endpoints/admin.ts +28 -10
- package/src/routes/endpoints/sync-rules.ts +42 -9
- package/src/storage/BucketStorageFactory.ts +22 -2
- package/src/storage/PersistedSyncConfigContent.ts +3 -0
- package/src/storage/StorageProvider.ts +3 -0
- package/src/storage/SyncRulesBucketStorage.ts +1 -1
- package/src/storage/implementation/IncrementalReprocessingCompatibility.ts +13 -1
- package/test/src/AbstractReplicator.test.ts +156 -0
- package/test/src/diagnostics.test.ts +128 -0
- package/test/src/routes/admin.test.ts +235 -4
- package/test/src/routes/sync-rules.test.ts +124 -0
- package/test/src/source_table_config.test.ts +104 -0
- package/test/src/storage/BucketStorageFactory.test.ts +46 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ErrorCode, errors, router, schema } from '@powersync/lib-services-framework';
|
|
2
2
|
import { SqlSyncRules, SyncRulesErrors } from '@powersync/service-sync-rules';
|
|
3
3
|
import * as t from 'ts-codec';
|
|
4
|
-
import {
|
|
4
|
+
import { assertSourceCapabilities } from '../../api/source-capabilities.js';
|
|
5
|
+
import { logSyncConfigErrors, updateSyncRulesFromConfig } from '../../storage/BucketStorageFactory.js';
|
|
5
6
|
import { authApi } from '../auth.js';
|
|
6
7
|
import { routeDefinition } from '../router.js';
|
|
7
8
|
const DeploySyncRulesRequest = t.object({
|
|
@@ -45,6 +46,7 @@ export const deploySyncRules = routeDefinition({
|
|
|
45
46
|
const content = payload.params.content;
|
|
46
47
|
let syncConfig;
|
|
47
48
|
try {
|
|
49
|
+
// First ensure the SyncConfig parses correctly
|
|
48
50
|
const apiHandler = service_context.routerEngine.getAPI();
|
|
49
51
|
syncConfig = SqlSyncRules.fromYaml(content, {
|
|
50
52
|
...apiHandler.getParseSyncRulesOptions(),
|
|
@@ -60,6 +62,9 @@ export const deploySyncRules = routeDefinition({
|
|
|
60
62
|
details: e.message
|
|
61
63
|
});
|
|
62
64
|
}
|
|
65
|
+
logSyncConfigErrors(syncConfig);
|
|
66
|
+
// Validate if the current sources support the configuration specified in the sync config
|
|
67
|
+
await assertSourceCapabilities(service_context.routerEngine.getAPI(), syncConfig.config);
|
|
63
68
|
const sync_rules = await storageEngine.activeBucketStorage.updateSyncRules(updateSyncRulesFromConfig(syncConfig));
|
|
64
69
|
return {
|
|
65
70
|
slot_name: sync_rules.replicationStreamName
|
|
@@ -146,10 +151,16 @@ export const reprocessSyncRules = routeDefinition({
|
|
|
146
151
|
});
|
|
147
152
|
}
|
|
148
153
|
const sync_rules = active.content;
|
|
149
|
-
const
|
|
154
|
+
const parsed = SqlSyncRules.fromYaml(sync_rules.sync_rules_content, {
|
|
155
|
+
...payload.context.service_context.routerEngine.getAPI().getParseSyncRulesOptions(),
|
|
156
|
+
schema: undefined,
|
|
150
157
|
// This sync config already passed validation. But if the rules are not valid anymore due
|
|
151
158
|
// to a service change, we do want to report the error here.
|
|
152
|
-
|
|
159
|
+
throwOnError: true
|
|
160
|
+
});
|
|
161
|
+
logSyncConfigErrors(parsed);
|
|
162
|
+
await assertSourceCapabilities(payload.context.service_context.routerEngine.getAPI(), parsed.config);
|
|
163
|
+
const new_rules = await activeBucketStorage.updateSyncRules(updateSyncRulesFromConfig(parsed, {
|
|
153
164
|
version_label: sync_rules.version_label,
|
|
154
165
|
forceNewReplicationStream: true
|
|
155
166
|
}));
|
|
@@ -173,10 +184,32 @@ async function debugSyncRules(apiHandler, sync_rules) {
|
|
|
173
184
|
// No schema-based validation at this point
|
|
174
185
|
schema: undefined
|
|
175
186
|
});
|
|
176
|
-
const
|
|
177
|
-
const
|
|
187
|
+
const errors = [];
|
|
188
|
+
const warnings = rules.errors.filter((error) => error.type === 'warning').map((error) => error.message);
|
|
189
|
+
const recordError = (error) => {
|
|
190
|
+
errors.push(...(error instanceof SyncRulesErrors ? error.errors.map((e) => e.message) : [error.message]));
|
|
191
|
+
};
|
|
192
|
+
try {
|
|
193
|
+
const diagnostics = (await apiHandler.validateSourceCapabilities?.(rules.config)) ?? [];
|
|
194
|
+
for (const diagnostic of diagnostics) {
|
|
195
|
+
(diagnostic.level === 'fatal' ? errors : warnings).push(diagnostic.message);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch (e) {
|
|
199
|
+
recordError(e);
|
|
200
|
+
}
|
|
201
|
+
let resolved_tables = [];
|
|
202
|
+
try {
|
|
203
|
+
const source_table_patterns = rules.config.getSourceTables();
|
|
204
|
+
resolved_tables = await apiHandler.getDebugTablesInfo(source_table_patterns, rules.config);
|
|
205
|
+
}
|
|
206
|
+
catch (e) {
|
|
207
|
+
recordError(e);
|
|
208
|
+
}
|
|
178
209
|
return {
|
|
179
|
-
valid:
|
|
210
|
+
valid: errors.length == 0,
|
|
211
|
+
...(warnings.length > 0 ? { warnings } : {}),
|
|
212
|
+
...(errors.length > 0 ? { errors } : {}),
|
|
180
213
|
bucket_definitions: rules.config.debugRepresentation(),
|
|
181
214
|
source_tables: resolved_tables,
|
|
182
215
|
data_tables: rules.config.debugGetOutputTables()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-rules.js","sourceRoot":"","sources":["../../../src/routes/endpoints/sync-rules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AACtF,OAAO,EAAE,YAAY,EAAwB,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEpG,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"sync-rules.js","sourceRoot":"","sources":["../../../src/routes/endpoints/sync-rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BaseObserver } from '@powersync/lib-services-framework';
|
|
1
|
+
import { BaseObserver, logger } from '@powersync/lib-services-framework';
|
|
2
2
|
import { SerializedSyncPlan as RawSerializedSyncPlan, SerializedCompatibilityContext, SyncConfigWithErrors } from '@powersync/service-sync-rules';
|
|
3
3
|
import { ReplicationError } from '@powersync/service-types';
|
|
4
4
|
import { PersistedReplicationStream } from './PersistedReplicationStream.js';
|
|
@@ -165,6 +165,16 @@ export declare function updateSyncRulesFromYaml(content: string, options?: Omit<
|
|
|
165
165
|
validate?: boolean;
|
|
166
166
|
}): UpdateSyncRulesOptions;
|
|
167
167
|
export declare function updateSyncRulesFromConfig(parsed: SyncConfigWithErrors, options?: Omit<UpdateSyncRulesOptions, 'config'>): UpdateSyncRulesOptions;
|
|
168
|
+
/**
|
|
169
|
+
* Logs the errors and warnings of a parsed sync config
|
|
170
|
+
*
|
|
171
|
+
* Call this where a sync config is loaded or deployed, so that operators see these in the service logs and not only
|
|
172
|
+
* in the diagnostics and validate API responses.
|
|
173
|
+
*
|
|
174
|
+
* Fatal errors usually throw during parsing before this is reached. They can reach this when the sync config is parsed
|
|
175
|
+
* without validation, such as at startup with `exit_on_error: false`.
|
|
176
|
+
*/
|
|
177
|
+
export declare function logSyncConfigErrors(parsed: SyncConfigWithErrors, log?: typeof logger): void;
|
|
168
178
|
export interface GetIntanceOptions {
|
|
169
179
|
/**
|
|
170
180
|
* The job lease, including a lease acquired during initial configuration.
|
|
@@ -38,13 +38,14 @@ export class BucketStorageFactory extends BaseObserver {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
export function updateSyncRulesFromYaml(content, options) {
|
|
41
|
+
const { validate, ...updateOptions } = options ?? {};
|
|
41
42
|
const config = SqlSyncRules.fromYaml(content, {
|
|
42
43
|
// No schema-based validation at this point
|
|
43
44
|
schema: undefined,
|
|
44
45
|
defaultSchema: options?.defaultSchema ?? 'not_applicable', // Not needed for validation
|
|
45
|
-
throwOnError:
|
|
46
|
+
throwOnError: validate ?? false
|
|
46
47
|
});
|
|
47
|
-
return updateSyncRulesFromConfig(config,
|
|
48
|
+
return updateSyncRulesFromConfig(config, updateOptions);
|
|
48
49
|
}
|
|
49
50
|
export function updateSyncRulesFromConfig(parsed, options) {
|
|
50
51
|
let plan = null;
|
|
@@ -64,4 +65,23 @@ export function updateSyncRulesFromConfig(parsed, options) {
|
|
|
64
65
|
}
|
|
65
66
|
return { config: { yaml: config.content, plan, parsed }, ...options };
|
|
66
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Logs the errors and warnings of a parsed sync config
|
|
70
|
+
*
|
|
71
|
+
* Call this where a sync config is loaded or deployed, so that operators see these in the service logs and not only
|
|
72
|
+
* in the diagnostics and validate API responses.
|
|
73
|
+
*
|
|
74
|
+
* Fatal errors usually throw during parsing before this is reached. They can reach this when the sync config is parsed
|
|
75
|
+
* without validation, such as at startup with `exit_on_error: false`.
|
|
76
|
+
*/
|
|
77
|
+
export function logSyncConfigErrors(parsed, log = logger) {
|
|
78
|
+
for (const error of parsed.errors) {
|
|
79
|
+
if (error.type == 'warning') {
|
|
80
|
+
log.warn(`Sync config warning: ${error.message}`);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
log.error(`Sync config error: ${error.message}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
67
87
|
//# sourceMappingURL=BucketStorageFactory.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BucketStorageFactory.js","sourceRoot":"","sources":["../../src/storage/BucketStorageFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EACL,qBAAqB,EAGrB,iBAAiB,EACjB,YAAY,EAEb,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAE,qCAAqC,EAAE,MAAM,mBAAmB,CAAC;AAQ1E;;;;;;;GAOG;AACH,MAAM,OAAgB,oBACpB,SAAQ,YAA0C;IAGlD;;OAEG;IACH,KAAK,CAAC,kBAAkB,CACtB,OAA+B;QAE/B,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,sBAAsB,EAAE,CAAC;QACtD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAEhD,IACE,SAAS,EAAE,OAAO,CAAC,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI;YAC5D,SAAS,CAAC,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,aAAa,EACxD,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;YACrC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAC5B,CAAC;aAAM,IACL,SAAS,IAAI,IAAI;YACjB,MAAM,EAAE,OAAO,CAAC,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI;YACzD,MAAM,CAAC,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,aAAa,EACrD,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;YACrC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAC5B,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;YACnC,MAAM,oBAAoB,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YACjE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,oBAAoB,CAAC,YAAY,IAAI,SAAS,EAAE,CAAC;QACvG,CAAC;IACH,CAAC;IA8DD,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC;QACzB,MAAM,IAAI,CAAC,qBAAqB,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IACnF,CAAC;CACF;AAuGD,MAAM,UAAU,uBAAuB,CACrC,OAAe,EACf,OAAyE;IAEzE,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,OAAO,EAAE;QAC5C,2CAA2C;QAC3C,MAAM,EAAE,SAAS;QACjB,aAAa,EAAE,OAAO,EAAE,aAAa,IAAI,gBAAgB,EAAE,4BAA4B;QACvF,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"BucketStorageFactory.js","sourceRoot":"","sources":["../../src/storage/BucketStorageFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EACL,qBAAqB,EAGrB,iBAAiB,EACjB,YAAY,EAEb,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAE,qCAAqC,EAAE,MAAM,mBAAmB,CAAC;AAQ1E;;;;;;;GAOG;AACH,MAAM,OAAgB,oBACpB,SAAQ,YAA0C;IAGlD;;OAEG;IACH,KAAK,CAAC,kBAAkB,CACtB,OAA+B;QAE/B,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,sBAAsB,EAAE,CAAC;QACtD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAEhD,IACE,SAAS,EAAE,OAAO,CAAC,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI;YAC5D,SAAS,CAAC,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,aAAa,EACxD,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;YACrC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAC5B,CAAC;aAAM,IACL,SAAS,IAAI,IAAI;YACjB,MAAM,EAAE,OAAO,CAAC,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI;YACzD,MAAM,CAAC,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,aAAa,EACrD,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;YACrC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAC5B,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;YACnC,MAAM,oBAAoB,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YACjE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,oBAAoB,CAAC,YAAY,IAAI,SAAS,EAAE,CAAC;QACvG,CAAC;IACH,CAAC;IA8DD,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC;QACzB,MAAM,IAAI,CAAC,qBAAqB,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IACnF,CAAC;CACF;AAuGD,MAAM,UAAU,uBAAuB,CACrC,OAAe,EACf,OAAyE;IAEzE,MAAM,EAAE,QAAQ,EAAE,GAAG,aAAa,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;IACrD,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,OAAO,EAAE;QAC5C,2CAA2C;QAC3C,MAAM,EAAE,SAAS;QACjB,aAAa,EAAE,OAAO,EAAE,aAAa,IAAI,gBAAgB,EAAE,4BAA4B;QACvF,YAAY,EAAE,QAAQ,IAAI,KAAK;KAChC,CAAC,CAAC;IAEH,OAAO,yBAAyB,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,MAA4B,EAC5B,OAAgD;IAEhD,IAAI,IAAI,GAA8B,IAAI,CAAC;IAC3C,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAClC,IAAI,MAAM,YAAY,qBAAqB,EAAE,CAAC;QAC5C,MAAM,gBAAgB,GAA6B,EAAE,CAAC;QACtD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACvC,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/E,CAAC;QAED,IAAI,GAAG;YACL,aAAa,EAAE,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE;YAC/C,IAAI,EAAE,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC;YACpC,+GAA+G;YAC/G,gBAAgB;YAChB,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,qCAAqC,CAAC,CAAC,CAAC,CAAC;SACpE,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC;AACxE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAA4B,EAAE,MAAqB,MAAM;IAC3F,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClC,IAAI,KAAK,CAAC,IAAI,IAAI,SAAS,EAAE,CAAC;YAC5B,GAAG,CAAC,IAAI,CAAC,wBAAwB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACpD,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,KAAK,CAAC,sBAAsB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SyncConfigWithErrors } from '@powersync/service-sync-rules';
|
|
1
|
+
import { SourceConnectionMap, SyncConfigWithErrors } from '@powersync/service-sync-rules';
|
|
2
2
|
import { Logger } from 'winston';
|
|
3
3
|
import { SyncRuleState } from './BucketStorage.js';
|
|
4
4
|
import { SerializedSyncPlan, UpdateSyncRulesOptions } from './BucketStorageFactory.js';
|
|
@@ -62,4 +62,5 @@ export interface PersistedSyncConfigContentData {
|
|
|
62
62
|
export type PersistedSyncConfigId = string;
|
|
63
63
|
export interface ParseSyncConfigOptions {
|
|
64
64
|
defaultSchema: string;
|
|
65
|
+
connections?: SourceConnectionMap;
|
|
65
66
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PersistedSyncConfigContent.js","sourceRoot":"","sources":["../../src/storage/PersistedSyncConfigContent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACrG,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EAInB,UAAU,EACV,qBAAqB,
|
|
1
|
+
{"version":3,"file":"PersistedSyncConfigContent.js","sourceRoot":"","sources":["../../src/storage/PersistedSyncConfigContent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACrG,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EAInB,UAAU,EACV,qBAAqB,EAErB,YAAY,EAEZ,uBAAuB,EACvB,SAAS,EACV,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAMtC,OAAO,EAAE,sBAAsB,EAAwB,MAAM,2BAA2B,CAAC;AASzF,MAAM,UAAU,+BAA+B,CAAC,OAA+C;IAC7F,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;IAExE,IAAI,YAAY,IAAI,IAAI,EAAE,CAAC;QACzB,mEAAmE;QACnE,OAAO,YAAY,CAAC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,IAAI,GAAG,mBAAmB,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACpD,MAAM,aAAa,GAAG,oBAAoB,CAAC,WAAW,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;IACnF,MAAM,MAAM,GAAgB,EAAE,CAAC;IAC/B,kHAAkH;IAClH,8GAA8G;IAC9G,+GAA+G;IAC/G,IAAI,YAAY,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;QACrC,MAAM,UAAU,GAAG,uBAAuB,CAAC,YAAY,CAAC,gBAAgB,EAAE;YACxE,GAAG,YAAY;YACf,gHAAgH;YAChH,8GAA8G;YAC9G,0BAA0B,EAAE,KAAK;SAClC,CAAC,CAAC;QACH,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,IAAI,OAAO,CAAC,CAAC;QAC/E,IAAI,WAAW,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CACb,mDAAmD,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC1G,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;QAChC,MAAM,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACzE,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,qBAAqB,CAAC,IAAI,EAAE,aAAa,EAAE;QACjE,aAAa,EAAE,YAAY,CAAC,aAAa;QACzC,UAAU,EAAE,OAAO;KACpB,CAAC,CAAC;IAEH,2GAA2G;IAC3G,+FAA+F;IAC/F,WAAW,CAAC,cAAc,GAAG,cAAc,CAAC;IAE5C,IAAI,YAAY,CAAC,MAAM,EAAE,CAAC;QACxB,KAAK,MAAM,KAAK,IAAI,YAAY,CAAC,MAAM,EAAE,CAAC;YACxC,MAAM,QAAQ,GAA8B,KAAK,CAAC,QAAQ,IAAI;gBAC5D,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,YAAY;gBAClC,GAAG,EAAE,KAAK,CAAC,QAAQ,CAAC,UAAU;aAC/B,CAAC;YACF,MAAM,WAAW,GAAG,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;YACtE,WAAW,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC;YAE/B,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;AACzC,CAAC;AAED;;;;;;GAMG;AAEH,MAAM,OAAgB,0BAA0B;IACrC,mBAAmB,CAAS;IAC5B,kBAAkB,CAAS;IAC3B,aAAa,CAA4B;IACzC,qBAAqB,CAAS;IAC9B,cAAc,CAAS;IACvB,MAAM,CAAS;IACf,YAAY,CAA+B;IAC3C,eAAe,CAAgB;IAC/B,aAAa,CAAqB;IAE3C,YAAY,IAAoC;QAC9C,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,mBAAmB,CAAC;QACpD,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,CAAC;QAClD,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC;QACxC,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC,qBAAqB,CAAC;QACxD,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC;QAC1C,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC;QAC9C,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC;QAC5C,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC;QACxC,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,aAAa,GAAG,CAAC;QAClF,IAAI,CAAC,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,IAAI,CAAC,qBAAqB,IAAI,aAAa,GAAG,EAAE,CAAC,CAAC;IACpG,CAAC;IAED;;;;OAIG;IACH,gBAAgB;QACd,MAAM,aAAa,GAAG,sBAAsB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAClE,IAAI,aAAa,IAAI,IAAI,EAAE,CAAC;YAC1B,MAAM,IAAI,YAAY,CACpB,SAAS,CAAC,WAAW,EACrB,+BAA+B,IAAI,CAAC,cAAc,2BAA2B,IAAI,CAAC,mBAAmB,EAAE,CACxG,CAAC;QACJ,CAAC;QACD,OAAO,aAAa,CAAC;IACvB,CAAC;IAED;;;;OAIG;IACO,iBAAiB,CAAC,OAA+B;QACzD,OAAO,+BAA+B,CAAC;YACrC,OAAO,EAAE,IAAI,CAAC,kBAAkB;YAChC,YAAY,EAAE,IAAI,CAAC,aAAa;YAChC,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,YAAY,EAAE,OAAO;SACtB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,CAAC,OAA+B;QACpC,IAAI,cAA8B,CAAC;QACnC,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAE/C,MAAM,aAAa,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC9C,IACE,aAAa,CAAC,gBAAgB;YAC9B,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,mBAAmB,CAAC,kBAAkB,CAAC,EAC7E,CAAC;YACD,cAAc,GAAG,uBAAuB,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACrE,CAAC;aAAM,CAAC;YACN,cAAc,GAAG,uBAAuB,CAAC;QAC3C,CAAC;QAED,IAAI,QAAwC,CAAC;QAC7C,OAAO;YACL,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;YAC7C,qBAAqB,EAAE,IAAI,CAAC,qBAAqB;YACjD,WAAW,EAAE,CAAC,MAAM,CAAC;YACrB,cAAc;YACd,IAAI,kBAAkB;gBACpB,QAAQ,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,cAAc,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACnF,OAAO,QAAQ,CAAC;YAClB,CAAC;SACF,CAAC;IACJ,CAAC;IAED,eAAe,CAAC,OAAgD;QAC9D,4DAA4D;QAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,CAAC,EAAE,aAAa,EAAE,gBAAgB,EAAE,CAAC,CAAC;QAC3E,OAAO;YACL,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,kBAAkB,EAAE,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,EAAE;YAC3E,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,GAAG,OAAO;SACX,CAAC;IACJ,CAAC;CAMF"}
|
|
@@ -6,7 +6,7 @@ import * as util from '../util/util-index.js';
|
|
|
6
6
|
import { BucketStorageBatch, FlushedResult, SaveUpdate } from './BucketStorageBatch.js';
|
|
7
7
|
import { BucketStorageFactory } from './BucketStorageFactory.js';
|
|
8
8
|
import { ParsedSyncConfigSet } from './ParsedSyncConfigSet.js';
|
|
9
|
-
import { ParseSyncConfigOptions } from './PersistedSyncConfigContent.js';
|
|
9
|
+
import type { ParseSyncConfigOptions } from './PersistedSyncConfigContent.js';
|
|
10
10
|
import { SourceEntityDescriptor } from './SourceEntity.js';
|
|
11
11
|
import { SourceTable } from './SourceTable.js';
|
|
12
12
|
import { SourceTableCandidateReconciler } from './SourceTableReconciler.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CompatibilityContext } from '@powersync/service-sync-rules';
|
|
1
|
+
import { CompatibilityContext, sourceTableConfigsEqual } from '@powersync/service-sync-rules';
|
|
2
2
|
/**
|
|
3
3
|
* Check if a sync config update can use incremental reprocessing.
|
|
4
4
|
*/
|
|
@@ -26,6 +26,10 @@ export function isCompatible(existingPlans, updateConfig, logger) {
|
|
|
26
26
|
logger.info(`Compatibility options changed - incremental reprocessing not supported`);
|
|
27
27
|
return false;
|
|
28
28
|
}
|
|
29
|
+
if (existingPlans.some((existing) => !sourceTableConfigsEqual(existing.plan.sourceTableConfig ?? {}, updateConfig.plan.plan.sourceTableConfig ?? {}))) {
|
|
30
|
+
logger.info('Source table configuration changed - incremental reprocessing not supported');
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
29
33
|
return true;
|
|
30
34
|
}
|
|
31
35
|
//# sourceMappingURL=IncrementalReprocessingCompatibility.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IncrementalReprocessingCompatibility.js","sourceRoot":"","sources":["../../../src/storage/implementation/IncrementalReprocessingCompatibility.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"IncrementalReprocessingCompatibility.js","sourceRoot":"","sources":["../../../src/storage/implementation/IncrementalReprocessingCompatibility.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAI9F;;GAEG;AACH,MAAM,UAAU,YAAY,CAC1B,aAA4C,EAC5C,YAA8C,EAC9C,MAAc;IAEd,IAAI,YAAY,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;QAC9B,kDAAkD;QAClD,MAAM,CAAC,IAAI,CAAC,yEAAyE,CAAC,CAAC;QACvF,OAAO,KAAK,CAAC;IACf,CAAC;IAED,sEAAsE;IACtE,IAAI,aAAa,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QAC9B,iFAAiF;QACjF,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC;QAC/C,kDAAkD;QAClD,MAAM,CAAC,IAAI,CAAC,qGAAqG,CAAC,CAAC;QACnH,OAAO,KAAK,CAAC;IACf,CAAC;IAED,yGAAyG;IACzG,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,mBAAmB,GAAG,oBAAoB,CAAC,WAAW,CAAC,KAAM,CAAC,aAAa,CAAC,CAAC;IACnF,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;QAC1E,mCAAmC;QACnC,MAAM,CAAC,IAAI,CAAC,wEAAwE,CAAC,CAAC;QACtF,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IACE,aAAa,CAAC,IAAI,CAChB,CAAC,QAAQ,EAAE,EAAE,CACX,CAAC,uBAAuB,CACtB,QAAS,CAAC,IAAI,CAAC,iBAAiB,IAAI,EAAE,EACtC,YAAY,CAAC,IAAK,CAAC,IAAI,CAAC,iBAAiB,IAAI,EAAE,CAChD,CACJ,EACD,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,6EAA6E,CAAC,CAAC;QAC3F,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/package.json
CHANGED
|
@@ -4,18 +4,18 @@
|
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "1.27.
|
|
7
|
+
"version": "1.27.1",
|
|
8
8
|
"license": "FSL-1.1-ALv2",
|
|
9
9
|
"type": "module",
|
|
10
10
|
"exports": "./dist/index.js",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@js-sdsl/ordered-set": "^4.4.2",
|
|
13
13
|
"@opentelemetry/api": "^1.9.0",
|
|
14
|
-
"@opentelemetry/core": "^2.0
|
|
15
|
-
"@opentelemetry/exporter-metrics-otlp-http": "^0.
|
|
16
|
-
"@opentelemetry/exporter-prometheus": "^0.
|
|
17
|
-
"@opentelemetry/resources": "^2.0
|
|
18
|
-
"@opentelemetry/sdk-metrics": "^2.0
|
|
14
|
+
"@opentelemetry/core": "^2.8.0",
|
|
15
|
+
"@opentelemetry/exporter-metrics-otlp-http": "^0.219.0",
|
|
16
|
+
"@opentelemetry/exporter-prometheus": "^0.219.0",
|
|
17
|
+
"@opentelemetry/resources": "^2.8.0",
|
|
18
|
+
"@opentelemetry/sdk-metrics": "^2.8.0",
|
|
19
19
|
"async": "^3.2.4",
|
|
20
20
|
"async-mutex": "^0.5.0",
|
|
21
21
|
"bson": "^6.10.4",
|
|
@@ -33,17 +33,17 @@
|
|
|
33
33
|
"uuid": "^14.0.0",
|
|
34
34
|
"winston": "^3.13.0",
|
|
35
35
|
"yaml": "^2.8.3",
|
|
36
|
-
"@powersync/
|
|
36
|
+
"@powersync/service-rsocket-router": "0.2.29",
|
|
37
37
|
"@powersync/service-jsonbig": "0.17.13",
|
|
38
|
-
"@powersync/service-
|
|
39
|
-
"@powersync/service-sync-rules": "0.
|
|
40
|
-
"@powersync/
|
|
38
|
+
"@powersync/service-types": "0.20.0",
|
|
39
|
+
"@powersync/service-sync-rules": "0.44.0",
|
|
40
|
+
"@powersync/lib-services-framework": "0.10.4"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/async": "^3.2.24",
|
|
44
44
|
"@types/lodash": "^4.17.5",
|
|
45
45
|
"@types/negotiator": "^0.6.4",
|
|
46
|
-
"fastify": "^5.
|
|
46
|
+
"fastify": "^5.12.5",
|
|
47
47
|
"fastify-plugin": "^5.0.1"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
package/src/api/RouteAPI.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SyncConfig, TablePattern } from '@powersync/service-sync-rules';
|
|
2
2
|
import * as types from '@powersync/service-types';
|
|
3
|
-
import { ParseSyncConfigOptions
|
|
3
|
+
import type { ParseSyncConfigOptions } from '../storage/PersistedSyncConfigContent.js';
|
|
4
|
+
import { SyncRulesBucketStorage } from '../storage/storage-index.js';
|
|
4
5
|
|
|
5
6
|
export interface PatternResult {
|
|
6
7
|
schema: string;
|
|
@@ -40,6 +41,13 @@ export interface RouteAPI {
|
|
|
40
41
|
*/
|
|
41
42
|
getConnectionStatus(): Promise<types.ConnectionStatusV2>;
|
|
42
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Checks whether the source supports the capabilities required by this sync config.
|
|
46
|
+
* Must not modify the source. Return advisory warnings and fatal validation diagnostics.
|
|
47
|
+
* An empty array means no issues; throw only for unexpected failures.
|
|
48
|
+
*/
|
|
49
|
+
validateSourceCapabilities?(syncConfig: SyncConfig): Promise<types.ValidationDiagnostic[]>;
|
|
50
|
+
|
|
43
51
|
/**
|
|
44
52
|
* Expand sync config table patterns into table metadata from the source connection.
|
|
45
53
|
*
|
package/src/api/api-index.ts
CHANGED
package/src/api/diagnostics.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { logger, ServiceAssertionError } from '@powersync/lib-services-framework';
|
|
2
|
-
import { DEFAULT_TAG, SourceTableRef, SyncConfigWithErrors } from '@powersync/service-sync-rules';
|
|
2
|
+
import { DEFAULT_TAG, SourceTableRef, SyncConfigWithErrors, SyncRulesErrors } from '@powersync/service-sync-rules';
|
|
3
3
|
import { ReplicationError, SyncRulesStatus, TableInfo } from '@powersync/service-types';
|
|
4
4
|
|
|
5
5
|
import * as storage from '../storage/storage-index.js';
|
|
@@ -68,7 +68,11 @@ export async function getSyncRulesStatus(
|
|
|
68
68
|
version_label: syncConfig.version_label,
|
|
69
69
|
content: include_content ? syncConfig.sync_rules_content : undefined,
|
|
70
70
|
connections: [],
|
|
71
|
-
|
|
71
|
+
// Report each sync config error separately, retaining its source location.
|
|
72
|
+
errors:
|
|
73
|
+
e instanceof SyncRulesErrors
|
|
74
|
+
? e.errors.map((error) => syncConfigYamlErrorToReplicationError(error, now))
|
|
75
|
+
: [{ level: 'fatal', message: e.message, ts: now }]
|
|
72
76
|
};
|
|
73
77
|
}
|
|
74
78
|
|
|
@@ -81,20 +85,32 @@ export async function getSyncRulesStatus(
|
|
|
81
85
|
let replication_lag_bytes: number | undefined = undefined;
|
|
82
86
|
let slot_wal_budget: SlotWalBudgetInfo | undefined = undefined;
|
|
83
87
|
|
|
88
|
+
const validationErrors: ReplicationError[] = [];
|
|
84
89
|
let tables_flat: TableInfo[] = [];
|
|
85
90
|
|
|
86
91
|
if (check_connection) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
92
|
+
try {
|
|
93
|
+
validationErrors.push(...((await apiHandler.validateSourceCapabilities?.(rules)) ?? []));
|
|
94
|
+
} catch (e) {
|
|
95
|
+
validationErrors.push({ level: 'fatal', message: e.message, ts: now });
|
|
96
|
+
}
|
|
97
|
+
// Table inspection is independent of source capability checks. Preserve both failures
|
|
98
|
+
// and continue collecting diagnostics that do not depend on table metadata.
|
|
99
|
+
try {
|
|
100
|
+
const source_table_patterns = rules.getSourceTables();
|
|
101
|
+
const resolved_tables = await apiHandler.getDebugTablesInfo(source_table_patterns, rules);
|
|
102
|
+
tables_flat = resolved_tables.flatMap((info) => {
|
|
103
|
+
if (info.table) {
|
|
104
|
+
return [info.table];
|
|
105
|
+
} else if (info.tables) {
|
|
106
|
+
return info.tables;
|
|
107
|
+
} else {
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
} catch (e) {
|
|
112
|
+
validationErrors.push({ level: 'fatal', message: e.message, ts: now });
|
|
113
|
+
}
|
|
98
114
|
|
|
99
115
|
if (systemStorage) {
|
|
100
116
|
try {
|
|
@@ -151,7 +167,7 @@ export async function getSyncRulesStatus(
|
|
|
151
167
|
});
|
|
152
168
|
}
|
|
153
169
|
|
|
154
|
-
const errors = tables_flat.flatMap((info) => info.errors);
|
|
170
|
+
const errors = [...validationErrors, ...tables_flat.flatMap((info) => info.errors)];
|
|
155
171
|
const statusSource = await syncConfig.getSyncConfigStatus();
|
|
156
172
|
|
|
157
173
|
if (statusSource?.last_fatal_error) {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ErrorCode, ServiceError } from '@powersync/lib-services-framework';
|
|
2
|
+
import type { SyncConfig } from '@powersync/service-sync-rules';
|
|
3
|
+
import type { RouteAPI } from './RouteAPI.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Blocks deployment and reprocessing on fatal source diagnostics; warnings remain advisory.
|
|
7
|
+
* Capability failures use the same typed 422 error for deployment and reprocessing.
|
|
8
|
+
*/
|
|
9
|
+
export async function assertSourceCapabilities(api: RouteAPI, config: SyncConfig): Promise<void> {
|
|
10
|
+
try {
|
|
11
|
+
const diagnostics = (await api.validateSourceCapabilities?.(config)) ?? [];
|
|
12
|
+
const errors = diagnostics.filter((diagnostic) => diagnostic.level === 'fatal');
|
|
13
|
+
if (errors.length > 0) {
|
|
14
|
+
throw new Error(errors.map((error) => error.message).join('\n'));
|
|
15
|
+
}
|
|
16
|
+
} catch (error) {
|
|
17
|
+
throw new ServiceError({
|
|
18
|
+
status: 422,
|
|
19
|
+
code: ErrorCode.PSYNC_R0001,
|
|
20
|
+
description: 'Source capability validation failed',
|
|
21
|
+
details: error.message
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
package/src/auth/JwtPayload.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RequestJwtPayload } from '@powersync/service-sync-rules';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Payload from a JWT, always signed.
|
|
5
5
|
*/
|
|
6
|
-
export class JwtPayload extends
|
|
6
|
+
export class JwtPayload extends RequestJwtPayload {
|
|
7
7
|
/**
|
|
8
8
|
* Stringified version of sub. Used where we need a string user identifier, such as in write checkpoints
|
|
9
9
|
* and per-user metrics.
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { container, logger } from '@powersync/lib-services-framework';
|
|
2
2
|
import winston from 'winston';
|
|
3
3
|
import { MetricsEngine } from '../metrics/MetricsEngine.js';
|
|
4
|
-
import
|
|
4
|
+
import type { CreateJobOptions } from './AbstractReplicator.js';
|
|
5
5
|
import { ErrorRateLimiter } from './ErrorRateLimiter.js';
|
|
6
6
|
|
|
7
|
-
export interface AbstractReplicationJobOptions {
|
|
7
|
+
export interface AbstractReplicationJobOptions extends CreateJobOptions {
|
|
8
8
|
id: string;
|
|
9
|
-
storage: storage.SyncRulesBucketStorage;
|
|
10
9
|
metrics: MetricsEngine;
|
|
11
|
-
lock: storage.ReplicationLock;
|
|
12
10
|
rateLimiter: ErrorRateLimiter;
|
|
13
11
|
}
|
|
14
12
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { container, ErrorCode, logger, ReplicationAbortedError } from '@powersync/lib-services-framework';
|
|
2
|
+
import { DEFAULT_TAG, SqlSyncRules, type SyncConfig } from '@powersync/service-sync-rules';
|
|
2
3
|
import { ReplicationMetric } from '@powersync/service-types';
|
|
3
4
|
import { hrtime } from 'node:process';
|
|
4
5
|
import { setTimeout as sleep } from 'node:timers/promises';
|
|
@@ -7,6 +8,7 @@ import { MetricsEngine } from '../metrics/MetricsEngine.js';
|
|
|
7
8
|
import * as storage from '../storage/storage-index.js';
|
|
8
9
|
import { StorageEngine } from '../storage/storage-index.js';
|
|
9
10
|
import { SyncRulesProvider } from '../util/config/sync-rules/sync-rules-provider.js';
|
|
11
|
+
import type { ResolvedPowerSyncConfig } from '../util/config/types.js';
|
|
10
12
|
import { AbstractReplicationJob } from './AbstractReplicationJob.js';
|
|
11
13
|
import { ErrorRateLimiter } from './ErrorRateLimiter.js';
|
|
12
14
|
import { ConnectionTestResult } from './ReplicationModule.js';
|
|
@@ -30,6 +32,10 @@ export interface AbstractReplicatorOptions {
|
|
|
30
32
|
storageEngine: StorageEngine;
|
|
31
33
|
metricsEngine: MetricsEngine;
|
|
32
34
|
syncRuleProvider: SyncRulesProvider;
|
|
35
|
+
/**
|
|
36
|
+
* Source connection metadata from the service config, used when parsing filesystem-loaded sync configs.
|
|
37
|
+
*/
|
|
38
|
+
configuration?: Pick<ResolvedPowerSyncConfig, 'connections'>;
|
|
33
39
|
/**
|
|
34
40
|
* This limits the effect of retries when there is a persistent issue.
|
|
35
41
|
*/
|
|
@@ -73,6 +79,8 @@ export abstract class AbstractReplicator<T extends AbstractReplicationJob = Abst
|
|
|
73
79
|
|
|
74
80
|
private abortController: AbortController | undefined;
|
|
75
81
|
|
|
82
|
+
private assertSourceCapabilities: ((config: SyncConfig) => Promise<void>) | undefined;
|
|
83
|
+
|
|
76
84
|
protected constructor(private options: AbstractReplicatorOptions) {
|
|
77
85
|
this.logger = logger.child({ name: `Replicator:${options.id}` });
|
|
78
86
|
const heartbeatIntervalSeconds = options.heartbeatIntervalSeconds ?? DEFAULT_HEARTBEAT_INTERVAL_SECONDS;
|
|
@@ -105,6 +113,13 @@ export abstract class AbstractReplicator<T extends AbstractReplicationJob = Abst
|
|
|
105
113
|
return this.options.syncRuleProvider;
|
|
106
114
|
}
|
|
107
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Default schema for startup sync config validation. Source modules with a known default should override this.
|
|
118
|
+
*/
|
|
119
|
+
protected get defaultSchema(): string {
|
|
120
|
+
return 'not_applicable';
|
|
121
|
+
}
|
|
122
|
+
|
|
108
123
|
protected get rateLimiter() {
|
|
109
124
|
return this.options.rateLimiter;
|
|
110
125
|
}
|
|
@@ -117,6 +132,13 @@ export abstract class AbstractReplicator<T extends AbstractReplicationJob = Abst
|
|
|
117
132
|
return this.abortController?.signal.aborted;
|
|
118
133
|
}
|
|
119
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Register an assertion that blocks unsupported file-loaded sync configs before replication.
|
|
137
|
+
*/
|
|
138
|
+
public registerSourceCapabilitiesAssertion(assertion: (config: SyncConfig) => Promise<void>): void {
|
|
139
|
+
this.assertSourceCapabilities = assertion;
|
|
140
|
+
}
|
|
141
|
+
|
|
120
142
|
public async start(): Promise<void> {
|
|
121
143
|
this.abortController = new AbortController();
|
|
122
144
|
this.runLoop().catch((e) => {
|
|
@@ -165,10 +187,30 @@ export abstract class AbstractReplicator<T extends AbstractReplicationJob = Abst
|
|
|
165
187
|
// versions before that check was added, so we keep the lock for now - for where te service version and sync config is updated at
|
|
166
188
|
// the same time.
|
|
167
189
|
|
|
190
|
+
const parsed = SqlSyncRules.fromYaml(loadedSyncConfig, {
|
|
191
|
+
schema: undefined,
|
|
192
|
+
defaultSchema: this.defaultSchema,
|
|
193
|
+
connections:
|
|
194
|
+
this.options.configuration?.connections &&
|
|
195
|
+
Object.fromEntries(
|
|
196
|
+
this.options.configuration.connections.map((connection) => [
|
|
197
|
+
connection.tag ?? DEFAULT_TAG,
|
|
198
|
+
{ type: connection.type }
|
|
199
|
+
])
|
|
200
|
+
),
|
|
201
|
+
throwOnError: this.syncRuleProvider.exitOnError
|
|
202
|
+
});
|
|
203
|
+
storage.logSyncConfigErrors(parsed, this.logger);
|
|
204
|
+
try {
|
|
205
|
+
await this.assertSourceCapabilities?.(parsed.config);
|
|
206
|
+
} catch (error) {
|
|
207
|
+
if (this.syncRuleProvider.exitOnError) throw error;
|
|
208
|
+
// Persist the config for diagnostics; the job-start check will prevent unsafe replication.
|
|
209
|
+
this.logger.error('Source capability validation failed for the sync config', error);
|
|
210
|
+
}
|
|
168
211
|
const { lock } = await this.storage.configureSyncRules(
|
|
169
|
-
storage.
|
|
212
|
+
storage.updateSyncRulesFromConfig(parsed, {
|
|
170
213
|
lock: true,
|
|
171
|
-
validate: this.syncRuleProvider.exitOnError,
|
|
172
214
|
version_label: versionLabel
|
|
173
215
|
})
|
|
174
216
|
);
|
|
@@ -177,7 +219,6 @@ export abstract class AbstractReplicator<T extends AbstractReplicationJob = Abst
|
|
|
177
219
|
}
|
|
178
220
|
} catch (e) {
|
|
179
221
|
// Log and re-raise to exit.
|
|
180
|
-
// Should only reach this due to validation errors if exit_on_error is true.
|
|
181
222
|
this.logger.error(`Failed to update sync config`, e);
|
|
182
223
|
throw e;
|
|
183
224
|
}
|
|
@@ -90,8 +90,18 @@ export abstract class ReplicationModule<TConfig extends types.configFile.DataSou
|
|
|
90
90
|
// If decoding fails, this will raise a hard error, and stop the service.
|
|
91
91
|
this.decodeConfig(baseMatchingConfig);
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
const sourceAPI = this.createRouteAPIAdapter();
|
|
94
|
+
// The router exists even in replication-only mode and owns adapter shutdown through the service lifecycle.
|
|
95
|
+
context.routerEngine.registerAPI(sourceAPI);
|
|
96
|
+
if (context.replicationEngine) {
|
|
97
|
+
const replicator = this.createReplicator(context);
|
|
98
|
+
if (sourceAPI.validateSourceCapabilities != null) {
|
|
99
|
+
// KLUDGE: Reuse the adapter validation for filesystem-loaded configs.
|
|
100
|
+
// A shared validation interface could replace this registration through the route adapter in the future.
|
|
101
|
+
replicator.registerSourceCapabilitiesAssertion((config) => api.assertSourceCapabilities(sourceAPI, config));
|
|
102
|
+
}
|
|
103
|
+
context.replicationEngine.register(replicator);
|
|
104
|
+
}
|
|
95
105
|
}
|
|
96
106
|
|
|
97
107
|
protected decodeConfig(config: TConfig): void {
|