@powersync/service-core 0.0.0-dev-20260602073133 → 0.0.0-dev-20260803144812

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.
Files changed (183) hide show
  1. package/CHANGELOG.md +83 -4
  2. package/dist/api/RouteAPI.d.ts +42 -14
  3. package/dist/api/diagnostics.d.ts +12 -1
  4. package/dist/api/diagnostics.js +34 -22
  5. package/dist/api/diagnostics.js.map +1 -1
  6. package/dist/entry/commands/compact-action.js +5 -1
  7. package/dist/entry/commands/compact-action.js.map +1 -1
  8. package/dist/modules/AbstractModule.d.ts +6 -2
  9. package/dist/modules/AbstractModule.js.map +1 -1
  10. package/dist/replication/AbstractReplicator.d.ts +26 -7
  11. package/dist/replication/AbstractReplicator.js +148 -68
  12. package/dist/replication/AbstractReplicator.js.map +1 -1
  13. package/dist/replication/ReplicationModule.d.ts +3 -3
  14. package/dist/replication/ReplicationModule.js.map +1 -1
  15. package/dist/routes/RouterEngine.d.ts +1 -0
  16. package/dist/routes/RouterEngine.js +6 -1
  17. package/dist/routes/RouterEngine.js.map +1 -1
  18. package/dist/routes/configure-fastify.d.ts +95 -56
  19. package/dist/routes/configure-fastify.js +15 -2
  20. package/dist/routes/configure-fastify.js.map +1 -1
  21. package/dist/routes/endpoints/admin.d.ts +24 -24
  22. package/dist/routes/endpoints/admin.js +46 -35
  23. package/dist/routes/endpoints/admin.js.map +1 -1
  24. package/dist/routes/endpoints/checkpointing.d.ts +62 -0
  25. package/dist/routes/endpoints/checkpointing.js +65 -7
  26. package/dist/routes/endpoints/checkpointing.js.map +1 -1
  27. package/dist/routes/endpoints/socket-route.js +3 -2
  28. package/dist/routes/endpoints/socket-route.js.map +1 -1
  29. package/dist/routes/endpoints/sync-rules.js +22 -13
  30. package/dist/routes/endpoints/sync-rules.js.map +1 -1
  31. package/dist/routes/endpoints/sync-stream.js +1 -1
  32. package/dist/routes/endpoints/sync-stream.js.map +1 -1
  33. package/dist/runner/teardown.js +8 -8
  34. package/dist/runner/teardown.js.map +1 -1
  35. package/dist/storage/BucketStorageBatch.d.ts +63 -17
  36. package/dist/storage/BucketStorageBatch.js.map +1 -1
  37. package/dist/storage/BucketStorageFactory.d.ts +22 -27
  38. package/dist/storage/BucketStorageFactory.js +4 -18
  39. package/dist/storage/BucketStorageFactory.js.map +1 -1
  40. package/dist/storage/CheckpointChecksumInvalidatedError.d.ts +12 -0
  41. package/dist/storage/CheckpointChecksumInvalidatedError.js +17 -0
  42. package/dist/storage/CheckpointChecksumInvalidatedError.js.map +1 -0
  43. package/dist/storage/ChecksumCache.d.ts +11 -6
  44. package/dist/storage/ChecksumCache.js +5 -4
  45. package/dist/storage/ChecksumCache.js.map +1 -1
  46. package/dist/storage/ParsedSyncConfigSet.d.ts +23 -0
  47. package/dist/storage/ParsedSyncConfigSet.js +2 -0
  48. package/dist/storage/ParsedSyncConfigSet.js.map +1 -0
  49. package/dist/storage/PersistedReplicationStream.d.ts +32 -0
  50. package/dist/storage/PersistedReplicationStream.js +26 -0
  51. package/dist/storage/PersistedReplicationStream.js.map +1 -0
  52. package/dist/storage/PersistedSyncConfigContent.d.ts +63 -0
  53. package/dist/storage/PersistedSyncConfigContent.js +125 -0
  54. package/dist/storage/PersistedSyncConfigContent.js.map +1 -0
  55. package/dist/storage/PersistedSyncConfigStatus.d.ts +13 -0
  56. package/dist/storage/PersistedSyncConfigStatus.js +2 -0
  57. package/dist/storage/PersistedSyncConfigStatus.js.map +1 -0
  58. package/dist/storage/SourceEntity.d.ts +6 -0
  59. package/dist/storage/SourceTable.d.ts +21 -3
  60. package/dist/storage/SourceTable.js +26 -3
  61. package/dist/storage/SourceTable.js.map +1 -1
  62. package/dist/storage/SyncRulesBucketStorage.d.ts +119 -21
  63. package/dist/storage/SyncRulesBucketStorage.js +3 -0
  64. package/dist/storage/SyncRulesBucketStorage.js.map +1 -1
  65. package/dist/storage/WriteCheckpointAPI.d.ts +60 -3
  66. package/dist/storage/WriteCheckpointAPI.js +33 -0
  67. package/dist/storage/WriteCheckpointAPI.js.map +1 -1
  68. package/dist/storage/implementation/BucketDefinitionMapping.d.ts +117 -0
  69. package/dist/storage/implementation/BucketDefinitionMapping.js +277 -0
  70. package/dist/storage/implementation/BucketDefinitionMapping.js.map +1 -0
  71. package/dist/storage/implementation/IncrementalReprocessingCompatibility.d.ts +6 -0
  72. package/dist/storage/implementation/IncrementalReprocessingCompatibility.js +31 -0
  73. package/dist/storage/implementation/IncrementalReprocessingCompatibility.js.map +1 -0
  74. package/dist/storage/implementation/IncrementalReprocessingSyncConfigLog.d.ts +17 -0
  75. package/dist/storage/implementation/IncrementalReprocessingSyncConfigLog.js +62 -0
  76. package/dist/storage/implementation/IncrementalReprocessingSyncConfigLog.js.map +1 -0
  77. package/dist/storage/implementation/ReplicationStreamStorageIds.d.ts +15 -0
  78. package/dist/storage/implementation/ReplicationStreamStorageIds.js +20 -0
  79. package/dist/storage/implementation/ReplicationStreamStorageIds.js.map +1 -0
  80. package/dist/storage/storage-index.d.ts +9 -1
  81. package/dist/storage/storage-index.js +9 -1
  82. package/dist/storage/storage-index.js.map +1 -1
  83. package/dist/sync/BucketChecksumState.d.ts +12 -2
  84. package/dist/sync/BucketChecksumState.js +69 -21
  85. package/dist/sync/BucketChecksumState.js.map +1 -1
  86. package/dist/sync/RequestTracker.d.ts +7 -0
  87. package/dist/sync/RequestTracker.js +12 -0
  88. package/dist/sync/RequestTracker.js.map +1 -1
  89. package/dist/sync/sync.js +154 -41
  90. package/dist/sync/sync.js.map +1 -1
  91. package/dist/sync/util.d.ts +5 -0
  92. package/dist/sync/util.js +9 -0
  93. package/dist/sync/util.js.map +1 -1
  94. package/dist/system/ServiceContext.d.ts +2 -0
  95. package/dist/system/ServiceContext.js +2 -0
  96. package/dist/system/ServiceContext.js.map +1 -1
  97. package/dist/tracing/PerformanceTracer.d.ts +23 -1
  98. package/dist/tracing/PerformanceTracer.js +11 -0
  99. package/dist/tracing/PerformanceTracer.js.map +1 -1
  100. package/dist/util/checkpointing.d.ts +4 -8
  101. package/dist/util/checkpointing.js +1 -16
  102. package/dist/util/checkpointing.js.map +1 -1
  103. package/dist/util/config/compound-config-collector.js +18 -2
  104. package/dist/util/config/compound-config-collector.js.map +1 -1
  105. package/dist/util/config/defaults.d.ts +2 -0
  106. package/dist/util/config/defaults.js +2 -0
  107. package/dist/util/config/defaults.js.map +1 -1
  108. package/dist/util/config/types.d.ts +3 -1
  109. package/dist/util/lsn.d.ts +4 -0
  110. package/dist/util/lsn.js +10 -0
  111. package/dist/util/lsn.js.map +1 -1
  112. package/dist/util/util-index.d.ts +1 -0
  113. package/dist/util/util-index.js +1 -0
  114. package/dist/util/util-index.js.map +1 -1
  115. package/dist/util/utils.d.ts +1 -1
  116. package/dist/util/utils.js +1 -1
  117. package/dist/util/write-checkpoint-batcher.d.ts +19 -0
  118. package/dist/util/write-checkpoint-batcher.js +100 -0
  119. package/dist/util/write-checkpoint-batcher.js.map +1 -0
  120. package/package.json +6 -7
  121. package/src/api/RouteAPI.ts +43 -14
  122. package/src/api/diagnostics.ts +43 -26
  123. package/src/entry/commands/compact-action.ts +7 -1
  124. package/src/modules/AbstractModule.ts +6 -2
  125. package/src/replication/AbstractReplicator.ts +181 -72
  126. package/src/replication/ReplicationModule.ts +2 -3
  127. package/src/routes/RouterEngine.ts +7 -1
  128. package/src/routes/configure-fastify.ts +25 -2
  129. package/src/routes/endpoints/admin.ts +72 -50
  130. package/src/routes/endpoints/checkpointing.ts +79 -8
  131. package/src/routes/endpoints/socket-route.ts +3 -2
  132. package/src/routes/endpoints/sync-rules.ts +23 -13
  133. package/src/routes/endpoints/sync-stream.ts +1 -1
  134. package/src/runner/teardown.ts +8 -8
  135. package/src/storage/BucketStorageBatch.ts +64 -18
  136. package/src/storage/BucketStorageFactory.ts +30 -39
  137. package/src/storage/CheckpointChecksumInvalidatedError.ts +17 -0
  138. package/src/storage/ChecksumCache.ts +27 -14
  139. package/src/storage/ParsedSyncConfigSet.ts +25 -0
  140. package/src/storage/PersistedReplicationStream.ts +55 -0
  141. package/src/storage/PersistedSyncConfigContent.ts +192 -0
  142. package/src/storage/PersistedSyncConfigStatus.ts +14 -0
  143. package/src/storage/SourceEntity.ts +6 -0
  144. package/src/storage/SourceTable.ts +34 -3
  145. package/src/storage/SyncRulesBucketStorage.ts +138 -22
  146. package/src/storage/WriteCheckpointAPI.ts +108 -3
  147. package/src/storage/implementation/BucketDefinitionMapping.ts +436 -0
  148. package/src/storage/implementation/IncrementalReprocessingCompatibility.ts +41 -0
  149. package/src/storage/implementation/IncrementalReprocessingSyncConfigLog.ts +109 -0
  150. package/src/storage/implementation/ReplicationStreamStorageIds.ts +21 -0
  151. package/src/storage/storage-index.ts +10 -1
  152. package/src/sync/BucketChecksumState.ts +103 -21
  153. package/src/sync/RequestTracker.ts +20 -0
  154. package/src/sync/sync.ts +183 -48
  155. package/src/sync/util.ts +12 -0
  156. package/src/system/ServiceContext.ts +7 -0
  157. package/src/tracing/PerformanceTracer.ts +41 -1
  158. package/src/util/checkpointing.ts +4 -22
  159. package/src/util/config/compound-config-collector.ts +25 -1
  160. package/src/util/config/defaults.ts +2 -0
  161. package/src/util/config/types.ts +3 -1
  162. package/src/util/lsn.ts +9 -0
  163. package/src/util/util-index.ts +1 -0
  164. package/src/util/utils.ts +1 -1
  165. package/src/util/write-checkpoint-batcher.ts +142 -0
  166. package/test/src/AbstractReplicator.test.ts +115 -0
  167. package/test/src/checksum_cache.test.ts +22 -0
  168. package/test/src/config.test.ts +102 -0
  169. package/test/src/diagnostics.test.ts +62 -34
  170. package/test/src/module-loader.test.ts +33 -1
  171. package/test/src/routes/admin.test.ts +182 -18
  172. package/test/src/routes/checkpointing.test.ts +54 -0
  173. package/test/src/routes/mocks.ts +6 -2
  174. package/test/src/storage/SourceTable.test.ts +89 -0
  175. package/test/src/sync/BucketChecksumState.test.ts +98 -12
  176. package/test/src/sync/util.test.ts +13 -1
  177. package/test/src/util/checkpointing.test.ts +249 -0
  178. package/tsconfig.json +1 -4
  179. package/tsconfig.tsbuildinfo +1 -1
  180. package/dist/storage/PersistedSyncRulesContent.d.ts +0 -59
  181. package/dist/storage/PersistedSyncRulesContent.js +0 -100
  182. package/dist/storage/PersistedSyncRulesContent.js.map +0 -1
  183. package/src/storage/PersistedSyncRulesContent.ts +0 -174
