@powersync/common 0.0.0-dev-20250210155038 → 0.0.0-dev-20250416114737

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.
@@ -1,40 +1,130 @@
1
1
  export type SyncDataFlowStatus = Partial<{
2
2
  downloading: boolean;
3
3
  uploading: boolean;
4
+ /**
5
+ * Error during downloading (including connecting).
6
+ *
7
+ * Cleared on the next successful data download.
8
+ */
9
+ downloadError?: Error;
10
+ /**
11
+ * Error during uploading.
12
+ * Cleared on the next successful upload.
13
+ */
14
+ uploadError?: Error;
4
15
  }>;
16
+ export interface SyncPriorityStatus {
17
+ priority: number;
18
+ lastSyncedAt?: Date;
19
+ hasSynced?: boolean;
20
+ }
5
21
  export type SyncStatusOptions = {
6
22
  connected?: boolean;
7
23
  connecting?: boolean;
8
24
  dataFlow?: SyncDataFlowStatus;
9
25
  lastSyncedAt?: Date;
10
26
  hasSynced?: boolean;
27
+ priorityStatusEntries?: SyncPriorityStatus[];
11
28
  };
12
29
  export declare class SyncStatus {
13
30
  protected options: SyncStatusOptions;
14
31
  constructor(options: SyncStatusOptions);
15
32
  /**
16
- * true if currently connected.
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.
17
36
  */
18
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
+ */
19
43
  get connecting(): boolean;
20
44
  /**
21
- * Time that a last sync has fully completed, if any.
22
- * Currently this is reset to null after a restart.
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.
23
49
  */
24
50
  get lastSyncedAt(): Date | undefined;
25
51
  /**
26
- * Indicates whether there has been at least one full sync, if any.
27
- * Is undefined when unknown, for example when state is still being loaded from the database.
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.
28
56
  */
29
57
  get hasSynced(): boolean | undefined;
30
58
  /**
31
- * Upload/download status
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.
32
65
  */
33
66
  get dataFlowStatus(): Partial<{
34
67
  downloading: boolean;
35
68
  uploading: boolean;
69
+ /**
70
+ * Error during downloading (including connecting).
71
+ *
72
+ * Cleared on the next successful data download.
73
+ */
74
+ downloadError?: Error;
75
+ /**
76
+ * Error during uploading.
77
+ * Cleared on the next successful upload.
78
+ */
79
+ uploadError?: Error;
36
80
  }>;
81
+ /**
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.
86
+ */
87
+ get priorityStatusEntries(): SyncPriorityStatus[];
88
+ /**
89
+ * Reports the sync status (a pair of {@link SyncStatus#hasSynced} and {@link SyncStatus#lastSyncedAt} fields)
90
+ * for a specific bucket priority level.
91
+ *
92
+ * When buckets with different priorities are declared, PowerSync may choose to synchronize higher-priority
93
+ * buckets first. When a consistent view over all buckets for all priorities up until the given priority is
94
+ * reached, PowerSync makes data from those buckets available before lower-priority buckets have finished
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
102
+ * with a priority of 1 may return information for priority level 3.
103
+ *
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
106
+ */
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
+ */
37
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
+ */
38
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
+ */
39
128
  toJSON(): SyncStatusOptions;
129
+ private static comparePriorities;
40
130
  }
@@ -4,30 +4,46 @@ export class SyncStatus {
4
4
  this.options = options;
5
5
  }
