@powersync/web 1.38.2 → 1.38.3

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 (69) hide show
  1. package/dist/worker/SharedSyncImplementation.umd.js +548 -345
  2. package/dist/worker/SharedSyncImplementation.umd.js.map +1 -1
  3. package/dist/worker/WASQLiteDB.umd.js +548 -345
  4. package/dist/worker/WASQLiteDB.umd.js.map +1 -1
  5. package/lib/package.json +2 -2
  6. package/lib/src/attachments/IndexDBFileSystemAdapter.js +1 -0
  7. package/lib/src/attachments/IndexDBFileSystemAdapter.js.map +1 -0
  8. package/lib/src/db/NavigatorTriggerClaimManager.js +1 -0
  9. package/lib/src/db/NavigatorTriggerClaimManager.js.map +1 -0
  10. package/lib/src/db/PowerSyncDatabase.js +1 -0
  11. package/lib/src/db/PowerSyncDatabase.js.map +1 -0
  12. package/lib/src/db/adapters/AbstractWebPowerSyncDatabaseOpenFactory.js +1 -0
  13. package/lib/src/db/adapters/AbstractWebPowerSyncDatabaseOpenFactory.js.map +1 -0
  14. package/lib/src/db/adapters/AsyncWebAdapter.js +1 -0
  15. package/lib/src/db/adapters/AsyncWebAdapter.js.map +1 -0
  16. package/lib/src/db/adapters/SSRDBAdapter.js +1 -0
  17. package/lib/src/db/adapters/SSRDBAdapter.js.map +1 -0
  18. package/lib/src/db/adapters/WebDBAdapter.js +1 -0
  19. package/lib/src/db/adapters/WebDBAdapter.js.map +1 -0
  20. package/lib/src/db/adapters/wa-sqlite/ConcurrentConnection.js +1 -0
  21. package/lib/src/db/adapters/wa-sqlite/ConcurrentConnection.js.map +1 -0
  22. package/lib/src/db/adapters/wa-sqlite/DatabaseClient.js +1 -0
  23. package/lib/src/db/adapters/wa-sqlite/DatabaseClient.js.map +1 -0
  24. package/lib/src/db/adapters/wa-sqlite/DatabaseServer.js +1 -0
  25. package/lib/src/db/adapters/wa-sqlite/DatabaseServer.js.map +1 -0
  26. package/lib/src/db/adapters/wa-sqlite/RawSqliteConnection.js +1 -0
  27. package/lib/src/db/adapters/wa-sqlite/RawSqliteConnection.js.map +1 -0
  28. package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.js +1 -0
  29. package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.js.map +1 -0
  30. package/lib/src/db/adapters/wa-sqlite/WASQLitePowerSyncDatabaseOpenFactory.js +1 -0
  31. package/lib/src/db/adapters/wa-sqlite/WASQLitePowerSyncDatabaseOpenFactory.js.map +1 -0
  32. package/lib/src/db/adapters/wa-sqlite/vfs.js +1 -0
  33. package/lib/src/db/adapters/wa-sqlite/vfs.js.map +1 -0
  34. package/lib/src/db/adapters/web-sql-flags.js +1 -0
  35. package/lib/src/db/adapters/web-sql-flags.js.map +1 -0
  36. package/lib/src/db/sync/SSRWebStreamingSyncImplementation.js +1 -0
  37. package/lib/src/db/sync/SSRWebStreamingSyncImplementation.js.map +1 -0
  38. package/lib/src/db/sync/SharedWebStreamingSyncImplementation.js +1 -0
  39. package/lib/src/db/sync/SharedWebStreamingSyncImplementation.js.map +1 -0
  40. package/lib/src/db/sync/WebRemote.js +1 -0
  41. package/lib/src/db/sync/WebRemote.js.map +1 -0
  42. package/lib/src/db/sync/WebStreamingSyncImplementation.js +1 -0
  43. package/lib/src/db/sync/WebStreamingSyncImplementation.js.map +1 -0
  44. package/lib/src/db/sync/userAgent.js +1 -0
  45. package/lib/src/db/sync/userAgent.js.map +1 -0
  46. package/lib/src/index.js +1 -0
  47. package/lib/src/index.js.map +1 -0
  48. package/lib/src/shared/navigator.js +1 -0
  49. package/lib/src/shared/navigator.js.map +1 -0
  50. package/lib/src/shared/tab_close_signal.js +1 -0
  51. package/lib/src/shared/tab_close_signal.js.map +1 -0
  52. package/lib/src/worker/db/MultiDatabaseServer.js +1 -0
  53. package/lib/src/worker/db/MultiDatabaseServer.js.map +1 -0
  54. package/lib/src/worker/db/WASQLiteDB.worker.js +1 -0
  55. package/lib/src/worker/db/WASQLiteDB.worker.js.map +1 -0
  56. package/lib/src/worker/db/open-worker-database.js +1 -0
  57. package/lib/src/worker/db/open-worker-database.js.map +1 -0
  58. package/lib/src/worker/sync/AbstractSharedSyncClientProvider.js +1 -0
  59. package/lib/src/worker/sync/AbstractSharedSyncClientProvider.js.map +1 -0
  60. package/lib/src/worker/sync/BroadcastLogger.js +1 -0
  61. package/lib/src/worker/sync/BroadcastLogger.js.map +1 -0
  62. package/lib/src/worker/sync/SharedSyncImplementation.js +1 -0
  63. package/lib/src/worker/sync/SharedSyncImplementation.js.map +1 -0
  64. package/lib/src/worker/sync/SharedSyncImplementation.worker.js +1 -0
  65. package/lib/src/worker/sync/SharedSyncImplementation.worker.js.map +1 -0
  66. package/lib/src/worker/sync/WorkerClient.js +1 -0
  67. package/lib/src/worker/sync/WorkerClient.js.map +1 -0
  68. package/lib/tsconfig.tsbuildinfo +1 -1
  69. package/package.json +3 -3
@@ -1733,7 +1733,10 @@ __webpack_require__.r(__webpack_exports__);
1733
1733
  /* harmony export */ sanitizeUUID: () => (/* binding */ sanitizeUUID),
1734
1734
  /* harmony export */ timeoutSignal: () => (/* binding */ timeoutSignal)
1735
1735
  /* harmony export */ });
1736
- // https://www.sqlite.org/lang_expr.html#castexpr
1736
+ /**
1737
+ * @see https://www.sqlite.org/lang_expr.html#castexpr
1738
+ * @public
1739
+ */
1737
1740
  var ColumnType;