@@ -17,6 +17,17 @@ export interface BaseWriteCheckpointIdentifier {
17
17
  */
18
18
  user_id: string;
19
19
  }
20
+ export interface ClientRequestedCheckpointOptions {
21
+ /**
22
+ * Supplied for client-generated checkpoint requests.
23
+ *
24
+ * If omitted, storage creates or stores a regular write checkpoint.
25
+ * If supplied for managed write checkpoints, storage only uses it when it is
26
+ * greater than the stored id for the user_id. Same or lower supplied ids are
27
+ * no-ops, and storage returns the current stored id.
28
+ */
29
+ checkpoint_request_id?: bigint;
30
+ }
20
31
  export interface CustomWriteCheckpointFilters extends BaseWriteCheckpointIdentifier {
21
32
  /**
22
33
  * Replication stream which was active when this checkpoint was created.
@@ -25,9 +36,17 @@ export interface CustomWriteCheckpointFilters extends BaseWriteCheckpointIdentif
25
36
  }
26
37
  export interface BatchedCustomWriteCheckpointOptions extends BaseWriteCheckpointIdentifier {
27
38
  /**
28
- * A supplied incrementing Write Checkpoint number
39
+ * A supplied incrementing checkpoint request id. This is still named
40
+ * "write checkpoint" in storage APIs for backwards compatibility.
29
41
  */
30
42
  checkpoint: bigint;
43
+ /**
44
+ * Required when this custom checkpoint was created from a client checkpoint
45
+ * request and should be eligible for checkpoint request retention cleanup.
46
+ * Omit or set to null for persistent custom checkpoints owned by the source
47
+ * or integration.
48
+ */
49
+ checkpoint_requested_at?: Date | null;
31
50
  }
