@powersync/common 1.23.0 → 1.25.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.
@@ -10,7 +10,7 @@ import { PowerSyncBackendConnector } from './connection/PowerSyncBackendConnecto
10
10
  import { BucketStorageAdapter } from './sync/bucket/BucketStorageAdapter.js';
11
11
  import { CrudBatch } from './sync/bucket/CrudBatch.js';
12
12
  import { CrudTransaction } from './sync/bucket/CrudTransaction.js';
13
- import { type AdditionalConnectionOptions, type PowerSyncConnectionOptions, StreamingSyncImplementation, StreamingSyncImplementationListener, type RequiredAdditionalConnectionOptions } from './sync/stream/AbstractStreamingSyncImplementation.js';
13
+ import { StreamingSyncImplementation, StreamingSyncImplementationListener, type AdditionalConnectionOptions, type PowerSyncConnectionOptions, type RequiredAdditionalConnectionOptions } from './sync/stream/AbstractStreamingSyncImplementation.js';
14
14
  export interface DisconnectAndClearOptions {
15
15
  /** When set to false, data in local-only tables is preserved. */
16
16
  clearLocal?: boolean;
@@ -141,6 +141,7 @@ export declare abstract class AbstractPowerSyncDatabase extends BaseObserver<Pow
141
141
  * Whether a connection to the PowerSync service is currently open.
142
142
  */
143
143
  get connected(): boolean;
144
+ get connecting(): boolean;
144
145
  /**
145
146
  * Opens the DBAdapter given open options using a default open factory
146
147
  */
@@ -152,9 +153,18 @@ export declare abstract class AbstractPowerSyncDatabase extends BaseObserver<Pow
152
153
  */
153
154
  waitForReady(): Promise<void>;
154
155
  /**
156
+ * Wait for the first sync operation to complete.
157
+ *
158
+ * @argument request Either an abort signal (after which the promise will complete regardless of
159
+ * whether a full sync was completed) or an object providing an abort signal and a priority target.
160
+ * When a priority target is set, the promise may complete when all buckets with the given (or higher)
161
+ * priorities have been synchronized. This can be earlier than a complete sync.
155
162
  * @returns A promise which will resolve once the first full sync has completed.
156
163
  */
157
- waitForFirstSync(signal?: AbortSignal): Promise<void>;
164
+ waitForFirstSync(request?: AbortSignal | {
165
+ signal?: AbortSignal;
166
+ priority?: number;
167
+ }): Promise<void>;
158
168
  /**
159
169
  * Allows for extended implementations to execute custom initialization
160
170
  * logic as part of the total init process
@@ -9,12 +9,12 @@ import { ControlledExecutor } from '../utils/ControlledExecutor.js';
9
9
  import { mutexRunExclusive } from '../utils/mutex.js';
10
10
  import { throttleTrailing } from '../utils/throttle.js';
11
11
  import { isDBAdapter, isSQLOpenFactory, isSQLOpenOptions } from './SQLOpenFactory.js';
12
+ import { runOnSchemaChange } from './runOnSchemaChange.js';
12
13
  import { PSInternalTable } from './sync/bucket/BucketStorageAdapter.js';
13
14
  import { CrudBatch } from './sync/bucket/CrudBatch.js';
14
15
  import { CrudEntry } from './sync/bucket/CrudEntry.js';
15
16
  import { CrudTransaction } from './sync/bucket/CrudTransaction.js';
16
17
  import { DEFAULT_CRUD_UPLOAD_THROTTLE_MS, DEFAULT_RETRY_DELAY_MS } from './sync/stream/AbstractStreamingSyncImplementation.js';
17
- import { runOnSchemaChange } from './runOnSchemaChange.js';
18
18
  const POWERSYNC_TABLE_MATCH = /(^ps_data__|^ps_data_local__)/;
19
19
  const DEFAULT_DISCONNECT_CLEAR_OPTIONS = {
20
20
  clearLocal: true
@@ -42,6 +42,10 @@ export const DEFAULT_LOCK_TIMEOUT_MS = 120_000; // 2 mins
42
42
  export const isPowerSyncDatabaseOptionsWithSettings = (test) => {
43
43
  return typeof test == 'object' && isSQLOpenOptions(test.database);
44
44
  };
45
+ /**
46
+ * The priority used by the core extension to indicate that a full sync was completed.
47
+ */
48
+ const FULL_SYNC_PRIORITY = 2147483647;
45
49
  export class AbstractPowerSyncDatabase extends BaseObserver {
46
50
  options;
47
51
  /**
@@ -114,6 +118,9 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
114
118
  get connected() {
115
119
  return this.currentStatus?.connected || false;
116
120
  }
121
+ get connecting() {
122
+ return this.currentStatus?.connecting || false;
123
+ }
117
124
  /**
118
125
  * @returns A promise which will resolve once initialization is completed.
119
126
  */
@@ -124,16 +131,27 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
124
131
  await this._isReadyPromise;
125
132
  }
126
133
  /**
134
+ * Wait for the first sync operation to complete.
135
+ *
136
+ * @argument request Either an abort signal (after which the promise will complete regardless of
137
+ * whether a full sync was completed) or an object providing an abort signal and a priority target.
138
+ * When a priority target is set, the promise may complete when all buckets with the given (or higher)
139
+ * priorities have been synchronized. This can be earlier than a complete sync.
127
140
  * @returns A promise which will resolve once the first full sync has completed.
128
141
  */
129
- async waitForFirstSync(signal) {
130
- if (this.currentStatus.hasSynced) {
142
+ async waitForFirstSync(request) {
143
+ const signal = request instanceof AbortSignal ? request : request?.signal;
144
+ const priority = request && 'priority' in request ? request.priority : undefined;
145
+ const statusMatches = priority === undefined
146
+ ? (status) => status.hasSynced
147
+ : (status) => status.statusForPriority(priority).hasSynced;
148
+ if (statusMatches(this.currentStatus)) {
131
149
  return;
132
150
  }
133
151
  return new Promise((resolve) => {
134
152
  const dispose = this.registerListener({
135
153
  statusChanged: (status) => {
136
- if (status.hasSynced) {
154
+ if (statusMatches(status)) {
137
155
  dispose();
138
156
  resolve();
139
157
  }
@@ -174,19 +192,36 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
174
192
  .map((n) => parseInt(n));
175
193
  }
176
194
  catch (e) {
177
- throw new Error(`Unsupported powersync extension version. Need >=0.2.0 <1.0.0, got: ${this.sdkVersion}. Details: ${e.message}`);
195
+ throw new Error(`Unsupported powersync extension version. Need >=0.3.11 <1.0.0, got: ${this.sdkVersion}. Details: ${e.message}`);
178
196
  }
179
- // Validate >=0.2.0 <1.0.0
180
- if (versionInts[0] != 0 || versionInts[1] < 2 || versionInts[2] < 0) {
181
- throw new Error(`Unsupported powersync extension version. Need >=0.2.0 <1.0.0, got: ${this.sdkVersion}`);
197
+ // Validate >=0.3.11 <1.0.0
198
+ if (versionInts[0] != 0 || versionInts[1] < 3 || (versionInts[1] == 3 && versionInts[2] < 11)) {
199
+ throw new Error(`Unsupported powersync extension version. Need >=0.3.11 <1.0.0, got: ${this.sdkVersion}`);
182
200
  }
183
201
  }
184
202
  async updateHasSynced() {
185
- const result = await this.database.get('SELECT powersync_last_synced_at() as synced_at');
186
- const hasSynced = result.synced_at != null;
187
- const syncedAt = result.synced_at != null ? new Date(result.synced_at + 'Z') : undefined;
188
- if (hasSynced != this.currentStatus.hasSynced) {
189
- this.currentStatus = new SyncStatus({ ...this.currentStatus.toJSON(), hasSynced, lastSyncedAt: syncedAt });
203
+ const result = await this.database.getAll('SELECT priority, last_synced_at FROM ps_sync_state ORDER BY priority DESC');
204
+ let lastCompleteSync;
205
+ const priorityStatusEntries = [];
206
+ for (const { priority, last_synced_at } of result) {
207
+ const parsedDate = new Date(last_synced_at + 'Z');
208
+ if (priority == FULL_SYNC_PRIORITY) {
209
+ // This lowest-possible priority represents a complete sync.
210
+ lastCompleteSync = parsedDate;
211
+ }
212
+ else {
213
+ priorityStatusEntries.push({ priority, hasSynced: true, lastSyncedAt: parsedDate });
214
+ }
215
+ }
216
+ const hasSynced = lastCompleteSync != null;
217
+ const updatedStatus = new SyncStatus({
218
+ ...this.currentStatus.toJSON(),
219
+ hasSynced,
220
+ priorityStatusEntries,
221
+ lastSyncedAt: lastCompleteSync
222
+ });
223
+ if (!updatedStatus.isEqual(this.currentStatus)) {
224
+ this.currentStatus = updatedStatus;
190
225
  this.iterateListeners((l) => l.statusChanged?.(this.currentStatus));
191
226
  }
192
227
  }
@@ -242,7 +277,7 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
242
277
  const { retryDelayMs, crudUploadThrottleMs } = this.resolvedConnectionOptions(options);
243
278
  this.syncStreamImplementation = this.generateSyncStreamImplementation(connector, {
244
279
  retryDelayMs,
245
- crudUploadThrottleMs,
280
+ crudUploadThrottleMs
246
281
  });
247
282
  this.syncStatusListenerDisposer = this.syncStreamImplementation.registerListener({
248
283
  statusChanged: (status) => {
@@ -299,12 +334,15 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
299
334
  */
300
335
  async close(options = DEFAULT_POWERSYNC_CLOSE_OPTIONS) {
301
336
  await this.waitForReady();
337
+ if (this.closed) {
338
+ return;
339
+ }
302
340
  const { disconnect } = options;
303
341
  if (disconnect) {
304
342
  await this.disconnect();
305
343
  }
306
344
  await this.syncStreamImplementation?.dispose();
307
- this.database.close();
345
+ await this.database.close();
308
346
  this.closed = true;
309
347
  }
310
348
  /**
@@ -2,6 +2,10 @@ import { BaseListener, BaseObserver, Disposable } from '../../../utils/BaseObser
2
2
  import { CrudBatch } from './CrudBatch.js';
3
3
  import { CrudEntry, OpId } from './CrudEntry.js';
4
4
  import { SyncDataBatch } from './SyncDataBatch.js';
5
+ export interface BucketDescription {
6
+ name: string;
7
+ priority: number;
8
+ }
5
9
  export interface Checkpoint {
6
10
  last_op_id: OpId;
7
11
  buckets: BucketChecksum[];
@@ -25,6 +29,7 @@ export interface SyncLocalDatabaseResult {
25
29
  }
26
30
  export interface BucketChecksum {
27
31
  bucket: string;
32
+ priority?: number;
28
33
  /**
29
34
  * 32-bit unsigned hash.
30
35
  */
@@ -51,7 +56,7 @@ export interface BucketStorageAdapter extends BaseObserver<BucketStorageListener
51
56
  setTargetCheckpoint(checkpoint: Checkpoint): Promise<void>;
52
57
  startSession(): void;
53
58
  getBucketStates(): Promise<BucketState[]>;
54
- syncLocalDatabase(checkpoint: Checkpoint): Promise<{
59
+ syncLocalDatabase(checkpoint: Checkpoint, priority?: number): Promise<{
55
60
  checkpointValid: boolean;
56
61
  ready: boolean;
57
62
  failures?: any[];
@@ -37,14 +37,14 @@ export declare class SqliteBucketStorage extends BaseObserver<BucketStorageListe
37
37
  */
38
38
  private deleteBucket;
39
39
  hasCompletedSync(): Promise<boolean>;
40
- syncLocalDatabase(checkpoint: Checkpoint): Promise<SyncLocalDatabaseResult>;
40
+ syncLocalDatabase(checkpoint: Checkpoint, priority?: number): Promise<SyncLocalDatabaseResult>;
41
41
  /**
42
42
  * Atomically update the local state to the current checkpoint.
43
43
  *
44
44
  * This includes creating new tables, dropping old tables, and copying data over from the oplog.
45
45
  */
46
46
  private updateObjectsFromBuckets;
47
- validateChecksums(checkpoint: Checkpoint): Promise<SyncLocalDatabaseResult>;
47
+ validateChecksums(checkpoint: Checkpoint, priority: number | undefined): Promise<SyncLocalDatabaseResult>;
48
48
  /**
49
49
  * Force a compact, for tests.
50
50
  */
@@ -106,8 +106,8 @@ export class SqliteBucketStorage extends BaseObserver {
106
106
  }
107
107
  return completed;
108
108
  }
109
- async syncLocalDatabase(checkpoint) {
110
- const r = await this.validateChecksums(checkpoint);
109
+ async syncLocalDatabase(checkpoint, priority) {
110
+ const r = await this.validateChecksums(checkpoint, priority);
111
111
  if (!r.checkpointValid) {
112
112
  this.logger.error('Checksums failed for', r.checkpointFailures);
113
113
  for (const b of r.checkpointFailures ?? []) {
@@ -115,17 +115,21 @@ export class SqliteBucketStorage extends BaseObserver {
115
115
  }
116
116
  return { ready: false, checkpointValid: false, checkpointFailures: r.checkpointFailures };
117
117
  }
118
- const bucketNames = checkpoint.buckets.map((b) => b.bucket);
118
+ const buckets = checkpoint.buckets;
119
+ if (priority !== undefined) {
120
+ buckets.filter((b) => hasMatchingPriority(priority, b));
121
+ }
122
+ const bucketNames = buckets.map((b) => b.bucket);
119
123
  await this.writeTransaction(async (tx) => {
120
124
  await tx.execute(`UPDATE ps_buckets SET last_op = ? WHERE name IN (SELECT json_each.value FROM json_each(?))`, [
121
125
  checkpoint.last_op_id,
122
126
  JSON.stringify(bucketNames)
123
127
  ]);
124
- if (checkpoint.write_checkpoint) {
128
+ if (priority == null && checkpoint.write_checkpoint) {
125
129
  await tx.execute("UPDATE ps_buckets SET last_op = ? WHERE name = '$local'", [checkpoint.write_checkpoint]);
126
130
  }
127
131
  });
128
- const valid = await this.updateObjectsFromBuckets(checkpoint);
132
+ const valid = await this.updateObjectsFromBuckets(checkpoint, priority);
129
133
  if (!valid) {
130
134
  this.logger.debug('Not at a consistent checkpoint - cannot update local db');
131
135
  return { ready: false, checkpointValid: true };
@@ -141,19 +145,36 @@ export class SqliteBucketStorage extends BaseObserver {
141
145
  *
142
146
  * This includes creating new tables, dropping old tables, and copying data over from the oplog.
143
147
  */
144
- async updateObjectsFromBuckets(checkpoint) {
148
+ async updateObjectsFromBuckets(checkpoint, priority) {
149
+ let arg = '';
150
+ if (priority !== undefined) {
151
+ const affectedBuckets = [];
152
+ for (const desc of checkpoint.buckets) {
153
+ if (hasMatchingPriority(priority, desc)) {
154
+ affectedBuckets.push(desc.bucket);
155
+ }
156
+ }
157
+ arg = JSON.stringify({ priority, buckets: affectedBuckets });
158
+ }
145
159
  return this.writeTransaction(async (tx) => {
146
160
  const { insertId: result } = await tx.execute('INSERT INTO powersync_operations(op, data) VALUES(?, ?)', [
147
161
  'sync_local',
148
- ''
162
+ arg
149
163
  ]);
150
164
  return result == 1;
151
165
  });
152
166
  }
153
- async validateChecksums(checkpoint) {
154
- const rs = await this.db.execute('SELECT powersync_validate_checkpoint(?) as result', [JSON.stringify(checkpoint)]);
167
+ async validateChecksums(checkpoint, priority) {
168
+ if (priority !== undefined) {
169
+ // Only validate the buckets within the priority we care about
170
+ const newBuckets = checkpoint.buckets.filter((cs) => hasMatchingPriority(priority, cs));
171
+ checkpoint = { ...checkpoint, buckets: newBuckets };
172
+ }
173
+ const rs = await this.db.execute('SELECT powersync_validate_checkpoint(?) as result', [
174
+ JSON.stringify({ ...checkpoint })
175
+ ]);
155
176
  const resultItem = rs.rows?.item(0);
156
- this.logger.debug('validateChecksums result item', resultItem);
177
+ this.logger.debug('validateChecksums priority, checkpoint, result item', priority, checkpoint, resultItem);
157
178
  if (!resultItem) {
158
179
  return {
159
180
  checkpointValid: false,
@@ -304,3 +325,6 @@ export class SqliteBucketStorage extends BaseObserver {
304
325
  // No-op for now
305
326
  }
306
327
  }
328
+ function hasMatchingPriority(priority, bucket) {
329
+ return bucket.priority != null && bucket.priority <= priority;
330
+ }
@@ -16,6 +16,21 @@ export type SyncStreamOptions = {
16
16
  abortSignal?: AbortSignal;
17
17
  fetchOptions?: Request;
18
18
  };
19
+ export declare enum FetchStrategy {
20
+ /**
21
+ * Queues multiple sync events before processing, reducing round-trips.
22
+ * This comes at the cost of more processing overhead, which may cause ACK timeouts on older/weaker devices for big enough datasets.
23
+ */
24
+ Buffered = "buffered",
25
+ /**
26
+ * Processes each sync event immediately before requesting the next.
27
+ * This reduces processing overhead and improves real-time responsiveness.
28
+ */
29
+ Sequential = "sequential"
30
+ }
31
+ export type SocketSyncStreamOptions = SyncStreamOptions & {
32
+ fetchStrategy: FetchStrategy;
33
+ };
19
34
  export type FetchImplementation = typeof fetch;
20
35
  /**
21
36
  * Class wrapper for providing a fetch implementation.
@@ -72,7 +87,7 @@ export declare abstract class AbstractRemote {
72
87
  /**
73
88
  * Connects to the sync/stream websocket endpoint
74
89
  */
75
- socketStream(options: SyncStreamOptions): Promise<DataStream<StreamingSyncLine>>;
90
+ socketStream(options: SocketSyncStreamOptions): Promise<DataStream<StreamingSyncLine>>;
76
91
  /**
77
92
  * Connects to the sync/stream http endpoint
78
93
  */
@@ -3,19 +3,32 @@ import ndjsonStream from 'can-ndjson-stream';
3
3
  import Logger from 'js-logger';
4
4
  import { RSocketConnector } from 'rsocket-core';
5
5
  import { WebsocketClientTransport } from 'rsocket-websocket-client';
6
+ import PACKAGE from '../../../../package.json' with { type: 'json' };
6
7
  import { AbortOperation } from '../../../utils/AbortOperation.js';
7
8
  import { DataStream } from '../../../utils/DataStream.js';
8
- import { version as POWERSYNC_JS_VERSION } from '../../../../package.json';
9
9
  const POWERSYNC_TRAILING_SLASH_MATCH = /\/+$/;
10
+ const POWERSYNC_JS_VERSION = PACKAGE.version;
10
11
  // Refresh at least 30 sec before it expires
11
12
  const REFRESH_CREDENTIALS_SAFETY_PERIOD_MS = 30_000;
12
- const SYNC_QUEUE_REQUEST_N = 10;
13
13
  const SYNC_QUEUE_REQUEST_LOW_WATER = 5;
14
14
  // Keep alive message is sent every period
15
15
  const KEEP_ALIVE_MS = 20_000;
16
16
  // The ACK must be received in this period
17
17
  const KEEP_ALIVE_LIFETIME_MS = 30_000;
18
18
  export const DEFAULT_REMOTE_LOGGER = Logger.get('PowerSyncRemote');
19
+ export var FetchStrategy;
20
+ (function (FetchStrategy) {
21
+ /**
22
+ * Queues multiple sync events before processing, reducing round-trips.
23
+ * This comes at the cost of more processing overhead, which may cause ACK timeouts on older/weaker devices for big enough datasets.
24
+ */
25
+ FetchStrategy["Buffered"] = "buffered";
26
+ /**
27
+ * Processes each sync event immediately before requesting the next.
28
+ * This reduces processing overhead and improves real-time responsiveness.
29
+ */
30
+ FetchStrategy["Sequential"] = "sequential";
31
+ })(FetchStrategy || (FetchStrategy = {}));
19
32
  /**
20
33
  * Class wrapper for providing a fetch implementation.
21
34
  * The class wrapper is used to distinguish the fetchImplementation
@@ -144,7 +157,8 @@ export class AbstractRemote {
144
157
  * Connects to the sync/stream websocket endpoint
145
158
  */
146
159
  async socketStream(options) {
147
- const { path } = options;
160
+ const { path, fetchStrategy = FetchStrategy.Buffered } = options;
161
+ const syncQueueRequestSize = fetchStrategy == FetchStrategy.Buffered ? 10 : 1;
148
162
  const request = await this.buildRequest(path);
149
163
  const bson = await this.getBSON();
150
164
  // Add the user agent in the setup payload - we can't set custom
@@ -197,7 +211,7 @@ export class AbstractRemote {
197
211
  // Helps to prevent double close scenarios
198
212
  rsocket.onClose(() => (socketIsClosed = true));
199
213
  // We initially request this amount and expect these to arrive eventually
200
- let pendingEventsCount = SYNC_QUEUE_REQUEST_N;
214
+ let pendingEventsCount = syncQueueRequestSize;
201
215
  const disposeClosedListener = stream.registerListener({
202
216
  closed: () => {
203
217
  closeSocket();
@@ -211,7 +225,7 @@ export class AbstractRemote {
211
225
  metadata: Buffer.from(bson.serialize({
212
226
  path
213
227
  }))
214
- }, SYNC_QUEUE_REQUEST_N, // The initial N amount
228
+ }, syncQueueRequestSize, // The initial N amount
215
229
  {
216
230
  onError: (e) => {
217
231
  // Don't log closed as an error
@@ -250,10 +264,10 @@ export class AbstractRemote {
250
264
  const l = stream.registerListener({
251
265
  lowWater: async () => {
252
266
  // Request to fill up the queue
253
- const required = SYNC_QUEUE_REQUEST_N - pendingEventsCount;
267
+ const required = syncQueueRequestSize - pendingEventsCount;
254
268
  if (required > 0) {
255
- socket.request(SYNC_QUEUE_REQUEST_N - pendingEventsCount);
256
- pendingEventsCount = SYNC_QUEUE_REQUEST_N;
269
+ socket.request(syncQueueRequestSize - pendingEventsCount);
270
+ pendingEventsCount = syncQueueRequestSize;
257
271
  }
258
272
  },
259
273
  closed: () => {
@@ -2,7 +2,7 @@ import Logger, { ILogger } from 'js-logger';
2
2
  import { SyncStatus, SyncStatusOptions } from '../../../db/crud/SyncStatus.js';
3
3
  import { BaseListener, BaseObserver, Disposable } from '../../../utils/BaseObserver.js';
4
4
  import { BucketStorageAdapter } from '../bucket/BucketStorageAdapter.js';
5
- import { AbstractRemote } from './AbstractRemote.js';
5
+ import { AbstractRemote, FetchStrategy } from './AbstractRemote.js';
6
6
  import { StreamingSyncRequestParameterType } from './streaming-sync-types.js';
7
7
  export declare enum LockType {
8
8
  CRUD = "crud",
@@ -56,6 +56,10 @@ export interface BaseConnectionOptions {
56
56
  * Defaults to a HTTP streaming connection.
57
57
  */
58
58
  connectionMethod?: SyncStreamConnectionMethod;
59
+ /**
60
+ * The fetch strategy to use when streaming updates from the PowerSync backend instance.
61
+ */
62
+ fetchStrategy?: FetchStrategy;
59
63
  /**
60
64
  * These parameters are passed to the sync rules, and will be available under the`user_parameters` object.
61
65
  */
@@ -95,6 +99,7 @@ export interface StreamingSyncImplementation extends BaseObserver<StreamingSyncI
95
99
  triggerCrudUpload: () => void;
96
100
  waitForReady(): Promise<void>;
97
101
  waitForStatus(status: SyncStatusOptions): Promise<void>;
102
+ waitUntilStatusMatches(predicate: (status: SyncStatus) => boolean): Promise<void>;
98
103
  }
99
104
  export declare const DEFAULT_CRUD_UPLOAD_THROTTLE_MS = 1000;
100
105
  export declare const DEFAULT_RETRY_DELAY_MS = 5000;
@@ -116,6 +121,7 @@ export declare abstract class AbstractStreamingSyncImplementation extends BaseOb
116
121
  constructor(options: AbstractStreamingSyncImplementationOptions);
117
122
  waitForReady(): Promise<void>;
118
123
  waitForStatus(status: SyncStatusOptions): Promise<void>;
124
+ waitUntilStatusMatches(predicate: (status: SyncStatus) => boolean): Promise<void>;
119
125
  get lastSyncedAt(): Date | undefined;
120
126
  get isConnected(): boolean;
121
127
  protected get logger(): Logger.ILogger;
@@ -130,6 +136,7 @@ export declare abstract class AbstractStreamingSyncImplementation extends BaseOb
130
136
  * @deprecated use [connect instead]
131
137
  */
132
138
  streamingSync(signal?: AbortSignal, options?: PowerSyncConnectionOptions): Promise<void>;
139
+ private collectLocalBucketState;
133
140
  protected streamingSyncIteration(signal: AbortSignal, options?: PowerSyncConnectionOptions): Promise<{
134
141
  retry?: boolean;
135
142
  }>;