@powersync/web 2.4.2 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/dist/index.react_native_web.js +142 -25
  2. package/dist/index.react_native_web.js.map +1 -1
  3. package/dist/worker/AccessHandlePoolVFS-Do8lc5Ck.js +2 -0
  4. package/dist/worker/AccessHandlePoolVFS-Do8lc5Ck.js.map +1 -0
  5. package/dist/worker/FacadeVFS-d1ZDvud7.js.map +1 -1
  6. package/dist/worker/IDBBatchAtomicVFS-CDb4d4wN.js +2 -0
  7. package/dist/worker/IDBBatchAtomicVFS-CDb4d4wN.js.map +1 -0
  8. package/dist/worker/MemoryVFS-DVJL5F8j.js.map +1 -1
  9. package/dist/worker/OPFSCoopSyncVFS-CDNBPKfy.js +2 -0
  10. package/dist/worker/OPFSCoopSyncVFS-CDNBPKfy.js.map +1 -0
  11. package/dist/worker/OPFSWriteAheadVFS-V9yBrLWl.js +2 -0
  12. package/dist/worker/OPFSWriteAheadVFS-V9yBrLWl.js.map +1 -0
  13. package/dist/worker/assets/mc-wa-sqlite-Cq3AePIW.wasm +0 -0
  14. package/dist/worker/assets/{mc-wa-sqlite-async-DdlQmAUV.wasm → mc-wa-sqlite-async-aRcIGeKj.wasm} +0 -0
  15. package/dist/worker/assets/wa-sqlite-CePoIZt_.wasm +0 -0
  16. package/dist/worker/assets/wa-sqlite-async-B3FiUnt1.wasm +0 -0
  17. package/dist/worker/{mc-wa-sqlite-PubB6u8c.js → mc-wa-sqlite-DRR2R_uj.js} +2 -2
  18. package/dist/worker/mc-wa-sqlite-DRR2R_uj.js.map +1 -0
  19. package/dist/worker/{mc-wa-sqlite-async-DJG_ANKO.js → mc-wa-sqlite-async-C40l6kIz.js} +2 -2
  20. package/dist/worker/mc-wa-sqlite-async-C40l6kIz.js.map +1 -0
  21. package/dist/worker/{wa-sqlite-D1_4mGs8.js → wa-sqlite-_a9CU4MM.js} +2 -2
  22. package/dist/worker/wa-sqlite-_a9CU4MM.js.map +1 -0
  23. package/dist/worker/wa-sqlite-async-Da0d0GJg.js +2 -0
  24. package/dist/worker/wa-sqlite-async-Da0d0GJg.js.map +1 -0
  25. package/dist/worker/{websockets-Q8W_lerF.js → websockets-Dx9ExO-W.js} +2 -2
  26. package/dist/worker/{websockets-Q8W_lerF.js.map → websockets-Dx9ExO-W.js.map} +1 -1
  27. package/dist/worker/worker.js +1 -1
  28. package/dist/worker/worker.js.map +1 -1
  29. package/lib/db/PowerSyncDatabase.d.ts +4 -3
  30. package/lib/db/PowerSyncDatabase.js +9 -2
  31. package/lib/db/PowerSyncDatabase.js.map +1 -1
  32. package/lib/db/adapters/options.d.ts +30 -0
  33. package/lib/db/adapters/options.js.map +1 -1
  34. package/lib/db/adapters/resolveAndValidateOptions.js +6 -1
  35. package/lib/db/adapters/resolveAndValidateOptions.js.map +1 -1
  36. package/lib/db/adapters/wa-sqlite/RawSqliteConnection.d.ts +5 -0
  37. package/lib/db/adapters/wa-sqlite/RawSqliteConnection.js +7 -2
  38. package/lib/db/adapters/wa-sqlite/RawSqliteConnection.js.map +1 -1
  39. package/lib/db/adapters/wa-sqlite/WASQLiteOpenFactory.js +4 -2
  40. package/lib/db/adapters/wa-sqlite/WASQLiteOpenFactory.js.map +1 -1
  41. package/lib/db/adapters/wa-sqlite/vfs.d.ts +24 -1
  42. package/lib/db/adapters/wa-sqlite/vfs.js +33 -4
  43. package/lib/db/adapters/wa-sqlite/vfs.js.map +1 -1
  44. package/lib/db/sync/SharedWebStreamingSyncImplementation.d.ts +2 -0
  45. package/lib/db/sync/SharedWebStreamingSyncImplementation.js +43 -12
  46. package/lib/db/sync/SharedWebStreamingSyncImplementation.js.map +1 -1
  47. package/lib/db/sync/WebRemote.d.ts +2 -3
  48. package/lib/db/sync/WebRemote.js +0 -2
  49. package/lib/db/sync/WebRemote.js.map +1 -1
  50. package/lib/db/sync/WebStreamingSyncImplementation.d.ts +8 -1
  51. package/lib/db/sync/WebStreamingSyncImplementation.js +14 -0
  52. package/lib/db/sync/WebStreamingSyncImplementation.js.map +1 -1
  53. package/lib/devtools/index.d.ts +7 -0
  54. package/lib/devtools/index.js +8 -0
  55. package/lib/devtools/index.js.map +1 -0
  56. package/lib/devtools/registry.d.ts +12 -0
  57. package/lib/devtools/registry.js +42 -0
  58. package/lib/devtools/registry.js.map +1 -0
  59. package/lib/worker/sync/BroadcastLogger.d.ts +1 -4
  60. package/lib/worker/sync/BroadcastLogger.js +14 -15
  61. package/lib/worker/sync/BroadcastLogger.js.map +1 -1
  62. package/lib/worker/sync/SharedSyncImplementation.d.ts +9 -2
  63. package/lib/worker/sync/SharedSyncImplementation.js +66 -37
  64. package/lib/worker/sync/SharedSyncImplementation.js.map +1 -1
  65. package/lib/worker/sync/WorkerClient.d.ts +3 -3
  66. package/lib/worker/sync/WorkerClient.js +3 -3
  67. package/lib/worker/sync/WorkerClient.js.map +1 -1
  68. package/package.json +12 -8
  69. package/src/db/PowerSyncDatabase.ts +12 -5
  70. package/src/db/adapters/options.ts +32 -0
  71. package/src/db/adapters/resolveAndValidateOptions.ts +9 -1
  72. package/src/db/adapters/wa-sqlite/RawSqliteConnection.ts +12 -2
  73. package/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.ts +6 -2
  74. package/src/db/adapters/wa-sqlite/vfs.ts +51 -4
  75. package/src/db/sync/SharedWebStreamingSyncImplementation.ts +54 -17
  76. package/src/db/sync/WebRemote.ts +2 -5
  77. package/src/db/sync/WebStreamingSyncImplementation.ts +18 -0
  78. package/src/devtools/index.ts +7 -0
  79. package/src/devtools/registry.ts +53 -0
  80. package/src/worker/sync/BroadcastLogger.ts +15 -15
  81. package/src/worker/sync/SharedSyncImplementation.ts +89 -48
  82. package/src/worker/sync/WorkerClient.ts +4 -3
  83. package/dist/worker/AccessHandlePoolVFS-BPUHfZME.js +0 -2
  84. package/dist/worker/AccessHandlePoolVFS-BPUHfZME.js.map +0 -1
  85. package/dist/worker/IDBBatchAtomicVFS-DbkDb777.js +0 -2
  86. package/dist/worker/IDBBatchAtomicVFS-DbkDb777.js.map +0 -1
  87. package/dist/worker/OPFSCoopSyncVFS-BgTiWPfa.js +0 -2
  88. package/dist/worker/OPFSCoopSyncVFS-BgTiWPfa.js.map +0 -1
  89. package/dist/worker/OPFSWriteAheadVFS-BW9pqSNn.js +0 -2
  90. package/dist/worker/OPFSWriteAheadVFS-BW9pqSNn.js.map +0 -1
  91. package/dist/worker/assets/mc-wa-sqlite-BHScYYZw.wasm +0 -0
  92. package/dist/worker/assets/wa-sqlite-CIxTmRHQ.wasm +0 -0
  93. package/dist/worker/assets/wa-sqlite-async-zc68fxQq.wasm +0 -0
  94. package/dist/worker/mc-wa-sqlite-PubB6u8c.js.map +0 -1
  95. package/dist/worker/mc-wa-sqlite-async-DJG_ANKO.js.map +0 -1
  96. package/dist/worker/wa-sqlite-D1_4mGs8.js.map +0 -1
  97. package/dist/worker/wa-sqlite-async-BxkwNY-2.js +0 -2
  98. package/dist/worker/wa-sqlite-async-BxkwNY-2.js.map +0 -1
