@powersync/service-core 1.25.0 → 1.26.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 +42 -0
- package/dist/api/diagnostics.js +2 -0
- package/dist/api/diagnostics.js.map +1 -1
- package/dist/entry/commands/compact-action.js +28 -24
- package/dist/entry/commands/compact-action.js.map +1 -1
- package/dist/metrics/metrics-interfaces.d.ts +5 -1
- package/dist/metrics/metrics-interfaces.js.map +1 -1
- package/dist/metrics/open-telemetry/MetricAttributeFilteringExporter.d.ts +36 -0
- package/dist/metrics/open-telemetry/MetricAttributeFilteringExporter.js +70 -0
- package/dist/metrics/open-telemetry/MetricAttributeFilteringExporter.js.map +1 -0
- package/dist/metrics/open-telemetry/OpenTelemetryMetricsFactory.js +6 -1
- package/dist/metrics/open-telemetry/OpenTelemetryMetricsFactory.js.map +1 -1
- package/dist/metrics/open-telemetry/util.js +7 -3
- package/dist/metrics/open-telemetry/util.js.map +1 -1
- package/dist/replication/AbstractReplicator.js +16 -6
- package/dist/replication/AbstractReplicator.js.map +1 -1
- package/dist/routes/configure-fastify.d.ts +9 -0
- package/dist/routes/endpoints/admin.d.ts +18 -0
- package/dist/routes/endpoints/admin.js +3 -1
- package/dist/routes/endpoints/admin.js.map +1 -1
- package/dist/routes/endpoints/sync-rules.js +3 -1
- package/dist/routes/endpoints/sync-rules.js.map +1 -1
- package/dist/storage/BucketStorageBatch.d.ts +2 -1
- package/dist/storage/BucketStorageBatch.js.map +1 -1
- package/dist/storage/BucketStorageFactory.d.ts +28 -4
- package/dist/storage/BucketStorageFactory.js +8 -4
- package/dist/storage/BucketStorageFactory.js.map +1 -1
- package/dist/storage/PersistedSyncConfigContent.d.ts +2 -0
- package/dist/storage/PersistedSyncConfigContent.js +23 -10
- package/dist/storage/PersistedSyncConfigContent.js.map +1 -1
- package/dist/storage/ReplicationEventPayload.d.ts +6 -1
- package/dist/storage/SourceTable.d.ts +13 -5
- package/dist/storage/SourceTable.js +8 -4
- package/dist/storage/SourceTable.js.map +1 -1
- package/dist/storage/StorageVersionConfig.d.ts +4 -0
- package/dist/storage/StorageVersionConfig.js +10 -1
- package/dist/storage/StorageVersionConfig.js.map +1 -1
- package/dist/storage/SyncRulesBucketStorage.d.ts +39 -7
- package/dist/storage/SyncRulesBucketStorage.js.map +1 -1
- package/dist/storage/WriteCheckpointAPI.d.ts +25 -3
- package/dist/storage/WriteCheckpointAPI.js.map +1 -1
- package/dist/storage/implementation/BucketDefinitionMapping.d.ts +23 -7
- package/dist/storage/implementation/BucketDefinitionMapping.js +88 -14
- package/dist/storage/implementation/BucketDefinitionMapping.js.map +1 -1
- package/dist/storage/implementation/IncrementalReprocessingSyncConfigLog.js +9 -1
- package/dist/storage/implementation/IncrementalReprocessingSyncConfigLog.js.map +1 -1
- package/dist/storage/storage-metrics.js +120 -4
- package/dist/storage/storage-metrics.js.map +1 -1
- package/dist/sync/BucketChecksumState.d.ts +1 -1
- package/dist/sync/BucketChecksumState.js.map +1 -1
- package/dist/sync/sync.js +37 -9
- package/dist/sync/sync.js.map +1 -1
- package/dist/sync/util.js +10 -1
- package/dist/sync/util.js.map +1 -1
- package/dist/util/config/compound-config-collector.js +5 -0
- package/dist/util/config/compound-config-collector.js.map +1 -1
- package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.js +1 -0
- package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.js.map +1 -1
- package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.js +1 -0
- package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.js.map +1 -1
- package/dist/util/config/sync-rules/sync-rules-provider.d.ts +2 -0
- package/dist/util/config/sync-rules/sync-rules-provider.js +3 -0
- package/dist/util/config/sync-rules/sync-rules-provider.js.map +1 -1
- package/dist/util/config/types.d.ts +1 -0
- package/dist/util/protocol-types.d.ts +4 -4
- package/dist/util/protocol-types.js +3 -2
- package/dist/util/protocol-types.js.map +1 -1
- package/dist/util/utils.d.ts +1 -0
- package/dist/util/utils.js +15 -0
- package/dist/util/utils.js.map +1 -1
- package/package.json +6 -5
- package/src/api/diagnostics.ts +2 -0
- package/src/entry/commands/compact-action.ts +32 -24
- package/src/metrics/metrics-interfaces.ts +6 -1
- package/src/metrics/open-telemetry/MetricAttributeFilteringExporter.ts +85 -0
- package/src/metrics/open-telemetry/OpenTelemetryMetricsFactory.ts +7 -2
- package/src/metrics/open-telemetry/util.ts +7 -3
- package/src/replication/AbstractReplicator.ts +22 -6
- package/src/routes/endpoints/admin.ts +3 -1
- package/src/routes/endpoints/sync-rules.ts +3 -1
- package/src/storage/BucketStorageBatch.ts +2 -1
- package/src/storage/BucketStorageFactory.ts +44 -8
- package/src/storage/PersistedSyncConfigContent.ts +26 -11
- package/src/storage/ReplicationEventPayload.ts +6 -1
- package/src/storage/SourceTable.ts +17 -4
- package/src/storage/StorageVersionConfig.ts +11 -1
- package/src/storage/SyncRulesBucketStorage.ts +47 -7
- package/src/storage/WriteCheckpointAPI.ts +32 -3
- package/src/storage/implementation/BucketDefinitionMapping.ts +120 -17
- package/src/storage/implementation/IncrementalReprocessingSyncConfigLog.ts +22 -5
- package/src/storage/storage-metrics.ts +154 -8
- package/src/sync/BucketChecksumState.ts +3 -1
- package/src/sync/sync.ts +40 -11
- package/src/sync/util.ts +21 -8
- package/src/util/config/compound-config-collector.ts +6 -0
- package/src/util/config/sync-rules/impl/base64-sync-rules-collector.ts +1 -0
- package/src/util/config/sync-rules/impl/filesystem-sync-rules-collector.ts +1 -0
- package/src/util/config/sync-rules/sync-rules-provider.ts +5 -0
- package/src/util/config/types.ts +1 -0
- package/src/util/protocol-types.ts +3 -2
- package/src/util/utils.ts +14 -0
- package/test/src/AbstractReplicator.test.ts +30 -0
- package/test/src/MetricAttributeFilteringExporter.test.ts +96 -0
- package/test/src/PersistedSyncConfigContent.test.ts +152 -0
- package/test/src/config.test.ts +40 -0
- package/test/src/diagnostics.test.ts +25 -0
- package/test/src/routes/admin.test.ts +8 -2
- package/test/src/routes/stream.test.ts +123 -2
- package/test/src/storage/SourceTable.test.ts +4 -1
- package/test/src/storage-metrics.test.ts +148 -0
- package/test/src/sync/util.test.ts +15 -0
- package/test/src/util/utils.test.ts +23 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -37,10 +37,17 @@ export abstract class BucketStorageFactory
|
|
|
37
37
|
const deploying = await this.getDeployingSyncConfig();
|
|
38
38
|
const active = await this.getActiveSyncConfig();
|
|
39
39
|
|
|
40
|
-
if (
|
|
40
|
+
if (
|
|
41
|
+
deploying?.content.sync_rules_content == options.config.yaml &&
|
|
42
|
+
deploying.content.version_label == options.version_label
|
|
43
|
+
) {
|
|
41
44
|
logger.info('Sync config unchanged');
|
|
42
45
|
return { updated: false };
|
|
43
|
-
} else if (
|
|
46
|
+
} else if (
|
|
47
|
+
deploying == null &&
|
|
48
|
+
active?.content.sync_rules_content == options.config.yaml &&
|
|
49
|
+
active.content.version_label == options.version_label
|
|
50
|
+
) {
|
|
44
51
|
logger.info('Sync config unchanged');
|
|
45
52
|
return { updated: false };
|
|
46
53
|
} else {
|
|
@@ -141,9 +148,32 @@ export interface StorageMetrics {
|
|
|
141
148
|
* Size of current_data.
|
|
142
149
|
*/
|
|
143
150
|
replication_size_bytes: number;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Size of active object-storage references, such as S3 bucket-data objects.
|
|
154
|
+
*/
|
|
155
|
+
object_storage_size_bytes?: number;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Per-sync-config storage sizes, when the storage backend can provide them.
|
|
159
|
+
*/
|
|
160
|
+
sync_config_metrics?: StorageSyncConfigMetrics[];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface StorageSyncConfigMetrics {
|
|
164
|
+
sync_config_id: string;
|
|
165
|
+
sync_config_state: string;
|
|
166
|
+
/** Optional operator-supplied label identifying this sync config version. */
|
|
167
|
+
version_label?: string;
|
|
168
|
+
attributed_bucket_data_bytes: number;
|
|
169
|
+
attributed_parameter_indexes_bytes: number;
|
|
170
|
+
attributed_source_records_bytes: number;
|
|
171
|
+
attributed_object_storage_bytes: number;
|
|
144
172
|
}
|
|
145
173
|
|
|
146
174
|
export interface UpdateSyncRulesOptions {
|
|
175
|
+
/** Optional operator-supplied label identifying this deployed sync config version. */
|
|
176
|
+
version_label?: string;
|
|
147
177
|
config: {
|
|
148
178
|
yaml: string;
|
|
149
179
|
/**
|
|
@@ -161,6 +191,12 @@ export interface UpdateSyncRulesOptions {
|
|
|
161
191
|
lock?: boolean;
|
|
162
192
|
storageVersion?: number;
|
|
163
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Start a replacement replication stream instead of incrementally reprocessing a
|
|
196
|
+
* compatible active stream. Used when the current stream needs a full reprocess.
|
|
197
|
+
*/
|
|
198
|
+
forceNewReplicationStream?: boolean;
|
|
199
|
+
|
|
164
200
|
/**
|
|
165
201
|
* Only relevant if the result is used. This does not affect the persisted config.
|
|
166
202
|
*/
|
|
@@ -174,11 +210,10 @@ export interface SerializedSyncPlan {
|
|
|
174
210
|
plan: RawSerializedSyncPlan;
|
|
175
211
|
compatibility: SerializedCompatibilityContext;
|
|
176
212
|
/**
|
|
177
|
-
*
|
|
178
|
-
* yet.
|
|
213
|
+
* Raw event SQL persisted as a compatibility mirror for compiled {@link plan} events.
|
|
179
214
|
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
215
|
+
* Compiled events are an additive plan field. Older services ignore that field and restore these descriptors through
|
|
216
|
+
* the legacy evaluator. Keep dual-writing this field until a future plan version explicitly removes that support.
|
|
182
217
|
*/
|
|
183
218
|
eventDescriptors: Record<string, string[]>;
|
|
184
219
|
errors?: ReplicationError[];
|
|
@@ -206,13 +241,14 @@ export function updateSyncRulesFromConfig(
|
|
|
206
241
|
const { config, errors } = parsed;
|
|
207
242
|
if (config instanceof PrecompiledSyncConfig) {
|
|
208
243
|
const eventDescriptors: Record<string, string[]> = {};
|
|
209
|
-
for (const event of config.
|
|
210
|
-
eventDescriptors[event.name] = event.sourceQueries.map((
|
|
244
|
+
for (const event of config.plan.events) {
|
|
245
|
+
eventDescriptors[event.name] = event.sourceQueries.map((query) => query.sql);
|
|
211
246
|
}
|
|
212
247
|
|
|
213
248
|
plan = {
|
|
214
249
|
compatibility: config.compatibility.serialize(),
|
|
215
250
|
plan: serializeSyncPlan(config.plan),
|
|
251
|
+
// Dual-write raw SQL so older services can ignore additive compiled plan events without losing event behavior.
|
|
216
252
|
eventDescriptors,
|
|
217
253
|
errors: errors.map((e) => syncConfigYamlErrorToReplicationError(e))
|
|
218
254
|
};
|
|
@@ -2,6 +2,7 @@ import { logger as defaultLogger, ErrorCode, ServiceError } from '@powersync/lib
|
|
|
2
2
|
import {
|
|
3
3
|
CompatibilityContext,
|
|
4
4
|
CompatibilityOption,
|
|
5
|
+
compileEventDefinitions,
|
|
5
6
|
DEFAULT_HYDRATION_STATE,
|
|
6
7
|
deserializeSyncPlan,
|
|
7
8
|
ErrorLocation,
|
|
@@ -9,7 +10,6 @@ import {
|
|
|
9
10
|
HydrationState,
|
|
10
11
|
nodeSqlite,
|
|
11
12
|
PrecompiledSyncConfig,
|
|
12
|
-
SqlEventDescriptor,
|
|
13
13
|
SqlSyncRules,
|
|
14
14
|
SyncConfigWithErrors,
|
|
15
15
|
versionedHydrationState,
|
|
@@ -40,17 +40,28 @@ export function parsePersistedSyncConfigContent(options: ParsePersistedSyncConfi
|
|
|
40
40
|
|
|
41
41
|
const plan = deserializeSyncPlan(compiledPlan.plan);
|
|
42
42
|
const compatibility = CompatibilityContext.deserialize(compiledPlan.compatibility);
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
const errors: YamlError[] = [];
|
|
44
|
+
// Compiled events are additive to plan versions 1 and 2. New readers prefer them when present; when an older plan
|
|
45
|
+
// does not contain them, normalize the dual-written raw SQL at this loading boundary. This keeps legacy event
|
|
46
|
+
// evaluators out of PrecompiledSyncConfig while older binaries can continue reading the same persisted config.
|
|
47
|
+
if (compiledPlan.plan.events == null) {
|
|
48
|
+
const normalized = compileEventDefinitions(compiledPlan.eventDescriptors, {
|
|
49
|
+
...parseOptions,
|
|
50
|
+
// The legacy evaluator ignored event payload filters. Preserve that behavior for plans deployed before compiled
|
|
51
|
+
// events existed; a redeploy compiles and validates those filters before the replacement config is activated.
|
|
52
|
+
compileEventPayloadFilters: false
|
|
53
|
+
});
|
|
54
|
+
const fatalErrors = normalized.errors.filter((error) => error.type == 'fatal');
|
|
55
|
+
if (fatalErrors.length != 0) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
`Failed to compile persisted replication events: ${fatalErrors.map((error) => error.message).join(', ')}`
|
|
58
|
+
);
|
|
48
59
|
}
|
|
49
|
-
|
|
50
|
-
|
|
60
|
+
plan.events = normalized.events;
|
|
61
|
+
errors.push(...normalized.errors.map((error) => new YamlError(error)));
|
|
51
62
|
}
|
|
52
63
|
|
|
53
|
-
const precompiled = new PrecompiledSyncConfig(plan, compatibility,
|
|
64
|
+
const precompiled = new PrecompiledSyncConfig(plan, compatibility, {
|
|
54
65
|
defaultSchema: parseOptions.defaultSchema,
|
|
55
66
|
sourceText: content
|
|
56
67
|
});
|
|
@@ -59,7 +70,6 @@ export function parsePersistedSyncConfigContent(options: ParsePersistedSyncConfi
|
|
|
59
70
|
// This means asUpdateOptions will not change the storage version, even if the default changes.
|
|
60
71
|
precompiled.storageVersion = storageVersion;
|
|
61
72
|
|
|
62
|
-
const errors: YamlError[] = [];
|
|
63
73
|
if (compiledPlan.errors) {
|
|
64
74
|
for (const error of compiledPlan.errors) {
|
|
65
75
|
const location: ErrorLocation | undefined = error.location && {
|
|
@@ -93,6 +103,7 @@ export abstract class PersistedSyncConfigContent implements PersistedSyncConfigC
|
|
|
93
103
|
readonly logger: Logger;
|
|
94
104
|
readonly syncConfigId: PersistedSyncConfigId | null;
|
|
95
105
|
readonly syncConfigState: SyncRuleState;
|
|
106
|
+
readonly version_label: string | undefined;
|
|
96
107
|
|
|
97
108
|
constructor(data: PersistedSyncConfigContentData) {
|
|
98
109
|
this.replicationStreamId = data.replicationStreamId;
|
|
@@ -102,7 +113,9 @@ export abstract class PersistedSyncConfigContent implements PersistedSyncConfigC
|
|
|
102
113
|
this.storageVersion = data.storageVersion;
|
|
103
114
|
this.syncConfigId = data.syncConfigId ?? null;
|
|
104
115
|
this.syncConfigState = data.syncConfigState;
|
|
105
|
-
this.
|
|
116
|
+
this.version_label = data.version_label;
|
|
117
|
+
const versionPrefix = this.version_label == null ? '' : `[${this.version_label}]`;
|
|
118
|
+
this.logger = defaultLogger.child({ prefix: `[${this.replicationStreamName}]${versionPrefix} ` });
|
|
106
119
|
}
|
|
107
120
|
|
|
108
121
|
/**
|
|
@@ -167,6 +180,7 @@ export abstract class PersistedSyncConfigContent implements PersistedSyncConfigC
|
|
|
167
180
|
const parsed = this.parseSingleConfig({ defaultSchema: 'not_applicable' });
|
|
168
181
|
return {
|
|
169
182
|
config: { yaml: this.sync_rules_content, plan: this.compiled_plan, parsed },
|
|
183
|
+
version_label: this.version_label,
|
|
170
184
|
...options
|
|
171
185
|
};
|
|
172
186
|
}
|
|
@@ -185,6 +199,7 @@ export interface PersistedSyncConfigContentData {
|
|
|
185
199
|
|
|
186
200
|
readonly syncConfigId?: PersistedSyncConfigId | null;
|
|
187
201
|
readonly syncConfigState: SyncRuleState;
|
|
202
|
+
readonly version_label?: string;
|
|
188
203
|
}
|
|
189
204
|
export type PersistedSyncConfigId = string;
|
|
190
205
|
export interface ParseSyncConfigOptions {
|
|
@@ -11,6 +11,11 @@ export type EventData = {
|
|
|
11
11
|
export type ReplicationEventPayload = {
|
|
12
12
|
batch: BucketStorageBatch;
|
|
13
13
|
data: EventData;
|
|
14
|
-
event: sync_rules.
|
|
14
|
+
event: sync_rules.HydratedEventDescriptor;
|
|
15
|
+
/**
|
|
16
|
+
* Storage-assigned id for this event definition. Present when storage uses persisted event mappings, allowing event
|
|
17
|
+
* handlers to route custom checkpoints without deriving an id from compiled event content.
|
|
18
|
+
*/
|
|
19
|
+
event_id?: sync_rules.EventDefinitionId;
|
|
15
20
|
table: SourceTable;
|
|
16
21
|
};
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
BucketDataSource,
|
|
3
3
|
BucketDefinitionId,
|
|
4
4
|
DEFAULT_TAG,
|
|
5
|
+
EventDefinitionId,
|
|
5
6
|
ParameterIndexId,
|
|
6
7
|
ParameterIndexLookupCreator,
|
|
7
8
|
SourceTableRef
|
|
@@ -35,6 +36,13 @@ export interface SourceTableOptions {
|
|
|
35
36
|
parameterLookupSources: ParameterIndexLookupCreator[];
|
|
36
37
|
bucketDataSourceIds?: Set<BucketDefinitionId>;
|
|
37
38
|
parameterLookupSourceIds?: Set<ParameterIndexId>;
|
|
39
|
+
/**
|
|
40
|
+
* Compiled event definitions assigned to this persisted source-table record.
|
|
41
|
+
*
|
|
42
|
+
* Undefined is the legacy/non-incremental representation where event selection is
|
|
43
|
+
* based on the table ref. V3 incremental storage always supplies this set.
|
|
44
|
+
*/
|
|
45
|
+
eventDefinitionIds?: Set<EventDefinitionId>;
|
|
38
46
|
/**
|
|
39
47
|
* Source-specific metadata. Null when no metadata has been recorded.
|
|
40
48
|
*/
|
|
@@ -75,11 +83,11 @@ export class SourceTable {
|
|
|
75
83
|
public syncParameters = true;
|
|
76
84
|
|
|
77
85
|
/**
|
|
78
|
-
* True if this table should
|
|
86
|
+
* True if this table should evaluate event definitions for row changes.
|
|
79
87
|
*
|
|
80
|
-
* This value is resolved externally, and cached here.
|
|
81
|
-
*
|
|
82
|
-
*
|
|
88
|
+
* This value is resolved externally, and cached here. V3 storage assigns disjoint
|
|
89
|
+
* event-definition ids to SourceTables for the same physical table. Multiple records
|
|
90
|
+
* may evaluate different events, but each event id is evaluated through at most one record.
|
|
83
91
|
*
|
|
84
92
|
* Defaults to true for tests.
|
|
85
93
|
*/
|
|
@@ -150,6 +158,10 @@ export class SourceTable {
|
|
|
150
158
|
return this.options.parameterLookupSourceIds;
|
|
151
159
|
}
|
|
152
160
|
|
|
161
|
+
get eventDefinitionIds() {
|
|
162
|
+
return this.options.eventDefinitionIds;
|
|
163
|
+
}
|
|
164
|
+
|
|
153
165
|
get sourceMetadata() {
|
|
154
166
|
return this.options.sourceMetadata ?? null;
|
|
155
167
|
}
|
|
@@ -192,6 +204,7 @@ export class SourceTable {
|
|
|
192
204
|
bucketDataSourceIds: this.bucketDataSourceIds == null ? undefined : new Set(this.bucketDataSourceIds),
|
|
193
205
|
parameterLookupSourceIds:
|
|
194
206
|
this.parameterLookupSourceIds == null ? undefined : new Set(this.parameterLookupSourceIds),
|
|
207
|
+
eventDefinitionIds: this.eventDefinitionIds == null ? undefined : new Set(this.eventDefinitionIds),
|
|
195
208
|
sourceMetadata: structuredClone(sourceMetadata)
|
|
196
209
|
});
|
|
197
210
|
copy.syncData = this.syncData;
|
|
@@ -39,6 +39,11 @@ export const STORAGE_VERSION_2 = 2;
|
|
|
39
39
|
*/
|
|
40
40
|
export const STORAGE_VERSION_3 = 3;
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Same as version 3, but marked as stable.
|
|
44
|
+
*/
|
|
45
|
+
export const STORAGE_VERSION_4 = 4;
|
|
46
|
+
|
|
42
47
|
/**
|
|
43
48
|
* Oldest supported storage version.
|
|
44
49
|
*/
|
|
@@ -54,7 +59,7 @@ export const CURRENT_STORAGE_VERSION = STORAGE_VERSION_2;
|
|
|
54
59
|
*
|
|
55
60
|
* This includes unstable versions.
|
|
56
61
|
*/
|
|
57
|
-
export const SUPPORTED_STORAGE_VERSIONS = [STORAGE_VERSION_1, STORAGE_VERSION_2, STORAGE_VERSION_3];
|
|
62
|
+
export const SUPPORTED_STORAGE_VERSIONS = [STORAGE_VERSION_1, STORAGE_VERSION_2, STORAGE_VERSION_3, STORAGE_VERSION_4];
|
|
58
63
|
|
|
59
64
|
/**
|
|
60
65
|
* Shared storage-version behavior across storage implementations.
|
|
@@ -74,5 +79,10 @@ export const STORAGE_VERSION_CONFIG: Record<number, StorageVersionConfig | undef
|
|
|
74
79
|
version: STORAGE_VERSION_3,
|
|
75
80
|
versionedBuckets: true,
|
|
76
81
|
softDeleteCurrentData: true
|
|
82
|
+
},
|
|
83
|
+
[STORAGE_VERSION_4]: {
|
|
84
|
+
version: STORAGE_VERSION_4,
|
|
85
|
+
versionedBuckets: true,
|
|
86
|
+
softDeleteCurrentData: true
|
|
77
87
|
}
|
|
78
88
|
};
|
|
@@ -97,12 +97,20 @@ export interface SyncRulesBucketStorage
|
|
|
97
97
|
*/
|
|
98
98
|
reportError(e: any): Promise<void>;
|
|
99
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Whether parameter compaction can run when {@link CompactOptions.incrementalOnly} is set.
|
|
102
|
+
*
|
|
103
|
+
* Storage implementations that do not support incremental parameter compaction must return
|
|
104
|
+
* false; the compact command will skip parameter compaction in that mode.
|
|
105
|
+
*/
|
|
106
|
+
supportsIncrementalParameterCompaction(): boolean;
|
|
107
|
+
|
|
100
108
|
compact(options?: CompactOptions): Promise<void>;
|
|
101
109
|
|
|
102
110
|
/**
|
|
103
|
-
*
|
|
111
|
+
* Compact storage after initial replication, before the first checkpoint exists.
|
|
104
112
|
*/
|
|
105
|
-
|
|
113
|
+
compactInitialReplication(options: CompactInitialReplicationOptions): Promise<CompactInitialReplicationResults>;
|
|
106
114
|
|
|
107
115
|
// ## Read operations
|
|
108
116
|
|
|
@@ -277,6 +285,14 @@ export interface CreateWriterOptions extends ParseSyncConfigOptions {
|
|
|
277
285
|
tracer?: PerformanceTracer<'storage' | 'evaluate'>;
|
|
278
286
|
|
|
279
287
|
logger?: Logger;
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Aborts long-running storage work started by this writer, such as uploads to object storage.
|
|
291
|
+
*
|
|
292
|
+
* This does not replace flushing or committing at the appropriate source boundary: it only
|
|
293
|
+
* cancels work that is still in flight when replication stops.
|
|
294
|
+
*/
|
|
295
|
+
signal?: AbortSignal;
|
|
280
296
|
}
|
|
281
297
|
|
|
282
298
|
export interface StorageHooks {
|
|
@@ -321,6 +337,15 @@ export interface CompactOptions {
|
|
|
321
337
|
|
|
322
338
|
compactParameterData?: boolean;
|
|
323
339
|
|
|
340
|
+
/**
|
|
341
|
+
* Only perform compaction that can be done incrementally.
|
|
342
|
+
*
|
|
343
|
+
* This includes full bucket compaction on MongoDB V3 storage.
|
|
344
|
+
*
|
|
345
|
+
* On MongoDB v1 and Postgres storage, this makes compacting a no-op.
|
|
346
|
+
*/
|
|
347
|
+
incrementalOnly?: boolean;
|
|
348
|
+
|
|
324
349
|
/**
|
|
325
350
|
* Delete client-requested write checkpoints created before this time.
|
|
326
351
|
*
|
|
@@ -354,6 +379,18 @@ export interface CompactOptions {
|
|
|
354
379
|
*/
|
|
355
380
|
minChangeRatio?: number;
|
|
356
381
|
|
|
382
|
+
/** Minimum delay before a V3 bucket is checked for chunk compaction. Default: five minutes. */
|
|
383
|
+
minCompactChunkIntervalMs?: number;
|
|
384
|
+
|
|
385
|
+
/** Minimum elapsed write pressure before the v3 sliding-scale full compact. Default: two hours. */
|
|
386
|
+
minCompactFullIntervalMs?: number;
|
|
387
|
+
|
|
388
|
+
/** Maximum age of writes not covered by a v3 full compact. */
|
|
389
|
+
maxCompactFullIntervalMs?: number;
|
|
390
|
+
|
|
391
|
+
/** How long a v3 worker owns a claimed bucket before another worker may recover it. */
|
|
392
|
+
compactLeaseDurationMs?: number;
|
|
393
|
+
|
|
357
394
|
/**
|
|
358
395
|
* Internal/testing use: Cache size for compacting parameters.
|
|
359
396
|
*/
|
|
@@ -364,12 +401,12 @@ export interface CompactOptions {
|
|
|
364
401
|
logger?: Logger;
|
|
365
402
|
}
|
|
366
403
|
|
|
367
|
-
export interface
|
|
404
|
+
export interface CompactInitialReplicationOptions {
|
|
368
405
|
/**
|
|
369
|
-
*
|
|
406
|
+
* Compact data up to this op id.
|
|
370
407
|
*
|
|
371
408
|
* Defaults to the highest persisted op id for the replication stream, which covers
|
|
372
|
-
* the common case of
|
|
409
|
+
* the common case of compacting right after initial replication, before
|
|
373
410
|
* the first checkpoint exists.
|
|
374
411
|
*/
|
|
375
412
|
maxOpId?: util.InternalOpId;
|
|
@@ -377,9 +414,9 @@ export interface PopulateChecksumCacheOptions {
|
|
|
377
414
|
signal?: AbortSignal;
|
|
378
415
|
}
|
|
379
416
|
|
|
380
|
-
export interface
|
|
417
|
+
export interface CompactInitialReplicationResults {
|
|
381
418
|
/**
|
|
382
|
-
* Number of buckets
|
|
419
|
+
* Number of buckets processed.
|
|
383
420
|
*/
|
|
384
421
|
buckets: number;
|
|
385
422
|
}
|
|
@@ -419,6 +456,9 @@ export interface BucketDataBatchOptions {
|
|
|
419
456
|
/** Abort any in-progress work for this batch, including object-storage downloads. */
|
|
420
457
|
signal?: AbortSignal;
|
|
421
458
|
|
|
459
|
+
/** Traces data reads performed by the storage implementation. */
|
|
460
|
+
tracer?: PerformanceTracer<string>;
|
|
461
|
+
|
|
422
462
|
/** Limit number of documents returned. Defaults to 1000. */
|
|
423
463
|
limit?: number;
|
|
424
464
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { EventDefinitionId } from '@powersync/service-sync-rules';
|
|
2
|
+
|
|
1
3
|
export enum WriteCheckpointMode {
|
|
2
4
|
/**
|
|
3
5
|
* Raw mappings of `user_id` to `write_checkpoint`s should
|
|
@@ -31,7 +33,9 @@ export interface ClientRequestedCheckpointOptions {
|
|
|
31
33
|
checkpoint_request_id?: bigint;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
export
|
|
36
|
+
export type SyncStorageCustomWriteCheckpointFilters = BaseWriteCheckpointIdentifier;
|
|
37
|
+
|
|
38
|
+
export interface CustomWriteCheckpointFilters extends SyncStorageCustomWriteCheckpointFilters {
|
|
35
39
|
/**
|
|
36
40
|
* Replication stream which was active when this checkpoint was created.
|
|
37
41
|
*/
|
|
@@ -44,6 +48,14 @@ export interface BatchedCustomWriteCheckpointOptions extends BaseWriteCheckpoint
|
|
|
44
48
|
* "write checkpoint" in storage APIs for backwards compatibility.
|
|
45
49
|
*/
|
|
46
50
|
checkpoint: bigint;
|
|
51
|
+
/**
|
|
52
|
+
* Compiled event definition which created the checkpoint.
|
|
53
|
+
*
|
|
54
|
+
* Incremental replication uses this to keep checkpoint records produced by
|
|
55
|
+
* active and processing sync configs separate. This is required by v3
|
|
56
|
+
* storage and unused by legacy storage versions.
|
|
57
|
+
*/
|
|
58
|
+
event_id?: EventDefinitionId;
|
|
47
59
|
/**
|
|
48
60
|
* Required when this custom checkpoint was created from a client checkpoint
|
|
49
61
|
* request and should be eligible for checkpoint request retention cleanup.
|
|
@@ -155,12 +167,29 @@ function shouldReplaceManagedWriteCheckpoint(
|
|
|
155
167
|
return candidateRequestId > existingRequestId;
|
|
156
168
|
}
|
|
157
169
|
|
|
158
|
-
export type SyncStorageLastWriteCheckpointFilters =
|
|
170
|
+
export type SyncStorageLastWriteCheckpointFilters =
|
|
171
|
+
| SyncStorageCustomWriteCheckpointFilters
|
|
172
|
+
| ManagedWriteCheckpointFilters;
|
|
159
173
|
export type LastWriteCheckpointFilters = CustomWriteCheckpointFilters | ManagedWriteCheckpointFilters;
|
|
160
174
|
|
|
175
|
+
/** Configures checkpoint ownership and generation for a storage instance. */
|
|
176
|
+
export type WriteCheckpointModeConfig =
|
|
177
|
+
| {
|
|
178
|
+
mode: WriteCheckpointMode.CUSTOM;
|
|
179
|
+
/**
|
|
180
|
+
* Name of the event whose custom checkpoints are served. Storage resolves this name through the active sync
|
|
181
|
+
* config's persisted mapping; integrations must not construct or persist event ids themselves. Required by
|
|
182
|
+
* storage implementations that scope custom checkpoints by event definition.
|
|
183
|
+
*/
|
|
184
|
+
eventName?: string;
|
|
185
|
+
}
|
|
186
|
+
| {
|
|
187
|
+
mode: WriteCheckpointMode.MANAGED;
|
|
188
|
+
};
|
|
189
|
+
|
|
161
190
|
export interface BaseWriteCheckpointAPI {
|
|
162
191
|
readonly writeCheckpointMode: WriteCheckpointMode;
|
|
163
|
-
setWriteCheckpointMode(
|
|
192
|
+
setWriteCheckpointMode(config: WriteCheckpointModeConfig): void;
|
|
164
193
|
createManagedWriteCheckpoints(
|
|
165
194
|
checkpoints: ManagedWriteCheckpointOptions[]
|
|
166
195
|
): Promise<CreateManagedWriteCheckpointsResult>;
|