@powersync/common 1.27.0 → 1.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundle.mjs +8 -3
- package/lib/client/AbstractPowerSyncDatabase.d.ts +78 -5
- package/lib/client/AbstractPowerSyncDatabase.js +84 -11
- package/lib/client/sync/stream/AbstractRemote.d.ts +8 -0
- package/lib/client/sync/stream/AbstractRemote.js +8 -2
- package/lib/client/sync/stream/AbstractStreamingSyncImplementation.d.ts +3 -3
- package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js +65 -61
- package/lib/db/crud/SyncStatus.d.ts +55 -14
- package/lib/db/crud/SyncStatus.js +55 -14
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/utils/Logger.d.ts +31 -0
- package/lib/utils/Logger.js +36 -0
- package/lib/utils/{throttle.d.ts → async.d.ts} +1 -0
- package/lib/utils/{throttle.js → async.js} +10 -0
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@ import Logger from 'js-logger';
|
|
|
2
2
|
import { SyncStatus } from '../../../db/crud/SyncStatus.js';
|
|
3
3
|
import { AbortOperation } from '../../../utils/AbortOperation.js';
|
|
4
4
|
import { BaseObserver } from '../../../utils/BaseObserver.js';
|
|
5
|
-
import { throttleLeadingTrailing } from '../../../utils/
|
|
5
|
+
import { onAbortPromise, throttleLeadingTrailing } from '../../../utils/async.js';
|
|
6
6
|
import { SyncDataBucket } from '../bucket/SyncDataBucket.js';
|
|
7
7
|
import { FetchStrategy } from './AbstractRemote.js';
|
|
8
8
|
import { isStreamingKeepalive, isStreamingSyncCheckpoint, isStreamingSyncCheckpointComplete, isStreamingSyncCheckpointDiff, isStreamingSyncCheckpointPartiallyComplete, isStreamingSyncData } from './streaming-sync-types.js';
|
|
@@ -39,6 +39,7 @@ export class AbstractStreamingSyncImplementation extends BaseObserver {
|
|
|
39
39
|
abortController;
|
|
40
40
|
crudUpdateListener;
|
|
41
41
|
streamingSyncPromise;
|
|
42
|
+
pendingCrudUpload;
|
|
42
43
|
syncStatus;
|
|
43
44
|
triggerCrudUpload;
|
|
44
45
|
constructor(options) {
|
|
@@ -55,10 +56,15 @@ export class AbstractStreamingSyncImplementation extends BaseObserver {
|
|
|
55
56
|
});
|
|
56
57
|
this.abortController = null;
|
|
57
58
|
this.triggerCrudUpload = throttleLeadingTrailing(() => {
|
|
58
|
-
if (!this.syncStatus.connected || this.
|
|
59
|
+
if (!this.syncStatus.connected || this.pendingCrudUpload != null) {
|
|
59
60
|
return;
|
|
60
61
|
}
|
|
61
|
-
this.
|
|
62
|
+
this.pendingCrudUpload = new Promise((resolve) => {
|
|
63
|
+
this._uploadAllCrud().finally(() => {
|
|
64
|
+
this.pendingCrudUpload = undefined;
|
|
65
|
+
resolve();
|
|
66
|
+
});
|
|
67
|
+
});
|
|
62
68
|
}, this.options.crudUploadThrottleMs);
|
|
63
69
|
}
|
|
64
70
|
async waitForReady() { }
|
|
@@ -280,16 +286,8 @@ The next upload iteration will be delayed.`);
|
|
|
280
286
|
if (signal?.aborted) {
|
|
281
287
|
break;
|
|
282
288
|
}
|
|
283
|
-
|
|
284
|
-
if
|
|
285
|
-
/**
|
|
286
|
-
* A sync error ocurred that we cannot recover from here.
|
|
287
|
-
* This loop must terminate.
|
|
288
|
-
* The nestedAbortController will close any open network requests and streams below.
|
|
289
|
-
*/
|
|
290
|
-
break;
|
|
291
|
-
}
|
|
292
|
-
// Continue immediately
|
|
289
|
+
await this.streamingSyncIteration(nestedAbortController.signal, options);
|
|
290
|
+
// Continue immediately, streamingSyncIteration will wait before completing if necessary.
|
|
293
291
|
}
|
|
294
292
|
catch (ex) {
|
|
295
293
|
/**
|
|
@@ -341,7 +339,7 @@ The next upload iteration will be delayed.`);
|
|
|
341
339
|
return [req, localDescriptions];
|
|
342
340
|
}
|
|
343
341
|
async streamingSyncIteration(signal, options) {
|
|
344
|
-
|
|
342
|
+
await this.obtainLock({
|
|
345
343
|
type: LockType.SYNC,
|
|
346
344
|
signal,
|
|
347
345
|
callback: async () => {
|
|
@@ -384,7 +382,7 @@ The next upload iteration will be delayed.`);
|
|
|
384
382
|
const line = await stream.read();
|
|
385
383
|
if (!line) {
|
|
386
384
|
// The stream has closed while waiting
|
|
387
|
-
return
|
|
385
|
+
return;
|
|
388
386
|
}
|
|
389
387
|
// A connection is active and messages are being received
|
|
390
388
|
if (!this.syncStatus.connected) {
|
|
@@ -413,30 +411,12 @@ The next upload iteration will be delayed.`);
|
|
|
413
411
|
await this.options.adapter.setTargetCheckpoint(targetCheckpoint);
|
|
414
412
|
}
|
|
415
413
|
else if (isStreamingSyncCheckpointComplete(line)) {
|
|
416
|
-
this.
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
// This means checksums failed. Start again with a new checkpoint.
|
|
420
|
-
// TODO: better back-off
|
|
421
|
-
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
422
|
-
return { retry: true };
|
|
423
|
-
}
|
|
424
|
-
else if (!result.ready) {
|
|
425
|
-
// Checksums valid, but need more data for a consistent checkpoint.
|
|
426
|
-
// Continue waiting.
|
|
427
|
-
// landing here the whole time
|
|
414
|
+
const result = await this.applyCheckpoint(targetCheckpoint, signal);
|
|
415
|
+
if (result.endIteration) {
|
|
416
|
+
return;
|
|
428
417
|
}
|
|
429
|
-
else {
|
|
418
|
+
else if (result.applied) {
|
|
430
419
|
appliedCheckpoint = targetCheckpoint;
|
|
431
|
-
this.logger.debug('validated checkpoint', appliedCheckpoint);
|
|
432
|
-
this.updateSyncStatus({
|
|
433
|
-
connected: true,
|
|
434
|
-
lastSyncedAt: new Date(),
|
|
435
|
-
dataFlow: {
|
|
436
|
-
downloading: false,
|
|
437
|
-
downloadError: undefined
|
|
438
|
-
}
|
|
439
|
-
});
|
|
440
420
|
}
|
|
441
421
|
validatedCheckpoint = targetCheckpoint;
|
|
442
422
|
}
|
|
@@ -448,10 +428,11 @@ The next upload iteration will be delayed.`);
|
|
|
448
428
|
// This means checksums failed. Start again with a new checkpoint.
|
|
449
429
|
// TODO: better back-off
|
|
450
430
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
451
|
-
return
|
|
431
|
+
return;
|
|
452
432
|
}
|
|
453
433
|
else if (!result.ready) {
|
|
454
|
-
//
|
|
434
|
+
// If we have pending uploads, we can't complete new checkpoints outside of priority 0.
|
|
435
|
+
// We'll resolve this for a complete checkpoint.
|
|
455
436
|
}
|
|
456
437
|
else {
|
|
457
438
|
// We'll keep on downloading, but can report that this priority is synced now.
|
|
@@ -522,7 +503,7 @@ The next upload iteration will be delayed.`);
|
|
|
522
503
|
* (uses the same one), this should have some delay.
|
|
523
504
|
*/
|
|
524
505
|
await this.delayRetry();
|
|
525
|
-
return
|
|
506
|
+
return;
|
|
526
507
|
}
|
|
527
508
|
this.triggerCrudUpload();
|
|
528
509
|
}
|
|
@@ -539,38 +520,61 @@ The next upload iteration will be delayed.`);
|
|
|
539
520
|
});
|
|
540
521
|
}
|
|
541
522
|
else if (validatedCheckpoint === targetCheckpoint) {
|
|
542
|
-
const result = await this.
|
|
543
|
-
if (
|
|
544
|
-
|
|
545
|
-
// TODO: better back-off
|
|
546
|
-
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
547
|
-
return { retry: false };
|
|
523
|
+
const result = await this.applyCheckpoint(targetCheckpoint, signal);
|
|
524
|
+
if (result.endIteration) {
|
|
525
|
+
return;
|
|
548
526
|
}
|
|
549
|
-
else if (
|
|
550
|
-
// Checksums valid, but need more data for a consistent checkpoint.
|
|
551
|
-
// Continue waiting.
|
|
552
|
-
}
|
|
553
|
-
else {
|
|
527
|
+
else if (result.applied) {
|
|
554
528
|
appliedCheckpoint = targetCheckpoint;
|
|
555
|
-
this.updateSyncStatus({
|
|
556
|
-
connected: true,
|
|
557
|
-
lastSyncedAt: new Date(),
|
|
558
|
-
priorityStatusEntries: [],
|
|
559
|
-
dataFlow: {
|
|
560
|
-
downloading: false,
|
|
561
|
-
downloadError: undefined
|
|
562
|
-
}
|
|
563
|
-
});
|
|
564
529
|
}
|
|
565
530
|
}
|
|
566
531
|
}
|
|
567
532
|
}
|
|
568
533
|
this.logger.debug('Stream input empty');
|
|
569
534
|
// Connection closed. Likely due to auth issue.
|
|
570
|
-
return
|
|
535
|
+
return;
|
|
571
536
|
}
|
|
572
537
|
});
|
|
573
538
|
}
|
|
539
|
+
async applyCheckpoint(checkpoint, abort) {
|
|
540
|
+
let result = await this.options.adapter.syncLocalDatabase(checkpoint);
|
|
541
|
+
const pending = this.pendingCrudUpload;
|
|
542
|
+
if (!result.checkpointValid) {
|
|
543
|
+
this.logger.debug('Checksum mismatch in checkpoint, will reconnect');
|
|
544
|
+
// This means checksums failed. Start again with a new checkpoint.
|
|
545
|
+
// TODO: better back-off
|
|
546
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
547
|
+
return { applied: false, endIteration: true };
|
|
548
|
+
}
|
|
549
|
+
else if (!result.ready && pending != null) {
|
|
550
|
+
// We have pending entries in the local upload queue or are waiting to confirm a write
|
|
551
|
+
// checkpoint, which prevented this checkpoint from applying. Wait for that to complete and
|
|
552
|
+
// try again.
|
|
553
|
+
this.logger.debug('Could not apply checkpoint due to local data. Waiting for in-progress upload before retrying.');
|
|
554
|
+
await Promise.race([pending, onAbortPromise(abort)]);
|
|
555
|
+
if (abort.aborted) {
|
|
556
|
+
return { applied: false, endIteration: true };
|
|
557
|
+
}
|
|
558
|
+
// Try again now that uploads have completed.
|
|
559
|
+
result = await this.options.adapter.syncLocalDatabase(checkpoint);
|
|
560
|
+
}
|
|
561
|
+
if (result.checkpointValid && result.ready) {
|
|
562
|
+
this.logger.debug('validated checkpoint', checkpoint);
|
|
563
|
+
this.updateSyncStatus({
|
|
564
|
+
connected: true,
|
|
565
|
+
lastSyncedAt: new Date(),
|
|
566
|
+
dataFlow: {
|
|
567
|
+
downloading: false,
|
|
568
|
+
downloadError: undefined
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
return { applied: true, endIteration: false };
|
|
572
|
+
}
|
|
573
|
+
else {
|
|
574
|
+
this.logger.debug('Could not apply checkpoint. Waiting for next sync complete line.');
|
|
575
|
+
return { applied: false, endIteration: false };
|
|
576
|
+
}
|
|
577
|
+
}
|
|
574
578
|
updateSyncStatus(options) {
|
|
575
579
|
const updatedStatus = new SyncStatus({
|
|
576
580
|
connected: options.connected ?? this.syncStatus.connected,
|
|
@@ -30,22 +30,38 @@ export declare class SyncStatus {
|
|
|
30
30
|
protected options: SyncStatusOptions;
|
|
31
31
|
constructor(options: SyncStatusOptions);
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
33
|
+
* Indicates if the client is currently connected to the PowerSync service.
|
|
34
|
+
*
|
|
35
|
+
* @returns {boolean} True if connected, false otherwise. Defaults to false if not specified.
|
|
34
36
|
*/
|
|
35
37
|
get connected(): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Indicates if the client is in the process of establishing a connection to the PowerSync service.
|
|
40
|
+
*
|
|
41
|
+
* @returns {boolean} True if connecting, false otherwise. Defaults to false if not specified.
|
|
42
|
+
*/
|
|
36
43
|
get connecting(): boolean;
|
|
37
44
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
45
|
+
* Time that a last sync has fully completed, if any.
|
|
46
|
+
* This timestamp is reset to null after a restart of the PowerSync service.
|
|
47
|
+
*
|
|
48
|
+
* @returns {Date | undefined} The timestamp of the last successful sync, or undefined if no sync has completed.
|
|
40
49
|
*/
|
|
41
50
|
get lastSyncedAt(): Date | undefined;
|
|
42
51
|
/**
|
|
43
|
-
* Indicates whether there has been at least one full sync
|
|
44
|
-
*
|
|
52
|
+
* Indicates whether there has been at least one full sync completed since initialization.
|
|
53
|
+
*
|
|
54
|
+
* @returns {boolean | undefined} True if at least one sync has completed, false if no sync has completed,
|
|
55
|
+
* or undefined when the state is still being loaded from the database.
|
|
45
56
|
*/
|
|
46
57
|
get hasSynced(): boolean | undefined;
|
|
47
58
|
/**
|
|
48
|
-
*
|
|
59
|
+
* Provides the current data flow status regarding uploads and downloads.
|
|
60
|
+
*
|
|
61
|
+
* @returns {SyncDataFlowStatus} An object containing:
|
|
62
|
+
* - downloading: True if actively downloading changes (only when connected is also true)
|
|
63
|
+
* - uploading: True if actively uploading changes
|
|
64
|
+
* Defaults to {downloading: false, uploading: false} if not specified.
|
|
49
65
|
*/
|
|
50
66
|
get dataFlowStatus(): Partial<{
|
|
51
67
|
downloading: boolean;
|
|
@@ -63,27 +79,52 @@ export declare class SyncStatus {
|
|
|
63
79
|
uploadError?: Error;
|
|
64
80
|
}>;
|
|
65
81
|
/**
|
|
66
|
-
*
|
|
82
|
+
* Provides sync status information for all bucket priorities, sorted by priority (highest first).
|
|
83
|
+
*
|
|
84
|
+
* @returns {SyncPriorityStatus[]} An array of status entries for different sync priority levels,
|
|
85
|
+
* sorted with highest priorities (lower numbers) first.
|
|
67
86
|
*/
|
|
68
87
|
get priorityStatusEntries(): SyncPriorityStatus[];
|
|
69
88
|
/**
|
|
70
|
-
* Reports a pair of {@link SyncStatus#hasSynced} and {@link SyncStatus#lastSyncedAt} fields
|
|
71
|
-
*
|
|
89
|
+
* Reports the sync status (a pair of {@link SyncStatus#hasSynced} and {@link SyncStatus#lastSyncedAt} fields)
|
|
90
|
+
* for a specific bucket priority level.
|
|
72
91
|
*
|
|
73
92
|
* When buckets with different priorities are declared, PowerSync may choose to synchronize higher-priority
|
|
74
93
|
* buckets first. When a consistent view over all buckets for all priorities up until the given priority is
|
|
75
94
|
* reached, PowerSync makes data from those buckets available before lower-priority buckets have finished
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
95
|
+
* syncing.
|
|
96
|
+
*
|
|
97
|
+
* This method returns the status for the requested priority or the next higher priority level that has
|
|
98
|
+
* status information available. This is because when PowerSync makes data for a given priority available,
|
|
99
|
+
* all buckets in higher-priorities are guaranteed to be consistent with that checkpoint.
|
|
100
|
+
*
|
|
101
|
+
* For example, if PowerSync just finished synchronizing buckets in priority level 3, calling this method
|
|
80
102
|
* with a priority of 1 may return information for priority level 3.
|
|
81
103
|
*
|
|
82
|
-
* @param priority The bucket priority for which the status should be reported
|
|
104
|
+
* @param {number} priority The bucket priority for which the status should be reported
|
|
105
|
+
* @returns {SyncPriorityStatus} Status information for the requested priority level or the next higher level with available status
|
|
83
106
|
*/
|
|
84
107
|
statusForPriority(priority: number): SyncPriorityStatus;
|
|
108
|
+
/**
|
|
109
|
+
* Compares this SyncStatus instance with another to determine if they are equal.
|
|
110
|
+
* Equality is determined by comparing the serialized JSON representation of both instances.
|
|
111
|
+
*
|
|
112
|
+
* @param {SyncStatus} status The SyncStatus instance to compare against
|
|
113
|
+
* @returns {boolean} True if the instances are considered equal, false otherwise
|
|
114
|
+
*/
|
|
85
115
|
isEqual(status: SyncStatus): boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Creates a human-readable string representation of the current sync status.
|
|
118
|
+
* Includes information about connection state, sync completion, and data flow.
|
|
119
|
+
*
|
|
120
|
+
* @returns {string} A string representation of the sync status
|
|
121
|
+
*/
|
|
86
122
|
getMessage(): string;
|
|
123
|
+
/**
|
|
124
|
+
* Serializes the SyncStatus instance to a plain object.
|
|
125
|
+
*
|
|
126
|
+
* @returns {SyncStatusOptions} A plain object representation of the sync status
|
|
127
|
+
*/
|
|
87
128
|
toJSON(): SyncStatusOptions;
|
|
88
129
|
private static comparePriorities;
|
|
89
130
|
}
|
|
@@ -4,30 +4,46 @@ export class SyncStatus {
|
|
|
4
4
|
this.options = options;
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Indicates if the client is currently connected to the PowerSync service.
|
|
8
|
+
*
|
|
9
|
+
* @returns {boolean} True if connected, false otherwise. Defaults to false if not specified.
|
|
8
10
|
*/
|
|
9
11
|
get connected() {
|
|
10
12
|
return this.options.connected ?? false;
|
|
11
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Indicates if the client is in the process of establishing a connection to the PowerSync service.
|
|
16
|
+
*
|
|
17
|
+
* @returns {boolean} True if connecting, false otherwise. Defaults to false if not specified.
|
|
18
|
+
*/
|
|
12
19
|
get connecting() {
|
|
13
20
|
return this.options.connecting ?? false;
|
|
14
21
|
}
|
|
15
22
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
23
|
+
* Time that a last sync has fully completed, if any.
|
|
24
|
+
* This timestamp is reset to null after a restart of the PowerSync service.
|
|
25
|
+
*
|
|
26
|
+
* @returns {Date | undefined} The timestamp of the last successful sync, or undefined if no sync has completed.
|
|
18
27
|
*/
|
|
19
28
|
get lastSyncedAt() {
|
|
20
29
|
return this.options.lastSyncedAt;
|
|
21
30
|
}
|
|
22
31
|
/**
|
|
23
|
-
* Indicates whether there has been at least one full sync
|
|
24
|
-
*
|
|
32
|
+
* Indicates whether there has been at least one full sync completed since initialization.
|
|
33
|
+
*
|
|
34
|
+
* @returns {boolean | undefined} True if at least one sync has completed, false if no sync has completed,
|
|
35
|
+
* or undefined when the state is still being loaded from the database.
|
|
25
36
|
*/
|
|
26
37
|
get hasSynced() {
|
|
27
38
|
return this.options.hasSynced;
|
|
28
39
|
}
|
|
29
40
|
/**
|
|
30
|
-
*
|
|
41
|
+
* Provides the current data flow status regarding uploads and downloads.
|
|
42
|
+
*
|
|
43
|
+
* @returns {SyncDataFlowStatus} An object containing:
|
|
44
|
+
* - downloading: True if actively downloading changes (only when connected is also true)
|
|
45
|
+
* - uploading: True if actively uploading changes
|
|
46
|
+
* Defaults to {downloading: false, uploading: false} if not specified.
|
|
31
47
|
*/
|
|
32
48
|
get dataFlowStatus() {
|
|
33
49
|
return (this.options.dataFlow ?? {
|
|
@@ -43,25 +59,32 @@ export class SyncStatus {
|
|
|
43
59
|
});
|
|
44
60
|
}
|
|
45
61
|
/**
|
|
46
|
-
*
|
|
62
|
+
* Provides sync status information for all bucket priorities, sorted by priority (highest first).
|
|
63
|
+
*
|
|
64
|
+
* @returns {SyncPriorityStatus[]} An array of status entries for different sync priority levels,
|
|
65
|
+
* sorted with highest priorities (lower numbers) first.
|
|
47
66
|
*/
|
|
48
67
|
get priorityStatusEntries() {
|
|
49
68
|
return (this.options.priorityStatusEntries ?? []).slice().sort(SyncStatus.comparePriorities);
|
|
50
69
|
}
|
|
51
70
|
/**
|
|
52
|
-
* Reports a pair of {@link SyncStatus#hasSynced} and {@link SyncStatus#lastSyncedAt} fields
|
|
53
|
-
*
|
|
71
|
+
* Reports the sync status (a pair of {@link SyncStatus#hasSynced} and {@link SyncStatus#lastSyncedAt} fields)
|
|
72
|
+
* for a specific bucket priority level.
|
|
54
73
|
*
|
|
55
74
|
* When buckets with different priorities are declared, PowerSync may choose to synchronize higher-priority
|
|
56
75
|
* buckets first. When a consistent view over all buckets for all priorities up until the given priority is
|
|
57
76
|
* reached, PowerSync makes data from those buckets available before lower-priority buckets have finished
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
77
|
+
* syncing.
|
|
78
|
+
*
|
|
79
|
+
* This method returns the status for the requested priority or the next higher priority level that has
|
|
80
|
+
* status information available. This is because when PowerSync makes data for a given priority available,
|
|
81
|
+
* all buckets in higher-priorities are guaranteed to be consistent with that checkpoint.
|
|
82
|
+
*
|
|
83
|
+
* For example, if PowerSync just finished synchronizing buckets in priority level 3, calling this method
|
|
62
84
|
* with a priority of 1 may return information for priority level 3.
|
|
63
85
|
*
|
|
64
|
-
* @param priority The bucket priority for which the status should be reported
|
|
86
|
+
* @param {number} priority The bucket priority for which the status should be reported
|
|
87
|
+
* @returns {SyncPriorityStatus} Status information for the requested priority level or the next higher level with available status
|
|
65
88
|
*/
|
|
66
89
|
statusForPriority(priority) {
|
|
67
90
|
// priorityStatusEntries are sorted by ascending priorities (so higher numbers to lower numbers).
|
|
@@ -78,13 +101,31 @@ export class SyncStatus {
|
|
|
78
101
|
hasSynced: this.hasSynced
|
|
79
102
|
};
|
|
80
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Compares this SyncStatus instance with another to determine if they are equal.
|
|
106
|
+
* Equality is determined by comparing the serialized JSON representation of both instances.
|
|
107
|
+
*
|
|
108
|
+
* @param {SyncStatus} status The SyncStatus instance to compare against
|
|
109
|
+
* @returns {boolean} True if the instances are considered equal, false otherwise
|
|
110
|
+
*/
|
|
81
111
|
isEqual(status) {
|
|
82
112
|
return JSON.stringify(this.options) == JSON.stringify(status.options);
|
|
83
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Creates a human-readable string representation of the current sync status.
|
|
116
|
+
* Includes information about connection state, sync completion, and data flow.
|
|
117
|
+
*
|
|
118
|
+
* @returns {string} A string representation of the sync status
|
|
119
|
+
*/
|
|
84
120
|
getMessage() {
|
|
85
121
|
const dataFlow = this.dataFlowStatus;
|
|
86
122
|
return `SyncStatus<connected: ${this.connected} connecting: ${this.connecting} lastSyncedAt: ${this.lastSyncedAt} hasSynced: ${this.hasSynced}. Downloading: ${dataFlow.downloading}. Uploading: ${dataFlow.uploading}. UploadError: ${dataFlow.uploadError}, DownloadError?: ${dataFlow.downloadError}>`;
|
|
87
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Serializes the SyncStatus instance to a plain object.
|
|
126
|
+
*
|
|
127
|
+
* @returns {SyncStatusOptions} A plain object representation of the sync status
|
|
128
|
+
*/
|
|
88
129
|
toJSON() {
|
|
89
130
|
return {
|
|
90
131
|
connected: this.connected,
|
package/lib/index.d.ts
CHANGED
|
@@ -32,5 +32,6 @@ export * from './db/DBAdapter.js';
|
|
|
32
32
|
export * from './utils/AbortOperation.js';
|
|
33
33
|
export * from './utils/BaseObserver.js';
|
|
34
34
|
export * from './utils/DataStream.js';
|
|
35
|
+
export * from './utils/Logger.js';
|
|
35
36
|
export * from './utils/parseQuery.js';
|
|
36
37
|
export * from './types/types.js';
|
package/lib/index.js
CHANGED
|
@@ -32,5 +32,6 @@ export * from './db/DBAdapter.js';
|
|
|
32
32
|
export * from './utils/AbortOperation.js';
|
|
33
33
|
export * from './utils/BaseObserver.js';
|
|
34
34
|
export * from './utils/DataStream.js';
|
|
35
|
+
export * from './utils/Logger.js';
|
|
35
36
|
export * from './utils/parseQuery.js';
|
|
36
37
|
export * from './types/types.js';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import Logger, { type ILogger, type ILogLevel } from 'js-logger';
|
|
2
|
+
export { GlobalLogger, ILogger, ILoggerOpts, ILogHandler, ILogLevel } from 'js-logger';
|
|
3
|
+
export declare const LogLevel: {
|
|
4
|
+
TRACE: Logger.ILogLevel;
|
|
5
|
+
DEBUG: Logger.ILogLevel;
|
|
6
|
+
INFO: Logger.ILogLevel;
|
|
7
|
+
TIME: Logger.ILogLevel;
|
|
8
|
+
WARN: Logger.ILogLevel;
|
|
9
|
+
ERROR: Logger.ILogLevel;
|
|
10
|
+
OFF: Logger.ILogLevel;
|
|
11
|
+
};
|
|
12
|
+
export interface CreateLoggerOptions {
|
|
13
|
+
logLevel?: ILogLevel;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Retrieves the base (default) logger instance.
|
|
17
|
+
*
|
|
18
|
+
* This base logger controls the default logging configuration and is shared
|
|
19
|
+
* across all loggers created with `createLogger`. Adjusting settings on this
|
|
20
|
+
* base logger affects all loggers derived from it unless explicitly overridden.
|
|
21
|
+
*
|
|
22
|
+
*/
|
|
23
|
+
export declare function createBaseLogger(): typeof Logger;
|
|
24
|
+
/**
|
|
25
|
+
* Creates and configures a new named logger based on the base logger.
|
|
26
|
+
*
|
|
27
|
+
* Named loggers allow specific modules or areas of your application to have
|
|
28
|
+
* their own logging levels and behaviors. These loggers inherit configuration
|
|
29
|
+
* from the base logger by default but can override settings independently.
|
|
30
|
+
*/
|
|
31
|
+
export declare function createLogger(name: string, options?: CreateLoggerOptions): ILogger;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import Logger from 'js-logger';
|
|
2
|
+
const TypedLogger = Logger;
|
|
3
|
+
export const LogLevel = {
|
|
4
|
+
TRACE: TypedLogger.TRACE,
|
|
5
|
+
DEBUG: TypedLogger.DEBUG,
|
|
6
|
+
INFO: TypedLogger.INFO,
|
|
7
|
+
TIME: TypedLogger.TIME,
|
|
8
|
+
WARN: TypedLogger.WARN,
|
|
9
|
+
ERROR: TypedLogger.ERROR,
|
|
10
|
+
OFF: TypedLogger.OFF
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Retrieves the base (default) logger instance.
|
|
14
|
+
*
|
|
15
|
+
* This base logger controls the default logging configuration and is shared
|
|
16
|
+
* across all loggers created with `createLogger`. Adjusting settings on this
|
|
17
|
+
* base logger affects all loggers derived from it unless explicitly overridden.
|
|
18
|
+
*
|
|
19
|
+
*/
|
|
20
|
+
export function createBaseLogger() {
|
|
21
|
+
return Logger;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Creates and configures a new named logger based on the base logger.
|
|
25
|
+
*
|
|
26
|
+
* Named loggers allow specific modules or areas of your application to have
|
|
27
|
+
* their own logging levels and behaviors. These loggers inherit configuration
|
|
28
|
+
* from the base logger by default but can override settings independently.
|
|
29
|
+
*/
|
|
30
|
+
export function createLogger(name, options = {}) {
|
|
31
|
+
const logger = Logger.get(name);
|
|
32
|
+
if (options.logLevel) {
|
|
33
|
+
logger.setLevel(options.logLevel);
|
|
34
|
+
}
|
|
35
|
+
return logger;
|
|
36
|
+
}
|
|
@@ -12,3 +12,4 @@ export declare function throttleTrailing(func: () => void, wait: number): () =>
|
|
|
12
12
|
* Roughly equivalent to lodash/throttle with {leading: true, trailing: true}
|
|
13
13
|
*/
|
|
14
14
|
export declare function throttleLeadingTrailing(func: () => void, wait: number): () => void;
|
|
15
|
+
export declare function onAbortPromise(signal: AbortSignal): Promise<void>;
|
|
@@ -43,3 +43,13 @@ export function throttleLeadingTrailing(func, wait) {
|
|
|
43
43
|
}
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
|
+
export function onAbortPromise(signal) {
|
|
47
|
+
return new Promise((resolve) => {
|
|
48
|
+
if (signal.aborted) {
|
|
49
|
+
resolve();
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
signal.onabort = () => resolve();
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|