@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
@@ -569,12 +569,26 @@ class SyncStatus {
569
569
  return {
570
570
  connected: this.connected,
571
571
  connecting: this.connecting,
572
- dataFlow: this.dataFlowStatus,
572
+ dataFlow: {
573
+ ...this.dataFlowStatus,
574
+ uploadError: this.serializeError(this.dataFlowStatus.uploadError),
575
+ downloadError: this.serializeError(this.dataFlowStatus.downloadError)
576
+ },
573
577
  lastSyncedAt: this.lastSyncedAt,
574
578
  hasSynced: this.hasSynced,
575
579
  priorityStatusEntries: this.priorityStatusEntries
576
580
  };
577
581
  }
582
+ serializeError(error) {
583
+ if (typeof error == 'undefined') {
584
+ return undefined;
585
+ }
586
+ return {
587
+ name: error.name,
588
+ message: error.message,
589
+ stack: error.stack
590
+ };
591
+ }
578
592
  static comparePriorities(a, b) {
579
593
  return b.priority - a.priority; // Reverse because higher priorities have lower numbers
580
594
  }
@@ -6702,7 +6716,7 @@ function requireDist () {
6702
6716
 
6703
6717
  var distExports = requireDist();
6704
6718
 
6705
- var version = "1.41.0";
6719
+ var version = "1.43.1";
6706
6720
  var PACKAGE = {
6707
6721
  version: version};
6708
6722
 
@@ -7450,9 +7464,11 @@ class AbstractRemote {
7450
7464
  // Create a new stream splitting the response at line endings while also handling cancellations
7451
7465
  // by closing the reader.
7452
7466
  const reader = res.body.getReader();
7467
+ let readerReleased = false;
7453
7468
  // This will close the network request and read stream
7454
7469
  const closeReader = async () => {
7455
7470
  try {
7471
+ readerReleased = true;
7456
7472
  await reader.cancel();
7457
7473
  }
7458
7474
  catch (ex) {
@@ -7460,17 +7476,21 @@ class AbstractRemote {
7460
7476
  }
7461
7477
  reader.releaseLock();
7462
7478
  };
7479
+ const stream = new DataStream({
7480
+ logger: this.logger,
7481
+ mapLine: mapLine
7482
+ });
7463
7483
  abortSignal?.addEventListener('abort', () => {
7464
7484
  closeReader();
7485
+ stream.close();
7465
7486
  });
7466
7487
  const decoder = this.createTextDecoder();
7467
7488
  let buffer = '';
7468
- const stream = new DataStream({
7469
- logger: this.logger,
7470
- mapLine: mapLine
7471
- });
7472
7489
  const l = stream.registerListener({
7473
7490
  lowWater: async () => {
7491
+ if (stream.closed || abortSignal?.aborted || readerReleased) {
7492
+ return;
7493
+ }
7474
7494
  try {
7475
7495
  let didCompleteLine = false;
7476
7496
  while (!didCompleteLine) {
@@ -7794,7 +7814,7 @@ The next upload iteration will be delayed.`);
7794
7814
  uploadError: ex
7795
7815
  }
7796
7816
  });
7797
- await this.delayRetry(controller.signal);
7817
+ await this.delayRetry(controller.signal, this.options.crudUploadThrottleMs);
7798
7818
  if (!this.isConnected) {
7799
7819
  // Exit the upload loop if the sync stream is no longer connected
7800
7820
  break;
@@ -8505,14 +8525,14 @@ The next upload iteration will be delayed.`);
8505
8525
  // trigger this for all updates
8506
8526
  this.iterateListeners((cb) => cb.statusUpdated?.(options));
8507
8527
  }
8508
- async delayRetry(signal) {
8528
+ async delayRetry(signal, delayMs) {
8509
8529
  return new Promise((resolve) => {
8510
8530
  if (signal?.aborted) {
8511
8531
  // If the signal is already aborted, resolve immediately
8512
8532
  resolve();
8513
8533
  return;
8514
8534
  }
8515
- const { retryDelayMs } = this.options;
8535
+ const delay = delayMs ?? this.options.retryDelayMs;
8516
8536
  let timeoutId;
8517
8537
  const endDelay = () => {
8518
8538
  resolve();
@@ -8523,7 +8543,7 @@ The next upload iteration will be delayed.`);
8523
8543
  signal?.removeEventListener('abort', endDelay);
8524
8544
  };
8525
8545
  signal?.addEventListener('abort', endDelay, { once: true });
8526
- timeoutId = setTimeout(endDelay, retryDelayMs);
8546
+ timeoutId = setTimeout(endDelay, delay);
8527
8547
  });
8528
8548
  }
8529
8549
  updateSubscriptions(subscriptions) {
@@ -8630,6 +8650,7 @@ class TriggerManagerImpl {
8630
8650
  await hooks?.beforeCreate?.(tx);
8631
8651
  await tx.execute(/* sql */ `
8632
8652
  CREATE TEMP TABLE ${destination} (
8653
+ operation_id INTEGER PRIMARY KEY AUTOINCREMENT,
8633
8654
  id TEXT,
8634
8655
  operation TEXT,
8635
8656
  timestamp TEXT,
@@ -8740,17 +8761,20 @@ class TriggerManagerImpl {
8740
8761
  const callbackResult = await options.onChange({
8741
8762
  ...tx,
8742
8763
  destinationTable: destination,
8743
- withDiff: async (query, params) => {
8764
+ withDiff: async (query, params, options) => {
8744
8765
  // Wrap the query to expose the destination table
8766
+ const operationIdSelect = options?.castOperationIdAsText
8767
+ ? 'id, operation, CAST(operation_id AS TEXT) as operation_id, timestamp, value, previous_value'
8768
+ : '*';
8745
8769
  const wrappedQuery = /* sql */ `
8746
8770
  WITH
8747
8771
  DIFF AS (
8748
8772
  SELECT
8749
- *
8773
+ ${operationIdSelect}
8750
8774
  FROM
8751
8775
  ${destination}
8752
8776
  ORDER BY
8753
- timestamp ASC
8777
+ operation_id ASC
8754
8778
  ) ${query}
8755
8779
  `;
8756
8780
  return tx.getAll(wrappedQuery, params);
@@ -8764,13 +8788,14 @@ class TriggerManagerImpl {
8764
8788
  id,
8765
8789
  ${contextColumns.length > 0
8766
8790
  ? `${contextColumns.map((col) => `json_extract(value, '$.${col}') as ${col}`).join(', ')},`
8767
- : ''} operation as __operation,
8791
+ : ''} operation_id as __operation_id,
8792
+ operation as __operation,
8768
8793
  timestamp as __timestamp,
8769
8794
  previous_value as __previous_value
8770
8795
  FROM
8771
8796
  ${destination}
8772
8797
  ORDER BY
8773
- __timestamp ASC
8798
+ __operation_id ASC
8774
8799
  ) ${query}
8775
8800
  `;
8776
8801
  return tx.getAll(wrappedQuery, params);
@@ -10044,7 +10069,7 @@ class SqliteBucketStorage extends BaseObserver {
10044
10069
  // Nothing to update
10045
10070
  return false;
10046
10071
  }
10047
- const rs = await this.db.getAll("SELECT seq FROM sqlite_sequence WHERE name = 'ps_crud'");
10072
+ const rs = await this.db.getAll("SELECT seq FROM main.sqlite_sequence WHERE name = 'ps_crud'");
10048
10073
  if (!rs.length) {
10049
10074
  // Nothing to update
10050
10075
  return false;
@@ -10058,7 +10083,7 @@ class SqliteBucketStorage extends BaseObserver {
10058
10083
  this.logger.debug(`New data uploaded since write checkpoint ${opId} - need new write checkpoint`);
10059
10084
  return false;
10060
10085
  }
10061
- const rs = await tx.execute("SELECT seq FROM sqlite_sequence WHERE name = 'ps_crud'");
10086
+ const rs = await tx.execute("SELECT seq FROM main.sqlite_sequence WHERE name = 'ps_crud'");
10062
10087
  if (!rs.rows?.length) {
10063
10088
  // assert isNotEmpty
10064
10089
  throw new Error('SQLite Sequence should not be empty');