@powersync/common 1.44.0 → 1.46.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.
Files changed (49) hide show
  1. package/dist/bundle.cjs +442 -2057
  2. package/dist/bundle.cjs.map +1 -1
  3. package/dist/bundle.mjs +439 -2058
  4. package/dist/bundle.mjs.map +1 -1
  5. package/dist/bundle.node.cjs +341 -127
  6. package/dist/bundle.node.cjs.map +1 -1
  7. package/dist/bundle.node.mjs +338 -128
  8. package/dist/bundle.node.mjs.map +1 -1
  9. package/dist/index.d.cts +263 -164
  10. package/lib/client/AbstractPowerSyncDatabase.d.ts +9 -2
  11. package/lib/client/AbstractPowerSyncDatabase.js +18 -5
  12. package/lib/client/AbstractPowerSyncDatabase.js.map +1 -1
  13. package/lib/client/ConnectionManager.d.ts +1 -1
  14. package/lib/client/ConnectionManager.js.map +1 -1
  15. package/lib/client/sync/stream/AbstractRemote.js +41 -32
  16. package/lib/client/sync/stream/AbstractRemote.js.map +1 -1
  17. package/lib/client/sync/stream/AbstractStreamingSyncImplementation.d.ts +7 -12
  18. package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js +10 -12
  19. package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js.map +1 -1
  20. package/lib/client/triggers/MemoryTriggerClaimManager.d.ts +6 -0
  21. package/lib/client/triggers/MemoryTriggerClaimManager.js +21 -0
  22. package/lib/client/triggers/MemoryTriggerClaimManager.js.map +1 -0
  23. package/lib/client/triggers/TriggerManager.d.ts +37 -0
  24. package/lib/client/triggers/TriggerManagerImpl.d.ts +24 -3
  25. package/lib/client/triggers/TriggerManagerImpl.js +133 -11
  26. package/lib/client/triggers/TriggerManagerImpl.js.map +1 -1
  27. package/lib/db/ConnectionClosedError.d.ts +10 -0
  28. package/lib/db/ConnectionClosedError.js +21 -0
  29. package/lib/db/ConnectionClosedError.js.map +1 -0
  30. package/lib/db/crud/SyncStatus.d.ts +11 -2
  31. package/lib/db/crud/SyncStatus.js +19 -1
  32. package/lib/db/crud/SyncStatus.js.map +1 -1
  33. package/lib/index.d.ts +4 -0
  34. package/lib/index.js +4 -0
  35. package/lib/index.js.map +1 -1
  36. package/lib/utils/DataStream.js +11 -2
  37. package/lib/utils/DataStream.js.map +1 -1
  38. package/package.json +4 -3
  39. package/src/client/AbstractPowerSyncDatabase.ts +21 -6
  40. package/src/client/ConnectionManager.ts +1 -1
  41. package/src/client/sync/stream/AbstractRemote.ts +47 -35
  42. package/src/client/sync/stream/AbstractStreamingSyncImplementation.ts +11 -15
  43. package/src/client/triggers/MemoryTriggerClaimManager.ts +25 -0
  44. package/src/client/triggers/TriggerManager.ts +50 -6
  45. package/src/client/triggers/TriggerManagerImpl.ts +177 -13
  46. package/src/db/ConnectionClosedError.ts +23 -0
  47. package/src/db/crud/SyncStatus.ts +22 -3
  48. package/src/index.ts +4 -0
  49. package/src/utils/DataStream.ts +13 -2
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Thrown when an underlying database connection is closed.
3
+ * This is particularly relevant when worker connections are marked as closed while
4
+ * operations are still in progress.
5
+ */
6
+ export class ConnectionClosedError extends Error {
7
+ static NAME = 'ConnectionClosedError';
8
+
9
+ static MATCHES(input: any) {
10
+ /**
11
+ * If there are weird package issues which cause multiple versions of classes to be present, the instanceof
12
+ * check might fail. This also performs a failsafe check.
13
+ * This might also happen if the Error is serialized and parsed over a bridging channel like a MessagePort.
14
+ */
15
+ return (
16
+ input instanceof ConnectionClosedError || (input instanceof Error && input.name == ConnectionClosedError.NAME)
17
+ );
18
+ }
19
+ constructor(message: string) {
20
+ super(message);
21
+ this.name = ConnectionClosedError.NAME;
22
+ }
23
+ }
@@ -1,7 +1,7 @@
1
- import { CoreStreamSubscription } from '../../client/sync/stream/core-instruction.js';
2
1
  import { SyncClientImplementation } from '../../client/sync/stream/AbstractStreamingSyncImplementation.js';
3
- import { InternalProgressInformation, ProgressWithOperations, SyncProgress } from './SyncProgress.js';
2
+ import { CoreStreamSubscription } from '../../client/sync/stream/core-instruction.js';
4
3
  import { SyncStreamDescription, SyncSubscriptionDescription } from '../../client/sync/sync-streams.js';