32
51
  export interface CustomWriteCheckpointOptions extends BatchedCustomWriteCheckpointOptions {
33
52
  /**
@@ -44,13 +63,51 @@ export interface ManagedWriteCheckpointFilters extends BaseWriteCheckpointIdenti
44
63
  */
45
64
  heads: Record<string, string>;
46
65
  }
47
- export type ManagedWriteCheckpointOptions = ManagedWriteCheckpointFilters;
66
+ export type ManagedWriteCheckpointOptions = ManagedWriteCheckpointFilters & ClientRequestedCheckpointOptions;
67
+ export interface CreateManagedWriteCheckpointsResult {
68
+ /**
69
+ * Current managed checkpoint id for each full user_id after applying the batch.
70
+ */
71
+ writeCheckpoints: Map<string, bigint>;
72
+ /**
73
+ * True when the source marker must be forced so replication observes the
74
+ * stored head. Callers use this to advance the source marker once for the
75
+ * whole batch.
76
+ *
77
+ * This must be true whenever a checkpoint in the batch has not yet been
78
+ * processed by replication - both freshly created/advanced checkpoints and
79
+ * existing checkpoints matched by a stale or duplicate request that are still
80
+ * pending. Already-processed checkpoints do not need a new marker.
81
+ *
82
+ * The case this guards against is a lost source marker on a stale retry. The
83
+ * source marker is forced after the checkpoint is persisted, so the two are
84
+ * not atomic (storage and source are usually different databases). Without
85
+ * this flag, the following sequence strands the checkpoint:
86
+ *
87
+ * 1. A client-supplied checkpoint id is persisted (write checkpoint stored,
88
+ * processed_at_lsn null).
89
+ * 2. Forcing the source marker fails, so the request errors and the client
90
+ * retries with the same id.
91
+ * 3. The retry is a no-op for the stored id (monotonic, not greater), so if
92
+ * we only advanced on "a row changed" we would skip the marker.
93
+ * 4. On an idle source nothing else moves replication past the stored head,
94
+ * so the checkpoint never gets acknowledged and the client waits forever.
95
+ *
96
+ * Reporting true while the checkpoint is still pending makes the retry re-force
97
+ * the marker, which resolves the wait.
98
+ *
99
+ * Backends that do not track a per-row processed indicator may conservatively
100
+ * report true whenever any checkpoint was matched.
101
+ */
102
+ shouldAdvance: boolean;
103
+ }
104
+ export declare function uniqueManagedWriteCheckpoints(checkpoints: ManagedWriteCheckpointOptions[]): ManagedWriteCheckpointOptions[];
48
105
  export type SyncStorageLastWriteCheckpointFilters = BaseWriteCheckpointIdentifier | ManagedWriteCheckpointFilters;