1738
1741
  (function (ColumnType) {
1739
1742
  ColumnType["TEXT"] = "TEXT";
@@ -1749,14 +1752,24 @@ const integer = {
1749
1752
  const real = {
1750
1753
  type: ColumnType.REAL
1751
1754
  };
1752
- // powersync-sqlite-core limits the number of column per table to 1999, due to internal SQLite limits.
1753
- // In earlier versions this was limited to 63.
1755
+ /**
1756
+ * powersync-sqlite-core limits the number of column per table to 1999, due to internal SQLite limits.
1757
+ * In earlier versions this was limited to 63.
1758
+ *
1759
+ * @internal
1760
+ */
1754
1761
  const MAX_AMOUNT_OF_COLUMNS = 1999;
1762
+ /**
1763
+ * @public
1764
+ */
1755
1765
  const column = {
1756
1766
  text,
1757
1767
  integer,
1758
1768
  real
1759
1769
  };
1770
+ /**
1771
+ * @public
1772
+ */
1760
1773
  class Column {
1761
1774
  options;
1762
1775
  constructor(options) {
@@ -1776,9 +1789,15 @@ class Column {
1776
1789
  }
1777
1790
  }
1778
1791
 
1792
+ /**
1793
+ * @internal
1794
+ */
1779
1795
  const DEFAULT_INDEX_COLUMN_OPTIONS = {
1780
1796
  ascending: true
1781
1797
  };
1798
+ /**
1799
+ * @public
1800
+ */
1782
1801
  class IndexedColumn {
1783
1802
  options;
1784
1803
  static createAscending(column) {
@@ -1805,9 +1824,15 @@ class IndexedColumn {
1805
1824
  }
1806
1825
  }
1807
1826
 
1827
+ /**
1828
+ * @internal
1829
+ */
1808
1830
  const DEFAULT_INDEX_OPTIONS = {
1809
1831
  columns: []
1810
1832
  };
1833
+ /**
1834
+ * @public
1835
+ */
1811
1836
  class Index {
1812
1837
  options;
1813
1838
  static createAscending(options, columnNames) {
@@ -1849,6 +1874,9 @@ function encodeTableOptions(options) {
1849
1874
  };
1850
1875
  }
1851
1876
 
1877
+ /**
1878
+ * @internal
1879
+ */
1852
1880
  const DEFAULT_TABLE_OPTIONS = {
1853
1881
  indexes: [],
1854
1882
  insertOnly: false,
@@ -1857,7 +1885,13 @@ const DEFAULT_TABLE_OPTIONS = {
1857
1885
  trackMetadata: false,
1858
1886
  ignoreEmptyUpdates: false
1859
1887
  };
1888
+ /**
1889
+ * @internal
1890
+ */
1860
1891
  const InvalidSQLCharacters = /["'%,.#\s[\]]/;
1892
+ /**
1893
+ * @public
1894
+ */
1861
1895
  class Table {
1862
1896
  options;
1863
1897
  _mappedColumns;
@@ -2048,6 +2082,11 @@ class Table {
2048
2082
  }
2049
2083
  }
2050
2084
 
2085
+ /**
2086
+ * The default name of the local table storing attachment data.
2087
+ *
2088
+ * @alpha
2089
+ */
2051
2090
  const ATTACHMENT_TABLE = 'attachments';
2052
2091
  /**
2053
2092
  * Maps a database row to an AttachmentRecord.
@@ -2055,7 +2094,7 @@ const ATTACHMENT_TABLE = 'attachments';
2055
2094
  * @param row - The database row object
2056
2095
  * @returns The corresponding AttachmentRecord
2057
2096
  *
2058
- * @experimental
2097
+ * @alpha
2059
2098
  */
2060
2099
  function attachmentFromSql(row) {
2061
2100
  return {
@@ -2073,7 +2112,7 @@ function attachmentFromSql(row) {
2073
2112
  /**
2074
2113
  * AttachmentState represents the current synchronization state of an attachment.
2075
2114
  *
2076
- * @experimental
2115
+ * @alpha
2077
2116
  */
2078
2117
  var AttachmentState;
2079
2118
  (function (AttachmentState) {
@@ -2086,7 +2125,7 @@ var AttachmentState;
2086
2125
  /**
2087
2126
  * AttachmentTable defines the schema for the attachment queue table.
2088
2127
  *
2089
- * @internal
2128
+ * @alpha
2090
2129
  */
2091
2130
  class AttachmentTable extends Table {
2092
2131
  constructor(options) {
@@ -2114,7 +2153,8 @@ class AttachmentTable extends Table {
2114
2153
  * Provides methods to query, insert, update, and delete attachment records with
2115
2154
  * proper transaction management through PowerSync.
2116
2155
  *
2117
- * @internal
2156
+ * @experimental
2157
+ * @alpha
2118
2158
  */
2119
2159
  class AttachmentContext {
2120
2160
  /** PowerSync database instance for executing queries */
@@ -2336,6 +2376,9 @@ class AttachmentContext {
2336
2376
  }
2337
2377
  }
2338
2378
 
2379
+ /**
2380
+ * @public
2381
+ */
2339
2382
  var WatchedQueryListenerEvent;
2340
2383
  (function (WatchedQueryListenerEvent) {
2341
2384
  WatchedQueryListenerEvent["ON_DATA"] = "onData";
@@ -2344,176 +2387,18 @@ var WatchedQueryListenerEvent;
2344
2387
  WatchedQueryListenerEvent["SETTINGS_WILL_UPDATE"] = "settingsWillUpdate";
2345
2388
  WatchedQueryListenerEvent["CLOSED"] = "closed";
2346
2389
  })(WatchedQueryListenerEvent || (WatchedQueryListenerEvent = {}));
2390
+ /**
2391
+ * @internal
2392
+ */
2347
2393
  const DEFAULT_WATCH_THROTTLE_MS = 30;
2394
+ /**
2395
+ * @internal
2396
+ */
2348
2397
  const DEFAULT_WATCH_QUERY_OPTIONS = {
2349
2398
  throttleMs: DEFAULT_WATCH_THROTTLE_MS,
2350
2399
  reportFetching: true
2351
2400
  };
2352
2401
 
2353
- /**
2354
- * Orchestrates attachment synchronization between local and remote storage.
2355
- * Handles uploads, downloads, deletions, and state transitions.
2356
- *
2357
- * @internal
2358
- */
2359
- class SyncingService {
2360
- attachmentService;
2361
- localStorage;
2362
- remoteStorage;
2363
- logger;
2364
- errorHandler;
2365
- constructor(attachmentService, localStorage, remoteStorage, logger, errorHandler) {
2366
- this.attachmentService = attachmentService;
2367
- this.localStorage = localStorage;
2368
- this.remoteStorage = remoteStorage;
2369
- this.logger = logger;
2370
- this.errorHandler = errorHandler;
2371
- }
2372
- /**
2373
- * Processes attachments based on their state (upload, download, or delete).
2374
- * All updates are saved in a single batch after processing.
2375
- *
2376
- * @param attachments - Array of attachment records to process
2377
- * @param context - Attachment context for database operations
2378
- * @returns Promise that resolves when all attachments have been processed and saved
2379
- */
2380
- async processAttachments(attachments, context) {
2381
- const updatedAttachments = [];
2382
- for (const attachment of attachments) {
2383
- switch (attachment.state) {
2384
- case AttachmentState.QUEUED_UPLOAD:
2385
- const uploaded = await this.uploadAttachment(attachment);
2386
- updatedAttachments.push(uploaded);
2387
- break;
2388
- case AttachmentState.QUEUED_DOWNLOAD:
2389
- const downloaded = await this.downloadAttachment(attachment);
2390
- updatedAttachments.push(downloaded);
2391
- break;
2392
- case AttachmentState.QUEUED_DELETE:
2393
- const deleted = await this.deleteAttachment(attachment, context);
2394
- updatedAttachments.push(deleted);
2395
- break;
2396
- }
2397
- }
2398
- await context.saveAttachments(updatedAttachments);
2399
- }
2400
- /**
2401
- * Uploads an attachment from local storage to remote storage.
2402
- * On success, marks as SYNCED. On failure, defers to error handler or archives.
2403
- *
2404
- * @param attachment - The attachment record to upload
2405
- * @returns Updated attachment record with new state
2406
- * @throws Error if the attachment has no localUri
2407
- */
2408
- async uploadAttachment(attachment) {
2409
- this.logger.info(`Uploading attachment ${attachment.filename}`);
2410
- try {
2411
- if (attachment.localUri == null) {
2412
- throw new Error(`No localUri for attachment ${attachment.id}`);
2413
- }
2414
- const fileBlob = await this.localStorage.readFile(attachment.localUri);
2415
- await this.remoteStorage.uploadFile(fileBlob, attachment);
2416
- return {
2417
- ...attachment,
2418
- state: AttachmentState.SYNCED,
2419
- hasSynced: true
2420
- };
2421
- }
2422
- catch (error) {
2423
- const shouldRetry = (await this.errorHandler?.onUploadError(attachment, error)) ?? true;
2424
- if (!shouldRetry) {
2425
- return {
2426
- ...attachment,
2427
- state: AttachmentState.ARCHIVED
2428
- };
2429
- }
2430
- return attachment;
2431
- }
2432
- }
2433
- /**
2434
- * Downloads an attachment from remote storage to local storage.
2435
- * Retrieves the file, converts to base64, and saves locally.
2436
- * On success, marks as SYNCED. On failure, defers to error handler or archives.
2437
- *
2438
- * @param attachment - The attachment record to download
2439
- * @returns Updated attachment record with local URI and new state
2440
- */
2441
- async downloadAttachment(attachment) {
2442
- this.logger.info(`Downloading attachment ${attachment.filename}`);
2443
- try {
2444
- const fileData = await this.remoteStorage.downloadFile(attachment);
2445
- const localUri = this.localStorage.getLocalUri(attachment.filename);
2446
- await this.localStorage.saveFile(localUri, fileData);
2447
- return {
2448
- ...attachment,
2449
- state: AttachmentState.SYNCED,
2450
- localUri: localUri,
2451
- hasSynced: true
2452
- };
2453
- }
2454
- catch (error) {
2455
- const shouldRetry = (await this.errorHandler?.onDownloadError(attachment, error)) ?? true;
2456
- if (!shouldRetry) {
2457
- return {
2458
- ...attachment,
2459
- state: AttachmentState.ARCHIVED
2460
- };
2461
- }
2462
- return attachment;
2463
- }
2464
- }
2465
- /**
2466
- * Deletes an attachment from both remote and local storage.
2467
- * Removes the remote file, local file (if exists), and the attachment record.
2468
- * On failure, defers to error handler or archives.
2469
- *
2470
- * @param attachment - The attachment record to delete
2471
- * @param context - Attachment context for database operations
2472
- * @returns Updated attachment record
2473
- */
2474
- async deleteAttachment(attachment, context) {
2475
- try {
2476
- await this.remoteStorage.deleteFile(attachment);
2477
- if (attachment.localUri) {
2478
- await this.localStorage.deleteFile(attachment.localUri);
2479
- }
2480
- await context.deleteAttachment(attachment.id);
2481
- return {
2482
- ...attachment,
2483
- state: AttachmentState.ARCHIVED
2484
- };
2485
- }
2486
- catch (error) {
2487
- const shouldRetry = (await this.errorHandler?.onDeleteError(attachment, error)) ?? true;
2488
- if (!shouldRetry) {
2489
- return {
2490
- ...attachment,
2491
- state: AttachmentState.ARCHIVED
2492
- };
2493
- }
2494
- return attachment;
2495
- }
2496
- }
2497
- /**
2498
- * Performs cleanup of archived attachments by removing their local files and records.
2499
- * Errors during local file deletion are logged but do not prevent record deletion.
2500
- */
2501
- async deleteArchivedAttachments(context) {
2502
- return await context.deleteArchivedAttachments(async (archivedAttachments) => {
2503
- for (const attachment of archivedAttachments) {
2504
- if (attachment.localUri) {
2505
- try {
2506
- await this.localStorage.deleteFile(attachment.localUri);
2507
- }
2508
- catch (error) {
2509
- this.logger.error('Error deleting local file for archived attachment', error);
2510
- }
2511
- }
2512
- }
2513
- });
2514
- }
2515
- }
2516
-
2517
2402
  /**
2518
2403
  * A simple fixed-capacity queue implementation.
2519
2404
  *
@@ -2670,93 +2555,260 @@ class Semaphore {
2670
2555
  return { release, item: items[0] };
2671
2556
  }
2672
2557
  /**
2673
- * Requests access to all items from the pool.
2558
+ * Requests access to all items from the pool.
2559
+ *
2560
+ * The returned `release` callback must be invoked to return items into the pool.
2561
+ */
2562
+ requestAll(abort) {
2563
+ return this.requestPermits(this.size, abort);
2564
+ }
2565
+ }
2566
+ /**
2567
+ * An asynchronous mutex implementation.
2568
+ *
2569
+ * @internal This class is meant to be used in PowerSync SDKs only, and is not part of the public API.
2570
+ */
2571
+ class Mutex {
2572
+ inner = new Semaphore([null]);
2573
+ async acquire(abort) {
2574
+ const { release } = await this.inner.requestOne(abort);
2575
+ return release;
2576
+ }
2577
+ async runExclusive(fn, abort) {
2578
+ const returnMutex = await this.acquire(abort);
2579
+ try {
2580
+ return await fn();
2581
+ }
2582
+ finally {
2583
+ returnMutex();
2584
+ }
2585
+ }
2586
+ }
2587
+ /**
2588
+ * @internal
2589
+ */
2590
+ function timeoutSignal(timeout) {
2591
+ if (timeout == null)
2592
+ return;
2593
+ if ('timeout' in AbortSignal)
2594
+ return AbortSignal.timeout(timeout);
2595
+ const controller = new AbortController();
2596
+ setTimeout(() => controller.abort(new Error('Timeout waiting for lock')), timeout);
2597
+ return controller.signal;
2598
+ }
2599
+
2600
+ /**
2601
+ * Service for querying and watching attachment records in the database.
2602
+ *
2603
+ * @internal
2604
+ */
2605
+ class AttachmentService {
2606
+ db;
2607
+ logger;
2608
+ tableName;
2609
+ mutex = new Mutex();
2610
+ context;
2611
+ constructor(db, logger, tableName = 'attachments', archivedCacheLimit = 100) {
2612
+ this.db = db;
2613
+ this.logger = logger;
2614
+ this.tableName = tableName;
2615
+ this.context = new AttachmentContext(db, tableName, logger, archivedCacheLimit);
2616
+ }
2617
+ /**
2618
+ * Creates a differential watch query for active attachments requiring synchronization.
2619
+ * @returns Watch query that emits changes for queued uploads, downloads, and deletes
2620
+ */
2621
+ watchActiveAttachments({ throttleMs } = {}) {
2622
+ this.logger.info('Watching active attachments...');
2623
+ const watch = this.db
2624
+ .query({
2625
+ sql: /* sql */ `
2626
+ SELECT
2627
+ *
2628
+ FROM
2629
+ ${this.tableName}
2630
+ WHERE
2631
+ state = ?
2632
+ OR state = ?
2633
+ OR state = ?
2634
+ ORDER BY
2635
+ timestamp ASC
2636
+ `,
2637
+ parameters: [AttachmentState.QUEUED_UPLOAD, AttachmentState.QUEUED_DOWNLOAD, AttachmentState.QUEUED_DELETE]
2638
+ })
2639
+ .differentialWatch({ throttleMs });
2640
+ return watch;
2641
+ }
2642
+ /**
2643
+ * Executes a callback with exclusive access to the attachment context.
2644
+ */
2645
+ async withContext(callback) {
2646
+ return this.mutex.runExclusive(async () => {
2647
+ return callback(this.context);
2648
+ });
2649
+ }
2650
+ }
2651
+
2652
+ /**
2653
+ * Orchestrates attachment synchronization between local and remote storage.
2654
+ * Handles uploads, downloads, deletions, and state transitions.
2655
+ *
2656
+ * @internal
2657
+ */
2658
+ class SyncingService {
2659
+ attachmentService;
2660
+ localStorage;
2661
+ remoteStorage;
2662
+ logger;
2663
+ errorHandler;
2664
+ constructor(attachmentService, localStorage, remoteStorage, logger, errorHandler) {
2665
+ this.attachmentService = attachmentService;
2666
+ this.localStorage = localStorage;
2667
+ this.remoteStorage = remoteStorage;
2668
+ this.logger = logger;
2669
+ this.errorHandler = errorHandler;
2670
+ }
2671
+ /**
2672
+ * Processes attachments based on their state (upload, download, or delete).
2673
+ * All updates are saved in a single batch after processing.
2674
+ *
2675
+ * @param attachments - Array of attachment records to process
2676
+ * @param context - Attachment context for database operations
2677
+ * @returns Promise that resolves when all attachments have been processed and saved
2678
+ */
2679
+ async processAttachments(attachments, context) {
2680
+ const updatedAttachments = [];
2681
+ for (const attachment of attachments) {
2682
+ switch (attachment.state) {
2683
+ case AttachmentState.QUEUED_UPLOAD:
2684
+ const uploaded = await this.uploadAttachment(attachment);
2685
+ updatedAttachments.push(uploaded);
2686
+ break;
2687
+ case AttachmentState.QUEUED_DOWNLOAD:
2688
+ const downloaded = await this.downloadAttachment(attachment);
2689
+ updatedAttachments.push(downloaded);
2690
+ break;
2691
+ case AttachmentState.QUEUED_DELETE:
2692
+ const deleted = await this.deleteAttachment(attachment, context);
2693
+ updatedAttachments.push(deleted);
2694
+ break;
2695
+ }
2696
+ }
2697
+ await context.saveAttachments(updatedAttachments);
2698
+ }
2699
+ /**
2700
+ * Uploads an attachment from local storage to remote storage.
2701
+ * On success, marks as SYNCED. On failure, defers to error handler or archives.
2702
+ *
2703
+ * @param attachment - The attachment record to upload
2704
+ * @returns Updated attachment record with new state
2705
+ * @throws Error if the attachment has no localUri
2706
+ */
2707
+ async uploadAttachment(attachment) {
2708
+ this.logger.info(`Uploading attachment ${attachment.filename}`);
2709
+ try {
2710
+ if (attachment.localUri == null) {
2711
+ throw new Error(`No localUri for attachment ${attachment.id}`);
2712
+ }
2713
+ const fileBlob = await this.localStorage.readFile(attachment.localUri);
2714
+ await this.remoteStorage.uploadFile(fileBlob, attachment);
2715
+ return {
2716
+ ...attachment,
2717
+ state: AttachmentState.SYNCED,
2718
+ hasSynced: true
2719
+ };
2720
+ }
2721
+ catch (error) {
2722
+ const shouldRetry = (await this.errorHandler?.onUploadError(attachment, error)) ?? true;
2723
+ if (!shouldRetry) {
2724
+ return {
2725
+ ...attachment,
2726
+ state: AttachmentState.ARCHIVED
2727
+ };
2728
+ }
2729
+ return attachment;
2730
+ }
2731
+ }
2732
+ /**
2733
+ * Downloads an attachment from remote storage to local storage.
2734
+ * Retrieves the file, converts to base64, and saves locally.
2735
+ * On success, marks as SYNCED. On failure, defers to error handler or archives.
2736
+ *
2737
+ * @param attachment - The attachment record to download
2738
+ * @returns Updated attachment record with local URI and new state
2739
+ */
2740
+ async downloadAttachment(attachment) {
2741
+ this.logger.info(`Downloading attachment ${attachment.filename}`);
2742
+ try {
2743
+ const fileData = await this.remoteStorage.downloadFile(attachment);
2744
+ const localUri = this.localStorage.getLocalUri(attachment.filename);
2745
+ await this.localStorage.saveFile(localUri, fileData);
2746
+ return {
2747
+ ...attachment,
2748
+ state: AttachmentState.SYNCED,
2749
+ localUri: localUri,
2750
+ hasSynced: true
2751
+ };
2752
+ }
2753
+ catch (error) {
2754
+ const shouldRetry = (await this.errorHandler?.onDownloadError(attachment, error)) ?? true;
2755
+ if (!shouldRetry) {
2756
+ return {
2757
+ ...attachment,
2758
+ state: AttachmentState.ARCHIVED
2759
+ };
2760
+ }
2761
+ return attachment;
2762
+ }
2763
+ }
2764
+ /**
2765
+ * Deletes an attachment from both remote and local storage.
2766
+ * Removes the remote file, local file (if exists), and the attachment record.
2767
+ * On failure, defers to error handler or archives.
2674
2768
  *
2675
- * The returned `release` callback must be invoked to return items into the pool.
2769
+ * @param attachment - The attachment record to delete
2770
+ * @param context - Attachment context for database operations
2771
+ * @returns Updated attachment record
2676
2772
  */
2677
- requestAll(abort) {
2678
- return this.requestPermits(this.size, abort);
2679
- }
2680
- }
2681
- /**
2682
- * An asynchronous mutex implementation.
2683
- *
2684
- * @internal This class is meant to be used in PowerSync SDKs only, and is not part of the public API.
2685
- */
2686
- class Mutex {
2687
- inner = new Semaphore([null]);
2688
- async acquire(abort) {
2689
- const { release } = await this.inner.requestOne(abort);
2690
- return release;
2691
- }
2692
- async runExclusive(fn, abort) {
2693
- const returnMutex = await this.acquire(abort);
2773
+ async deleteAttachment(attachment, context) {
2694
2774
  try {
2695
- return await fn();
2775
+ await this.remoteStorage.deleteFile(attachment);
2776
+ if (attachment.localUri) {
2777
+ await this.localStorage.deleteFile(attachment.localUri);
2778
+ }
2779
+ await context.deleteAttachment(attachment.id);
2780
+ return {
2781
+ ...attachment,
2782
+ state: AttachmentState.ARCHIVED
2783
+ };
2696
2784
  }
2697
- finally {
2698
- returnMutex();
2785
+ catch (error) {
2786
+ const shouldRetry = (await this.errorHandler?.onDeleteError(attachment, error)) ?? true;
2787
+ if (!shouldRetry) {
2788
+ return {
2789
+ ...attachment,
2790
+ state: AttachmentState.ARCHIVED
2791
+ };
2792
+ }
2793
+ return attachment;
2699
2794
  }
2700
2795
  }
2701
- }
2702
- function timeoutSignal(timeout) {
2703
- if (timeout == null)
2704
- return;
2705
- if ('timeout' in AbortSignal)
2706
- return AbortSignal.timeout(timeout);
2707
- const controller = new AbortController();
2708
- setTimeout(() => controller.abort(new Error('Timeout waiting for lock')), timeout);
2709
- return controller.signal;
2710
- }
2711
-
2712
- /**
2713
- * Service for querying and watching attachment records in the database.
2714
- *
2715
- * @internal
2716
- */
2717
- class AttachmentService {
2718
- db;
2719
- logger;
2720
- tableName;
2721
- mutex = new Mutex();
2722
- context;
2723
- constructor(db, logger, tableName = 'attachments', archivedCacheLimit = 100) {
2724
- this.db = db;
2725
- this.logger = logger;
2726
- this.tableName = tableName;
2727
- this.context = new AttachmentContext(db, tableName, logger, archivedCacheLimit);
2728
- }
2729
- /**
2730
- * Creates a differential watch query for active attachments requiring synchronization.
2731
- * @returns Watch query that emits changes for queued uploads, downloads, and deletes
2732
- */
2733
- watchActiveAttachments({ throttleMs } = {}) {
2734
- this.logger.info('Watching active attachments...');
2735
- const watch = this.db
2736
- .query({
2737
- sql: /* sql */ `
2738
- SELECT
2739
- *
2740
- FROM
2741
- ${this.tableName}
2742
- WHERE
2743
- state = ?
2744
- OR state = ?
2745
- OR state = ?
2746
- ORDER BY
2747
- timestamp ASC
2748
- `,
2749
- parameters: [AttachmentState.QUEUED_UPLOAD, AttachmentState.QUEUED_DOWNLOAD, AttachmentState.QUEUED_DELETE]
2750
- })
2751
- .differentialWatch({ throttleMs });
2752
- return watch;
2753
- }
2754
2796
  /**
2755
- * Executes a callback with exclusive access to the attachment context.
2797
+ * Performs cleanup of archived attachments by removing their local files and records.
2798
+ * Errors during local file deletion are logged but do not prevent record deletion.
2756
2799
  */
2757
- async withContext(callback) {
2758
- return this.mutex.runExclusive(async () => {
2759
- return callback(this.context);
2800
+ async deleteArchivedAttachments(context) {
2801
+ return await context.deleteArchivedAttachments(async (archivedAttachments) => {
2802
+ for (const attachment of archivedAttachments) {
2803
+ if (attachment.localUri) {
2804
+ try {
2805
+ await this.localStorage.deleteFile(attachment.localUri);
2806
+ }
2807
+ catch (error) {
2808
+ this.logger.error('Error deleting local file for archived attachment', error);
2809
+ }
2810
+ }
2811
+ }
2760
2812
  });
2761
2813
  }
2762
2814
  }
@@ -2817,16 +2869,6 @@ class AttachmentQueue {
2817
2869
  * Creates a new AttachmentQueue instance.
2818
2870
  *
2819
2871
  * @param options - Configuration options
2820
- * @param options.db - PowerSync database instance
2821
- * @param options.remoteStorage - Remote storage adapter for upload/download operations
2822
- * @param options.localStorage - Local storage adapter for file persistence
2823
- * @param options.watchAttachments - Callback for monitoring attachment changes in your data model
2824
- * @param options.tableName - Name of the table to store attachment records. Default: 'ps_attachment_queue'
2825
- * @param options.logger - Logger instance. Defaults to db.logger
2826
- * @param options.syncIntervalMs - Periodic polling interval in milliseconds for retrying failed uploads/downloads. Default: 30000
2827
- * @param options.syncThrottleDuration - Throttle duration in milliseconds for the reactive watch query that detects attachment changes. Prevents rapid-fire syncs during bulk changes. Default: 30
2828
- * @param options.downloadAttachments - Whether to automatically download remote attachments. Default: true
2829
- * @param options.archivedCacheLimit - Maximum archived attachments before cleanup. Default: 100
2830
2872
  */
2831
2873
  constructor({ db, localStorage, remoteStorage, watchAttachments, logger, tableName = ATTACHMENT_TABLE, syncIntervalMs = 30 * 1000, syncThrottleDuration = DEFAULT_WATCH_THROTTLE_MS, downloadAttachments = true, archivedCacheLimit = 100, errorHandler }) {
2832
2874
  this.db = db;
@@ -2915,6 +2957,7 @@ class AttachmentQueue {
2915
2957
  state: AttachmentState.QUEUED_DOWNLOAD,
2916
2958
  hasSynced: false,
2917
2959
  metaData: watchedAttachment.metaData,
2960
+ mediaType: watchedAttachment.mediaType,
2918
2961
  timestamp: new Date().getTime()
2919
2962
  });
2920
2963
  continue;
@@ -3002,17 +3045,24 @@ class AttachmentQueue {
3002
3045
  this.statusListenerDispose = undefined;
3003
3046
  }
3004
3047
  }
3048
+ /**
3049
+ * Provides an {@link AttachmentContext} to a callback.
3050
+ *
3051
+ * The callback runs while the attachment queue mutex is held. Do not call
3052
+ * other {@link AttachmentQueue} methods from within the callback, as they may
3053
+ * attempt to acquire the same mutex and block indefinitely.
3054
+ */
3055
+ withAttachmentContext(callback) {
3056
+ /**
3057
+ * AttachmentService is internal and private in this class.
3058
+ * We only need to expose its locking and context functionality for extending classes.
3059
+ */
3060
+ return this.attachmentService.withContext(callback);
3061
+ }
3005
3062
  /**
3006
3063
  * Saves a file to local storage and queues it for upload to remote storage.
3007
3064
  *
3008
3065
  * @param options - File save options
3009
- * @param options.data - The file data as ArrayBuffer, Blob, or base64 string
3010
- * @param options.fileExtension - File extension (e.g., 'jpg', 'pdf')
3011
- * @param options.mediaType - MIME type of the file (e.g., 'image/jpeg')
3012
- * @param options.metaData - Optional metadata to associate with the attachment
3013
- * @param options.id - Optional custom ID. If not provided, a UUID will be generated
3014
- * @param options.updateHook - Optional callback to execute additional database operations
3015
- * within the same transaction as the attachment creation
3016
3066
  * @returns Promise resolving to the created attachment record
3017
3067
  */
3018
3068
  async saveFile({ data, fileExtension, mediaType, metaData, id, updateHook }) {
@@ -3125,6 +3175,9 @@ class AttachmentQueue {
3125
3175
  }
3126
3176
  }
3127
3177
 
3178
+ /**
3179
+ * @alpha
3180
+ */
3128
3181
  var EncodingType;
3129
3182
  (function (EncodingType) {
3130
3183
  EncodingType["UTF8"] = "utf8";
@@ -3588,7 +3641,9 @@ var Logger = /*@__PURE__*/getDefaultExportFromCjs(loggerExports);
3588
3641
  * different SQLite DB implementations.
3589
3642
  */
3590
3643
  /**
3591
- * Implements {@link DBGetUtils} on a {@link SqlRunner}.
3644
+ * Implements {@link DBGetUtils} on a {@link SqlExecutor}.
3645
+ *
3646
+ * @internal
3592
3647
  */
3593
3648
  function DBGetUtilsDefaultMixin(Base) {
3594
3649
  return class extends Base {
@@ -3632,6 +3687,8 @@ function DBGetUtilsDefaultMixin(Base) {
3632
3687
  }
3633
3688
  /**
3634
3689
  * Update table operation numbers from SQLite
3690
+ *
3691
+ * @public
3635
3692
  */
3636
3693
  var RowUpdateType;
3637
3694
  (function (RowUpdateType) {
@@ -3640,8 +3697,10 @@ var RowUpdateType;
3640
3697
  RowUpdateType[RowUpdateType["SQLITE_UPDATE"] = 23] = "SQLITE_UPDATE";
3641
3698
  })(RowUpdateType || (RowUpdateType = {}));
3642
3699
  /**
3643
- * A mixin to implement {@link DBAdapter} by delegating to {@link ConnectionPool.readLock} and
3644
- * {@link ConnectionPool.writeLock}.
3700
+ * A mixin to implement {@link DBAdapter} by delegating to {@link ConnectionPool#readLock} and
3701
+ * {@link ConnectionPool#writeLock}.
3702
+ *
3703
+ * @internal
3645
3704
  */
3646
3705
  function DBAdapterDefaultMixin(Base) {
3647
3706
  return class extends Base {
@@ -3729,9 +3788,15 @@ class TransactionImplementation extends DBGetUtilsDefaultMixin(BaseTransaction)
3729
3788
  }
3730
3789
  }
3731
3790
  }
3791
+ /**
3792
+ * @internal
3793
+ */
3732
3794
  function isBatchedUpdateNotification(update) {
3733
3795
  return 'tables' in update;
3734
3796
  }
3797
+ /**
3798
+ * @internal
3799
+ */
3735
3800
  function extractTableUpdates(update) {
3736
3801
  return isBatchedUpdateNotification(update) ? update.tables : [update.table];
3737
3802
  }
@@ -3759,6 +3824,8 @@ const FULL_SYNC_PRIORITY = 2147483647;
3759
3824
  *
3760
3825
  * Also note that data is downloaded in bulk, which means that individual counters are unlikely
3761
3826
  * to be updated one-by-one.
3827
+ *
3828
+ * @public
3762
3829
  */
3763
3830
  class SyncProgress {
3764
3831
  internal;
@@ -3797,6 +3864,9 @@ class SyncProgress {
3797
3864
  }
3798
3865
  }
3799
3866
 
3867
+ /**
3868
+ * @public
3869
+ */
3800
3870
  class SyncStatus {
3801
3871
  options;
3802
3872
  constructor(options) {
@@ -3807,6 +3877,8 @@ class SyncStatus {
3807
3877
  * implementation).
3808
3878
  *
3809
3879
  * This information is only available after a connection has been requested.
3880
+ *
3881
+ * @deprecated This always returns the Rust client (the only option).
3810
3882
  */
3811
3883
  get clientImplementation() {
3812
3884
  return this.options.clientImplementation;
@@ -3814,7 +3886,7 @@ class SyncStatus {
3814
3886
  /**
3815
3887
  * Indicates if the client is currently connected to the PowerSync service.
3816
3888
  *
3817
- * @returns {boolean} True if connected, false otherwise. Defaults to false if not specified.
3889
+ * @returns True if connected, false otherwise. Defaults to false if not specified.
3818
3890
  */
3819
3891
  get connected() {
3820
3892
  return this.options.connected ?? false;
@@ -3822,7 +3894,7 @@ class SyncStatus {
3822
3894
  /**
3823
3895
  * Indicates if the client is in the process of establishing a connection to the PowerSync service.
3824
3896
  *
3825
- * @returns {boolean} True if connecting, false otherwise. Defaults to false if not specified.
3897
+ * @returns True if connecting, false otherwise. Defaults to false if not specified.
3826
3898
  */
3827
3899
  get connecting() {
3828
3900
  return this.options.connecting ?? false;
@@ -3831,7 +3903,7 @@ class SyncStatus {
3831
3903
  * Time that a last sync has fully completed, if any.
3832
3904
  * This timestamp is reset to null after a restart of the PowerSync service.
3833
3905
  *
3834
- * @returns {Date | undefined} The timestamp of the last successful sync, or undefined if no sync has completed.
3906
+ * @returns The timestamp of the last successful sync, or undefined if no sync has completed.
3835
3907
  */
3836
3908
  get lastSyncedAt() {
3837
3909
  return this.options.lastSyncedAt;
@@ -3839,7 +3911,7 @@ class SyncStatus {
3839
3911
  /**
3840
3912
  * Indicates whether there has been at least one full sync completed since initialization.
3841
3913
  *
3842
- * @returns {boolean | undefined} True if at least one sync has completed, false if no sync has completed,
3914
+ * @returns True if at least one sync has completed, false if no sync has completed,
3843
3915
  * or undefined when the state is still being loaded from the database.
3844
3916
  */
3845
3917
  get hasSynced() {
@@ -3848,10 +3920,10 @@ class SyncStatus {
3848
3920
  /**
3849
3921
  * Provides the current data flow status regarding uploads and downloads.
3850
3922
  *
3851
- * @returns {SyncDataFlowStatus} An object containing:
3923
+ * @returns An object containing:
3852
3924
  * - downloading: True if actively downloading changes (only when connected is also true)
3853
3925
  * - uploading: True if actively uploading changes
3854
- * Defaults to {downloading: false, uploading: false} if not specified.
3926
+ * Defaults to `{downloading: false, uploading: false}` if not specified.
3855
3927
  */
3856
3928
  get dataFlowStatus() {
3857
3929
  return (this.options.dataFlow ?? {
@@ -3876,7 +3948,7 @@ class SyncStatus {
3876
3948
  return this.options.dataFlow?.internalStreamSubscriptions?.map((core) => new SyncStreamStatusView(this, core));
3877
3949
  }
3878
3950
  /**
3879
- * If the `stream` appears in {@link syncStreams}, returns the current status for that stream.
3951
+ * If the `stream` appears in {@link SyncStatus.syncStreams}, returns the current status for that stream.
3880
3952
  */
3881
3953
  forStream(stream) {
3882
3954
  const asJson = JSON.stringify(stream.parameters);
@@ -3886,7 +3958,7 @@ class SyncStatus {
3886
3958
  /**
3887
3959
  * Provides sync status information for all bucket priorities, sorted by priority (highest first).
3888
3960
  *
3889
- * @returns {SyncPriorityStatus[]} An array of status entries for different sync priority levels,
3961
+ * @returns An array of status entries for different sync priority levels,
3890
3962
  * sorted with highest priorities (lower numbers) first.
3891
3963
  */
3892
3964
  get priorityStatusEntries() {
@@ -3921,8 +3993,8 @@ class SyncStatus {
3921
3993
  * For example, if PowerSync just finished synchronizing buckets in priority level 3, calling this method
3922
3994
  * with a priority of 1 may return information for priority level 3.
3923
3995
  *
3924
- * @param {number} priority The bucket priority for which the status should be reported
3925
- * @returns {SyncPriorityStatus} Status information for the requested priority level or the next higher level with available status
3996
+ * @param priority - The bucket priority for which the status should be reported
3997
+ * @returns Status information for the requested priority level or the next higher level with available status
3926
3998
  */
3927
3999
  statusForPriority(priority) {
3928
4000
  // priorityStatusEntries are sorted by ascending priorities (so higher numbers to lower numbers).
@@ -3943,8 +4015,8 @@ class SyncStatus {
3943
4015
  * Compares this SyncStatus instance with another to determine if they are equal.
3944
4016
  * Equality is determined by comparing the serialized JSON representation of both instances.
3945
4017
  *
3946
- * @param {SyncStatus} status The SyncStatus instance to compare against
3947
- * @returns {boolean} True if the instances are considered equal, false otherwise
4018
+ * @param status - The SyncStatus instance to compare against
4019
+ * @returns True if the instances are considered equal, false otherwise
3948
4020
  */
3949
4021
  isEqual(status) {
3950
4022
  /**
@@ -3967,7 +4039,7 @@ class SyncStatus {
3967
4039
  * Creates a human-readable string representation of the current sync status.
3968
4040
  * Includes information about connection state, sync completion, and data flow.
3969
4041
  *
3970
- * @returns {string} A string representation of the sync status
4042
+ * @returns A string representation of the sync status
3971
4043
  */
3972
4044
  getMessage() {
3973
4045
  const dataFlow = this.dataFlowStatus;
@@ -3976,7 +4048,7 @@ class SyncStatus {
3976
4048
  /**
3977
4049
  * Serializes the SyncStatus instance to a plain object.
3978
4050
  *
3979
- * @returns {SyncStatusOptions} A plain object representation of the sync status
4051
+ * @returns A plain object representation of the sync status
3980
4052
  */
3981
4053
  toJSON() {
3982
4054
  return {
@@ -4042,6 +4114,9 @@ class SyncStreamStatusView {
4042
4114
  }
4043
4115
  }
4044
4116
 
4117
+ /**
4118
+ * @public
4119
+ */
4045
4120
  class UploadQueueStats {
4046
4121
  count;
4047
4122
  size;
@@ -4067,6 +4142,9 @@ class UploadQueueStats {
4067
4142
  }
4068
4143
  }
4069
4144
 
4145
+ /**
4146
+ * @internal
4147
+ */
4070
4148
  class BaseObserver {
4071
4149
  listeners = new Set();
4072
4150
  constructor() { }
@@ -4094,6 +4172,9 @@ class BaseObserver {
4094
4172
  }
4095
4173
  }
4096
4174
 
4175
+ /**
4176
+ * @internal
4177
+ */
4097
4178
  class ControlledExecutor {
4098
4179
  task;
4099
4180
  /**
@@ -4361,7 +4442,7 @@ class ConnectionManager extends BaseObserver {
4361
4442
  /**
4362
4443
  * Close the sync connection.
4363
4444
  *
4364
- * Use {@link connect} to connect again.
4445
+ * Use {@link ConnectionManager.connect} to connect again.
4365
4446
  */
4366
4447
  async disconnect() {
4367
4448
  // This will help abort pending connects
@@ -4501,6 +4582,8 @@ const _finalizer = 'FinalizationRegistry' in globalThis
4501
4582
  /**
4502
4583
  * An efficient comparator for {@link WatchedQuery} created with {@link Query#watch}. This has the ability to determine if a query
4503
4584
  * result has changes without necessarily processing all items in the result.
4585
+ *
4586
+ * @public
4504
4587
  */
4505
4588
  class ArrayComparator {
4506
4589
  options;
@@ -4528,6 +4611,8 @@ class ArrayComparator {
4528
4611
  }
4529
4612
  /**
4530
4613
  * Watched query comparator that always reports changed result sets.
4614
+ *
4615
+ * @public
4531
4616
  */
4532
4617
  const FalsyComparator = {
4533
4618
  checkEquality: () => false // Default comparator that always returns false
@@ -4735,6 +4820,8 @@ class AbstractQueryProcessor extends MetaBaseObserver {
4735
4820
  /**
4736
4821
  * An empty differential result set.
4737
4822
  * This is used as the initial state for differential incrementally watched queries.
4823
+ *
4824
+ * @internal
4738
4825
  */
4739
4826
  const EMPTY_DIFFERENTIAL = {
4740
4827
  added: [],
@@ -4747,6 +4834,8 @@ const EMPTY_DIFFERENTIAL = {
4747
4834
  * Default implementation of the {@link DifferentialWatchedQueryComparator} for watched queries.
4748
4835
  * It keys items by their `id` property if available, alternatively it uses JSON stringification
4749
4836
  * of the entire item for the key and comparison.
4837
+ *
4838
+ * @internal
4750
4839
  */
4751
4840
  const DEFAULT_ROW_COMPARATOR = {
4752
4841
  keyBy: (item) => {
@@ -5027,6 +5116,8 @@ class CustomQuery {
5027
5116
 
5028
5117
  /**
5029
5118
  * Tests if the input is a {@link SQLOpenOptions}
5119
+ *
5120
+ * @internal
5030
5121
  */
5031
5122
  const isSQLOpenOptions = (test) => {
5032
5123
  // typeof null is `object`, but you cannot use the `in` operator on `null.
@@ -5034,17 +5125,24 @@ const isSQLOpenOptions = (test) => {
5034
5125
  };
5035
5126
  /**
5036
5127
  * Tests if input is a {@link SQLOpenFactory}
5128
+ *
5129
+ * @internal
5037
5130
  */
5038
5131
  const isSQLOpenFactory = (test) => {
5039
5132
  return typeof test?.openDB == 'function';
5040
5133
  };
5041
5134
  /**
5042
5135
  * Tests if input is a {@link DBAdapter}
5136
+ *
5137
+ * @internal
5043
5138
  */
5044
5139
  const isDBAdapter = (test) => {
5045
5140
  return typeof test?.writeTransaction == 'function';
5046
5141
  };
5047
5142
 
5143
+ /**
5144
+ * @internal
5145
+ */
5048
5146
  var PSInternalTable;
5049
5147
  (function (PSInternalTable) {
5050
5148
  PSInternalTable["DATA"] = "ps_data";
@@ -5053,6 +5151,9 @@ var PSInternalTable;
5053
5151
  PSInternalTable["OPLOG"] = "ps_oplog";
5054
5152
  PSInternalTable["UNTYPED"] = "ps_untyped";
5055
5153
  })(PSInternalTable || (PSInternalTable = {}));
5154
+ /**
5155
+ * @internal
5156
+ */
5056
5157
  var PowerSyncControlCommand;
5057
5158
  (function (PowerSyncControlCommand) {
5058
5159
  PowerSyncControlCommand["PROCESS_TEXT_LINE"] = "line_text";
@@ -5070,6 +5171,8 @@ var PowerSyncControlCommand;
5070
5171
 
5071
5172
  /**
5072
5173
  * A batch of client-side changes.
5174
+ *
5175
+ * @public
5073
5176
  */
5074
5177
  class CrudBatch {
5075
5178
  crud;
@@ -5096,6 +5199,8 @@ class CrudBatch {
5096
5199
 
5097
5200
  /**
5098
5201
  * Type of local change.
5202
+ *
5203
+ * @public
5099
5204
  */
5100
5205
  var UpdateType;
5101
5206
  (function (UpdateType) {
@@ -5108,6 +5213,8 @@ var UpdateType;
5108
5213
  })(UpdateType || (UpdateType = {}));
5109
5214
  /**
5110
5215
  * A single client-side change.
5216
+ *
5217
+ * @public
5111
5218
  */
5112
5219
  class CrudEntry {
5113
5220
  /**
@@ -5204,6 +5311,9 @@ class CrudEntry {
5204
5311
  }
5205
5312
  }
5206
5313
 
5314
+ /**
5315
+ * @public
5316
+ */
5207
5317
  class CrudTransaction extends CrudBatch {
5208
5318
  crud;
5209
5319
  complete;
@@ -5232,6 +5342,8 @@ class CrudTransaction extends CrudBatch {
5232
5342
  * Calls to Abortcontroller.abort(reason: any) will result in the
5233
5343
  * `reason` being thrown. This is not necessarily an error,
5234
5344
  * but extends error for better logging purposes.
5345
+ *
5346
+ * @internal
5235
5347
  */
5236
5348
  class AbortOperation extends Error {
5237
5349
  reason;
@@ -12402,7 +12514,7 @@ function requireDist () {
12402
12514
 
12403
12515
  var distExports = requireDist();
12404
12516
 
12405
- var version = "1.53.2";
12517
+ var version = "1.54.0";
12406
12518
  var PACKAGE = {
12407
12519
  version: version};
12408
12520
 
@@ -12532,7 +12644,8 @@ class WebsocketClientTransport {
12532
12644
  removeListeners();
12533
12645
  resolve(new WebsocketDuplexConnectionExports.WebsocketDuplexConnection(websocket, new distExports.Deserializer(), multiplexerDemultiplexerFactory));
12534
12646
  };
12535
- const errorListener = (ev) => {
12647
+ const errorListener = (event) => {
12648
+ const ev = event;
12536
12649
  removeListeners();
12537
12650
  // We add a default error in that case.
12538
12651
  if (ev.error != null) {
@@ -12775,7 +12888,13 @@ const SOCKET_TIMEOUT_MS = 30_000;
12775
12888
  // If there is a backlog of messages (for example on slow connections), keepalive messages could be delayed
12776
12889
  // significantly. Therefore this is longer than the socket timeout.
12777
12890
  const KEEP_ALIVE_LIFETIME_MS = 90_000;
12891
+ /**
12892
+ * @internal
12893
+ */
12778
12894
  const DEFAULT_REMOTE_LOGGER = Logger.get('PowerSyncRemote');
12895
+ /**
12896
+ * @public
12897
+ */
12779
12898
  var FetchStrategy;
12780
12899
  (function (FetchStrategy) {
12781
12900
  /**
@@ -12794,12 +12913,17 @@ var FetchStrategy;
12794
12913
  * The class wrapper is used to distinguish the fetchImplementation
12795
12914
  * option in [AbstractRemoteOptions] from the general fetch method
12796
12915
  * which is typeof "function"
12916
+ *
12917
+ * @internal
12797
12918
  */
12798
12919
  class FetchImplementationProvider {
12799
12920
  getFetch() {
12800
12921
  throw new Error('Unspecified fetch implementation');
12801
12922
  }
12802
12923
  }
12924
+ /**
12925
+ * @internal
12926
+ */
12803
12927
  const DEFAULT_REMOTE_OPTIONS = {
12804
12928
  socketUrlTransformer: (url) => url.replace(/^https?:\/\//, function (match) {
12805
12929
  return match === 'https://' ? 'wss://' : 'ws://';
@@ -12807,6 +12931,9 @@ const DEFAULT_REMOTE_OPTIONS = {
12807
12931
  fetchImplementation: new FetchImplementationProvider(),
12808
12932
  fetchOptions: {}
12809
12933
  };
12934
+ /**
12935
+ * @internal
12936
+ */
12810
12937
  class AbstractRemote {
12811
12938
  connector;
12812
12939
  logger;
@@ -13216,7 +13343,7 @@ class AbstractRemote {
13216
13343
  * Posts a `/sync/stream` request.
13217
13344
  *
13218
13345
  * Depending on the `Content-Type` of the response, this returns strings for sync lines or encoded BSON documents as
13219
- * {@link Uint8Array}s.
13346
+ * `Uint8Array`s.
13220
13347
  */
13221
13348
  async fetchStream(options) {
13222
13349
  const { isBson, stream } = await this.fetchStreamRaw(options);
@@ -13258,16 +13385,26 @@ function isInterruptingInstruction(instruction) {
13258
13385
  return 'EstablishSyncStream' in instruction || 'CloseSyncStream' in instruction;
13259
13386
  }
13260
13387
 
13388
+ /**
13389
+ * @internal
13390
+ */
13261
13391
  var LockType;
13262
13392
  (function (LockType) {
13263
13393
  LockType["CRUD"] = "crud";
13264
13394
  LockType["SYNC"] = "sync";
13265
13395
  })(LockType || (LockType = {}));
13396
+ /**
13397
+ * @public
13398
+ */
13266
13399
  var SyncStreamConnectionMethod;
13267
13400
  (function (SyncStreamConnectionMethod) {
13268
13401
  SyncStreamConnectionMethod["HTTP"] = "http";
13269
13402
  SyncStreamConnectionMethod["WEB_SOCKET"] = "web-socket";
13270
13403
  })(SyncStreamConnectionMethod || (SyncStreamConnectionMethod = {}));
13404
+ /**
13405
+ * @deprecated Deprecated since {@link SyncClientImplementation.RUST} is the only option.
13406
+ * @public
13407
+ */
13271
13408
  var SyncClientImplementation;
13272
13409
  (function (SyncClientImplementation) {
13273
13410
  /**
@@ -13279,8 +13416,8 @@ var SyncClientImplementation;
13279
13416
  * ## Compatibility warning
13280
13417
  *
13281
13418
  * The Rust sync client stores sync data in a format that is slightly different than the one used
13282
- * by the old JavaScript client. When adopting the {@link RUST} client on existing databases, the PowerSync SDK will
13283
- * migrate the format automatically.
13419
+ * by the old JavaScript client. When adopting the {@link SyncClientImplementation.RUST} client on existing databases,
13420
+ * the PowerSync SDK will migrate the format automatically.
13284
13421
  *
13285
13422
  * SDK versions supporting both the JavaScript and the Rust client support both formats with the JavaScript client
13286
13423
  * implementaiton. However, downgrading to an SDK version that only supports the JavaScript client would not be
@@ -13290,14 +13427,29 @@ var SyncClientImplementation;
13290
13427
  })(SyncClientImplementation || (SyncClientImplementation = {}));
13291
13428
  /**
13292
13429
  * The default {@link SyncClientImplementation} to use, {@link SyncClientImplementation.RUST}.
13430
+ *
13431
+ * @deprecated Deprecated since {@link SyncClientImplementation.RUST} is the only option.
13432
+ * @public
13293
13433
  */
13294
13434
  const DEFAULT_SYNC_CLIENT_IMPLEMENTATION = SyncClientImplementation.RUST;
13435
+ /**
13436
+ * @internal
13437
+ */
13295
13438
  const DEFAULT_CRUD_UPLOAD_THROTTLE_MS = 1000;
13439
+ /**
13440
+ * @internal
13441
+ */
13296
13442
  const DEFAULT_RETRY_DELAY_MS = 5000;
13443
+ /**
13444
+ * @internal
13445
+ */
13297
13446
  const DEFAULT_STREAMING_SYNC_OPTIONS = {
13298
13447
  retryDelayMs: DEFAULT_RETRY_DELAY_MS,
13299
13448
  crudUploadThrottleMs: DEFAULT_CRUD_UPLOAD_THROTTLE_MS
13300
13449
  };
13450
+ /**
13451
+ * @internal
13452
+ */
13301
13453
  const DEFAULT_STREAM_CONNECTION_OPTIONS = {
13302
13454
  appMetadata: {},
13303
13455
  connectionMethod: SyncStreamConnectionMethod.WEB_SOCKET,
@@ -13307,6 +13459,9 @@ const DEFAULT_STREAM_CONNECTION_OPTIONS = {
13307
13459
  serializedSchema: undefined,
13308
13460
  includeDefaultStreams: true
13309
13461
  };
13462
+ /**
13463
+ * @internal
13464
+ */
13310
13465
  class AbstractStreamingSyncImplementation extends BaseObserver {
13311
13466
  options;
13312
13467
  abortController;
@@ -13630,7 +13785,7 @@ The next upload iteration will be delayed.`);
13630
13785
  this.handleActiveStreamsChange?.();
13631
13786
  }
13632
13787
  /**
13633
- * Older versions of the JS SDK used to encode subkeys as JSON in {@link OplogEntry.toJSON}.
13788
+ * Older versions of the JS SDK used to encode subkeys as JSON in `OplogEntry.toJSON`.
13634
13789
  * Because subkeys are always strings, this leads to quotes being added around them in `ps_oplog`.
13635
13790
  * While this is not a problem as long as it's done consistently, it causes issues when a database
13636
13791
  * created by the JS SDK is used with other SDKs, or (more likely) when the new Rust sync client
@@ -13640,7 +13795,7 @@ The next upload iteration will be delayed.`);
13640
13795
  * migration is only triggered when necessary (for now). The function returns whether the new format
13641
13796
  * should be used, so that the JS SDK is able to write to updated databases.
13642
13797
  *
13643
- * @param requireFixedKeyFormat Whether we require the new format or also support the old one.
13798
+ * @param requireFixedKeyFormat - Whether we require the new format or also support the old one.
13644
13799
  * The Rust client requires the new subkey format.
13645
13800
  * @returns Whether the database is now using the new, fixed subkey format.
13646
13801
  */
@@ -13947,7 +14102,8 @@ const MEMORY_TRIGGER_CLAIM_MANAGER = {
13947
14102
 
13948
14103
  /**
13949
14104
  * SQLite operations to track changes for with {@link TriggerManager}
13950
- * @experimental
14105
+ *
14106
+ * @experimental @alpha
13951
14107
  */
13952
14108
  var DiffTriggerOperation;
13953
14109
  (function (DiffTriggerOperation) {
@@ -14009,8 +14165,8 @@ class TriggerManagerImpl {
14009
14165
  get db() {
14010
14166
  return this.options.db;
14011
14167
  }
14012
- async getUUID() {
14013
- const { id: uuid } = await this.db.get(/* sql */ `
14168
+ async getUUID(ctx) {
14169
+ const { id: uuid } = await (ctx ?? this.db).get(/* sql */ `
14014
14170
  SELECT
14015
14171
  uuid () as id
14016
14172
  `);
@@ -14123,7 +14279,7 @@ class TriggerManagerImpl {
14123
14279
  const replicatedColumns = columns ?? sourceDefinition.columns.map((col) => col.name);
14124
14280
  const internalSource = sourceDefinition.internalName;
14125
14281
  const triggerIds = [];
14126
- const id = await this.getUUID();
14282
+ const id = await this.getUUID(setupContext);
14127
14283
  const releaseStorageClaim = useStorage ? await this.options.claimManager.obtainClaim(id) : null;
14128
14284
  /**
14129
14285
  * We default to replicating all columns if no columns array is provided.
@@ -14363,18 +14519,29 @@ const POWERSYNC_TABLE_MATCH = /(^ps_data__|^ps_data_local__)/;
14363
14519
  const DEFAULT_DISCONNECT_CLEAR_OPTIONS = {
14364
14520
  clearLocal: true
14365
14521
  };
14522
+ /**
14523
+ * @internal
14524
+ */
14366
14525
  const DEFAULT_POWERSYNC_CLOSE_OPTIONS = {
14367
14526
  disconnect: true
14368
14527
  };
14528
+ /**
14529
+ * @internal
14530
+ */
14369
14531
  const DEFAULT_POWERSYNC_DB_OPTIONS = {
14370
14532
  retryDelayMs: 5000,
14371
14533
  crudUploadThrottleMs: DEFAULT_CRUD_UPLOAD_THROTTLE_MS
14372
14534
  };
14535
+ /**
14536
+ * @internal
14537
+ */
14373
14538
  const DEFAULT_CRUD_BATCH_LIMIT = 100;
14374
14539
  /**
14375
14540
  * Requesting nested or recursive locks can block the application in some circumstances.
14376
14541
  * This default lock timeout will act as a failsafe to throw an error if a lock cannot
14377
14542
  * be obtained.
14543
+ *
14544
+ * @internal
14378
14545
  */
14379
14546
  const DEFAULT_LOCK_TIMEOUT_MS = 120_000; // 2 mins
14380
14547
  /**
@@ -14384,6 +14551,9 @@ const DEFAULT_LOCK_TIMEOUT_MS = 120_000; // 2 mins
14384
14551
  const isPowerSyncDatabaseOptionsWithSettings = (test) => {
14385
14552
  return typeof test == 'object' && isSQLOpenOptions(test.database);
14386
14553
  };
14554
+ /**
14555
+ * @public
14556
+ */
14387
14557
  class AbstractPowerSyncDatabase extends BaseObserver {
14388
14558
  options;
14389
14559
  /**
@@ -14541,7 +14711,7 @@ class AbstractPowerSyncDatabase extends BaseObserver {
14541
14711
  /**
14542
14712
  * Wait for the first sync operation to complete.
14543
14713
  *
14544
- * @param request Either an abort signal (after which the promise will complete regardless of
14714
+ * @param request - Either an abort signal (after which the promise will complete regardless of
14545
14715
  * whether a full sync was completed) or an object providing an abort signal and a priority target.
14546
14716
  * When a priority target is set, the promise may complete when all buckets with the given (or higher)
14547
14717
  * priorities have been synchronized. This can be earlier than a complete sync.
@@ -14696,7 +14866,7 @@ class AbstractPowerSyncDatabase extends BaseObserver {
14696
14866
  /**
14697
14867
  * Close the sync connection.
14698
14868
  *
14699
- * Use {@link connect} to connect again.
14869
+ * Use {@link AbstractPowerSyncDatabase.connect} to connect again.
14700
14870
  */
14701
14871
  async disconnect() {
14702
14872
  return this.connectionManager.disconnect();
@@ -14723,8 +14893,8 @@ class AbstractPowerSyncDatabase extends BaseObserver {
14723
14893
  /**
14724
14894
  * Create a sync stream to query its status or to subscribe to it.
14725
14895
  *
14726
- * @param name The name of the stream to subscribe to.
14727
- * @param params Optional parameters for the stream subscription.
14896
+ * @param name - The name of the stream to subscribe to.
14897
+ * @param params - Optional parameters for the stream subscription.
14728
14898
  * @returns A {@link SyncStream} instance that can be subscribed to.
14729
14899
  * @experimental Sync streams are currently in alpha.
14730
14900
  */
@@ -14782,14 +14952,14 @@ class AbstractPowerSyncDatabase extends BaseObserver {
14782
14952
  * Once the data have been successfully uploaded, call {@link CrudBatch.complete} before
14783
14953
  * requesting the next batch.
14784
14954
  *
14785
- * Use {@link limit} to specify the maximum number of updates to return in a single
14955
+ * Use the `limit` parameter to specify the maximum number of updates to return in a single
14786
14956
  * batch.
14787
14957
  *
14788
14958
  * This method does include transaction ids in the result, but does not group
14789
14959
  * data by transaction. One batch may contain data from multiple transactions,
14790
14960
  * and a single transaction may be split over multiple batches.
14791
14961
  *
14792
- * @param limit Maximum number of CRUD entries to include in the batch
14962
+ * @param limit - Maximum number of CRUD entries to include in the batch
14793
14963
  * @returns A batch of CRUD operations to upload, or null if there are none
14794
14964
  */
14795
14965
  async getCrudBatch(limit = DEFAULT_CRUD_BATCH_LIMIT) {
@@ -14816,7 +14986,7 @@ class AbstractPowerSyncDatabase extends BaseObserver {
14816
14986
  * Once the data have been successfully uploaded, call {@link CrudTransaction.complete} before
14817
14987
  * requesting the next transaction.
14818
14988
  *
14819
- * Unlike {@link getCrudBatch}, this only returns data from a single transaction at a time.
14989
+ * Unlike {@link AbstractPowerSyncDatabase.getCrudBatch}, this only returns data from a single transaction at a time.
14820
14990
  * All data for the transaction is loaded into memory.
14821
14991
  *
14822
14992
  * @returns A transaction of CRUD operations to upload, or null if there are none
@@ -14831,7 +15001,7 @@ class AbstractPowerSyncDatabase extends BaseObserver {
14831
15001
  * This is typically used from the {@link PowerSyncBackendConnector.uploadData} callback. Each entry emitted by the
14832
15002
  * returned iterator is a full transaction containing all local writes made while that transaction was active.
14833
15003
  *
14834
- * Unlike {@link getNextCrudTransaction}, which always returns the oldest transaction that hasn't been
15004
+ * Unlike {@link AbstractPowerSyncDatabase.getNextCrudTransaction}, which always returns the oldest transaction that hasn't been
14835
15005
  * {@link CrudTransaction.complete}d yet, this iterator can be used to receive multiple transactions. Calling
14836
15006
  * {@link CrudTransaction.complete} will mark that and all prior transactions emitted by the iterator as completed.
14837
15007
  *
@@ -14925,8 +15095,8 @@ SELECT * FROM crud_entries;
14925
15095
  * the returned result's `rowsAffected` may be `0` for successful `UPDATE` and `DELETE` statements.
14926
15096
  * Use a `RETURNING` clause and inspect `result.rows` when you need to confirm which rows changed.
14927
15097
  *
14928
- * @param sql The SQL query to execute
14929
- * @param parameters Optional array of parameters to bind to the query
15098
+ * @param sql - The SQL query to execute
15099
+ * @param parameters - Optional array of parameters to bind to the query
14930
15100
  * @returns The query result as an object with structured key-value pairs
14931
15101
  */
14932
15102
  async execute(sql, parameters) {
@@ -14936,8 +15106,8 @@ SELECT * FROM crud_entries;
14936
15106
  * Execute a SQL write (INSERT/UPDATE/DELETE) query directly on the database without any PowerSync processing.
14937
15107
  * This bypasses certain PowerSync abstractions and is useful for accessing the raw database results.
14938
15108
  *
14939
- * @param sql The SQL query to execute
14940
- * @param parameters Optional array of parameters to bind to the query
15109
+ * @param sql - The SQL query to execute
15110
+ * @param parameters - Optional array of parameters to bind to the query
14941
15111
  * @returns The raw query result from the underlying database as a nested array of raw values, where each row is
14942
15112
  * represented as an array of column values without field names.
14943
15113
  */
@@ -14950,8 +15120,8 @@ SELECT * FROM crud_entries;
14950
15120
  * and optionally return results.
14951
15121
  * This is faster than executing separately with each parameter set.
14952
15122
  *
14953
- * @param sql The SQL query to execute
14954
- * @param parameters Optional 2D array of parameter sets, where each inner array is a set of parameters for one execution
15123
+ * @param sql - The SQL query to execute
15124
+ * @param parameters - Optional 2D array of parameter sets, where each inner array is a set of parameters for one execution
14955
15125
  * @returns The query result
14956
15126
  */
14957
15127
  async executeBatch(sql, parameters) {
@@ -14961,8 +15131,8 @@ SELECT * FROM crud_entries;
14961
15131
  /**
14962
15132
  * Execute a read-only query and return results.
14963
15133
  *
14964
- * @param sql The SQL query to execute
14965
- * @param parameters Optional array of parameters to bind to the query
15134
+ * @param sql - The SQL query to execute
15135
+ * @param parameters - Optional array of parameters to bind to the query
14966
15136
  * @returns An array of results
14967
15137
  */
14968
15138
  async getAll(sql, parameters) {
@@ -14972,8 +15142,8 @@ SELECT * FROM crud_entries;
14972
15142
  /**
14973
15143
  * Execute a read-only query and return the first result, or null if the ResultSet is empty.
14974
15144
  *
14975
- * @param sql The SQL query to execute
14976
- * @param parameters Optional array of parameters to bind to the query
15145
+ * @param sql - The SQL query to execute
15146
+ * @param parameters - Optional array of parameters to bind to the query
14977
15147
  * @returns The first result if found, or null if no results are returned
14978
15148
  */
14979
15149
  async getOptional(sql, parameters) {
@@ -14983,8 +15153,8 @@ SELECT * FROM crud_entries;
14983
15153
  /**
14984
15154
  * Execute a read-only query and return the first result, error if the ResultSet is empty.
14985
15155
  *
14986
- * @param sql The SQL query to execute
14987
- * @param parameters Optional array of parameters to bind to the query
15156
+ * @param sql - The SQL query to execute
15157
+ * @param parameters - Optional array of parameters to bind to the query
14988
15158
  * @returns The first result matching the query
14989
15159
  * @throws Error if no rows are returned
14990
15160
  */
@@ -14994,7 +15164,7 @@ SELECT * FROM crud_entries;
14994
15164
  }
14995
15165
  /**
14996
15166
  * Takes a read lock, without starting a transaction.
14997
- * In most cases, {@link readTransaction} should be used instead.
15167
+ * In most cases, {@link AbstractPowerSyncDatabase.readTransaction} should be used instead.
14998
15168
  */
14999
15169
  async readLock(callback) {
15000
15170
  await this.waitForReady();
@@ -15002,7 +15172,7 @@ SELECT * FROM crud_entries;
15002
15172
  }
15003
15173
  /**
15004
15174
  * Takes a global lock, without starting a transaction.
15005
- * In most cases, {@link writeTransaction} should be used instead.
15175
+ * In most cases, {@link AbstractPowerSyncDatabase.writeTransaction} should be used instead.
15006
15176
  */
15007
15177
  async writeLock(callback) {
15008
15178
  await this.waitForReady();
@@ -15013,8 +15183,8 @@ SELECT * FROM crud_entries;
15013
15183
  * Read transactions can run concurrently to a write transaction.
15014
15184
  * Changes from any write transaction are not visible to read transactions started before it.
15015
15185
  *
15016
- * @param callback Function to execute within the transaction
15017
- * @param lockTimeout Time in milliseconds to wait for a lock before throwing an error
15186
+ * @param callback - Function to execute within the transaction
15187
+ * @param lockTimeout - Time in milliseconds to wait for a lock before throwing an error
15018
15188
  * @returns The result of the callback
15019
15189
  * @throws Error if the lock cannot be obtained within the timeout period
15020
15190
  */
@@ -15031,8 +15201,8 @@ SELECT * FROM crud_entries;
15031
15201
  * This takes a global lock - only one write transaction can execute against the database at a time.
15032
15202
  * Statements within the transaction must be done on the provided {@link Transaction} interface.
15033
15203
  *
15034
- * @param callback Function to execute within the transaction
15035
- * @param lockTimeout Time in milliseconds to wait for a lock before throwing an error
15204
+ * @param callback - Function to execute within the transaction
15205
+ * @param lockTimeout - Time in milliseconds to wait for a lock before throwing an error
15036
15206
  * @returns The result of the callback
15037
15207
  * @throws Error if the lock cannot be obtained within the timeout period
15038
15208
  */
@@ -15109,15 +15279,15 @@ SELECT * FROM crud_entries;
15109
15279
  }
15110
15280
  /**
15111
15281
  * Execute a read query every time the source tables are modified.
15112
- * Use {@link SQLWatchOptions.throttleMs} to specify the minimum interval between queries.
15282
+ * Use {@link SQLOnChangeOptions.throttleMs} to specify the minimum interval between queries.
15113
15283
  * Source tables are automatically detected using `EXPLAIN QUERY PLAN`.
15114
15284
  *
15115
15285
  * Note that the `onChange` callback member of the handler is required.
15116
15286
  *
15117
- * @param sql The SQL query to execute
15118
- * @param parameters Optional array of parameters to bind to the query
15119
- * @param handler Callbacks for handling results and errors
15120
- * @param options Options for configuring watch behavior
15287
+ * @param sql - The SQL query to execute
15288
+ * @param parameters - Optional array of parameters to bind to the query
15289
+ * @param handler - Callbacks for handling results and errors
15290
+ * @param options - Options for configuring watch behavior
15121
15291
  */
15122
15292
  watchWithCallback(sql, parameters, handler, options) {
15123
15293
  const { onResult, onError = (e) => this.logger.error(e) } = handler ?? {};
@@ -15130,7 +15300,7 @@ SELECT * FROM crud_entries;
15130
15300
  const watchedQuery = new OnChangeQueryProcessor({
15131
15301
  db: this,
15132
15302
  comparator,
15133
- placeholderData: null,
15303
+ placeholderData: null, // FIXME
15134
15304
  watchOptions: {
15135
15305
  query: {
15136
15306
  compile: () => ({
@@ -15163,12 +15333,12 @@ SELECT * FROM crud_entries;
15163
15333
  }
15164
15334
  /**
15165
15335
  * Execute a read query every time the source tables are modified.
15166
- * Use {@link SQLWatchOptions.throttleMs} to specify the minimum interval between queries.
15336
+ * Use {@link SQLOnChangeOptions.throttleMs} to specify the minimum interval between queries.
15167
15337
  * Source tables are automatically detected using `EXPLAIN QUERY PLAN`.
15168
15338
  *
15169
- * @param sql The SQL query to execute
15170
- * @param parameters Optional array of parameters to bind to the query
15171
- * @param options Options for configuring watch behavior
15339
+ * @param sql - The SQL query to execute
15340
+ * @param parameters - Optional array of parameters to bind to the query
15341
+ * @param options - Options for configuring watch behavior
15172
15342
  * @returns An AsyncIterable that yields QueryResults whenever the data changes
15173
15343
  */
15174
15344
  watchWithAsyncGenerator(sql, parameters, options) {
@@ -15192,9 +15362,9 @@ SELECT * FROM crud_entries;
15192
15362
  * If tables are specified in the options, those are used directly.
15193
15363
  * Otherwise, analyzes the query using EXPLAIN to determine which tables are accessed.
15194
15364
  *
15195
- * @param sql The SQL query to analyze
15196
- * @param parameters Optional parameters for the SQL query
15197
- * @param options Optional watch options that may contain explicit table list
15365
+ * @param sql - The SQL query to analyze
15366
+ * @param parameters - Optional parameters for the SQL query
15367
+ * @param options - Optional watch options that may contain explicit table list
15198
15368
  * @returns Array of table names that the query depends on
15199
15369
  */
15200
15370
  async resolveTables(sql, parameters, options) {
@@ -15223,13 +15393,13 @@ SELECT * FROM crud_entries;
15223
15393
  /**
15224
15394
  * Invoke the provided callback on any changes to any of the specified tables.
15225
15395
  *
15226
- * This is preferred over {@link watchWithCallback} when multiple queries need to be performed
15396
+ * This is preferred over {@link AbstractPowerSyncDatabase.watchWithCallback} when multiple queries need to be performed
15227
15397
  * together when data is changed.
15228
15398
  *
15229
15399
  * Note that the `onChange` callback member of the handler is required.
15230
15400
  *
15231
- * @param handler Callbacks for handling change events and errors
15232
- * @param options Options for configuring watch behavior
15401
+ * @param handler - Callbacks for handling change events and errors
15402
+ * @param options - Options for configuring watch behavior
15233
15403
  * @returns A dispose function to stop watching for changes
15234
15404
  */
15235
15405
  onChangeWithCallback(handler, options) {
@@ -15272,12 +15442,12 @@ SELECT * FROM crud_entries;
15272
15442
  /**
15273
15443
  * Create a Stream of changes to any of the specified tables.
15274
15444
  *
15275
- * This is preferred over {@link watchWithAsyncGenerator} when multiple queries need to be performed
15276
- * together when data is changed.
15445
+ * This is preferred over {@link AbstractPowerSyncDatabase.watchWithAsyncGenerator} when multiple queries need to be
15446
+ * performed together when data is changed.
15277
15447
  *
15278
15448
  * Note: do not declare this as `async *onChange` as it will not work in React Native.
15279
15449
  *
15280
- * @param options Options for configuring watch behavior
15450
+ * @param options - Options for configuring watch behavior
15281
15451
  * @returns An AsyncIterable that yields change events whenever the specified tables change
15282
15452
  */
15283
15453
  onChangeWithAsyncGenerator(options) {
@@ -15315,15 +15485,15 @@ SELECT * FROM crud_entries;
15315
15485
  changedTables.add(table);
15316
15486
  }
15317
15487
  }
15318
- /**
15319
- * @ignore
15320
- */
15321
15488
  async executeReadOnly(sql, params) {
15322
15489
  await this.waitForReady();
15323
15490
  return this.database.readLock((tx) => tx.execute(sql, params));
15324
15491
  }
15325
15492
  }
15326
15493
 
15494
+ /**
15495
+ * @internal
15496
+ */
15327
15497
  class AbstractPowerSyncDatabaseOpenFactory {
15328
15498
  options;
15329
15499
  constructor(options) {
@@ -15348,6 +15518,9 @@ class AbstractPowerSyncDatabaseOpenFactory {
15348
15518
  }
15349
15519
  }
15350
15520
 
15521
+ /**
15522
+ * @internal
15523
+ */
15351
15524
  function runOnSchemaChange(callback, db, options) {
15352
15525
  const triggerWatchedQuery = () => {
15353
15526
  const abortController = new AbortController();
@@ -15372,6 +15545,9 @@ function runOnSchemaChange(callback, db, options) {
15372
15545
  triggerWatchedQuery();
15373
15546
  }
15374
15547
 
15548
+ /**
15549
+ * @public
15550
+ */
15375
15551
  function compilableQueryWatch(db, query, handler, options) {
15376
15552
  const { onResult, onError = (e) => { } } = handler ?? {};
15377
15553
  if (!onResult) {
@@ -15409,8 +15585,14 @@ function compilableQueryWatch(db, query, handler, options) {
15409
15585
  runOnSchemaChange(watchQuery, db, options);
15410
15586
  }
15411
15587
 
15588
+ /**
15589
+ * @internal
15590
+ */
15412
15591
  const MAX_OP_ID = '9223372036854775807';
15413
15592
 
15593
+ /**
15594
+ * @internal
15595
+ */
15414
15596
  class SqliteBucketStorage extends BaseObserver {
15415
15597
  db;
15416
15598
  logger;
@@ -15571,6 +15753,8 @@ class SqliteBucketStorage extends BaseObserver {
15571
15753
  * Thrown when an underlying database connection is closed.
15572
15754
  * This is particularly relevant when worker connections are marked as closed while
15573
15755
  * operations are still in progress.
15756
+ *
15757
+ * @internal
15574
15758
  */
15575
15759
  class ConnectionClosedError extends Error {
15576
15760
  static NAME = 'ConnectionClosedError';
@@ -15590,6 +15774,8 @@ class ConnectionClosedError extends Error {
15590
15774
 
15591
15775
  /**
15592
15776
  * A schema is a collection of tables. It is used to define the structure of a database.
15777
+ *
15778
+ * @public
15593
15779
  */
15594
15780
  class Schema {
15595
15781
  /*
@@ -15626,7 +15812,7 @@ class Schema {
15626
15812
  * Since raw tables are not backed by JSON, running complex queries on them may be more efficient. Further, they allow
15627
15813
  * using client-side table and column constraints.
15628
15814
  *
15629
- * @param tables An object of (table name, raw table definition) entries.
15815
+ * @param tables - An object of (table name, raw table definition) entries.
15630
15816
  */
15631
15817
  withRawTables(tables) {
15632
15818
  for (const [name, rawTableDefinition] of Object.entries(tables)) {
@@ -15672,6 +15858,8 @@ class Schema {
15672
15858
  Generate a new table from the columns and indexes
15673
15859
  @deprecated You should use {@link Table} instead as it now allows TableV2 syntax.
15674
15860
  This will be removed in the next major release.
15861
+
15862
+ @public
15675
15863
  */
15676
15864
  class TableV2 extends Table {
15677
15865
  }
@@ -15682,6 +15870,8 @@ function sanitizeString(input) {
15682
15870
  /**
15683
15871
  * Helper function for sanitizing UUID input strings.
15684
15872
  * Typically used with {@link sanitizeSQL}.
15873
+ *
15874
+ * @alpha
15685
15875
  */
15686
15876
  function sanitizeUUID(uuid) {
15687
15877
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
@@ -15718,6 +15908,8 @@ function sanitizeUUID(uuid) {
15718
15908
  * // Incorrect:
15719
15909
  * sanitizeSQL`New.id = '${myID}'` // Produces double quotes: New.id = ''O''Reilly''
15720
15910
  * ```
15911
+ *
15912
+ * @alpha
15721
15913
  */
15722
15914
  function sanitizeSQL(strings, ...values) {
15723
15915
  let result = '';
@@ -15747,6 +15939,8 @@ function sanitizeSQL(strings, ...values) {
15747
15939
 
15748
15940
  /**
15749
15941
  * Performs a {@link AbstractPowerSyncDatabase.getAll} operation for a watched query.
15942
+ *
15943
+ * @public
15750
15944
  */
15751
15945
  class GetAllQuery {
15752
15946
  options;
@@ -15771,6 +15965,9 @@ class GetAllQuery {
15771
15965
  }
15772
15966
 
15773
15967
  const TypedLogger = Logger;
15968
+ /**
15969
+ * @public
15970
+ */
15774
15971
  const LogLevel = {
15775
15972
  TRACE: TypedLogger.TRACE,
15776
15973
  DEBUG: TypedLogger.DEBUG,
@@ -15787,6 +15984,7 @@ const LogLevel = {
15787
15984
  * across all loggers created with `createLogger`. Adjusting settings on this
15788
15985
  * base logger affects all loggers derived from it unless explicitly overridden.
15789
15986
  *
15987
+ * @public
15790
15988
  */
15791
15989
  function createBaseLogger() {
15792
15990
  return Logger;
@@ -15797,6 +15995,8 @@ function createBaseLogger() {
15797
15995
  * Named loggers allow specific modules or areas of your application to have
15798
15996
  * their own logging levels and behaviors. These loggers inherit configuration
15799
15997
  * from the base logger by default but can override settings independently.
15998
+ *
15999
+ * @public
15800
16000
  */
15801
16001
  function createLogger(name, options = {}) {
15802
16002
  const logger = Logger.get(name);
@@ -15806,6 +16006,9 @@ function createLogger(name, options = {}) {
15806
16006
  return logger;
15807
16007
  }
15808
16008
 
16009
+ /**
16010
+ * @internal
16011
+ */
15809
16012
  const parseQuery = (query, parameters) => {
15810
16013
  let sqlStatement;
15811
16014
  if (typeof query == 'string') {