6
6
  /**
7
- * true if currently connected.
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
- * Time that a last sync has fully completed, if any.
17
- * Currently this is reset to null after a restart.
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, if any.
24
- * Is undefined when unknown, for example when state is still being loaded from the database.
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
- * Upload/download status
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 ?? {
@@ -42,20 +58,85 @@ export class SyncStatus {
42
58
  uploading: false
43
59
  });
44
60
  }
61
+ /**
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.
66
+ */
67
+ get priorityStatusEntries() {
68
+ return (this.options.priorityStatusEntries ?? []).slice().sort(SyncStatus.comparePriorities);
69
+ }
70
+ /**
71
+ * Reports the sync status (a pair of {@link SyncStatus#hasSynced} and {@link SyncStatus#lastSyncedAt} fields)
72
+ * for a specific bucket priority level.
73
+ *
74
+ * When buckets with different priorities are declared, PowerSync may choose to synchronize higher-priority
75
+ * buckets first. When a consistent view over all buckets for all priorities up until the given priority is
76
+ * reached, PowerSync makes data from those buckets available before lower-priority buckets have finished
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
84
+ * with a priority of 1 may return information for priority level 3.
85
+ *
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
88
+ */
89
+ statusForPriority(priority) {
90
+ // priorityStatusEntries are sorted by ascending priorities (so higher numbers to lower numbers).
91
+ for (const known of this.priorityStatusEntries) {
92
+ // We look for the first entry that doesn't have a higher priority.
93
+ if (known.priority >= priority) {
94
+ return known;
95
+ }
96
+ }
97
+ // If we have a complete sync, that necessarily includes all priorities.
98
+ return {
99
+ priority,
100
+ lastSyncedAt: this.lastSyncedAt,
101
+ hasSynced: this.hasSynced
102
+ };
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
+ */
45
111
  isEqual(status) {
46
112
  return JSON.stringify(this.options) == JSON.stringify(status.options);
47
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
+ */
48
120
  getMessage() {
49
121
  const dataFlow = this.dataFlowStatus;
50
- return `SyncStatus<connected: ${this.connected} connecting: ${this.connecting} lastSyncedAt: ${this.lastSyncedAt} hasSynced: ${this.hasSynced}. Downloading: ${dataFlow.downloading}. Uploading: ${dataFlow.uploading}`;
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}>`;
51
123
  }
124
+ /**
125
+ * Serializes the SyncStatus instance to a plain object.
126
+ *
127
+ * @returns {SyncStatusOptions} A plain object representation of the sync status
128
+ */
52
129
  toJSON() {
53
130
  return {
54
131
  connected: this.connected,
55
132
  connecting: this.connecting,
56
133
  dataFlow: this.dataFlowStatus,
57
134
  lastSyncedAt: this.lastSyncedAt,
58
- hasSynced: this.hasSynced
135
+ hasSynced: this.hasSynced,
136
+ priorityStatusEntries: this.priorityStatusEntries
59
137
  };
60
138
  }
139
+ static comparePriorities(a, b) {
140
+ return b.priority - a.priority; // Reverse because higher priorities have lower numbers
141
+ }
61
142
  }
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';
@@ -63,9 +63,6 @@ export class DataStream extends BaseObserver {
63
63
  * @returns a Data payload or Null if the stream closed.
64
64
  */
65
65
  async read() {
66
- if (this.dataQueue.length <= this.lowWatermark) {
67
- await this.iterateAsyncErrored(async (l) => l.lowWater?.());
68
- }
69
66
  if (this.closed) {
70
67
  return null;
71
68
  }
@@ -133,12 +130,14 @@ export class DataStream extends BaseObserver {
133
130
  return Array.from(this.listeners.values()).some((l) => !!l.data);
134
131
  }
135
132
  async _processQueue() {
136
- if (!this.dataQueue.length || this.isClosed || !this.hasDataReader()) {
133
+ if (this.isClosed || !this.hasDataReader()) {
137
134
  Promise.resolve().then(() => (this.processingPromise = null));
138
135
  return;
139
136
  }
140
- const data = this.dataQueue.shift();
141
- await this.iterateAsyncErrored(async (l) => l.data?.(data));
137
+ if (this.dataQueue.length) {
138
+ const data = this.dataQueue.shift();
139
+ await this.iterateAsyncErrored(async (l) => l.data?.(data));
140
+ }
142
141
  if (this.dataQueue.length <= this.lowWatermark) {
143
142
  await this.iterateAsyncErrored(async (l) => l.lowWater?.());
144
143
  }
@@ -0,0 +1,16 @@
1
+ import Logger, { ILogger, ILogLevel } from 'js-logger';
2
+ export { GlobalLogger, ILogger, ILoggerOpts, ILogHandler, ILogLevel } from 'js-logger';
3
+ export declare const LogLevels: {
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
+ export declare function createBaseLogger(): typeof Logger;
16
+ export declare function createLogger(name: string, options?: CreateLoggerOptions): ILogger;
@@ -0,0 +1,21 @@
1
+ import Logger from 'js-logger';
2
+ const TypedLogger = Logger;
3
+ export const LogLevels = {
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
+ export function createBaseLogger() {
13
+ return Logger;
14
+ }
15
+ export function createLogger(name, options = {}) {
16
+ const logger = Logger.get(name);
17
+ if (options.logLevel) {
18
+ logger.setLevel(options.logLevel);
19
+ }
20
+ return logger;
21
+ }
@@ -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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@powersync/common",
3
- "version": "0.0.0-dev-20250210155038",
3
+ "version": "0.0.0-dev-20250416114737",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"