@powersync/common 0.0.0-dev-20250526133243 → 0.0.0-dev-20250528152729
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/dist/bundle.mjs +3 -3
- package/lib/client/AbstractPowerSyncDatabase.d.ts +3 -32
- package/lib/client/AbstractPowerSyncDatabase.js +31 -133
- package/lib/client/ConnectionManager.d.ts +72 -0
- package/lib/client/ConnectionManager.js +161 -0
- package/lib/index.d.ts +13 -14
- package/lib/index.js +13 -14
- package/package.json +1 -1
|
@@ -5,6 +5,7 @@ import { SyncStatus } from '../db/crud/SyncStatus.js';
|
|
|
5
5
|
import { UploadQueueStats } from '../db/crud/UploadQueueStatus.js';
|
|
6
6
|
import { Schema } from '../db/schema/Schema.js';
|
|
7
7
|
import { BaseObserver } from '../utils/BaseObserver.js';
|
|
8
|
+
import { ConnectionManager } from './ConnectionManager.js';
|
|
8
9
|
import { SQLOpenFactory, SQLOpenOptions } from './SQLOpenFactory.js';
|
|
9
10
|
import { PowerSyncBackendConnector } from './connection/PowerSyncBackendConnector.js';
|
|
10
11
|
import { BucketStorageAdapter } from './sync/bucket/BucketStorageAdapter.js';
|
|
@@ -79,10 +80,6 @@ export interface PowerSyncCloseOptions {
|
|
|
79
80
|
*/
|
|
80
81
|
disconnect?: boolean;
|
|
81
82
|
}
|
|
82
|
-
type StoredConnectionOptions = {
|
|
83
|
-
connector: PowerSyncBackendConnector;
|
|
84
|
-
options: PowerSyncConnectionOptions;
|
|
85
|
-
};
|
|
86
83
|
export declare const DEFAULT_POWERSYNC_CLOSE_OPTIONS: PowerSyncCloseOptions;
|
|
87
84
|
export declare const DEFAULT_WATCH_THROTTLE_MS = 30;
|
|
88
85
|
export declare const DEFAULT_POWERSYNC_DB_OPTIONS: {
|
|
@@ -118,35 +115,13 @@ export declare abstract class AbstractPowerSyncDatabase extends BaseObserver<Pow
|
|
|
118
115
|
* Current connection status.
|
|
119
116
|
*/
|
|
120
117
|
currentStatus: SyncStatus;
|
|
121
|
-
syncStreamImplementation?: StreamingSyncImplementation;
|
|
122
118
|
sdkVersion: string;
|
|
123
119
|
protected bucketStorageAdapter: BucketStorageAdapter;
|
|
124
|
-
private syncStatusListenerDisposer?;
|
|
125
120
|
protected _isReadyPromise: Promise<void>;
|
|
121
|
+
protected connectionManager: ConnectionManager;
|
|
122
|
+
get syncStreamImplementation(): StreamingSyncImplementation | null;
|
|
126
123
|
protected _schema: Schema;
|
|
127
124
|
private _database;
|
|
128
|
-
/**
|
|
129
|
-
* Tracks active connection attempts
|
|
130
|
-
*/
|
|
131
|
-
protected connectingPromise: Promise<void> | null;
|
|
132
|
-
/**
|
|
133
|
-
* Tracks actively instantiating a streaming sync implementation.
|
|
134
|
-
*/
|
|
135
|
-
protected syncStreamInitPromise: Promise<void> | null;
|
|
136
|
-
/**
|
|
137
|
-
* Active disconnect operation. Calling disconnect multiple times
|
|
138
|
-
* will resolve to the same operation.
|
|
139
|
-
*/
|
|
140
|
-
protected disconnectingPromise: Promise<void> | null;
|
|
141
|
-
/**
|
|
142
|
-
* Tracks the last parameters supplied to `connect` calls.
|
|
143
|
-
* Calling `connect` multiple times in succession will result in:
|
|
144
|
-
* - 1 pending connection operation which will be aborted.
|
|
145
|
-
* - updating the last set of parameters while waiting for the pending
|
|
146
|
-
* attempt to be aborted
|
|
147
|
-
* - internally connecting with the last set of parameters
|
|
148
|
-
*/
|
|
149
|
-
protected pendingConnectionOptions: StoredConnectionOptions | null;
|
|
150
125
|
protected connectionMutex: Mutex;
|
|
151
126
|
constructor(options: PowerSyncDatabaseOptionsWithDBAdapter);
|
|
152
127
|
constructor(options: PowerSyncDatabaseOptionsWithOpenFactory);
|
|
@@ -222,7 +197,6 @@ export declare abstract class AbstractPowerSyncDatabase extends BaseObserver<Pow
|
|
|
222
197
|
* Locking here is mostly only important on web for multiple tab scenarios.
|
|
223
198
|
*/
|
|
224
199
|
protected runExclusive<T>(callback: () => Promise<T>): Promise<T>;
|
|
225
|
-
protected connectInternal(): Promise<void>;
|
|
226
200
|
/**
|
|
227
201
|
* Connects to stream of events from the PowerSync instance.
|
|
228
202
|
*/
|
|
@@ -233,8 +207,6 @@ export declare abstract class AbstractPowerSyncDatabase extends BaseObserver<Pow
|
|
|
233
207
|
* Use {@link connect} to connect again.
|
|
234
208
|
*/
|
|
235
209
|
disconnect(): Promise<void>;
|
|
236
|
-
protected disconnectInternal(): Promise<void>;
|
|
237
|
-
protected performDisconnect(): Promise<void>;
|
|
238
210
|
/**
|
|
239
211
|
* Disconnect and clear the database.
|
|
240
212
|
* Use this when logging out.
|
|
@@ -519,4 +491,3 @@ export declare abstract class AbstractPowerSyncDatabase extends BaseObserver<Pow
|
|
|
519
491
|
*/
|
|
520
492
|
private executeReadOnly;
|
|
521
493
|
}
|
|
522
|
-
export {};
|
|
@@ -9,6 +9,7 @@ import { BaseObserver } from '../utils/BaseObserver.js';
|
|
|
9
9
|
import { ControlledExecutor } from '../utils/ControlledExecutor.js';
|
|
10
10
|
import { throttleTrailing } from '../utils/async.js';
|
|
11
11
|
import { mutexRunExclusive } from '../utils/mutex.js';
|
|
12
|
+
import { ConnectionManager } from './ConnectionManager.js';
|
|
12
13
|
import { isDBAdapter, isSQLOpenFactory, isSQLOpenOptions } from './SQLOpenFactory.js';
|
|
13
14
|
import { runOnSchemaChange } from './runOnSchemaChange.js';
|
|
14
15
|
import { PSInternalTable } from './sync/bucket/BucketStorageAdapter.js';
|
|
@@ -59,35 +60,15 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
59
60
|
* Current connection status.
|
|
60
61
|
*/
|
|
61
62
|
currentStatus;
|
|
62
|
-
syncStreamImplementation;
|
|
63
63
|
sdkVersion;
|
|
64
64
|
bucketStorageAdapter;
|
|
65
|
-
syncStatusListenerDisposer;
|
|
66
65
|
_isReadyPromise;
|
|
66
|
+
connectionManager;
|
|
67
|
+
get syncStreamImplementation() {
|
|
68
|
+
return this.connectionManager.syncStreamImplementation;
|
|
69
|
+
}
|
|
67
70
|
_schema;
|
|
68
71
|
_database;
|
|
69
|
-
/**
|
|
70
|
-
* Tracks active connection attempts
|
|
71
|
-
*/
|
|
72
|
-
connectingPromise;
|
|
73
|
-
/**
|
|
74
|
-
* Tracks actively instantiating a streaming sync implementation.
|
|
75
|
-
*/
|
|
76
|
-
syncStreamInitPromise;
|
|
77
|
-
/**
|
|
78
|
-
* Active disconnect operation. Calling disconnect multiple times
|
|
79
|
-
* will resolve to the same operation.
|
|
80
|
-
*/
|
|
81
|
-
disconnectingPromise;
|
|
82
|
-
/**
|
|
83
|
-
* Tracks the last parameters supplied to `connect` calls.
|
|
84
|
-
* Calling `connect` multiple times in succession will result in:
|
|
85
|
-
* - 1 pending connection operation which will be aborted.
|
|
86
|
-
* - updating the last set of parameters while waiting for the pending
|
|
87
|
-
* attempt to be aborted
|
|
88
|
-
* - internally connecting with the last set of parameters
|
|
89
|
-
*/
|
|
90
|
-
pendingConnectionOptions;
|
|
91
72
|
connectionMutex;
|
|
92
73
|
constructor(options) {
|
|
93
74
|
super();
|
|
@@ -115,11 +96,31 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
115
96
|
this._schema = schema;
|
|
116
97
|
this.ready = false;
|
|
117
98
|
this.sdkVersion = '';
|
|
118
|
-
this.connectingPromise = null;
|
|
119
|
-
this.syncStreamInitPromise = null;
|
|
120
|
-
this.pendingConnectionOptions = null;
|
|
121
99
|
this.connectionMutex = new Mutex();
|
|
122
100
|
// Start async init
|
|
101
|
+
this.connectionManager = new ConnectionManager({
|
|
102
|
+
createSyncImplementation: async (connector, options) => {
|
|
103
|
+
await this.waitForReady();
|
|
104
|
+
return this.runExclusive(async () => {
|
|
105
|
+
const sync = this.generateSyncStreamImplementation(connector, this.resolvedConnectionOptions(options));
|
|
106
|
+
const onDispose = sync.registerListener({
|
|
107
|
+
statusChanged: (status) => {
|
|
108
|
+
this.currentStatus = new SyncStatus({
|
|
109
|
+
...status.toJSON(),
|
|
110
|
+
hasSynced: this.currentStatus?.hasSynced || !!status.lastSyncedAt
|
|
111
|
+
});
|
|
112
|
+
this.iterateListeners((cb) => cb.statusChanged?.(this.currentStatus));
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
await sync.waitForReady();
|
|
116
|
+
return {
|
|
117
|
+
sync,
|
|
118
|
+
onDispose
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
logger: this.logger
|
|
123
|
+
});
|
|
123
124
|
this._isReadyPromise = this.initialize();
|
|
124
125
|
}
|
|
125
126
|
/**
|
|
@@ -299,93 +300,11 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
299
300
|
runExclusive(callback) {
|
|
300
301
|
return this.connectionMutex.runExclusive(callback);
|
|
301
302
|
}
|
|
302
|
-
async connectInternal() {
|
|
303
|
-
let appliedOptions = null;
|
|
304
|
-
// This method ensures a disconnect before any connection attempt
|
|
305
|
-
await this.disconnectInternal();
|
|
306
|
-
/**
|
|
307
|
-
* This portion creates a sync implementation which can be racy when disconnecting or
|
|
308
|
-
* if multiple tabs on web are in use.
|
|
309
|
-
* This is protected in an exclusive lock.
|
|
310
|
-
* The promise tracks the creation which is used to synchronize disconnect attempts.
|
|
311
|
-
*/
|
|
312
|
-
this.syncStreamInitPromise = this.runExclusive(async () => {
|
|
313
|
-
if (this.closed) {
|
|
314
|
-
throw new Error('Cannot connect using a closed client');
|
|
315
|
-
}
|
|
316
|
-
// Always await this if present since we will be populating a new sync implementation shortly
|
|
317
|
-
await this.disconnectingPromise;
|
|
318
|
-
if (!this.pendingConnectionOptions) {
|
|
319
|
-
// A disconnect could have cleared this.
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
// get pending options and clear it in order for other connect attempts to queue other options
|
|
323
|
-
const { connector, options } = this.pendingConnectionOptions;
|
|
324
|
-
appliedOptions = options;
|
|
325
|
-
this.pendingConnectionOptions = null;
|
|
326
|
-
this.syncStreamImplementation = this.generateSyncStreamImplementation(connector, this.resolvedConnectionOptions(options));
|
|
327
|
-
this.syncStatusListenerDisposer = this.syncStreamImplementation.registerListener({
|
|
328
|
-
statusChanged: (status) => {
|
|
329
|
-
this.currentStatus = new SyncStatus({
|
|
330
|
-
...status.toJSON(),
|
|
331
|
-
hasSynced: this.currentStatus?.hasSynced || !!status.lastSyncedAt
|
|
332
|
-
});
|
|
333
|
-
this.iterateListeners((cb) => cb.statusChanged?.(this.currentStatus));
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
|
-
await this.syncStreamImplementation.waitForReady();
|
|
337
|
-
});
|
|
338
|
-
await this.syncStreamInitPromise;
|
|
339
|
-
this.syncStreamInitPromise = null;
|
|
340
|
-
if (!appliedOptions) {
|
|
341
|
-
// A disconnect could have cleared the options which did not create a syncStreamImplementation
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
// It might be possible that a disconnect triggered between the last check
|
|
345
|
-
// and this point. Awaiting here allows the sync stream to be cleared if disconnected.
|
|
346
|
-
await this.disconnectingPromise;
|
|
347
|
-
this.syncStreamImplementation?.triggerCrudUpload();
|
|
348
|
-
this.options.logger?.debug('Attempting to connect to PowerSync instance');
|
|
349
|
-
await this.syncStreamImplementation?.connect(appliedOptions);
|
|
350
|
-
}
|
|
351
303
|
/**
|
|
352
304
|
* Connects to stream of events from the PowerSync instance.
|
|
353
305
|
*/
|
|
354
306
|
async connect(connector, options) {
|
|
355
|
-
|
|
356
|
-
const hadPendingOptions = !!this.pendingConnectionOptions;
|
|
357
|
-
// Update pending options to the latest values
|
|
358
|
-
this.pendingConnectionOptions = {
|
|
359
|
-
connector,
|
|
360
|
-
options: options ?? {}
|
|
361
|
-
};
|
|
362
|
-
await this.waitForReady();
|
|
363
|
-
// Disconnecting here provides aborting in progress connection attempts.
|
|
364
|
-
// The connectInternal method will clear pending options once it starts connecting (with the options).
|
|
365
|
-
// We only need to trigger a disconnect here if we have already reached the point of connecting.
|
|
366
|
-
// If we do already have pending options, a disconnect has already been performed.
|
|
367
|
-
// The connectInternal method also does a sanity disconnect to prevent straggler connections.
|
|
368
|
-
if (!hadPendingOptions) {
|
|
369
|
-
await this.disconnectInternal();
|
|
370
|
-
}
|
|
371
|
-
// Triggers a connect which checks if pending options are available after the connect completes.
|
|
372
|
-
// The completion can be for a successful, unsuccessful or aborted connection attempt.
|
|
373
|
-
// If pending options are available another connection will be triggered.
|
|
374
|
-
const checkConnection = async () => {
|
|
375
|
-
if (this.pendingConnectionOptions) {
|
|
376
|
-
// Pending options have been placed while connecting.
|
|
377
|
-
// Need to reconnect.
|
|
378
|
-
this.connectingPromise = this.connectInternal().finally(checkConnection);
|
|
379
|
-
return this.connectingPromise;
|
|
380
|
-
}
|
|
381
|
-
else {
|
|
382
|
-
// Clear the connecting promise, done.
|
|
383
|
-
this.connectingPromise = null;
|
|
384
|
-
return;
|
|
385
|
-
}
|
|
386
|
-
};
|
|
387
|
-
this.connectingPromise ??= this.connectInternal().finally(checkConnection);
|
|
388
|
-
return this.connectingPromise;
|
|
307
|
+
return this.connectionManager.connect(connector, options);
|
|
389
308
|
}
|
|
390
309
|
/**
|
|
391
310
|
* Close the sync connection.
|
|
@@ -393,28 +312,7 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
393
312
|
* Use {@link connect} to connect again.
|
|
394
313
|
*/
|
|
395
314
|
async disconnect() {
|
|
396
|
-
|
|
397
|
-
// This will help abort pending connects
|
|
398
|
-
this.pendingConnectionOptions = null;
|
|
399
|
-
await this.disconnectInternal();
|
|
400
|
-
}
|
|
401
|
-
async disconnectInternal() {
|
|
402
|
-
if (this.disconnectingPromise) {
|
|
403
|
-
// A disconnect is already in progress
|
|
404
|
-
return this.disconnectingPromise;
|
|
405
|
-
}
|
|
406
|
-
// Wait if a sync stream implementation is being created before closing it
|
|
407
|
-
// (syncStreamImplementation must be assigned before we can properly dispose it)
|
|
408
|
-
await this.syncStreamInitPromise;
|
|
409
|
-
this.disconnectingPromise = this.performDisconnect();
|
|
410
|
-
await this.disconnectingPromise;
|
|
411
|
-
this.disconnectingPromise = null;
|
|
412
|
-
}
|
|
413
|
-
async performDisconnect() {
|
|
414
|
-
await this.syncStreamImplementation?.disconnect();
|
|
415
|
-
this.syncStatusListenerDisposer?.();
|
|
416
|
-
await this.syncStreamImplementation?.dispose();
|
|
417
|
-
this.syncStreamImplementation = undefined;
|
|
315
|
+
return this.connectionManager.disconnect();
|
|
418
316
|
}
|
|
419
317
|
/**
|
|
420
318
|
* Disconnect and clear the database.
|
|
@@ -453,7 +351,7 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
453
351
|
if (disconnect) {
|
|
454
352
|
await this.disconnect();
|
|
455
353
|
}
|
|
456
|
-
await this.
|
|
354
|
+
await this.connectionManager.close();
|
|
457
355
|
await this.database.close();
|
|
458
356
|
this.closed = true;
|
|
459
357
|
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { ILogger } from 'js-logger';
|
|
2
|
+
import { BaseListener, BaseObserver } from '../utils/BaseObserver.js';
|
|
3
|
+
import { PowerSyncBackendConnector } from './connection/PowerSyncBackendConnector.js';
|
|
4
|
+
import { PowerSyncConnectionOptions, StreamingSyncImplementation } from './sync/stream/AbstractStreamingSyncImplementation.js';
|
|
5
|
+
/**
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export interface ConnectionManagerSyncImplementationResult {
|
|
9
|
+
sync: StreamingSyncImplementation;
|
|
10
|
+
onDispose: () => Promise<void> | void;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
export interface ConnectionManagerOptions {
|
|
16
|
+
createSyncImplementation(connector: PowerSyncBackendConnector, options: PowerSyncConnectionOptions): Promise<ConnectionManagerSyncImplementationResult>;
|
|
17
|
+
logger: ILogger;
|
|
18
|
+
}
|
|
19
|
+
type StoredConnectionOptions = {
|
|
20
|
+
connector: PowerSyncBackendConnector;
|
|
21
|
+
options: PowerSyncConnectionOptions;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
export interface ConnectionManagerListener extends BaseListener {
|
|
27
|
+
syncStreamCreated: (sync: StreamingSyncImplementation) => void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
export declare class ConnectionManager extends BaseObserver<ConnectionManagerListener> {
|
|
33
|
+
protected options: ConnectionManagerOptions;
|
|
34
|
+
/**
|
|
35
|
+
* Tracks active connection attempts
|
|
36
|
+
*/
|
|
37
|
+
protected connectingPromise: Promise<void> | null;
|
|
38
|
+
/**
|
|
39
|
+
* Tracks actively instantiating a streaming sync implementation.
|
|
40
|
+
*/
|
|
41
|
+
protected syncStreamInitPromise: Promise<void> | null;
|
|
42
|
+
/**
|
|
43
|
+
* Active disconnect operation. Calling disconnect multiple times
|
|
44
|
+
* will resolve to the same operation.
|
|
45
|
+
*/
|
|
46
|
+
protected disconnectingPromise: Promise<void> | null;
|
|
47
|
+
/**
|
|
48
|
+
* Tracks the last parameters supplied to `connect` calls.
|
|
49
|
+
* Calling `connect` multiple times in succession will result in:
|
|
50
|
+
* - 1 pending connection operation which will be aborted.
|
|
51
|
+
* - updating the last set of parameters while waiting for the pending
|
|
52
|
+
* attempt to be aborted
|
|
53
|
+
* - internally connecting with the last set of parameters
|
|
54
|
+
*/
|
|
55
|
+
protected pendingConnectionOptions: StoredConnectionOptions | null;
|
|
56
|
+
syncStreamImplementation: StreamingSyncImplementation | null;
|
|
57
|
+
syncDisposer: (() => Promise<void> | void) | null;
|
|
58
|
+
constructor(options: ConnectionManagerOptions);
|
|
59
|
+
get logger(): ILogger;
|
|
60
|
+
close(): Promise<void>;
|
|
61
|
+
connect(connector: PowerSyncBackendConnector, options?: PowerSyncConnectionOptions): Promise<void>;
|
|
62
|
+
protected connectInternal(): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Close the sync connection.
|
|
65
|
+
*
|
|
66
|
+
* Use {@link connect} to connect again.
|
|
67
|
+
*/
|
|
68
|
+
disconnect(): Promise<void>;
|
|
69
|
+
protected disconnectInternal(): Promise<void>;
|
|
70
|
+
protected performDisconnect(): Promise<void>;
|
|
71
|
+
}
|
|
72
|
+
export {};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { BaseObserver } from '../utils/BaseObserver.js';
|
|
2
|
+
/**
|
|
3
|
+
* @internal
|
|
4
|
+
*/
|
|
5
|
+
export class ConnectionManager extends BaseObserver {
|
|
6
|
+
options;
|
|
7
|
+
/**
|
|
8
|
+
* Tracks active connection attempts
|
|
9
|
+
*/
|
|
10
|
+
connectingPromise;
|
|
11
|
+
/**
|
|
12
|
+
* Tracks actively instantiating a streaming sync implementation.
|
|
13
|
+
*/
|
|
14
|
+
syncStreamInitPromise;
|
|
15
|
+
/**
|
|
16
|
+
* Active disconnect operation. Calling disconnect multiple times
|
|
17
|
+
* will resolve to the same operation.
|
|
18
|
+
*/
|
|
19
|
+
disconnectingPromise;
|
|
20
|
+
/**
|
|
21
|
+
* Tracks the last parameters supplied to `connect` calls.
|
|
22
|
+
* Calling `connect` multiple times in succession will result in:
|
|
23
|
+
* - 1 pending connection operation which will be aborted.
|
|
24
|
+
* - updating the last set of parameters while waiting for the pending
|
|
25
|
+
* attempt to be aborted
|
|
26
|
+
* - internally connecting with the last set of parameters
|
|
27
|
+
*/
|
|
28
|
+
pendingConnectionOptions;
|
|
29
|
+
syncStreamImplementation;
|
|
30
|
+
syncDisposer;
|
|
31
|
+
constructor(options) {
|
|
32
|
+
super();
|
|
33
|
+
this.options = options;
|
|
34
|
+
this.connectingPromise = null;
|
|
35
|
+
this.syncStreamInitPromise = null;
|
|
36
|
+
this.disconnectingPromise = null;
|
|
37
|
+
this.pendingConnectionOptions = null;
|
|
38
|
+
this.syncStreamImplementation = null;
|
|
39
|
+
this.syncDisposer = null;
|
|
40
|
+
}
|
|
41
|
+
get logger() {
|
|
42
|
+
return this.options.logger;
|
|
43
|
+
}
|
|
44
|
+
async close() {
|
|
45
|
+
await this.syncDisposer?.();
|
|
46
|
+
}
|
|
47
|
+
async connect(connector, options) {
|
|
48
|
+
// Keep track if there were pending operations before this call
|
|
49
|
+
const hadPendingOptions = !!this.pendingConnectionOptions;
|
|
50
|
+
// Update pending options to the latest values
|
|
51
|
+
this.pendingConnectionOptions = {
|
|
52
|
+
connector,
|
|
53
|
+
options: options ?? {}
|
|
54
|
+
};
|
|
55
|
+
// Disconnecting here provides aborting in progress connection attempts.
|
|
56
|
+
// The connectInternal method will clear pending options once it starts connecting (with the options).
|
|
57
|
+
// We only need to trigger a disconnect here if we have already reached the point of connecting.
|
|
58
|
+
// If we do already have pending options, a disconnect has already been performed.
|
|
59
|
+
// The connectInternal method also does a sanity disconnect to prevent straggler connections.
|
|
60
|
+
// We should also disconnect if we have already completed a connection attempt.
|
|
61
|
+
if (!hadPendingOptions) {
|
|
62
|
+
await this.disconnectInternal();
|
|
63
|
+
}
|
|
64
|
+
// Triggers a connect which checks if pending options are available after the connect completes.
|
|
65
|
+
// The completion can be for a successful, unsuccessful or aborted connection attempt.
|
|
66
|
+
// If pending options are available another connection will be triggered.
|
|
67
|
+
const checkConnection = async () => {
|
|
68
|
+
if (this.pendingConnectionOptions) {
|
|
69
|
+
// Pending options have been placed while connecting.
|
|
70
|
+
// Need to reconnect.
|
|
71
|
+
this.connectingPromise = this.connectInternal().finally(checkConnection);
|
|
72
|
+
return this.connectingPromise;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// Clear the connecting promise, done.
|
|
76
|
+
this.connectingPromise = null;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
this.connectingPromise ??= this.connectInternal().finally(checkConnection);
|
|
81
|
+
return this.connectingPromise;
|
|
82
|
+
}
|
|
83
|
+
async connectInternal() {
|
|
84
|
+
let appliedOptions = null;
|
|
85
|
+
// This method ensures a disconnect before any connection attempt
|
|
86
|
+
await this.disconnectInternal();
|
|
87
|
+
/**
|
|
88
|
+
* This portion creates a sync implementation which can be racy when disconnecting or
|
|
89
|
+
* if multiple tabs on web are in use.
|
|
90
|
+
* This is protected in an exclusive lock.
|
|
91
|
+
* The promise tracks the creation which is used to synchronize disconnect attempts.
|
|
92
|
+
*/
|
|
93
|
+
this.syncStreamInitPromise = new Promise(async (resolve, reject) => {
|
|
94
|
+
try {
|
|
95
|
+
if (!this.pendingConnectionOptions) {
|
|
96
|
+
this.logger.debug('No pending connection options found, not creating sync stream implementation');
|
|
97
|
+
// A disconnect could have cleared this.
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const { connector, options } = this.pendingConnectionOptions;
|
|
101
|
+
appliedOptions = options;
|
|
102
|
+
this.pendingConnectionOptions = null;
|
|
103
|
+
const { sync, onDispose } = await this.options.createSyncImplementation(connector, options);
|
|
104
|
+
this.iterateListeners((l) => l.syncStreamCreated?.(sync));
|
|
105
|
+
this.syncStreamImplementation = sync;
|
|
106
|
+
this.syncDisposer = onDispose;
|
|
107
|
+
await this.syncStreamImplementation.waitForReady();
|
|
108
|
+
resolve();
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
reject(error);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
await this.syncStreamInitPromise;
|
|
115
|
+
this.syncStreamInitPromise = null;
|
|
116
|
+
if (!appliedOptions) {
|
|
117
|
+
// A disconnect could have cleared the options which did not create a syncStreamImplementation
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
// It might be possible that a disconnect triggered between the last check
|
|
121
|
+
// and this point. Awaiting here allows the sync stream to be cleared if disconnected.
|
|
122
|
+
await this.disconnectingPromise;
|
|
123
|
+
this.logger.debug('Attempting to connect to PowerSync instance');
|
|
124
|
+
await this.syncStreamImplementation?.connect(appliedOptions);
|
|
125
|
+
this.syncStreamImplementation?.triggerCrudUpload();
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Close the sync connection.
|
|
129
|
+
*
|
|
130
|
+
* Use {@link connect} to connect again.
|
|
131
|
+
*/
|
|
132
|
+
async disconnect() {
|
|
133
|
+
// This will help abort pending connects
|
|
134
|
+
this.pendingConnectionOptions = null;
|
|
135
|
+
await this.disconnectInternal();
|
|
136
|
+
}
|
|
137
|
+
async disconnectInternal() {
|
|
138
|
+
if (this.disconnectingPromise) {
|
|
139
|
+
// A disconnect is already in progress
|
|
140
|
+
return this.disconnectingPromise;
|
|
141
|
+
}
|
|
142
|
+
// Wait if a sync stream implementation is being created before closing it
|
|
143
|
+
// (syncStreamImplementation must be assigned before we can properly dispose it)
|
|
144
|
+
await this.syncStreamInitPromise;
|
|
145
|
+
this.disconnectingPromise = this.performDisconnect();
|
|
146
|
+
await this.disconnectingPromise;
|
|
147
|
+
this.disconnectingPromise = null;
|
|
148
|
+
}
|
|
149
|
+
async performDisconnect() {
|
|
150
|
+
// Keep reference to the sync stream implementation and disposer
|
|
151
|
+
// The class members will be cleared before we trigger the disconnect
|
|
152
|
+
// to prevent any further calls to the sync stream implementation.
|
|
153
|
+
const sync = this.syncStreamImplementation;
|
|
154
|
+
this.syncStreamImplementation = null;
|
|
155
|
+
const disposer = this.syncDisposer;
|
|
156
|
+
this.syncDisposer = null;
|
|
157
|
+
await sync?.disconnect();
|
|
158
|
+
await sync?.dispose();
|
|
159
|
+
await disposer?.();
|
|
160
|
+
}
|
|
161
|
+
}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,35 +1,34 @@
|
|
|
1
1
|
export * from './client/AbstractPowerSyncDatabase.js';
|
|
2
2
|
export * from './client/AbstractPowerSyncOpenFactory.js';
|
|
3
|
-
export
|
|
3
|
+
export { compilableQueryWatch, CompilableQueryWatchHandler } from './client/compilableQueryWatch.js';
|
|
4
4
|
export * from './client/connection/PowerSyncBackendConnector.js';
|
|
5
5
|
export * from './client/connection/PowerSyncCredentials.js';
|
|
6
|
-
export
|
|
6
|
+
export { MAX_OP_ID } from './client/constants.js';
|
|
7
7
|
export { runOnSchemaChange } from './client/runOnSchemaChange.js';
|
|
8
|
-
export
|
|
9
|
-
export
|
|
10
|
-
export * from './client/sync/bucket/SqliteBucketStorage.js';
|
|
8
|
+
export * from './client/SQLOpenFactory.js';
|
|
9
|
+
export * from './client/sync/bucket/BucketStorageAdapter.js';
|
|
11
10
|
export * from './client/sync/bucket/CrudBatch.js';
|
|
11
|
+
export { CrudEntry, OpId, UpdateType } from './client/sync/bucket/CrudEntry.js';
|
|
12
12
|
export * from './client/sync/bucket/CrudTransaction.js';
|
|
13
|
+
export * from './client/sync/bucket/OplogEntry.js';
|
|
14
|
+
export * from './client/sync/bucket/OpType.js';
|
|
15
|
+
export * from './client/sync/bucket/SqliteBucketStorage.js';
|
|
13
16
|
export * from './client/sync/bucket/SyncDataBatch.js';
|
|
14
17
|
export * from './client/sync/bucket/SyncDataBucket.js';
|
|
15
|
-
export * from './client/sync/bucket/OpType.js';
|
|
16
|
-
export * from './client/sync/bucket/OplogEntry.js';
|
|
17
18
|
export * from './client/sync/stream/AbstractRemote.js';
|
|
18
19
|
export * from './client/sync/stream/AbstractStreamingSyncImplementation.js';
|
|
19
20
|
export * from './client/sync/stream/streaming-sync-types.js';
|
|
20
|
-
export
|
|
21
|
+
export * from './client/ConnectionManager.js';
|
|
21
22
|
export { ProgressWithOperations, SyncProgress } from './db/crud/SyncProgress.js';
|
|
22
23
|
export * from './db/crud/SyncStatus.js';
|
|
23
24
|
export * from './db/crud/UploadQueueStatus.js';
|
|
24
|
-
export * from './db/
|
|
25
|
-
export * from './db/schema/
|
|
25
|
+
export * from './db/DBAdapter.js';
|
|
26
|
+
export * from './db/schema/Column.js';
|
|
26
27
|
export * from './db/schema/Index.js';
|
|
27
28
|
export * from './db/schema/IndexedColumn.js';
|
|
28
|
-
export * from './db/schema/
|
|
29
|
+
export * from './db/schema/Schema.js';
|
|
30
|
+
export * from './db/schema/Table.js';
|
|
29
31
|
export * from './db/schema/TableV2.js';
|
|
30
|
-
export * from './db/crud/SyncStatus.js';
|
|
31
|
-
export * from './db/crud/UploadQueueStatus.js';
|
|
32
|
-
export * from './db/DBAdapter.js';
|
|
33
32
|
export * from './utils/AbortOperation.js';
|
|
34
33
|
export * from './utils/BaseObserver.js';
|
|
35
34
|
export * from './utils/DataStream.js';
|
package/lib/index.js
CHANGED
|
@@ -1,35 +1,34 @@
|
|
|
1
1
|
export * from './client/AbstractPowerSyncDatabase.js';
|
|
2
2
|
export * from './client/AbstractPowerSyncOpenFactory.js';
|
|
3
|
-
export
|
|
3
|
+
export { compilableQueryWatch } from './client/compilableQueryWatch.js';
|
|
4
4
|
export * from './client/connection/PowerSyncBackendConnector.js';
|
|
5
5
|
export * from './client/connection/PowerSyncCredentials.js';
|
|
6
|
-
export
|
|
6
|
+
export { MAX_OP_ID } from './client/constants.js';
|
|
7
7
|
export { runOnSchemaChange } from './client/runOnSchemaChange.js';
|
|
8
|
-
export
|
|
9
|
-
export
|
|
10
|
-
export * from './client/sync/bucket/SqliteBucketStorage.js';
|
|
8
|
+
export * from './client/SQLOpenFactory.js';
|
|
9
|
+
export * from './client/sync/bucket/BucketStorageAdapter.js';
|
|
11
10
|
export * from './client/sync/bucket/CrudBatch.js';
|
|
11
|
+
export { CrudEntry, UpdateType } from './client/sync/bucket/CrudEntry.js';
|
|
12
12
|
export * from './client/sync/bucket/CrudTransaction.js';
|
|
13
|
+
export * from './client/sync/bucket/OplogEntry.js';
|
|
14
|
+
export * from './client/sync/bucket/OpType.js';
|
|
15
|
+
export * from './client/sync/bucket/SqliteBucketStorage.js';
|
|
13
16
|
export * from './client/sync/bucket/SyncDataBatch.js';
|
|
14
17
|
export * from './client/sync/bucket/SyncDataBucket.js';
|
|
15
|
-
export * from './client/sync/bucket/OpType.js';
|
|
16
|
-
export * from './client/sync/bucket/OplogEntry.js';
|
|
17
18
|
export * from './client/sync/stream/AbstractRemote.js';
|
|
18
19
|
export * from './client/sync/stream/AbstractStreamingSyncImplementation.js';
|
|
19
20
|
export * from './client/sync/stream/streaming-sync-types.js';
|
|
20
|
-
export
|
|
21
|
+
export * from './client/ConnectionManager.js';
|
|
21
22
|
export { SyncProgress } from './db/crud/SyncProgress.js';
|
|
22
23
|
export * from './db/crud/SyncStatus.js';
|
|
23
24
|
export * from './db/crud/UploadQueueStatus.js';
|
|
24
|
-
export * from './db/
|
|
25
|
-
export * from './db/schema/
|
|
25
|
+
export * from './db/DBAdapter.js';
|
|
26
|
+
export * from './db/schema/Column.js';
|
|
26
27
|
export * from './db/schema/Index.js';
|
|
27
28
|
export * from './db/schema/IndexedColumn.js';
|
|
28
|
-
export * from './db/schema/
|
|
29
|
+
export * from './db/schema/Schema.js';
|
|
30
|
+
export * from './db/schema/Table.js';
|
|
29
31
|
export * from './db/schema/TableV2.js';
|
|
30
|
-
export * from './db/crud/SyncStatus.js';
|
|
31
|
-
export * from './db/crud/UploadQueueStatus.js';
|
|
32
|
-
export * from './db/DBAdapter.js';
|
|
33
32
|
export * from './utils/AbortOperation.js';
|
|
34
33
|
export * from './utils/BaseObserver.js';
|
|
35
34
|
export * from './utils/DataStream.js';
|