49
106
  export type LastWriteCheckpointFilters = CustomWriteCheckpointFilters | ManagedWriteCheckpointFilters;
50
107
  export interface BaseWriteCheckpointAPI {
51
108
  readonly writeCheckpointMode: WriteCheckpointMode;
52
109
  setWriteCheckpointMode(mode: WriteCheckpointMode): void;
53
- createManagedWriteCheckpoint(checkpoint: ManagedWriteCheckpointOptions): Promise<bigint>;
110
+ createManagedWriteCheckpoints(checkpoints: ManagedWriteCheckpointOptions[]): Promise<CreateManagedWriteCheckpointsResult>;
54
111
  }
55
112
  /**
56
113
  * Write Checkpoint API to be used in conjunction with a {@link SyncRulesBucketStorage}.
@@ -12,5 +12,38 @@ export var WriteCheckpointMode;
12
12
  */
13
13
  WriteCheckpointMode["MANAGED"] = "managed";
14
14
  })(WriteCheckpointMode || (WriteCheckpointMode = {}));
15
+ export function uniqueManagedWriteCheckpoints(checkpoints) {
16
+ const byUser = new Map();
17
+ for (const checkpoint of checkpoints) {
18
+ const existing = byUser.get(checkpoint.user_id);
19
+ // A batch can contain entries for many users, and different users may use
20
+ // different request types (generated vs client-supplied). For a single full
21
+ // user_id, though, all entries should be the same type - a batch can still
22
+ // hold multiple entries for that user (e.g. coalesced requests), so we
23
+ // collapse them to one. For client-supplied ids we keep the greatest
24
+ // requested value, so lower stale ids cannot hide the request that should
25
+ // advance storage. For generated ids the entries are equivalent, so any one
26
+ // is kept.
27
+ //
28
+ // Mixing generated and supplied entries for the same user_id is not expected;
29
+ // shouldReplaceManagedWriteCheckpoint still resolves it deterministically
30
+ // (supplied wins) if that invariant is ever violated.
31
+ if (existing == null || shouldReplaceManagedWriteCheckpoint(existing, checkpoint)) {
32
+ byUser.set(checkpoint.user_id, checkpoint);
33
+ }
34
+ }
35
+ return [...byUser.values()];
36
+ }
37
+ function shouldReplaceManagedWriteCheckpoint(existing, candidate) {
38
+ const existingRequestId = existing.checkpoint_request_id;
39
+ const candidateRequestId = candidate.checkpoint_request_id;
40
+ if (candidateRequestId == null) {
41
+ return existingRequestId == null;
42
+ }
43
+ if (existingRequestId == null) {
44
+ return true;
45
+ }
46
+ return candidateRequestId > existingRequestId;
47
+ }
15
48
  export const DEFAULT_WRITE_CHECKPOINT_MODE = WriteCheckpointMode.MANAGED;
16
49
  //# sourceMappingURL=WriteCheckpointAPI.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WriteCheckpointAPI.js","sourceRoot":"","sources":["../../src/storage/WriteCheckpointAPI.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,mBAYX;AAZD,WAAY,mBAAmB;IAC7B;;;OAGG;IACH,wCAAiB,CAAA;IACjB;;;;OAIG;IACH,0CAAmB,CAAA;AACrB,CAAC,EAZW,mBAAmB,KAAnB,mBAAmB,QAY9B;AAoED,MAAM,CAAC,MAAM,6BAA6B,GAAG,mBAAmB,CAAC,OAAO,CAAC"}
