@powersync/common 0.0.0-dev-20251111122755 → 0.0.0-dev-20251201150812

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 (31) hide show
  1. package/dist/bundle.cjs +4560 -184
  2. package/dist/bundle.cjs.map +1 -1
  3. package/dist/bundle.mjs +4560 -184
  4. package/dist/bundle.mjs.map +1 -1
  5. package/dist/bundle.node.cjs +42 -17
  6. package/dist/bundle.node.cjs.map +1 -1
  7. package/dist/bundle.node.mjs +42 -17
  8. package/dist/bundle.node.mjs.map +1 -1
  9. package/dist/index.d.cts +226 -162
  10. package/lib/client/ConnectionManager.d.ts +1 -1
  11. package/lib/client/ConnectionManager.js.map +1 -1
  12. package/lib/client/sync/bucket/SqliteBucketStorage.js +2 -2
  13. package/lib/client/sync/bucket/SqliteBucketStorage.js.map +1 -1
  14. package/lib/client/sync/stream/AbstractRemote.js +10 -4
  15. package/lib/client/sync/stream/AbstractRemote.js.map +1 -1
  16. package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js +4 -4
  17. package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js.map +1 -1
  18. package/lib/client/triggers/TriggerManager.d.ts +71 -12
  19. package/lib/client/triggers/TriggerManagerImpl.js +10 -5
  20. package/lib/client/triggers/TriggerManagerImpl.js.map +1 -1
  21. package/lib/db/crud/SyncStatus.d.ts +7 -2
  22. package/lib/db/crud/SyncStatus.js +15 -1
  23. package/lib/db/crud/SyncStatus.js.map +1 -1
  24. package/package.json +2 -2
  25. package/src/client/ConnectionManager.ts +1 -1
  26. package/src/client/sync/bucket/SqliteBucketStorage.ts +2 -2
  27. package/src/client/sync/stream/AbstractRemote.ts +15 -5
  28. package/src/client/sync/stream/AbstractStreamingSyncImplementation.ts +5 -6
  29. package/src/client/triggers/TriggerManager.ts +79 -12
  30. package/src/client/triggers/TriggerManagerImpl.ts +12 -6
  31. package/src/db/crud/SyncStatus.ts +18 -3
@@ -571,12 +571,26 @@ class SyncStatus {
571
571
  return {
572
572
  connected: this.connected,
573
573
  connecting: this.connecting,
574
- dataFlow: this.dataFlowStatus,
574
+ dataFlow: {
575
+ ...this.dataFlowStatus,
576
+ uploadError: this.serializeError(this.dataFlowStatus.uploadError),
577
+ downloadError: this.serializeError(this.dataFlowStatus.downloadError)
578
+ },
575
579
  lastSyncedAt: this.lastSyncedAt,
576
580
  hasSynced: this.hasSynced,
577
581
  priorityStatusEntries: this.priorityStatusEntries
578
582
  };
579
583
  }
584
+ serializeError(error) {
585
+ if (typeof error == 'undefined') {
586
+ return undefined;
587
+ }
588
+ return {
589
+ name: error.name,
590
+ message: error.message,
591
+ stack: error.stack
592
+ };
593
+ }
580
594
  static comparePriorities(a, b) {
581
595
  return b.priority - a.priority; // Reverse because higher priorities have lower numbers
582
596
  }