@@ -1,7 +1,7 @@
1
1
  import { DBAdapter, LockContext, LogLevels, queryResultWithoutRows, BaseObserver } from '@powersync/common';
2
2
  export * from '@powersync/common';
3
3
  import * as Comlink from 'comlink';
4
- import { Mutex, ConnectionClosedError, Semaphore, LockType, AbstractRemote, AbstractStreamingSyncImplementation, BasePowerSyncDatabase, openDatabase } from '@powersync/shared-internals';
4
+ import { Mutex, ConnectionClosedError, Semaphore, LockType, AbstractRemote, AbstractStreamingSyncImplementation, serializeErrorForRelay, BasePowerSyncDatabase, openDatabase } from '@powersync/shared-internals';
5
5
  import { Factory, SQLITE_ROW } from '@journeyapps/wa-sqlite';
6
6
 
7
7
  /**
@@ -139,6 +139,35 @@ var WASQLiteVFS;
139
139
  function vfsRequiresDedicatedWorkers(vfs) {
140
140
  return vfs != WASQLiteVFS.IDBBatchAtomicVFS && vfs != WASQLiteVFS.InMemoryVfs;
141
141
  }
142
+ /**
143
+ * Whether the VFS can keep its files in a Storage Bucket, see {@link WebSpecificOpenOptions.storageBucket}.
144
+ */
145
+ function vfsSupportsStorageBuckets(vfs) {
146
+ return (vfs == WASQLiteVFS.OPFSCoopSyncVFS || vfs == WASQLiteVFS.OPFSWriteAheadVFS || vfs == WASQLiteVFS.AccessHandlePoolVFS);
147
+ }
148
+ /**
149
+ * Options for an OPFS-based VFS that keep its files in the named Storage Bucket, see
150
+ * {@link WebSpecificOpenOptions.storageBucket}. Without a bucket name, no options: the VFS uses the root of the
151
+ * origin private file system.
152
+ *
153
+ * @internal
154
+ */
155
+ function vfsOptionsForStorageBucket(storageBucket, storageBuckets = navigator.storageBuckets) {
156
+ if (storageBucket == null) {
157
+ return {};
158
+ }
159
+ if (storageBuckets == null) {
160
+ throw new Error(`The 'storageBucket' option needs the Storage Buckets API (navigator.storageBuckets), which this browser does not have. Check for it before setting the option.`);
161
+ }
162
+ return {
163
+ // Called by the VFS each time it needs its root directory. Opening the bucket again creates it when the
164
+ // browser deleted it with the rest of the site's data.
165
+ getRoot: () => storageBuckets.open(storageBucket).then((bucket) => bucket.getDirectory()),
166
+ // Keeps the locks and channels of a file apart from those of a file of the same name in another bucket.
167
+ // Bucket names cannot contain ':', so the names of two buckets never overlap.
168
+ prefix: `${storageBucket}:`
169
+ };
170
+ }
142
171
  async function asyncModuleFactory(encryptionKey) {
143
172
  if (encryptionKey) {
144
173
  const { default: factory } = await import('@journeyapps/wa-sqlite/dist/mc-wa-sqlite-async.mjs');
@@ -162,7 +191,7 @@ async function syncModuleFactory(encryptionKey) {
162
191
  /**
163
192
  * @internal
164
193
  */
165
- async function loadModuleAndVfs({ vfs, filename, encryptionKey }) {
194
+ async function loadModuleAndVfs({ vfs, filename, encryptionKey, storageBucket }) {
166
195
  let moduleFactory = syncModuleFactory;
167
196
  let resolveVfs;
168
197
  switch (vfs) {
@@ -178,19 +207,19 @@ async function loadModuleAndVfs({ vfs, filename, encryptionKey }) {
178
207
  case WASQLiteVFS.AccessHandlePoolVFS: {
179
208
  // @ts-expect-error The types for this import are missing upstream
180
209
  const { AccessHandlePoolVFS } = await import('@journeyapps/wa-sqlite/src/examples/AccessHandlePoolVFS.js');
181
- resolveVfs = (module) => AccessHandlePoolVFS.create(filename, module);
210
+ resolveVfs = (module) => AccessHandlePoolVFS.create(filename, module, vfsOptionsForStorageBucket(storageBucket));
182
211
  break;
183
212
  }
184
213
  case WASQLiteVFS.OPFSCoopSyncVFS: {
185
214
  // @ts-expect-error The types for this import are missing upstream
186
215
  const { OPFSCoopSyncVFS } = await import('@journeyapps/wa-sqlite/src/examples/OPFSCoopSyncVFS.js');
187
- resolveVfs = (module) => OPFSCoopSyncVFS.create(filename, module);
216
+ resolveVfs = (module) => OPFSCoopSyncVFS.create(filename, module, vfsOptionsForStorageBucket(storageBucket));
188
217
  break;
189
218
  }
190
219
  case WASQLiteVFS.OPFSWriteAheadVFS: {
191
220
  // @ts-expect-error The types for this import are missing upstream
192
221
  const { OPFSWriteAheadVFS } = await import('@journeyapps/wa-sqlite/src/examples/OPFSWriteAheadVFS.js');
193
- resolveVfs = (module) => OPFSWriteAheadVFS.create(filename, module, {});
222
+ resolveVfs = (module) => OPFSWriteAheadVFS.create(filename, module, vfsOptionsForStorageBucket(storageBucket));
194
223
  break;
195
224
  }
196
225
  case WASQLiteVFS.InMemoryVfs: {
@@ -439,6 +468,11 @@ function resolveAndValidateOptions(options) {
439
468
  if (vfsRequiresDedicatedWorkers(resolved.vfs) && !resolved.useWebWorker) {
440
469
  throw new Error(`Invalid configuration: The 'useWebWorker' flag must be true when using an OPFS-based VFS (${resolved.vfs}).`);
441
470
  }
471
+ if (resolved.storageBucket != null) {
472
+ if (!vfsSupportsStorageBuckets(resolved.vfs)) {
473
+ throw new Error(`Invalid configuration: The 'storageBucket' option needs an OPFS-based VFS, which ${resolved.vfs} is not.`);
474
+ }
475
+ }
442
476
  return resolved;
443
477
  }
444
478
 
@@ -530,9 +564,14 @@ class RawSqliteConnection {
530
564
  const sqlite3 = Factory(module);
531
565
  sqlite3.vfs_register(vfs, true);
532
566
  /**
533
- * Register the PowerSync core SQLite extension
567
+ * Register the PowerSync core and additional statically linked extensions
534
568
  */
535
- module.ccall('powersync_init_static', 'int', []);
569
+ for (const name of ['powersync_init_static', ...(this.options.additionalInitializationFunctions ?? [])]) {
570
+ const result = module.ccall(name, 'int', []);
571
+ if (result !== 0) {
572
+ throw new Error(`SQLite extension initializer ${name} failed with code ${result}`);
573
+ }
574
+ }
536
575
  /**
537
576
  * Create the multiple cipher vfs if an encryption key is provided
538
577
  */
@@ -1421,7 +1460,7 @@ class WASQLiteOpenFactory {
1421
1460
  return this.openAdapter();
1422
1461
  }
1423
1462
  async openConnection() {
1424
- const { enableMultiTabs, useWebWorker, vfs, dbFilename, encryptionKey, temporaryStorage, cacheSizeKb, preparedStatementsCache } = this.options;
1463
+ const { enableMultiTabs, useWebWorker, vfs, dbFilename, encryptionKey, temporaryStorage, cacheSizeKb, preparedStatementsCache, additionalInitializationFunctions, storageBucket } = this.options;
1425
1464
  if (!enableMultiTabs) {
1426
1465
  this.logger.log({ level: LogLevels.warn, message: 'Multiple tabs are not enabled in this browser' });
1427
1466
  }
@@ -1437,7 +1476,9 @@ class WASQLiteOpenFactory {
1437
1476
  temporaryStorage,
1438
1477
  cacheSizeKb,
1439
1478
  // TODO: Enable prepared statement cache by default?
1440
- preparedStatementsCache: preparedStatementsCache ?? 0
1479
+ preparedStatementsCache: preparedStatementsCache ?? 0,
1480
+ additionalInitializationFunctions,
1481
+ storageBucket
1441
1482
  };
1442
1483
  }
1443
1484
  if (useWebWorker) {
@@ -1653,10 +1694,8 @@ function getOsInfo(nav) {
1653
1694
  }
1654
1695
 
1655
1696
  class WebRemote extends AbstractRemote {
1656
- connector;
1657
1697
  constructor(connector, logger) {
1658
1698
  super(connector, logger);
1659
- this.connector = connector;
1660
1699
  }
1661
1700
  fetch({ resource, request }) {
1662
1701
  return fetch(resource, request);
@@ -1683,10 +1722,24 @@ class WebRemote extends AbstractRemote {
1683
1722
  let websockets;
1684
1723
 
1685
1724
  class WebStreamingSyncImplementation extends AbstractStreamingSyncImplementation {
1725
+ diagnosticsChannel;
1686
1726
  constructor(options) {
1687
1727
  // Super will store and provide default values for options
1688
1728
  super(options);
1689
1729
  }
1730
+ /**
1731
+ * Broadcasts a core diagnostics event on a same-origin channel for diagnostics tooling to consume.
1732
+ * The channel reaches the page even when sync runs in a shared worker.
1733
+ */
1734
+ emitDiagnostics(event) {
1735
+ this.diagnosticsChannel ??= new BroadcastChannel('powersync-diagnostics-events');
1736
+ this.diagnosticsChannel.postMessage(event);
1737
+ }
1738
+ async dispose() {
1739
+ await super.dispose();
1740
+ this.diagnosticsChannel?.close();
1741
+ this.diagnosticsChannel = undefined;
1742
+ }
1690
1743
  get webOptions() {
1691
1744
  return this.options;
1692
1745
  }
@@ -1731,11 +1784,24 @@ class SharedSyncClientProvider extends AbstractSharedSyncClientProvider {
1731
1784
  const { port } = await this.webDB.shareConnection();
1732
1785
  return Comlink.transfer(port, [port]);
1733
1786
  }
1787
+ async #relay(action) {
1788
+ try {
1789
+ return await action();
1790
+ }
1791
+ catch (ex) {
1792
+ /**
1793
+ * Connector callbacks run in this tab and their rejection crosses the
1794
+ * MessagePort to the sync worker, so serialize it here, where the error
1795
+ * originates, before Comlink's error transfer can drop custom fields.
1796
+ */
1797
+ throw serializeErrorForRelay(ex);
1798
+ }
1799
+ }
1734
1800
  invalidateCredentials() {
1735
1801
  this.options.remote.invalidateCredentials();
1736
1802
  }
1737
1803
  async fetchCredentials() {
1738
- const credentials = await this.options.remote.getCredentials();
1804
+ const credentials = await this.#relay(() => this.options.remote.getCredentials());
1739
1805
  if (credentials == null) {
1740
1806
  return null;
1741
1807
  }
@@ -1755,10 +1821,10 @@ class SharedSyncClientProvider extends AbstractSharedSyncClientProvider {
1755
1821
  * Don't return anything here, just incase something which is not
1756
1822
  * serializable is returned from the `uploadCrud` function.
1757
1823
  */
1758
- await this.options.uploadCrud();
1824
+ await this.#relay(() => this.options.connector.uploadCrud());
1759
1825
  }
1760
1826
  async postCheckpointRequest(clientId, requestId) {
1761
- return await this.options.postCheckpointRequest(clientId, requestId);
1827
+ return await this.#relay(async () => (await this.options.connector.postCheckpointRequest(clientId, requestId)) ?? null);
1762
1828
  }
1763
1829
  get logger() {
1764
1830
  return this.options.logger;
@@ -1835,9 +1901,13 @@ class SharedWebStreamingSyncImplementation extends WebStreamingSyncImplementatio
1835
1901
  * - The client sends the params to the shared worker after locks have been registered.
1836
1902
  */
1837
1903
  const closeSignal = await generateTabCloseSignal(this.abortOnClose.signal);
1904
+ const { identifier, connector } = this.options;
1838
1905
  // Awaiting here ensures the worker is waiting for the lock
1839
- await this.syncManager.addLockBasedCloseSignal(closeSignal);
1840
- const { identifier } = this.options;
1906
+ await this.syncManager.initialize(closeSignal, {
1907
+ hasFetchCredentials: !!connector.fetchCredentials,
1908
+ hasPostCheckpointRequest: !!connector.postCheckpointRequest,
1909
+ hasUploadCrud: !!connector.uploadCrud
1910
+ });
1841
1911
  await this.syncManager.setParams({
1842
1912
  dbParams: this.dbAdapter.getConfiguration(),
1843
1913
  streamOptions: {
@@ -1860,8 +1930,26 @@ class SharedWebStreamingSyncImplementation extends WebStreamingSyncImplementatio
1860
1930
  return this.syncManager.disconnect();
1861
1931
  }
1862
1932
  async dispose() {
1863
- await this.waitForReady();
1864
- await new Promise((resolve) => {
1933
+ let registeredWithWorker = true;
1934
+ try {
1935
+ await this.waitForReady();
1936
+ }
1937
+ catch {
1938
+ // The worker rejected this client (e.g. because it connects in a mode incompatible with other tabs), so it won't
1939
+ // acknowledge a close request either.
1940
+ registeredWithWorker = false;
1941
+ }
1942
+ if (registeredWithWorker) {
1943
+ await this.#closeWorkerClient();
1944
+ }
1945
+ await super.dispose();
1946
+ this.abortOnClose.abort();
1947
+ // Release the proxy
1948
+ this.syncManager[Comlink.releaseProxy]();
1949
+ this.worker.close();
1950
+ }
1951
+ #closeWorkerClient() {
1952
+ return new Promise((resolve) => {
1865
1953
  // This will always be a message port since we use shared workers.
1866
1954
  const messagePort = this.worker.endpoint;
1867
1955
  // Listen for the close acknowledgment from the worker
@@ -1878,11 +1966,6 @@ class SharedWebStreamingSyncImplementation extends WebStreamingSyncImplementatio
1878
1966
  };
1879
1967
  messagePort.postMessage(closeMessagePayload);
1880
1968
  });
1881
- await super.dispose();
1882
- this.abortOnClose.abort();
1883
- // Release the proxy
1884
- this.syncManager[Comlink.releaseProxy]();
1885
- this.worker.close();
1886
1969
  }
1887
1970
  async waitForReady() {
1888
1971
  return this.isInitialized;
@@ -1963,6 +2046,34 @@ class TabLocalStreamingSyncImplementation extends WebStreamingSyncImplementation
1963
2046
  }
1964
2047
  }
1965
2048
 
2049
+ /**
2050
+ * Live database instances in this page, for development tooling.
2051
+ *
2052
+ * Every {@link WebPowerSyncDatabase} registers itself when constructed and leaves when closed, so a
2053
+ * tool that runs in the same page (for example the diagnostics Vite plugin's injected agent) can find
2054
+ * the app's databases without the app wiring anything up. The set holds only instances that already
2055
+ * exist, so it adds nothing to a production bundle beyond the references themselves.
2056
+ */
2057
+ class DatabaseRegistry extends BaseObserver {
2058
+ databases = new Set();
2059
+ notify() {
2060
+ const snapshot = [...this.databases];
2061
+ this.iterateListeners((listener) => listener.databasesChanged?.(snapshot));
2062
+ }
2063
+ }
2064
+ const registry = new DatabaseRegistry();
2065
+ /** @internal Called by the database constructor. */
2066
+ function registerDatabase(db) {
2067
+ registry.databases.add(db);
2068
+ registry.notify();
2069
+ }
2070
+ /** @internal Called when the database closes. */
2071
+ function unregisterDatabase(db) {
2072
+ if (registry.databases.delete(db)) {
2073
+ registry.notify();
2074
+ }
2075
+ }
2076
+
1966
2077
  /**
1967
2078
  * @internal Use {@link PowerSyncDatabase} instead, this class is only used by other SDKs also needing web support.
1968
2079
  */
@@ -1975,6 +2086,11 @@ class WebPowerSyncDatabase extends BasePowerSyncDatabase {
1975
2086
  super(options);
1976
2087
  this.resolvedOpenOptions = resolvedOpenOptions;
1977
2088
  this.enableBroadcastLogs = options.broadcastLogs ?? true;
2089
+ // Lets development tooling in this page find the live databases.
2090
+ registerDatabase(this);
2091
+ }
2092
+ get sdkName() {
2093
+ return '@powersync/web';
1978
2094
  }
1979
2095
  async _initialize() {
1980
2096
  if (this.database instanceof AsyncDbAdapter) {
@@ -2015,11 +2131,12 @@ class WebPowerSyncDatabase extends BasePowerSyncDatabase {
2015
2131
  * By default the sync stream client is only disconnected if
2016
2132
  * multiple tabs are not enabled.
2017
2133
  */
2018
- close(options) {
2019
- return super.close({
2134
+ async close(options) {
2135
+ await super.close({
2020
2136
  // Don't disconnect by default if multiple tabs are enabled
2021
2137
  disconnect: options?.disconnect ?? !this.resolvedOpenOptions.enableMultiTabs
2022
2138
  });
2139
+ unregisterDatabase(this);
2023
2140
  }
2024
2141
  async loadVersion() {
2025
2142
  if (this.resolvedOpenOptions.ssrMode) {