@powersync/service-core 1.24.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 +59 -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/SourceEntity.d.ts +7 -2
- package/dist/storage/SourceTable.d.ts +37 -6
- package/dist/storage/SourceTable.js +42 -10
- package/dist/storage/SourceTable.js.map +1 -1
- package/dist/storage/SourceTableReconciler.d.ts +83 -0
- package/dist/storage/SourceTableReconciler.js +95 -0
- package/dist/storage/SourceTableReconciler.js.map +1 -0
- 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 +45 -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-index.d.ts +1 -0
- package/dist/storage/storage-index.js +1 -0
- package/dist/storage/storage-index.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 +2 -1
- package/dist/util/utils.js +16 -1
- 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/SourceEntity.ts +6 -2
- package/src/storage/SourceTable.ts +68 -11
- package/src/storage/SourceTableReconciler.ts +188 -0
- package/src/storage/StorageVersionConfig.ts +11 -1
- package/src/storage/SyncRulesBucketStorage.ts +53 -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-index.ts +1 -0
- 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 +15 -1
- 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/source-table-reconciler.test.ts +244 -0
- 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
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { DEFAULT_TAG } from '@powersync/service-sync-rules';
|
|
2
2
|
import * as util from '../util/util-index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Compare source-table ids without coercing between storage-specific types.
|
|
5
|
+
*/
|
|
6
|
+
export function sourceTableIdEquals(left, right) {
|
|
7
|
+
if (typeof left === 'string' || typeof right === 'string') {
|
|
8
|
+
return typeof left === 'string' && typeof right === 'string' && left === right;
|
|
9
|
+
}
|
|
10
|
+
return left.equals(right);
|
|
11
|
+
}
|
|
3
12
|
/**
|
|
4
13
|
* Represents a resolved source table.
|
|
5
14
|
*
|
|
@@ -26,11 +35,11 @@ export class SourceTable {
|
|
|
26
35
|
*/
|
|
27
36
|
syncParameters = true;
|
|
28
37
|
/**
|
|
29
|
-
* True if this table should
|
|
38
|
+
* True if this table should evaluate event definitions for row changes.
|
|
30
39
|
*
|
|
31
|
-
* This value is resolved externally, and cached here.
|
|
32
|
-
*
|
|
33
|
-
*
|
|
40
|
+
* This value is resolved externally, and cached here. V3 storage assigns disjoint
|
|
41
|
+
* event-definition ids to SourceTables for the same physical table. Multiple records
|
|
42
|
+
* may evaluate different events, but each event id is evaluated through at most one record.
|
|
34
43
|
*
|
|
35
44
|
* Defaults to true for tests.
|
|
36
45
|
*/
|
|
@@ -88,6 +97,12 @@ export class SourceTable {
|
|
|
88
97
|
get parameterLookupSourceIds() {
|
|
89
98
|
return this.options.parameterLookupSourceIds;
|
|
90
99
|
}
|
|
100
|
+
get eventDefinitionIds() {
|
|
101
|
+
return this.options.eventDefinitionIds;
|
|
102
|
+
}
|
|
103
|
+
get sourceMetadata() {
|
|
104
|
+
return this.options.sourceMetadata ?? null;
|
|
105
|
+
}
|
|
91
106
|
/**
|
|
92
107
|
* Sanitized name of the entity in the format of "{schema}.{entity name}".
|
|
93
108
|
* Suitable for safe use in Postgres queries.
|
|
@@ -102,22 +117,39 @@ export class SourceTable {
|
|
|
102
117
|
* In-memory clone of the table status.
|
|
103
118
|
*/
|
|
104
119
|
clone() {
|
|
120
|
+
return this.copyWithSourceMetadata(this.sourceMetadata);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Copy this table with different source metadata, preserving its resolved state.
|
|
124
|
+
*/
|
|
125
|
+
withSourceMetadata(sourceMetadata) {
|
|
126
|
+
return this.copyWithSourceMetadata(sourceMetadata);
|
|
127
|
+
}
|
|
128
|
+
copyWithSourceMetadata(sourceMetadata) {
|
|
105
129
|
const copy = new SourceTable({
|
|
106
130
|
id: this.id,
|
|
107
|
-
ref: this.options.ref,
|
|
131
|
+
ref: { ...this.options.ref },
|
|
108
132
|
objectId: this.objectId,
|
|
109
|
-
replicaIdColumns: this.replicaIdColumns,
|
|
133
|
+
replicaIdColumns: this.replicaIdColumns.map((column) => ({ ...column })),
|
|
110
134
|
snapshotComplete: this.snapshotComplete,
|
|
111
|
-
bucketDataSources: this.bucketDataSources,
|
|
112
|
-
parameterLookupSources: this.parameterLookupSources,
|
|
135
|
+
bucketDataSources: [...this.bucketDataSources],
|
|
136
|
+
parameterLookupSources: [...this.parameterLookupSources],
|
|
113
137
|
bucketDataSourceIds: this.bucketDataSourceIds == null ? undefined : new Set(this.bucketDataSourceIds),
|
|
114
|
-
parameterLookupSourceIds: this.parameterLookupSourceIds == null ? undefined : new Set(this.parameterLookupSourceIds)
|
|
138
|
+
parameterLookupSourceIds: this.parameterLookupSourceIds == null ? undefined : new Set(this.parameterLookupSourceIds),
|
|
139
|
+
eventDefinitionIds: this.eventDefinitionIds == null ? undefined : new Set(this.eventDefinitionIds),
|
|
140
|
+
sourceMetadata: structuredClone(sourceMetadata)
|
|
115
141
|
});
|
|
116
142
|
copy.syncData = this.syncData;
|
|
117
143
|
copy.syncParameters = this.syncParameters;
|
|
118
144
|
copy.syncEvent = this.syncEvent;
|
|
119
145
|
copy.storeCurrentData = this.storeCurrentData;
|
|
120
|
-
copy.snapshotStatus =
|
|
146
|
+
copy.snapshotStatus =
|
|
147
|
+
this.snapshotStatus == null
|
|
148
|
+
? undefined
|
|
149
|
+
: {
|
|
150
|
+
...this.snapshotStatus,
|
|
151
|
+
lastKey: this.snapshotStatus.lastKey?.slice() ?? null
|
|
152
|
+
};
|
|
121
153
|
return copy;
|
|
122
154
|
}
|
|
123
155
|
formatSnapshotProgress() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SourceTable.js","sourceRoot":"","sources":["../../src/storage/SourceTable.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,WAAW,
|
|
1
|
+
{"version":3,"file":"SourceTable.js","sourceRoot":"","sources":["../../src/storage/SourceTable.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { JsonValue, SourceEntityDescriptor } from './SourceEntity.js';
|
|
2
|
+
import { SourceTable, SourceTableCandidate, SourceTableId } from './SourceTable.js';
|
|
3
|
+
/**
|
|
4
|
+
* A source connector's classification of overlapping persisted tables.
|
|
5
|
+
*/
|
|
6
|
+
export interface SourceTableCandidateResolution {
|
|
7
|
+
/**
|
|
8
|
+
* Records storage can reuse. Copies may include updated source metadata.
|
|
9
|
+
*/
|
|
10
|
+
compatibleTables: ReadonlyArray<SourceTableCandidate>;
|
|
11
|
+
/**
|
|
12
|
+
* Records that cannot be reused. Every candidate must appear in exactly one result list.
|
|
13
|
+
*/
|
|
14
|
+
incompatibleTables: ReadonlyArray<SourceTableCandidate>;
|
|
15
|
+
/**
|
|
16
|
+
* Values for records storage creates during this resolution.
|
|
17
|
+
*/
|
|
18
|
+
newTableValues: SourceTableCreateValues;
|
|
19
|
+
}
|
|
20
|
+
export interface SourceTableCreateValues {
|
|
21
|
+
/**
|
|
22
|
+
* Source metadata for new records. Null means no metadata.
|
|
23
|
+
*/
|
|
24
|
+
sourceMetadata: JsonValue;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Input to a source-owned reconciliation callback. The callback may run inside a storage
|
|
28
|
+
* transaction, so it must not mutate storage or perform slow external work.
|
|
29
|
+
*/
|
|
30
|
+
export interface SourceTableCandidateReconcilerInput {
|
|
31
|
+
/**
|
|
32
|
+
* Source entity being resolved.
|
|
33
|
+
*/
|
|
34
|
+
source: SourceEntityDescriptor;
|
|
35
|
+
/**
|
|
36
|
+
* Persisted tables overlapping by name or object id.
|
|
37
|
+
*/
|
|
38
|
+
candidates: ReadonlyArray<SourceTableCandidate>;
|
|
39
|
+
}
|
|
40
|
+
export type SourceTableCandidateReconciler = (input: SourceTableCandidateReconcilerInput) => SourceTableCandidateResolution | Promise<SourceTableCandidateResolution>;
|
|
41
|
+
/**
|
|
42
|
+
* Compare replica-id columns in order.
|
|
43
|
+
*/
|
|
44
|
+
export declare function sameReplicaIdColumns(left: SourceTableCandidate['replicaIdColumns'], right: SourceEntityDescriptor): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Compare the shared source-table identity fields.
|
|
47
|
+
*/
|
|
48
|
+
export declare function sourceIdentityCompatible(source: SourceEntityDescriptor, candidate: SourceTableCandidate): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Default identity-based reconciliation for connectors without source-specific metadata.
|
|
51
|
+
*/
|
|
52
|
+
export declare const defaultSourceTableReconciler: SourceTableCandidateReconciler;
|
|
53
|
+
/**
|
|
54
|
+
* Check that every candidate was classified exactly once.
|
|
55
|
+
*/
|
|
56
|
+
export declare function validateSourceTableCandidateResolution(candidates: ReadonlyArray<SourceTableCandidate>, resolution: SourceTableCandidateResolution): void;
|
|
57
|
+
/**
|
|
58
|
+
* A source-metadata update to persist.
|
|
59
|
+
*/
|
|
60
|
+
export interface SourceTableMetadataUpdate {
|
|
61
|
+
id: SourceTableId;
|
|
62
|
+
sourceMetadata: JsonValue;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Rebuild a resolution from storage-owned tables, applying only reconciler-owned metadata to
|
|
66
|
+
* compatible tables. All other mutable table state comes from storage.
|
|
67
|
+
*
|
|
68
|
+
* Reconciler candidates are typed as read-only, but TypeScript types provide no runtime protection:
|
|
69
|
+
* callback code can cast a cloned candidate and mutate it. Rematerializing by id ensures those
|
|
70
|
+
* mutations are not trusted even when the compile-time boundary is bypassed.
|
|
71
|
+
*/
|
|
72
|
+
export declare function materializeSourceTableResolution(tables: ReadonlyArray<SourceTable>, resolution: SourceTableCandidateResolution): MaterializedSourceTableResolution;
|
|
73
|
+
export interface MaterializedSourceTableResolution {
|
|
74
|
+
compatibleTables: SourceTable[];
|
|
75
|
+
incompatibleTables: SourceTable[];
|
|
76
|
+
newTableValues: SourceTableCreateValues;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Return source-metadata changes from compatible candidates, comparing metadata by value against
|
|
80
|
+
* the original storage-owned tables. The reconciler may mutate its isolated candidate clones, so
|
|
81
|
+
* those clones cannot be used as the persisted baseline.
|
|
82
|
+
*/
|
|
83
|
+
export declare function diffSourceTableUpdates(persistedTables: ReadonlyArray<SourceTable>, resolution: SourceTableCandidateResolution): SourceTableMetadataUpdate[];
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { ServiceAssertionError } from '@powersync/lib-services-framework';
|
|
2
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
3
|
+
import { sourceTableIdEquals } from './SourceTable.js';
|
|
4
|
+
/**
|
|
5
|
+
* Compare replica-id columns in order.
|
|
6
|
+
*/
|
|
7
|
+
export function sameReplicaIdColumns(left, right) {
|
|
8
|
+
const target = right.replicaIdColumns;
|
|
9
|
+
return (left.length == target.length &&
|
|
10
|
+
left.every((column, index) => column.name == target[index].name && column.type == target[index].type && column.typeId == target[index].typeId));
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Compare the shared source-table identity fields.
|
|
14
|
+
*/
|
|
15
|
+
export function sourceIdentityCompatible(source, candidate) {
|
|
16
|
+
return (candidate.schema == source.schema &&
|
|
17
|
+
candidate.name == source.name &&
|
|
18
|
+
(source.objectId == null || candidate.objectId == source.objectId) &&
|
|
19
|
+
sameReplicaIdColumns(candidate.replicaIdColumns, source));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Default identity-based reconciliation for connectors without source-specific metadata.
|
|
23
|
+
*/
|
|
24
|
+
export const defaultSourceTableReconciler = ({ source, candidates }) => {
|
|
25
|
+
const compatibleTables = [];
|
|
26
|
+
const incompatibleTables = [];
|
|
27
|
+
for (const candidate of candidates) {
|
|
28
|
+
if (sourceIdentityCompatible(source, candidate)) {
|
|
29
|
+
compatibleTables.push(candidate);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
incompatibleTables.push(candidate);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return { compatibleTables, incompatibleTables, newTableValues: { sourceMetadata: null } };
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Check that every candidate was classified exactly once.
|
|
39
|
+
*/
|
|
40
|
+
export function validateSourceTableCandidateResolution(candidates, resolution) {
|
|
41
|
+
const classifiedTables = [...resolution.compatibleTables, ...resolution.incompatibleTables];
|
|
42
|
+
for (const candidate of candidates) {
|
|
43
|
+
const classifications = classifiedTables.filter((table) => sourceTableIdEquals(table.id, candidate.id));
|
|
44
|
+
if (classifications.length !== 1) {
|
|
45
|
+
throw new ServiceAssertionError(`Source table candidate ${candidate.id.toString()} must be classified exactly once, got ${classifications.length}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
for (const table of classifiedTables) {
|
|
49
|
+
if (!candidates.some((candidate) => sourceTableIdEquals(candidate.id, table.id))) {
|
|
50
|
+
throw new ServiceAssertionError(`Source table reconciliation returned unknown candidate ${table.id.toString()}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Rebuild a resolution from storage-owned tables, applying only reconciler-owned metadata to
|
|
56
|
+
* compatible tables. All other mutable table state comes from storage.
|
|
57
|
+
*
|
|
58
|
+
* Reconciler candidates are typed as read-only, but TypeScript types provide no runtime protection:
|
|
59
|
+
* callback code can cast a cloned candidate and mutate it. Rematerializing by id ensures those
|
|
60
|
+
* mutations are not trusted even when the compile-time boundary is bypassed.
|
|
61
|
+
*/
|
|
62
|
+
export function materializeSourceTableResolution(tables, resolution) {
|
|
63
|
+
const findTable = (candidate) => {
|
|
64
|
+
const table = tables.find((table) => sourceTableIdEquals(table.id, candidate.id));
|
|
65
|
+
if (table == null) {
|
|
66
|
+
throw new ServiceAssertionError(`Source table candidate ${candidate.id.toString()} was not persisted`);
|
|
67
|
+
}
|
|
68
|
+
return table;
|
|
69
|
+
};
|
|
70
|
+
return {
|
|
71
|
+
compatibleTables: resolution.compatibleTables.map((candidate) => findTable(candidate).withSourceMetadata(candidate.sourceMetadata)),
|
|
72
|
+
incompatibleTables: resolution.incompatibleTables.map(findTable),
|
|
73
|
+
newTableValues: resolution.newTableValues
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Return source-metadata changes from compatible candidates, comparing metadata by value against
|
|
78
|
+
* the original storage-owned tables. The reconciler may mutate its isolated candidate clones, so
|
|
79
|
+
* those clones cannot be used as the persisted baseline.
|
|
80
|
+
*/
|
|
81
|
+
export function diffSourceTableUpdates(persistedTables, resolution) {
|
|
82
|
+
const updates = [];
|
|
83
|
+
for (const resolvedTable of resolution.compatibleTables) {
|
|
84
|
+
const persistedTable = persistedTables.find((table) => sourceTableIdEquals(table.id, resolvedTable.id));
|
|
85
|
+
if (persistedTable == null) {
|
|
86
|
+
throw new ServiceAssertionError(`Source table reconciliation returned unknown candidate ${resolvedTable.id.toString()}`);
|
|
87
|
+
}
|
|
88
|
+
if (isDeepStrictEqual(persistedTable.sourceMetadata, resolvedTable.sourceMetadata)) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
updates.push({ id: resolvedTable.id, sourceMetadata: resolvedTable.sourceMetadata });
|
|
92
|
+
}
|
|
93
|
+
return updates;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=SourceTableReconciler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SourceTableReconciler.js","sourceRoot":"","sources":["../../src/storage/SourceTableReconciler.ts"],"names":[],"mappings":"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"}
|
|
@@ -33,6 +33,10 @@ export declare const STORAGE_VERSION_2 = 2;
|
|
|
33
33
|
* This is used to build towards incremental reprocessing.
|
|
34
34
|
*/
|
|
35
35
|
export declare const STORAGE_VERSION_3 = 3;
|
|
36
|
+
/**
|
|
37
|
+
* Same as version 3, but marked as stable.
|
|
38
|
+
*/
|
|
39
|
+
export declare const STORAGE_VERSION_4 = 4;
|
|
36
40
|
/**
|
|
37
41
|
* Oldest supported storage version.
|
|
38
42
|
*/
|
|
@@ -16,6 +16,10 @@ export const STORAGE_VERSION_2 = 2;
|
|
|
16
16
|
* This is used to build towards incremental reprocessing.
|
|
17
17
|
*/
|
|
18
18
|
export const STORAGE_VERSION_3 = 3;
|
|
19
|
+
/**
|
|
20
|
+
* Same as version 3, but marked as stable.
|
|
21
|
+
*/
|
|
22
|
+
export const STORAGE_VERSION_4 = 4;
|
|
19
23
|
/**
|
|
20
24
|
* Oldest supported storage version.
|
|
21
25
|
*/
|
|
@@ -29,7 +33,7 @@ export const CURRENT_STORAGE_VERSION = STORAGE_VERSION_2;
|
|
|
29
33
|
*
|
|
30
34
|
* This includes unstable versions.
|
|
31
35
|
*/
|
|
32
|
-
export const SUPPORTED_STORAGE_VERSIONS = [STORAGE_VERSION_1, STORAGE_VERSION_2, STORAGE_VERSION_3];
|
|
36
|
+
export const SUPPORTED_STORAGE_VERSIONS = [STORAGE_VERSION_1, STORAGE_VERSION_2, STORAGE_VERSION_3, STORAGE_VERSION_4];
|
|
33
37
|
/**
|
|
34
38
|
* Shared storage-version behavior across storage implementations.
|
|
35
39
|
*/
|
|
@@ -48,6 +52,11 @@ export const STORAGE_VERSION_CONFIG = {
|
|
|
48
52
|
version: STORAGE_VERSION_3,
|
|
49
53
|
versionedBuckets: true,
|
|
50
54
|
softDeleteCurrentData: true
|
|
55
|
+
},
|
|
56
|
+
[STORAGE_VERSION_4]: {
|
|
57
|
+
version: STORAGE_VERSION_4,
|
|
58
|
+
versionedBuckets: true,
|
|
59
|
+
softDeleteCurrentData: true
|
|
51
60
|
}
|
|
52
61
|
};
|
|
53
62
|
//# sourceMappingURL=StorageVersionConfig.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StorageVersionConfig.js","sourceRoot":"","sources":["../../src/storage/StorageVersionConfig.ts"],"names":[],"mappings":"AAoBA;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAEnC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAEnC;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAEnC;;GAEG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,iBAAiB,CAAC;AAExD;;GAEG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,iBAAiB,CAAC;AAEzD;;;;GAIG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"StorageVersionConfig.js","sourceRoot":"","sources":["../../src/storage/StorageVersionConfig.ts"],"names":[],"mappings":"AAoBA;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAEnC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAEnC;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAEnC;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAEnC;;GAEG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,iBAAiB,CAAC;AAExD;;GAEG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,iBAAiB,CAAC;AAEzD;;;;GAIG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,CAAC;AAEvH;;GAEG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAqD;IACtF,CAAC,iBAAiB,CAAC,EAAE;QACnB,OAAO,EAAE,iBAAiB;QAC1B,gBAAgB,EAAE,KAAK;QACvB,qBAAqB,EAAE,KAAK;KAC7B;IACD,CAAC,iBAAiB,CAAC,EAAE;QACnB,OAAO,EAAE,iBAAiB;QAC1B,gBAAgB,EAAE,IAAI;QACtB,qBAAqB,EAAE,KAAK;KAC7B;IACD,CAAC,iBAAiB,CAAC,EAAE;QACnB,OAAO,EAAE,iBAAiB;QAC1B,gBAAgB,EAAE,IAAI;QACtB,qBAAqB,EAAE,IAAI;KAC5B;IACD,CAAC,iBAAiB,CAAC,EAAE;QACnB,OAAO,EAAE,iBAAiB;QAC1B,gBAAgB,EAAE,IAAI;QACtB,qBAAqB,EAAE,IAAI;KAC5B;CACF,CAAC"}
|
|
@@ -9,6 +9,7 @@ import { ParsedSyncConfigSet } from './ParsedSyncConfigSet.js';
|
|
|
9
9
|
import { ParseSyncConfigOptions } from './PersistedSyncConfigContent.js';
|
|
10
10
|
import { SourceEntityDescriptor } from './SourceEntity.js';
|
|
11
11
|
import { SourceTable } from './SourceTable.js';
|
|
12
|
+
import { SourceTableCandidateReconciler } from './SourceTableReconciler.js';
|
|
12
13
|
import { StorageVersionConfig } from './StorageVersionConfig.js';
|
|
13
14
|
import { SyncStorageWriteCheckpointAPI } from './WriteCheckpointAPI.js';
|
|
14
15
|
/**
|
|
@@ -75,11 +76,18 @@ export interface SyncRulesBucketStorage extends ObserverClient<SyncRulesBucketSt
|
|
|
75
76
|
* Errors are cleared on flush.
|
|
76
77
|
*/
|
|
77
78
|
reportError(e: any): Promise<void>;
|
|
79
|
+
/**
|
|
80
|
+
* Whether parameter compaction can run when {@link CompactOptions.incrementalOnly} is set.
|
|
81
|
+
*
|
|
82
|
+
* Storage implementations that do not support incremental parameter compaction must return
|
|
83
|
+
* false; the compact command will skip parameter compaction in that mode.
|
|
84
|
+
*/
|
|
85
|
+
supportsIncrementalParameterCompaction(): boolean;
|
|
78
86
|
compact(options?: CompactOptions): Promise<void>;
|
|
79
87
|
/**
|
|
80
|
-
*
|
|
88
|
+
* Compact storage after initial replication, before the first checkpoint exists.
|
|
81
89
|
*/
|
|
82
|
-
|
|
90
|
+
compactInitialReplication(options: CompactInitialReplicationOptions): Promise<CompactInitialReplicationResults>;
|
|
83
91
|
getCheckpoint(): Promise<ReplicationCheckpoint>;
|
|
84
92
|
/**
|
|
85
93
|
* Given two checkpoints, return the changes in bucket data and parameters that may have occurred
|
|
@@ -168,6 +176,11 @@ export interface ResolveTablesOptions {
|
|
|
168
176
|
* Source table or collection metadata discovered during snapshot or streaming.
|
|
169
177
|
*/
|
|
170
178
|
source: SourceEntityDescriptor;
|
|
179
|
+
/**
|
|
180
|
+
* Classifies overlapping persisted tables. Defaults to identity-based reconciliation.
|
|
181
|
+
* This may run inside a storage transaction and must not mutate storage.
|
|
182
|
+
*/
|
|
183
|
+
reconcileSourceTables?: SourceTableCandidateReconciler;
|
|
171
184
|
/**
|
|
172
185
|
* For tests only - custom id generator for stable ids.
|
|
173
186
|
*/
|
|
@@ -220,6 +233,13 @@ export interface CreateWriterOptions extends ParseSyncConfigOptions {
|
|
|
220
233
|
hooks?: StorageHooks;
|
|
221
234
|
tracer?: PerformanceTracer<'storage' | 'evaluate'>;
|
|
222
235
|
logger?: Logger;
|
|
236
|
+
/**
|
|
237
|
+
* Aborts long-running storage work started by this writer, such as uploads to object storage.
|
|
238
|
+
*
|
|
239
|
+
* This does not replace flushing or committing at the appropriate source boundary: it only
|
|
240
|
+
* cancels work that is still in flight when replication stops.
|
|
241
|
+
*/
|
|
242
|
+
signal?: AbortSignal;
|
|
223
243
|
}
|
|
224
244
|
export interface StorageHooks {
|
|
225
245
|
beforeBatchFlush?: (batch: BucketStorageBatch) => Promise<void>;
|
|
@@ -258,6 +278,14 @@ export interface CompactOptions {
|
|
|
258
278
|
*/
|
|
259
279
|
compactBuckets?: string[];
|
|
260
280
|
compactParameterData?: boolean;
|
|
281
|
+
/**
|
|
282
|
+
* Only perform compaction that can be done incrementally.
|
|
283
|
+
*
|
|
284
|
+
* This includes full bucket compaction on MongoDB V3 storage.
|
|
285
|
+
*
|
|
286
|
+
* On MongoDB v1 and Postgres storage, this makes compacting a no-op.
|
|
287
|
+
*/
|
|
288
|
+
incrementalOnly?: boolean;
|
|
261
289
|
/**
|
|
262
290
|
* Delete client-requested write checkpoints created before this time.
|
|
263
291
|
*
|
|
@@ -284,6 +312,14 @@ export interface CompactOptions {
|
|
|
284
312
|
* Number between 0 and 1, default of 0.1.
|
|
285
313
|
*/
|
|
286
314
|
minChangeRatio?: number;
|
|
315
|
+
/** Minimum delay before a V3 bucket is checked for chunk compaction. Default: five minutes. */
|
|
316
|
+
minCompactChunkIntervalMs?: number;
|
|
317
|
+
/** Minimum elapsed write pressure before the v3 sliding-scale full compact. Default: two hours. */
|
|
318
|
+
minCompactFullIntervalMs?: number;
|
|
319
|
+
/** Maximum age of writes not covered by a v3 full compact. */
|
|
320
|
+
maxCompactFullIntervalMs?: number;
|
|
321
|
+
/** How long a v3 worker owns a claimed bucket before another worker may recover it. */
|
|
322
|
+
compactLeaseDurationMs?: number;
|
|
287
323
|
/**
|
|
288
324
|
* Internal/testing use: Cache size for compacting parameters.
|
|
289
325
|
*/
|
|
@@ -291,21 +327,21 @@ export interface CompactOptions {
|
|
|
291
327
|
signal?: AbortSignal;
|
|
292
328
|
logger?: Logger;
|
|
293
329
|
}
|
|
294
|
-
export interface
|
|
330
|
+
export interface CompactInitialReplicationOptions {
|
|
295
331
|
/**
|
|
296
|
-
*
|
|
332
|
+
* Compact data up to this op id.
|
|
297
333
|
*
|
|
298
334
|
* Defaults to the highest persisted op id for the replication stream, which covers
|
|
299
|
-
* the common case of
|
|
335
|
+
* the common case of compacting right after initial replication, before
|
|
300
336
|
* the first checkpoint exists.
|
|
301
337
|
*/
|
|
302
338
|
maxOpId?: util.InternalOpId;
|
|
303
339
|
minBucketChanges?: number;
|
|
304
340
|
signal?: AbortSignal;
|
|
305
341
|
}
|
|
306
|
-
export interface
|
|
342
|
+
export interface CompactInitialReplicationResults {
|
|
307
343
|
/**
|
|
308
|
-
* Number of buckets
|
|
344
|
+
* Number of buckets processed.
|
|
309
345
|
*/
|
|
310
346
|
buckets: number;
|
|
311
347
|
}
|
|
@@ -338,6 +374,8 @@ export interface BucketDataBatchOptions {
|
|
|
338
374
|
requestHint?: BucketRequestHint;
|
|
339
375
|
/** Abort any in-progress work for this batch, including object-storage downloads. */
|
|
340
376
|
signal?: AbortSignal;
|
|
377
|
+
/** Traces data reads performed by the storage implementation. */
|
|
378
|
+
tracer?: PerformanceTracer<string>;
|
|
341
379
|
/** Limit number of documents returned. Defaults to 1000. */
|
|
342
380
|
limit?: number;
|
|
343
381
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SyncRulesBucketStorage.js","sourceRoot":"","sources":["../../src/storage/SyncRulesBucketStorage.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SyncRulesBucketStorage.js","sourceRoot":"","sources":["../../src/storage/SyncRulesBucketStorage.ts"],"names":[],"mappings":"AA2eA,MAAM,UAAU,UAAU,CAAC,KAAmD;IAC5E,OAAQ,KAAgC,CAAC,OAAO,KAAK,SAAS,CAAC;AACjE,CAAC;AAiBD;;;;GAIG;AACH,MAAM,OAAO,8BAA+B,SAAQ,KAAK;IAE5C;IACA;IAFX,YACW,KAAa,EACb,SAAyC;QAElD,KAAK,CAAC,yCAAyC,KAAK,GAAG,CAAC,CAAC;QAHhD,UAAK,GAAL,KAAK,CAAQ;QACb,cAAS,GAAT,SAAS,CAAgC;IAGpD,CAAC;CACF;AAqDD,MAAM,CAAC,MAAM,yBAAyB,GAAsB;IAC1D,kBAAkB,EAAE,IAAI,GAAG,EAAU;IACrC,qBAAqB,EAAE,IAAI;IAC3B,uBAAuB,EAAE,IAAI,GAAG,EAAU;IAC1C,0BAA0B,EAAE,IAAI;CACjC,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EventDefinitionId } from '@powersync/service-sync-rules';
|
|
1
2
|
export declare enum WriteCheckpointMode {
|
|
2
3
|
/**
|
|
3
4
|
* Raw mappings of `user_id` to `write_checkpoint`s should
|
|
@@ -28,7 +29,8 @@ export interface ClientRequestedCheckpointOptions {
|
|
|
28
29
|
*/
|
|
29
30
|
checkpoint_request_id?: bigint;
|
|
30
31
|
}
|
|
31
|
-
export
|
|
32
|
+
export type SyncStorageCustomWriteCheckpointFilters = BaseWriteCheckpointIdentifier;
|
|
33
|
+
export interface CustomWriteCheckpointFilters extends SyncStorageCustomWriteCheckpointFilters {
|
|
32
34
|
/**
|
|
33
35
|
* Replication stream which was active when this checkpoint was created.
|
|
34
36
|
*/
|
|
@@ -40,6 +42,14 @@ export interface BatchedCustomWriteCheckpointOptions extends BaseWriteCheckpoint
|
|
|
40
42
|
* "write checkpoint" in storage APIs for backwards compatibility.
|
|
41
43
|
*/
|
|
42
44
|
checkpoint: bigint;
|
|
45
|
+
/**
|
|
46
|
+
* Compiled event definition which created the checkpoint.
|
|
47
|
+
*
|
|
48
|
+
* Incremental replication uses this to keep checkpoint records produced by
|
|
49
|
+
* active and processing sync configs separate. This is required by v3
|
|
50
|
+
* storage and unused by legacy storage versions.
|
|
51
|
+
*/
|
|
52
|
+
event_id?: EventDefinitionId;
|
|
43
53
|
/**
|
|
44
54
|
* Required when this custom checkpoint was created from a client checkpoint
|
|
45
55
|
* request and should be eligible for checkpoint request retention cleanup.
|
|
@@ -102,11 +112,23 @@ export interface CreateManagedWriteCheckpointsResult {
|
|
|
102
112
|
shouldAdvance: boolean;
|
|
103
113
|
}
|
|
104
114
|
export declare function uniqueManagedWriteCheckpoints(checkpoints: ManagedWriteCheckpointOptions[]): ManagedWriteCheckpointOptions[];
|
|
105
|
-
export type SyncStorageLastWriteCheckpointFilters =
|
|
115
|
+
export type SyncStorageLastWriteCheckpointFilters = SyncStorageCustomWriteCheckpointFilters | ManagedWriteCheckpointFilters;
|
|
106
116
|
export type LastWriteCheckpointFilters = CustomWriteCheckpointFilters | ManagedWriteCheckpointFilters;
|
|
117
|
+
/** Configures checkpoint ownership and generation for a storage instance. */
|
|
118
|
+
export type WriteCheckpointModeConfig = {
|
|
119
|
+
mode: WriteCheckpointMode.CUSTOM;
|
|
120
|
+
/**
|
|
121
|
+
* Name of the event whose custom checkpoints are served. Storage resolves this name through the active sync
|
|
122
|
+
* config's persisted mapping; integrations must not construct or persist event ids themselves. Required by
|
|
123
|
+
* storage implementations that scope custom checkpoints by event definition.
|
|
124
|
+
*/
|
|
125
|
+
eventName?: string;
|
|
126
|
+
} | {
|
|
127
|
+
mode: WriteCheckpointMode.MANAGED;
|
|
128
|
+
};
|
|
107
129
|
export interface BaseWriteCheckpointAPI {
|
|
108
130
|
readonly writeCheckpointMode: WriteCheckpointMode;
|
|
109
|
-
setWriteCheckpointMode(
|
|
131
|
+
setWriteCheckpointMode(config: WriteCheckpointModeConfig): void;
|
|
110
132
|
createManagedWriteCheckpoints(checkpoints: ManagedWriteCheckpointOptions[]): Promise<CreateManagedWriteCheckpointsResult>;
|
|
111
133
|
}
|
|
112
134
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WriteCheckpointAPI.js","sourceRoot":"","sources":["../../src/storage/WriteCheckpointAPI.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"WriteCheckpointAPI.js","sourceRoot":"","sources":["../../src/storage/WriteCheckpointAPI.ts"],"names":[],"mappings":"AAEA,MAAM,CAAN,IAAY,mBAYX;AAZD,WAAY,mBAAmB;IAC7B;;;OAGG;IACH,wCAAiB,CAAA;IACjB;;;;OAIG;IACH,0CAAmB,CAAA;AACrB,CAAC,EAZW,mBAAmB,KAAnB,mBAAmB,QAY9B;AA8GD,MAAM,UAAU,6BAA6B,CAC3C,WAA4C;IAE5C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAyC,CAAC;IAEhE,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAChD,0EAA0E;QAC1E,4EAA4E;QAC5E,2EAA2E;QAC3E,uEAAuE;QACvE,qEAAqE;QACrE,0EAA0E;QAC1E,4EAA4E;QAC5E,WAAW;QACX,EAAE;QACF,8EAA8E;QAC9E,0EAA0E;QAC1E,sDAAsD;QACtD,IAAI,QAAQ,IAAI,IAAI,IAAI,mCAAmC,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,CAAC;YAClF,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,mCAAmC,CAC1C,QAAuC,EACvC,SAAwC;IAExC,MAAM,iBAAiB,GAAG,QAAQ,CAAC,qBAAqB,CAAC;IACzD,MAAM,kBAAkB,GAAG,SAAS,CAAC,qBAAqB,CAAC;IAE3D,IAAI,kBAAkB,IAAI,IAAI,EAAE,CAAC;QAC/B,OAAO,iBAAiB,IAAI,IAAI,CAAC;IACnC,CAAC;IAED,IAAI,iBAAiB,IAAI,IAAI,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,kBAAkB,GAAG,iBAAiB,CAAC;AAChD,CAAC;AA+CD,MAAM,CAAC,MAAM,6BAA6B,GAAG,mBAAmB,CAAC,OAAO,CAAC"}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
import { BucketDataSource, BucketDefinitionId, ParameterIndexId, ParameterIndexLookupCreator, ParameterLookupDefinitionId, SerializedSyncPlan, SourceTableRef, SyncConfigWithErrors } from '@powersync/service-sync-rules';
|
|
1
|
+
import { BucketDataSource, BucketDefinitionId, EventDefinitionId, ParameterIndexId, ParameterIndexLookupCreator, ParameterLookupDefinitionId, SerializedSyncPlan, SourceTableRef, SyncConfigWithErrors } from '@powersync/service-sync-rules';
|
|
2
|
+
/** Minimal shape required to resolve an event's assigned id: its name is the per-config key. */
|
|
3
|
+
export interface NamedEventDefinition {
|
|
4
|
+
readonly name: string;
|
|
5
|
+
}
|
|
2
6
|
export interface SerializedSyncConfigWithMapping {
|
|
3
7
|
plan: SerializedSyncPlan;
|
|
4
8
|
mapping: SingleSyncConfigBucketDefinitionMapping;
|
|
5
9
|
}
|
|
6
|
-
export type IncrementalMappingDefinitionType = 'bucket_data' | 'parameter_lookup';
|
|
10
|
+
export type IncrementalMappingDefinitionType = 'bucket_data' | 'parameter_lookup' | 'event';
|
|
7
11
|
export interface IncrementalMappingDefinitionChange {
|
|
8
12
|
type: IncrementalMappingDefinitionType;
|
|
9
13
|
name: string;
|
|
10
|
-
id: BucketDefinitionId | ParameterIndexId;
|
|
14
|
+
id: BucketDefinitionId | ParameterIndexId | EventDefinitionId;
|
|
11
15
|
}
|
|
12
16
|
export interface IncrementalMappingChanges {
|
|
13
17
|
reusedDefinitions: IncrementalMappingDefinitionChange[];
|
|
@@ -36,6 +40,10 @@ export interface PersistedDefinitionMapping {
|
|
|
36
40
|
* Map of (lookupName, queryId) -> id, unique per replication stream.
|
|
37
41
|
*/
|
|
38
42
|
parameter_indexes: Record<string, string>;
|
|
43
|
+
/**
|
|
44
|
+
* Map of event name -> id, unique per replication stream. Absent for mappings persisted before events were tracked.
|
|
45
|
+
*/
|
|
46
|
+
events?: Record<string, string>;
|
|
39
47
|
}
|
|
40
48
|
/**
|
|
41
49
|
* Represents a mapping from bucket data sources and parameter lookup sources to stable IDs used for bucket definition and parameter index persistence.
|
|
@@ -53,7 +61,8 @@ export interface BucketDefinitionMapping {
|
|
|
53
61
|
parameterLookupId(source: ParameterIndexLookupCreator): ParameterIndexId;
|
|
54
62
|
allBucketDefinitionIds(): BucketDefinitionId[];
|
|
55
63
|
allParameterIndexIds(): ParameterIndexId[];
|
|
56
|
-
|
|
64
|
+
allEventDefinitionIds(): EventDefinitionId[];
|
|
65
|
+
syncConfigIdsForSourceTable(selectedSyncConfigIds: string[], table: SourceTableRef, bucketDataSourceIds: BucketDefinitionId[], parameterLookupSourceIds: ParameterIndexId[], eventDefinitionIds: EventDefinitionId[]): string[];
|
|
57
66
|
snapshotBlockingSourceTablesFilter(syncConfigId: string): Record<string, unknown>;
|
|
58
67
|
}
|
|
59
68
|
/**
|
|
@@ -67,6 +76,7 @@ export interface BucketDefinitionMapping {
|
|
|
67
76
|
export declare class SingleSyncConfigBucketDefinitionMapping implements BucketDefinitionMapping {
|
|
68
77
|
private definitions;
|
|
69
78
|
private parameterLookupMapping;
|
|
79
|
+
private events;
|
|
70
80
|
static fromPersistedMapping(mapping: PersistedDefinitionMapping): SingleSyncConfigBucketDefinitionMapping;
|
|
71
81
|
static fromParsedSyncConfig(syncConfig: SyncConfigWithErrors): SingleSyncConfigBucketDefinitionMapping;
|
|
72
82
|
/**
|
|
@@ -78,18 +88,22 @@ export declare class SingleSyncConfigBucketDefinitionMapping implements BucketDe
|
|
|
78
88
|
*/
|
|
79
89
|
static constructIncrementalMappingFromSerializedPlans(compatibleConfigs: SerializedSyncConfigWithMapping[], newPlan: SerializedSyncPlan, reservedMappings: SingleSyncConfigBucketDefinitionMapping[]): SingleSyncConfigBucketDefinitionMapping;
|
|
80
90
|
static constructIncrementalMappingWithChanges(compatibleConfigs: SerializedSyncConfigWithMapping[], newPlan: SerializedSyncPlan, reservedMappings: SingleSyncConfigBucketDefinitionMapping[]): IncrementalMappingResult;
|
|
81
|
-
constructor(definitions?: Record<string, BucketDefinitionId>, parameterLookupMapping?: Record<string, ParameterIndexId>);
|
|
91
|
+
constructor(definitions?: Record<string, BucketDefinitionId>, parameterLookupMapping?: Record<string, ParameterIndexId>, events?: Record<string, EventDefinitionId>);
|
|
82
92
|
bucketSourceId(source: BucketDataSource): BucketDefinitionId;
|
|
83
93
|
bucketSourceIdByName(uniqueName: string): BucketDefinitionId;
|
|
84
94
|
allBucketDefinitionIds(): BucketDefinitionId[];
|
|
85
95
|
bucketDefinitionEntries(): IncrementalMappingDefinitionChange[];
|
|
86
96
|
allParameterIndexIds(): ParameterIndexId[];
|
|
87
97
|
parameterIndexEntries(): IncrementalMappingDefinitionChange[];
|
|
98
|
+
allEventDefinitionIds(): EventDefinitionId[];
|
|
99
|
+
eventDefinitionEntries(): IncrementalMappingDefinitionChange[];
|
|
88
100
|
allDefinitionEntries(): IncrementalMappingDefinitionChange[];
|
|
89
101
|
parameterLookupId(source: ParameterIndexLookupCreator): ParameterIndexId;
|
|
90
102
|
parameterLookupIdByKey(key: string): ParameterIndexId;
|
|
103
|
+
eventId(event: NamedEventDefinition): EventDefinitionId;
|
|
104
|
+
eventDefinitionIdByName(name: string): EventDefinitionId;
|
|
91
105
|
serialize(): PersistedDefinitionMapping;
|
|
92
|
-
syncConfigIdsForSourceTable(selectedSyncConfigIds: string[], _table: SourceTableRef, bucketDataSourceIds: BucketDefinitionId[], parameterLookupSourceIds: ParameterIndexId[]): string[];
|
|
106
|
+
syncConfigIdsForSourceTable(selectedSyncConfigIds: string[], _table: SourceTableRef, bucketDataSourceIds: BucketDefinitionId[], parameterLookupSourceIds: ParameterIndexId[], eventDefinitionIds: EventDefinitionId[]): string[];
|
|
93
107
|
snapshotBlockingSourceTablesFilter(_syncConfigId: string): Record<string, unknown>;
|
|
94
108
|
}
|
|
95
109
|
/**
|
|
@@ -104,6 +118,7 @@ export declare class MultiSyncConfigBucketDefinitionMapping implements BucketDef
|
|
|
104
118
|
private bucketDataSourceSyncConfigIdsById;
|
|
105
119
|
private parameterLookupMappings;
|
|
106
120
|
private parameterLookupSyncConfigIdsById;
|
|
121
|
+
private eventDefinitionSyncConfigIdsById;
|
|
107
122
|
private syncConfigsById;
|
|
108
123
|
private mappings;
|
|
109
124
|
constructor(syncConfigs: SyncConfigWithRequiredMapping[]);
|
|
@@ -111,7 +126,8 @@ export declare class MultiSyncConfigBucketDefinitionMapping implements BucketDef
|
|
|
111
126
|
allBucketDefinitionIds(): BucketDefinitionId[];
|
|
112
127
|
parameterLookupId(source: ParameterIndexLookupCreator): ParameterIndexId;
|
|
113
128
|
allParameterIndexIds(): ParameterIndexId[];
|
|
114
|
-
|
|
129
|
+
allEventDefinitionIds(): EventDefinitionId[];
|
|
130
|
+
syncConfigIdsForSourceTable(_selectedSyncConfigIds: string[], _table: SourceTableRef, bucketDataSourceIds: BucketDefinitionId[], parameterLookupSourceIds: ParameterIndexId[], eventDefinitionIds: EventDefinitionId[]): string[];
|
|
115
131
|
snapshotBlockingSourceTablesFilter(syncConfigId: string): Record<string, unknown>;
|
|
116
132
|
}
|
|
117
133
|
export declare function parameterLookupKey(id: ParameterLookupDefinitionId): string;
|