1
+ {"version":3,"file":"WriteCheckpointAPI.js","sourceRoot":"","sources":["../../src/storage/WriteCheckpointAPI.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,mBAYX;AAZD,WAAY,mBAAmB;IAC7B;;;OAGG;IACH,wCAAiB,CAAA;IACjB;;;;OAIG;IACH,0CAAmB,CAAA;AACrB,CAAC,EAZW,mBAAmB,KAAnB,mBAAmB,QAY9B;AAoGD,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;AA8BD,MAAM,CAAC,MAAM,6BAA6B,GAAG,mBAAmB,CAAC,OAAO,CAAC"}
@@ -0,0 +1,117 @@
1
+ import { BucketDataSource, BucketDefinitionId, ParameterIndexId, ParameterIndexLookupCreator, ParameterLookupDefinitionId, SerializedSyncPlan, SourceTableRef, SyncConfigWithErrors } from '@powersync/service-sync-rules';
2
+ export interface SerializedSyncConfigWithMapping {
3
+ plan: SerializedSyncPlan;
4
+ mapping: SingleSyncConfigBucketDefinitionMapping;
5
+ }
6
+ export type IncrementalMappingDefinitionType = 'bucket_data' | 'parameter_lookup';
7
+ export interface IncrementalMappingDefinitionChange {
8
+ type: IncrementalMappingDefinitionType;
9
+ name: string;
10
+ id: BucketDefinitionId | ParameterIndexId;
11
+ }
12
+ export interface IncrementalMappingChanges {
13
+ reusedDefinitions: IncrementalMappingDefinitionChange[];
14
+ addedDefinitions: IncrementalMappingDefinitionChange[];
15
+ }
16
+ export interface IncrementalMappingResult {
17
+ mapping: SingleSyncConfigBucketDefinitionMapping;
18
+ changes: IncrementalMappingChanges;
19
+ }
20
+ export interface SyncConfigWithMapping {
21
+ syncConfigId?: string;
22
+ syncConfig: SyncConfigWithErrors;
23
+ mapping: SingleSyncConfigBucketDefinitionMapping | null;
24
+ }
25
+ export interface SyncConfigWithRequiredMapping {
26
+ syncConfigId: string;
27
+ syncConfig: SyncConfigWithErrors;
28
+ mapping: SingleSyncConfigBucketDefinitionMapping;
29
+ }
30
+ export interface PersistedDefinitionMapping {
31
+ /**
32
+ * Map of uniqueName -> id, unique per replication stream.
33
+ */
34
+ definitions: Record<string, string>;
35
+ /**
36
+ * Map of (lookupName, queryId) -> id, unique per replication stream.
37
+ */
38
+ parameter_indexes: Record<string, string>;
39
+ }
40
+ /**
41
+ * Represents a mapping from bucket data sources and parameter lookup sources to stable IDs used for bucket definition and parameter index persistence.
42
+ *
43
+ * Usage is deliberately restricted: writer/batch paths resolve through their own parsed
44
+ * sync config set's mapping, and read paths resolve through the persisted
45
+ * {@link SingleSyncConfigBucketDefinitionMapping} of the single sync config they serve.
46
+ * Do not construct ad-hoc resolution paths from parsed sources.
47
+ */
48
+ export interface BucketDefinitionMapping {
49
+ /**
50
+ * Given a BucketDataSource within the associated SyncConfig(s), return the BucketDefinitionId, or throw if not found.
51
+ */
52
+ bucketSourceId(source: BucketDataSource): BucketDefinitionId;
53
+ parameterLookupId(source: ParameterIndexLookupCreator): ParameterIndexId;
54
+ allBucketDefinitionIds(): BucketDefinitionId[];
55
+ allParameterIndexIds(): ParameterIndexId[];
56
+ syncConfigIdsForSourceTable(selectedSyncConfigIds: string[], table: SourceTableRef, bucketDataSourceIds: BucketDefinitionId[], parameterLookupSourceIds: ParameterIndexId[]): string[];
57
+ snapshotBlockingSourceTablesFilter(syncConfigId: string): Record<string, unknown>;
58
+ }
59
+ /**
60
+ * A BucketDefinitionMapping associated with a single SyncConfig.
61
+ *
62
+ * Within a single SyncConfig, unique names are the persistence key for bucket definitions,
63
+ * so lookups here are name-based by design. MongoHydrationState and
64
+ * MultiSyncConfigBucketDefinitionMapping handle the mapping across multiple SyncConfigs in
65
+ * the same replication stream, where names are not unique.
66
+ */
67
+ export declare class SingleSyncConfigBucketDefinitionMapping implements BucketDefinitionMapping {
68
+ private definitions;
69
+ private parameterLookupMapping;
70
+ static fromPersistedMapping(mapping: PersistedDefinitionMapping): SingleSyncConfigBucketDefinitionMapping;
71
+ static fromParsedSyncConfig(syncConfig: SyncConfigWithErrors): SingleSyncConfigBucketDefinitionMapping;
72
+ /**
73
+ *
74
+ * @param compatibleConfigs SyncConfigs with definitions that may be re-used
75
+ * @param newPlan
76
+ * @param reservedMappings _all_ mappings used currently and historically for the replication stream; used to construct new ids
77
+ * @returns
78
+ */
79
+ static constructIncrementalMappingFromSerializedPlans(compatibleConfigs: SerializedSyncConfigWithMapping[], newPlan: SerializedSyncPlan, reservedMappings: SingleSyncConfigBucketDefinitionMapping[]): SingleSyncConfigBucketDefinitionMapping;
80
+ static constructIncrementalMappingWithChanges(compatibleConfigs: SerializedSyncConfigWithMapping[], newPlan: SerializedSyncPlan, reservedMappings: SingleSyncConfigBucketDefinitionMapping[]): IncrementalMappingResult;
81
+ constructor(definitions?: Record<string, BucketDefinitionId>, parameterLookupMapping?: Record<string, ParameterIndexId>);
82
+ bucketSourceId(source: BucketDataSource): BucketDefinitionId;
83
+ bucketSourceIdByName(uniqueName: string): BucketDefinitionId;
84
+ allBucketDefinitionIds(): BucketDefinitionId[];
85
+ bucketDefinitionEntries(): IncrementalMappingDefinitionChange[];
86
+ allParameterIndexIds(): ParameterIndexId[];
87
+ parameterIndexEntries(): IncrementalMappingDefinitionChange[];
88
+ allDefinitionEntries(): IncrementalMappingDefinitionChange[];
89
+ parameterLookupId(source: ParameterIndexLookupCreator): ParameterIndexId;
90
+ parameterLookupIdByKey(key: string): ParameterIndexId;
91
+ serialize(): PersistedDefinitionMapping;
92
+ syncConfigIdsForSourceTable(selectedSyncConfigIds: string[], _table: SourceTableRef, bucketDataSourceIds: BucketDefinitionId[], parameterLookupSourceIds: ParameterIndexId[]): string[];
93
+ snapshotBlockingSourceTablesFilter(_syncConfigId: string): Record<string, unknown>;
94
+ }
95
+ /**
96
+ * A BucketDefinitionMapping across all SyncConfigs of one parse of a replication stream.
97
+ *
98
+ * Source lookups are strictly identity-based: a source that did not come from the parse
99
+ * this mapping was constructed with is an error. Unique names are not unique across sync
100
+ * configs in a replication stream, so there is deliberately no name-based fallback.
101
+ */
102
+ export declare class MultiSyncConfigBucketDefinitionMapping implements BucketDefinitionMapping {
103
+ private bucketDataSourceMappings;
104
+ private bucketDataSourceSyncConfigIdsById;
105
+ private parameterLookupMappings;
106
+ private parameterLookupSyncConfigIdsById;
107
+ private syncConfigsById;
108
+ private mappings;
109
+ constructor(syncConfigs: SyncConfigWithRequiredMapping[]);
110
+ bucketSourceId(source: BucketDataSource): BucketDefinitionId;
111
+ allBucketDefinitionIds(): BucketDefinitionId[];
112
+ parameterLookupId(source: ParameterIndexLookupCreator): ParameterIndexId;
113
+ allParameterIndexIds(): ParameterIndexId[];
114
+ syncConfigIdsForSourceTable(_selectedSyncConfigIds: string[], table: SourceTableRef, bucketDataSourceIds: BucketDefinitionId[], parameterLookupSourceIds: ParameterIndexId[]): string[];
115
+ snapshotBlockingSourceTablesFilter(syncConfigId: string): Record<string, unknown>;
116
+ }
117
+ export declare function parameterLookupKey(id: ParameterLookupDefinitionId): string;
@@ -0,0 +1,277 @@
1
+ import { ServiceAssertionError } from '@powersync/lib-services-framework';
2
+ import { HashMap, serializedStreamBucketDataSourceEquality, serializedStreamParameterIndexLookupCreatorEquality } from '@powersync/service-sync-rules';
3
+ /**
4
+ * A BucketDefinitionMapping associated with a single SyncConfig.
5
+ *
6
+ * Within a single SyncConfig, unique names are the persistence key for bucket definitions,
7
+ * so lookups here are name-based by design. MongoHydrationState and
8
+ * MultiSyncConfigBucketDefinitionMapping handle the mapping across multiple SyncConfigs in
9
+ * the same replication stream, where names are not unique.
10
+ */
11
+ export class SingleSyncConfigBucketDefinitionMapping {
12
+ definitions;
13
+ parameterLookupMapping;
14
+ static fromPersistedMapping(mapping) {
15
+ return new SingleSyncConfigBucketDefinitionMapping(mapping.definitions ?? {}, mapping.parameter_indexes ?? {});
16
+ }
17
+ static fromParsedSyncConfig(syncConfig) {
18
+ const definitionNames = syncConfig.config.bucketDataSources.map((source) => source.uniqueName).sort();
19
+ const parameterKeys = syncConfig.config.bucketParameterLookupSources
20
+ .map((source) => `${source.sourceId.lookupName}#${source.sourceId.queryId}`)
21
+ .sort();
22
+ const definitions = {};
23
+ const parameterLookups = {};
24
+ for (const [index, uniqueName] of definitionNames.entries()) {
25
+ definitions[uniqueName] = (index + 1).toString(16);
26
+ }
27
+ for (const [index, key] of parameterKeys.entries()) {
28
+ parameterLookups[key] = (index + 1).toString(16);
29
+ }
30
+ return new SingleSyncConfigBucketDefinitionMapping(definitions, parameterLookups);
31
+ }
32
+ /**
33
+ *
34
+ * @param compatibleConfigs SyncConfigs with definitions that may be re-used
35
+ * @param newPlan
36
+ * @param reservedMappings _all_ mappings used currently and historically for the replication stream; used to construct new ids
37
+ * @returns
38
+ */
39
+ static constructIncrementalMappingFromSerializedPlans(compatibleConfigs, newPlan, reservedMappings) {
40
+ return this.constructIncrementalMappingWithChanges(compatibleConfigs, newPlan, reservedMappings).mapping;
41
+ }
42
+ static constructIncrementalMappingWithChanges(compatibleConfigs, newPlan, reservedMappings) {
43
+ let nextBucketDefinitionId = reservedMappings
44
+ .map((mapping) => mapping.allBucketDefinitionIds())
45
+ .flat()
46
+ .reduce((maxId, id) => Math.max(maxId, parseInt(id, 16)), 0) + 1;
47
+ function generateNewBucketDefinitionId() {
48
+ const id = nextBucketDefinitionId.toString(16);
49
+ nextBucketDefinitionId++;
50
+ return id;
51
+ }
52
+ let nextParameterIndexId = reservedMappings
53
+ .map((mapping) => mapping.allParameterIndexIds())
54
+ .flat()
55
+ .reduce((maxId, id) => Math.max(maxId, parseInt(id, 16)), 0) + 1;
56
+ function generateNewParameterIndexId() {
57
+ const id = nextParameterIndexId.toString(16);
58
+ nextParameterIndexId++;
59
+ return id;
60
+ }
61
+ const definitions = {};
62
+ const parameterLookups = {};
63
+ const changes = {
64
+ reusedDefinitions: [],
65
+ addedDefinitions: []
66
+ };
67
+ const compatibleBuckets = new HashMap(serializedStreamBucketDataSourceEquality);
68
+ const compatibleParameterLookups = new HashMap(serializedStreamParameterIndexLookupCreatorEquality);
69
+ for (const config of compatibleConfigs) {
70
+ for (const bucket of config.plan.buckets) {
71
+ compatibleBuckets.putIfAbsent({ bucket, dataSources: config.plan.dataSources }, () => config.mapping.bucketSourceIdByName(bucket.uniqueName));
72
+ }
73
+ for (const parameterLookup of config.plan.parameterIndexes) {
74
+ compatibleParameterLookups.putIfAbsent(parameterLookup, () => config.mapping.parameterLookupIdByKey(parameterLookupKey(parameterLookup.lookupScope)));
75
+ }
76
+ }
77
+ for (const bucket of newPlan.buckets) {
78
+ const compatibleId = compatibleBuckets.get({ bucket, dataSources: newPlan.dataSources });
79
+ const id = compatibleId ?? generateNewBucketDefinitionId();
80
+ definitions[bucket.uniqueName] = id;
81
+ const change = {
82
+ type: 'bucket_data',
83
+ name: bucket.uniqueName,
84
+ id
85
+ };
86
+ if (compatibleId == null) {
87
+ changes.addedDefinitions.push(change);
88
+ }
89
+ else {
90
+ changes.reusedDefinitions.push(change);
91
+ }
92
+ }
93
+ for (const parameterLookup of newPlan.parameterIndexes) {
94
+ const compatibleId = compatibleParameterLookups.get(parameterLookup);
95
+ const id = compatibleId ?? generateNewParameterIndexId();
96
+ const key = parameterLookupKey(parameterLookup.lookupScope);
97
+ parameterLookups[key] = id;
98
+ const change = {
99
+ type: 'parameter_lookup',
100
+ name: key,
101
+ id
102
+ };
103
+ if (compatibleId == null) {
104
+ changes.addedDefinitions.push(change);
105
+ }
106
+ else {
107
+ changes.reusedDefinitions.push(change);
108
+ }
109
+ }
110
+ return {
111
+ mapping: new SingleSyncConfigBucketDefinitionMapping(definitions, parameterLookups),
112
+ changes
113
+ };
114
+ }
115
+ constructor(definitions = {}, parameterLookupMapping = {}) {
116
+ this.definitions = definitions;
117
+ this.parameterLookupMapping = parameterLookupMapping;
118
+ }
119
+ bucketSourceId(source) {
120
+ return this.bucketSourceIdByName(source.uniqueName);
121
+ }
122
+ bucketSourceIdByName(uniqueName) {
123
+ const defId = this.definitions[uniqueName];
124
+ if (defId == null) {
125
+ throw new ServiceAssertionError(`No mapping found for bucket source ${uniqueName}`);
126
+ }
127
+ return defId;
128
+ }
129
+ allBucketDefinitionIds() {
130
+ return Object.values(this.definitions);
131
+ }
132
+ bucketDefinitionEntries() {
133
+ return Object.entries(this.definitions).map(([name, id]) => ({
134
+ type: 'bucket_data',
135
+ name,
136
+ id
137
+ }));
138
+ }
139
+ allParameterIndexIds() {
140
+ return Object.values(this.parameterLookupMapping);
141
+ }
142
+ parameterIndexEntries() {
143
+ return Object.entries(this.parameterLookupMapping).map(([name, id]) => ({
144
+ type: 'parameter_lookup',
145
+ name,
146
+ id
147
+ }));
148
+ }
149
+ allDefinitionEntries() {
150
+ return [...this.bucketDefinitionEntries(), ...this.parameterIndexEntries()];
151
+ }
152
+ parameterLookupId(source) {
153
+ return this.parameterLookupIdByKey(parameterLookupKey(source.sourceId));
154
+ }
155
+ parameterLookupIdByKey(key) {
156
+ const defId = this.parameterLookupMapping[key];
157
+ if (defId == null) {
158
+ throw new ServiceAssertionError(`No mapping found for parameter lookup source ${key}`);
159
+ }
160
+ return defId;
161
+ }
162
+ serialize() {
163
+ return {
164
+ definitions: { ...this.definitions },
165
+ parameter_indexes: { ...this.parameterLookupMapping }
166
+ };
167
+ }
168
+ syncConfigIdsForSourceTable(selectedSyncConfigIds, _table, bucketDataSourceIds, parameterLookupSourceIds) {
169
+ return bucketDataSourceIds.length > 0 || parameterLookupSourceIds.length > 0 ? selectedSyncConfigIds : [];
170
+ }
171
+ snapshotBlockingSourceTablesFilter(_syncConfigId) {
172
+ const clauses = [];
173
+ const bucketDataSourceIds = this.allBucketDefinitionIds();
174
+ if (bucketDataSourceIds.length > 0) {
175
+ clauses.push({ bucket_data_source_ids: { $in: bucketDataSourceIds } });
176
+ }
177
+ const parameterLookupSourceIds = this.allParameterIndexIds();
178
+ if (parameterLookupSourceIds.length > 0) {
179
+ clauses.push({ parameter_lookup_source_ids: { $in: parameterLookupSourceIds } });
180
+ }
181
+ if (clauses.length == 0) {
182
+ return {
183
+ snapshot_done: false,
184
+ _id: { $exists: false }
185
+ };
186
+ }
187
+ return {
188
+ snapshot_done: false,
189
+ $or: clauses
190
+ };
191
+ }
192
+ }
193
+ /**
194
+ * A BucketDefinitionMapping across all SyncConfigs of one parse of a replication stream.
195
+ *
196
+ * Source lookups are strictly identity-based: a source that did not come from the parse
197
+ * this mapping was constructed with is an error. Unique names are not unique across sync
198
+ * configs in a replication stream, so there is deliberately no name-based fallback.
199
+ */
200
+ export class MultiSyncConfigBucketDefinitionMapping {
201
+ bucketDataSourceMappings = new WeakMap();
202
+ bucketDataSourceSyncConfigIdsById = new Map();
203
+ parameterLookupMappings = new WeakMap();
204
+ parameterLookupSyncConfigIdsById = new Map();
205
+ syncConfigsById = new Map();
206
+ mappings;
207
+ constructor(syncConfigs) {
208
+ this.mappings = syncConfigs.map((config) => config.mapping);
209
+ for (const config of syncConfigs) {
210
+ this.syncConfigsById.set(config.syncConfigId, config);
211
+ for (const source of config.syncConfig.config.bucketDataSources) {
212
+ this.bucketDataSourceMappings.set(source, config.mapping);
213
+ addSetEntry(this.bucketDataSourceSyncConfigIdsById, config.mapping.bucketSourceId(source), config.syncConfigId);
214
+ }
215
+ for (const source of config.syncConfig.config.bucketParameterLookupSources) {
216
+ this.parameterLookupMappings.set(source, config.mapping);
217
+ addSetEntry(this.parameterLookupSyncConfigIdsById, config.mapping.parameterLookupId(source), config.syncConfigId);
218
+ }
219
+ }
220
+ }
221
+ bucketSourceId(source) {
222
+ const mapping = this.bucketDataSourceMappings.get(source);
223
+ if (mapping == null) {
224
+ throw new ServiceAssertionError(`Bucket source ${source.uniqueName} is not associated with this parse of the sync configs`);
225
+ }
226
+ return mapping.bucketSourceId(source);
227
+ }
228
+ allBucketDefinitionIds() {
229
+ return [...new Set(this.mappings.flatMap((mapping) => mapping.allBucketDefinitionIds()))];
230
+ }
231
+ parameterLookupId(source) {
232
+ const mapping = this.parameterLookupMappings.get(source);
233
+ if (mapping == null) {
234
+ throw new ServiceAssertionError(`Parameter lookup source ${source.sourceId.lookupName}#${source.sourceId.queryId} is not associated with this parse of the sync configs`);
235
+ }
236
+ return mapping.parameterLookupId(source);
237
+ }
238
+ allParameterIndexIds() {
239
+ return [...new Set(this.mappings.flatMap((mapping) => mapping.allParameterIndexIds()))];
240
+ }
241
+ syncConfigIdsForSourceTable(_selectedSyncConfigIds, table, bucketDataSourceIds, parameterLookupSourceIds) {
242
+ const ids = new Set();
243
+ for (const sourceId of bucketDataSourceIds) {
244
+ addAll(ids, this.bucketDataSourceSyncConfigIdsById.get(sourceId));
245
+ }
246
+ for (const sourceId of parameterLookupSourceIds) {
247
+ addAll(ids, this.parameterLookupSyncConfigIdsById.get(sourceId));
248
+ }
249
+ for (const [syncConfigId, config] of this.syncConfigsById) {
250
+ if (config.syncConfig.config.tableTriggersEvent(table)) {
251
+ ids.add(syncConfigId);
252
+ }
253
+ }
254
+ return [...ids];
255
+ }
256
+ snapshotBlockingSourceTablesFilter(syncConfigId) {
257
+ const config = this.syncConfigsById.get(syncConfigId);
258
+ if (config == null) {
259
+ throw new ServiceAssertionError(`No mapping found for sync config ${syncConfigId}`);
260
+ }
261
+ return config.mapping.snapshotBlockingSourceTablesFilter(syncConfigId);
262
+ }
263
+ }
264
+ export function parameterLookupKey(id) {
265
+ return `${id.lookupName}#${id.queryId}`;
266
+ }
267
+ function addSetEntry(map, key, value) {
268
+ const existing = map.get(key) ?? new Set();
269
+ existing.add(value);
270
+ map.set(key, existing);
271
+ }
272
+ function addAll(target, values) {
273
+ for (const value of values ?? []) {
274
+ target.add(value);
275
+ }
276
+ }
277
+ //# sourceMappingURL=BucketDefinitionMapping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BucketDefinitionMapping.js","sourceRoot":"","sources":["../../../src/storage/implementation/BucketDefinitionMapping.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { Logger } from 'winston';
2
+ import { SerializedSyncPlan, UpdateSyncRulesOptions } from '../BucketStorageFactory.js';
3
+ /**
4
+ * Check if a sync config update can use incremental reprocessing.
5
+ */
6
+ export declare function isCompatible(existingPlans: (SerializedSyncPlan | null)[], updateConfig: UpdateSyncRulesOptions['config'], logger: Logger): boolean;
@@ -0,0 +1,31 @@
1
+ import { CompatibilityContext } from '@powersync/service-sync-rules';
2
+ /**
3
+ * Check if a sync config update can use incremental reprocessing.
4
+ */
5
+ export function isCompatible(existingPlans, updateConfig, logger) {
6
+ if (updateConfig.plan == null) {
7
+ // Only support sync streams with serialized plans
8
+ logger.info(`Not using current sync streams - incremental reprocessing not supported`);
9
+ return false;
10
+ }
11
+ // We don't check the storage version here - that is checked upstream.
12
+ if (existingPlans.length == 0) {
13
+ // Could technically be compatible, but there is no reason to re-use this stream.
14
+ return false;
15
+ }
16
+ if (existingPlans.some((plan) => plan == null)) {
17
+ // Only support sync streams with serialized plans
18
+ logger.info(`Existing replication stream not using current sync streams - incremental reprocessing not supported`);
19
+ return false;
20
+ }
21
+ // Technically we can compare the serialized compatibility versions? But this does not add much overhead.
22
+ const first = existingPlans[0];
23
+ const streamCompatibility = CompatibilityContext.deserialize(first.compatibility);
24
+ if (!streamCompatibility.equals(updateConfig.parsed.config.compatibility)) {
25
+ // Compatibility options must match
26
+ logger.info(`Compatibility options changed - incremental reprocessing not supported`);
27
+ return false;
28
+ }
29
+ return true;
30
+ }
31
+ //# sourceMappingURL=IncrementalReprocessingCompatibility.js.map
@@ -0,0 +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;AAIrE;;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,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { SyncConfigWithErrors } from '@powersync/service-sync-rules';
2
+ import { IncrementalMappingChanges, IncrementalMappingDefinitionChange, SingleSyncConfigBucketDefinitionMapping } from './BucketDefinitionMapping.js';
3
+ export interface IncrementalDefinitionLogEntry extends IncrementalMappingDefinitionChange {
4
+ sourceTables?: string[];
5
+ }
6
+ export interface IncrementalSyncConfigUpdateLog {
7
+ reusedDefinitions: IncrementalDefinitionLogEntry[];
8
+ addedDefinitions: IncrementalDefinitionLogEntry[];
9
+ droppedDefinitions: IncrementalDefinitionLogEntry[];
10
+ }
11
+ export declare function formatIncrementalSyncConfigUpdateLog(log: IncrementalSyncConfigUpdateLog): string;
12
+ export declare function describeIncrementalSyncConfigUpdate(options: {
13
+ activeMappings: SingleSyncConfigBucketDefinitionMapping[];
14
+ newMapping: SingleSyncConfigBucketDefinitionMapping;
15
+ newSyncConfig: SyncConfigWithErrors;
16
+ mappingChanges: IncrementalMappingChanges;
17
+ }): IncrementalSyncConfigUpdateLog;