4
+ import { InternalProgressInformation, ProgressWithOperations, SyncProgress } from './SyncProgress.js';
5
5
 
6
6
  export type SyncDataFlowStatus = Partial<{
7
7
  downloading: boolean;
@@ -250,13 +250,32 @@ export class SyncStatus {
250
250
  return {
251
251
  connected: this.connected,
252
252
  connecting: this.connecting,
253
- dataFlow: this.dataFlowStatus,
253
+ dataFlow: {
254
+ ...this.dataFlowStatus,
255
+ uploadError: this.serializeError(this.dataFlowStatus.uploadError),
256
+ downloadError: this.serializeError(this.dataFlowStatus.downloadError)
257
+ },
254
258
  lastSyncedAt: this.lastSyncedAt,
255
259
  hasSynced: this.hasSynced,
256
260
  priorityStatusEntries: this.priorityStatusEntries
257
261
  };
258
262
  }
259
263
 
264
+ /**
265
+ * Not all errors are serializable over a MessagePort. E.g. some `DomExceptions` fail to be passed across workers.
266
+ * This explicitly serializes errors in the SyncStatus.
267
+ */
268
+ protected serializeError(error?: Error) {
269
+ if (typeof error == 'undefined') {
270
+ return undefined;
271
+ }
272
+ return {
273
+ name: error.name,
274
+ message: error.message,
275
+ stack: error.stack
276
+ };
277
+ }
278
+
260
279
  private static comparePriorities(a: SyncPriorityStatus, b: SyncPriorityStatus) {
261
280
  return b.priority - a.priority; // Reverse because higher priorities have lower numbers
262
281
  }
package/src/index.ts CHANGED
@@ -21,6 +21,7 @@ export * from './client/sync/stream/streaming-sync-types.js';
21
21
  export * from './client/sync/sync-streams.js';
22
22
 
23
23
  export * from './client/ConnectionManager.js';
24
+ export * from './db/ConnectionClosedError.js';
24
25
  export { ProgressWithOperations, SyncProgress } from './db/crud/SyncProgress.js';
25
26
  export * from './db/crud/SyncStatus.js';
26
27
  export * from './db/crud/UploadQueueStatus.js';
@@ -28,13 +29,16 @@ export * from './db/DBAdapter.js';
28
29
  export * from './db/schema/Column.js';
29
30
  export * from './db/schema/Index.js';
30
31
  export * from './db/schema/IndexedColumn.js';
32
+ export * from './db/schema/RawTable.js';
31
33
  export * from './db/schema/Schema.js';
32
34
  export * from './db/schema/Table.js';
33
35
  export * from './db/schema/TableV2.js';
34
36
 
35
37
  export * from './client/Query.js';
38
+ export { MEMORY_TRIGGER_CLAIM_MANAGER } from './client/triggers/MemoryTriggerClaimManager.js';
36
39
  export * from './client/triggers/sanitizeSQL.js';
37
40
  export * from './client/triggers/TriggerManager.js';
41
+ export { TriggerManagerImpl } from './client/triggers/TriggerManagerImpl.js';
38
42
  export * from './client/watched/GetAllQuery.js';
39
43
  export * from './client/watched/processors/AbstractQueryProcessor.js';
40
44
  export * from './client/watched/processors/comparators.js';
@@ -110,6 +110,18 @@ export class DataStream<ParsedData, SourceData = any> extends BaseObserver<DataS
110
110
  return null;
111
111
  }
112
112
 
113
+ // Wait for any pending processing to complete first.
114
+ // This ensures we register our listener before calling processQueue(),
115
+ // avoiding a race where processQueue() sees no reader and returns early.
116
+ if (this.processingPromise) {
117
+ await this.processingPromise;
118
+ }
119
+
120
+ // Re-check after await - stream may have closed while we were waiting
121
+ if (this.closed) {
122
+ return null;
123
+ }
124
+
113
125
  return new Promise((resolve, reject) => {
114
126
  const l = this.registerListener({
115
127
  data: async (data) => {
@@ -151,7 +163,7 @@ export class DataStream<ParsedData, SourceData = any> extends BaseObserver<DataS
151
163
 
152
164
  const promise = (this.processingPromise = this._processQueue());
153
165
  promise.finally(() => {
154
- return (this.processingPromise = null);
166
+ this.processingPromise = null;
155
167
  });
156
168
  return promise;
157
169
  }
@@ -190,7 +202,6 @@ export class DataStream<ParsedData, SourceData = any> extends BaseObserver<DataS
190
202
  }
191
203
 
192
204
  if (this.dataQueue.length > 0) {
193
- // Next tick
194
205
  setTimeout(() => this.processQueue());
195
206
  }
196
207
  }