@@ -6704,7 +6718,7 @@ function requireDist () {
6704
6718
 
6705
6719
  var distExports = requireDist();
6706
6720
 
6707
- var version = "1.41.0";
6721
+ var version = "1.43.1";
6708
6722
  var PACKAGE = {
6709
6723
  version: version};
6710
6724
 
@@ -7452,9 +7466,11 @@ class AbstractRemote {
7452
7466
  // Create a new stream splitting the response at line endings while also handling cancellations
7453
7467
  // by closing the reader.
7454
7468
  const reader = res.body.getReader();
7469
+ let readerReleased = false;
7455
7470
  // This will close the network request and read stream
7456
7471
  const closeReader = async () => {
7457
7472
  try {
7473
+ readerReleased = true;
7458
7474
  await reader.cancel();
7459
7475
  }
7460
7476
  catch (ex) {
@@ -7462,17 +7478,21 @@ class AbstractRemote {
7462
7478
  }
7463
7479
  reader.releaseLock();
7464
7480
  };
7481
+ const stream = new DataStream({
7482
+ logger: this.logger,
7483
+ mapLine: mapLine
7484
+ });
7465
7485
  abortSignal?.addEventListener('abort', () => {
7466
7486
  closeReader();
7487
+ stream.close();
7467
7488
  });
7468
7489
  const decoder = this.createTextDecoder();
7469
7490
  let buffer = '';
7470
- const stream = new DataStream({
7471
- logger: this.logger,
7472
- mapLine: mapLine
7473
- });
7474
7491
  const l = stream.registerListener({
7475
7492
  lowWater: async () => {
7493
+ if (stream.closed || abortSignal?.aborted || readerReleased) {
7494
+ return;
7495
+ }
7476
7496
  try {
7477
7497
  let didCompleteLine = false;
7478
7498
  while (!didCompleteLine) {
@@ -7796,7 +7816,7 @@ The next upload iteration will be delayed.`);
7796
7816
  uploadError: ex
7797
7817
  }
7798
7818
  });
7799
- await this.delayRetry(controller.signal);
7819
+ await this.delayRetry(controller.signal, this.options.crudUploadThrottleMs);
7800
7820
  if (!this.isConnected) {
7801
7821
  // Exit the upload loop if the sync stream is no longer connected
7802
7822
  break;
@@ -8507,14 +8527,14 @@ The next upload iteration will be delayed.`);
8507
8527
  // trigger this for all updates
8508
8528
  this.iterateListeners((cb) => cb.statusUpdated?.(options));
8509
8529
  }
8510
- async delayRetry(signal) {
8530
+ async delayRetry(signal, delayMs) {
8511
8531
  return new Promise((resolve) => {
8512
8532
  if (signal?.aborted) {
8513
8533
  // If the signal is already aborted, resolve immediately
8514
8534
  resolve();
8515
8535
  return;
8516
8536
  }
8517
- const { retryDelayMs } = this.options;
8537
+ const delay = delayMs ?? this.options.retryDelayMs;
8518
8538
  let timeoutId;
8519
8539
  const endDelay = () => {
8520
8540
  resolve();
@@ -8525,7 +8545,7 @@ The next upload iteration will be delayed.`);
8525
8545
  signal?.removeEventListener('abort', endDelay);
8526
8546
  };
8527
8547
  signal?.addEventListener('abort', endDelay, { once: true });
8528
- timeoutId = setTimeout(endDelay, retryDelayMs);
8548
+ timeoutId = setTimeout(endDelay, delay);
8529
8549
  });
8530
8550
  }
8531
8551
  updateSubscriptions(subscriptions) {
@@ -8632,6 +8652,7 @@ class TriggerManagerImpl {
8632
8652
  await hooks?.beforeCreate?.(tx);
8633
8653
  await tx.execute(/* sql */ `
8634
8654
  CREATE TEMP TABLE ${destination} (
8655
+ operation_id INTEGER PRIMARY KEY AUTOINCREMENT,
8635
8656
  id TEXT,
8636
8657
  operation TEXT,
8637
8658
  timestamp TEXT,
@@ -8742,17 +8763,20 @@ class TriggerManagerImpl {
8742
8763
  const callbackResult = await options.onChange({
8743
8764
  ...tx,
8744
8765
  destinationTable: destination,
8745
- withDiff: async (query, params) => {
8766
+ withDiff: async (query, params, options) => {
8746
8767
  // Wrap the query to expose the destination table
8768
+ const operationIdSelect = options?.castOperationIdAsText
8769
+ ? 'id, operation, CAST(operation_id AS TEXT) as operation_id, timestamp, value, previous_value'
8770
+ : '*';
8747
8771
  const wrappedQuery = /* sql */ `
8748
8772
  WITH
8749
8773
  DIFF AS (
8750
8774
  SELECT
8751
- *
8775
+ ${operationIdSelect}
8752
8776
  FROM
8753
8777
  ${destination}
8754
8778
  ORDER BY
8755
- timestamp ASC
8779
+ operation_id ASC
8756
8780
  ) ${query}
8757
8781
  `;
8758
8782
  return tx.getAll(wrappedQuery, params);
@@ -8766,13 +8790,14 @@ class TriggerManagerImpl {
8766
8790
  id,
8767
8791
  ${contextColumns.length > 0
8768
8792
  ? `${contextColumns.map((col) => `json_extract(value, '$.${col}') as ${col}`).join(', ')},`
8769
- : ''} operation as __operation,
8793
+ : ''} operation_id as __operation_id,
8794
+ operation as __operation,
8770
8795
  timestamp as __timestamp,
8771
8796
  previous_value as __previous_value
8772
8797
  FROM
8773
8798
  ${destination}
8774
8799
  ORDER BY
8775
- __timestamp ASC
8800
+ __operation_id ASC
8776
8801
  ) ${query}
8777
8802
  `;
8778
8803
  return tx.getAll(wrappedQuery, params);
@@ -10046,7 +10071,7 @@ class SqliteBucketStorage extends BaseObserver {
10046
10071
  // Nothing to update
10047
10072
  return false;
10048
10073
  }
10049
- const rs = await this.db.getAll("SELECT seq FROM sqlite_sequence WHERE name = 'ps_crud'");
10074
+ const rs = await this.db.getAll("SELECT seq FROM main.sqlite_sequence WHERE name = 'ps_crud'");
10050
10075
  if (!rs.length) {
10051
10076
  // Nothing to update
10052
10077
  return false;
@@ -10060,7 +10085,7 @@ class SqliteBucketStorage extends BaseObserver {
10060
10085
  this.logger.debug(`New data uploaded since write checkpoint ${opId} - need new write checkpoint`);
10061
10086
  return false;
10062
10087
  }
10063
- const rs = await tx.execute("SELECT seq FROM sqlite_sequence WHERE name = 'ps_crud'");
10088
+ const rs = await tx.execute("SELECT seq FROM main.sqlite_sequence WHERE name = 'ps_crud'");
10064
10089
  if (!rs.rows?.length) {
10065
10090
  // assert isNotEmpty
10066
10091
  throw new Error('SQLite Sequence should not be empty');