@powersync/web 0.0.0-dev-20260120150240 → 0.0.0-dev-20260128165909

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 (36) hide show
  1. package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-89f0ba.index.umd.js +5 -1
  2. package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-89f0ba.index.umd.js.map +1 -1
  3. package/dist/index.umd.js +288 -65
  4. package/dist/index.umd.js.map +1 -1
  5. package/dist/worker/SharedSyncImplementation.umd.js +1438 -385
  6. package/dist/worker/SharedSyncImplementation.umd.js.map +1 -1
  7. package/dist/worker/WASQLiteDB.umd.js +1435 -386
  8. package/dist/worker/WASQLiteDB.umd.js.map +1 -1
  9. package/lib/package.json +2 -4
  10. package/lib/src/attachments/IndexDBFileSystemAdapter.d.ts +25 -0
  11. package/lib/src/attachments/IndexDBFileSystemAdapter.js +104 -0
  12. package/lib/src/db/NavigatorTriggerClaimManager.d.ts +6 -0
  13. package/lib/src/db/NavigatorTriggerClaimManager.js +20 -0
  14. package/lib/src/db/PowerSyncDatabase.d.ts +2 -1
  15. package/lib/src/db/PowerSyncDatabase.js +27 -1
  16. package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.d.ts +2 -2
  17. package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.js +5 -1
  18. package/lib/src/db/adapters/WebDBAdapter.d.ts +4 -1
  19. package/lib/src/db/adapters/wa-sqlite/InternalWASQLiteDBAdapter.d.ts +12 -0
  20. package/lib/src/db/adapters/wa-sqlite/InternalWASQLiteDBAdapter.js +19 -0
  21. package/lib/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.d.ts +2 -2
  22. package/lib/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.js +2 -2
  23. package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.js +2 -2
  24. package/lib/src/index.d.ts +1 -0
  25. package/lib/src/index.js +1 -0
  26. package/lib/tsconfig.tsbuildinfo +1 -1
  27. package/package.json +3 -5
  28. package/src/attachments/IndexDBFileSystemAdapter.ts +117 -0
  29. package/src/db/NavigatorTriggerClaimManager.ts +23 -0
  30. package/src/db/PowerSyncDatabase.ts +30 -1
  31. package/src/db/adapters/LockedAsyncDatabaseAdapter.ts +7 -3
  32. package/src/db/adapters/WebDBAdapter.ts +5 -1
  33. package/src/db/adapters/wa-sqlite/InternalWASQLiteDBAdapter.ts +23 -0
  34. package/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.ts +2 -2
  35. package/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.ts +2 -2
  36. package/src/index.ts +1 -0
package/lib/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@powersync/web",
3
- "version": "1.31.0",
3
+ "version": "1.32.0",
4
4
  "description": "PowerSync Web SDK",
5
5
  "main": "lib/src/index.js",
6
6
  "module": "lib/src/index.js",
@@ -67,7 +67,7 @@
67
67
  "license": "Apache-2.0",
68
68
  "peerDependencies": {
69
69
  "@journeyapps/wa-sqlite": "catalog:",
70
- "@powersync/common": "workspace:^1.45.0"
70
+ "@powersync/common": "workspace:^1.46.0"
71
71
  },
72
72
  "dependencies": {
73
73
  "@powersync/common": "workspace:*",
@@ -87,8 +87,6 @@
87
87
  "terser-webpack-plugin": "^5.3.9",
88
88
  "uuid": "catalog:",
89
89
  "vite": "catalog:",
90
- "vite-plugin-top-level-await": "catalog:",
91
- "vite-plugin-wasm": "catalog:",
92
90
  "vm-browserify": "^1.1.2",
93
91
  "webpack": "^5.90.1",
94
92
  "webpack-cli": "^5.1.4",
@@ -0,0 +1,25 @@
1
+ import { AttachmentData, EncodingType, LocalStorageAdapter } from '@powersync/common';
2
+ /**
3
+ * IndexDBFileSystemStorageAdapter implements LocalStorageAdapter using IndexedDB.
4
+ * Suitable for web browsers and web-based environments.
5
+ */
6
+ export declare class IndexDBFileSystemStorageAdapter implements LocalStorageAdapter {
7
+ private databaseName;
8
+ private dbPromise;
9
+ constructor(databaseName?: string);
10
+ initialize(): Promise<void>;
11
+ clear(): Promise<void>;
12
+ getLocalUri(filename: string): string;
13
+ private getStore;
14
+ saveFile(filePath: string, data: AttachmentData): Promise<number>;
15
+ readFile(fileUri: string, options?: {
16
+ encoding?: EncodingType;
17
+ mediaType?: string;
18
+ }): Promise<ArrayBuffer>;
19
+ deleteFile(uri: string, options?: {
20
+ filename?: string;
21
+ }): Promise<void>;
22
+ fileExists(fileUri: string): Promise<boolean>;
23
+ makeDir(path: string): Promise<void>;
24
+ rmDir(path: string): Promise<void>;
25
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * IndexDBFileSystemStorageAdapter implements LocalStorageAdapter using IndexedDB.
3
+ * Suitable for web browsers and web-based environments.
4
+ */
5
+ export class IndexDBFileSystemStorageAdapter {
6
+ databaseName;
7
+ dbPromise;
8
+ constructor(databaseName = 'PowerSyncFiles') {
9
+ this.databaseName = databaseName;
10
+ }
11
+ async initialize() {
12
+ this.dbPromise = new Promise((resolve, reject) => {
13
+ const request = indexedDB.open(this.databaseName, 1);
14
+ request.onupgradeneeded = () => {
15
+ request.result.createObjectStore('files');
16
+ };
17
+ request.onsuccess = () => resolve(request.result);
18
+ request.onerror = () => reject(request.error);
19
+ });
20
+ }
21
+ async clear() {
22
+ const db = await this.dbPromise;
23
+ return new Promise((resolve, reject) => {
24
+ const tx = db.transaction('files', 'readwrite');
25
+ const store = tx.objectStore('files');
26
+ const req = store.clear();
27
+ req.onsuccess = () => resolve();
28
+ req.onerror = () => reject(req.error);
29
+ });
30
+ }
31
+ getLocalUri(filename) {
32
+ return `indexeddb://${this.databaseName}/files/${filename}`;
33
+ }
34
+ async getStore(mode = 'readonly') {
35
+ const db = await this.dbPromise;
36
+ const tx = db.transaction('files', mode);
37
+ return tx.objectStore('files');
38
+ }
39
+ async saveFile(filePath, data) {
40
+ const store = await this.getStore('readwrite');
41
+ let dataToStore;
42
+ let size;
43
+ if (typeof data === 'string') {
44
+ const binaryString = atob(data);
45
+ const bytes = new Uint8Array(binaryString.length);
46
+ for (let i = 0; i < binaryString.length; i++) {
47
+ bytes[i] = binaryString.charCodeAt(i);
48
+ }
49
+ dataToStore = bytes.buffer;
50
+ size = bytes.byteLength;
51
+ }
52
+ else {
53
+ dataToStore = data;
54
+ size = dataToStore.byteLength;
55
+ }
56
+ return await new Promise((resolve, reject) => {
57
+ const req = store.put(dataToStore, filePath);
58
+ req.onsuccess = () => resolve(size);
59
+ req.onerror = () => reject(req.error);
60
+ });
61
+ }
62
+ async readFile(fileUri, options) {
63
+ const store = await this.getStore();
64
+ return new Promise((resolve, reject) => {
65
+ const req = store.get(fileUri);
66
+ req.onsuccess = async () => {
67
+ if (!req.result) {
68
+ reject(new Error('File not found'));
69
+ return;
70
+ }
71
+ resolve(req.result);
72
+ };
73
+ req.onerror = () => reject(req.error);
74
+ });
75
+ }
76
+ async deleteFile(uri, options) {
77
+ const store = await this.getStore('readwrite');
78
+ await new Promise((resolve, reject) => {
79
+ const req = store.delete(uri);
80
+ req.onsuccess = () => resolve();
81
+ req.onerror = () => reject(req.error);
82
+ });
83
+ }
84
+ async fileExists(fileUri) {
85
+ const store = await this.getStore();
86
+ return new Promise((resolve, reject) => {
87
+ const req = store.get(fileUri);
88
+ req.onsuccess = () => resolve(!!req.result);
89
+ req.onerror = () => reject(req.error);
90
+ });
91
+ }
92
+ async makeDir(path) {
93
+ // No-op for IndexedDB as it does not have a directory structure
94
+ }
95
+ async rmDir(path) {
96
+ const store = await this.getStore('readwrite');
97
+ const range = IDBKeyRange.bound(path + '/', path + '/\uffff', false, false);
98
+ await new Promise((resolve, reject) => {
99
+ const req = store.delete(range);
100
+ req.onsuccess = () => resolve();
101
+ req.onerror = () => reject(req.error);
102
+ });
103
+ }
104
+ }
@@ -0,0 +1,6 @@
1
+ import { TriggerClaimManager } from '@powersync/common';
2
+ /**
3
+ * @internal
4
+ * @experimental
5
+ */
6
+ export declare const NAVIGATOR_TRIGGER_CLAIM_MANAGER: TriggerClaimManager;
@@ -0,0 +1,20 @@
1
+ import { getNavigatorLocks } from '../shared/navigator.js';
2
+ /**
3
+ * @internal
4
+ * @experimental
5
+ */
6
+ export const NAVIGATOR_TRIGGER_CLAIM_MANAGER = {
7
+ async obtainClaim(identifier) {
8
+ return new Promise((resolveReleaser) => {
9
+ getNavigatorLocks().request(identifier, async () => {
10
+ await new Promise((releaseLock) => {
11
+ resolveReleaser(async () => releaseLock());
12
+ });
13
+ });
14
+ });
15
+ },
16
+ async checkClaim(identifier) {
17
+ const currentState = await getNavigatorLocks().query();
18
+ return currentState.held?.find((heldLock) => heldLock.name == identifier) != null;
19
+ }
20
+ };
@@ -1,4 +1,4 @@
1
- import { AbstractPowerSyncDatabase, DBAdapter, PowerSyncDatabaseOptions, PowerSyncDatabaseOptionsWithDBAdapter, PowerSyncDatabaseOptionsWithOpenFactory, PowerSyncDatabaseOptionsWithSettings, StreamingSyncImplementation, type BucketStorageAdapter, type PowerSyncBackendConnector, type PowerSyncCloseOptions, type RequiredAdditionalConnectionOptions } from '@powersync/common';
1
+ import { AbstractPowerSyncDatabase, DBAdapter, PowerSyncDatabaseOptions, PowerSyncDatabaseOptionsWithDBAdapter, PowerSyncDatabaseOptionsWithOpenFactory, PowerSyncDatabaseOptionsWithSettings, StreamingSyncImplementation, TriggerManagerConfig, type BucketStorageAdapter, type PowerSyncBackendConnector, type PowerSyncCloseOptions, type RequiredAdditionalConnectionOptions } from '@powersync/common';
2
2
  import { Mutex } from 'async-mutex';
3
3
  import { ResolvedWebSQLOpenOptions, WebSQLFlags } from './adapters/web-sql-flags.js';
4
4
  export interface WebPowerSyncFlags extends WebSQLFlags {
@@ -62,6 +62,7 @@ export declare class PowerSyncDatabase extends AbstractPowerSyncDatabase {
62
62
  constructor(options: WebPowerSyncDatabaseOptionsWithSettings);
63
63
  constructor(options: WebPowerSyncDatabaseOptions);
64
64
  _initialize(): Promise<void>;
65
+ protected generateTriggerManagerConfig(): TriggerManagerConfig;
65
66
  protected openDBAdapter(options: WebPowerSyncDatabaseOptionsWithSettings): DBAdapter;
66
67
  /**
67
68
  * Closes the database connection.
@@ -1,6 +1,8 @@
1
1
  import { AbstractPowerSyncDatabase, SqliteBucketStorage, isDBAdapter, isSQLOpenFactory } from '@powersync/common';
2
2
  import { Mutex } from 'async-mutex';
3
3
  import { getNavigatorLocks } from '../shared/navigator.js';
4
+ import { NAVIGATOR_TRIGGER_CLAIM_MANAGER } from './NavigatorTriggerClaimManager.js';
5
+ import { LockedAsyncDatabaseAdapter } from './adapters/LockedAsyncDatabaseAdapter.js';
4
6
  import { WASQLiteOpenFactory } from './adapters/wa-sqlite/WASQLiteOpenFactory.js';
5
7
  import { DEFAULT_WEB_SQL_FLAGS, isServerSide, resolveWebSQLFlags } from './adapters/web-sql-flags.js';
6
8
  import { SSRStreamingSyncImplementation } from './sync/SSRWebStreamingSyncImplementation.js';
@@ -58,7 +60,31 @@ export class PowerSyncDatabase extends AbstractPowerSyncDatabase {
58
60
  window.addEventListener('unload', this.unloadListener);
59
61
  }
60
62
  }
61
- async _initialize() { }
63
+ async _initialize() {
64
+ if (this.database instanceof LockedAsyncDatabaseAdapter) {
65
+ /**
66
+ * While init is done automatically,
67
+ * LockedAsyncDatabaseAdapter only exposes config after init.
68
+ * We can explicitly wait for init here in order to access config.
69
+ */
70
+ await this.database.init();
71
+ }
72
+ // In some cases, like the SQLJs adapter, we don't pass a WebDBAdapter, so we need to check.
73
+ if (typeof this.database.getConfiguration == 'function') {
74
+ const config = this.database.getConfiguration();
75
+ if (config.requiresPersistentTriggers) {
76
+ this.triggersImpl.updateDefaults({
77
+ useStorageByDefault: true
78
+ });
79
+ }
80
+ }
81
+ }
82
+ generateTriggerManagerConfig() {
83
+ return {
84
+ // We need to share hold information between tabs for web
85
+ claimManager: NAVIGATOR_TRIGGER_CLAIM_MANAGER
86
+ };
87
+ }
62
88
  openDBAdapter(options) {
63
89
  const defaultFactory = new WASQLiteOpenFactory({
64
90
  ...options.database,
@@ -1,6 +1,6 @@
1
1
  import { BaseObserver, DBAdapterListener, DBLockOptions, LockContext, QueryResult, Transaction, type ILogger } from '@powersync/common';
2
2
  import { AsyncDatabaseConnection } from './AsyncDatabaseConnection.js';
3
- import { SharedConnectionWorker, WebDBAdapter } from './WebDBAdapter.js';
3
+ import { SharedConnectionWorker, WebDBAdapter, WebDBAdapterConfiguration } from './WebDBAdapter.js';
4
4
  import { ResolvedWebSQLOpenOptions } from './web-sql-flags.js';
5
5
  /**
6
6
  * @internal
@@ -55,7 +55,7 @@ export declare class LockedAsyncDatabaseAdapter extends BaseObserver<LockedAsync
55
55
  */
56
56
  reOpenInternalDB(): Promise<void>;
57
57
  protected _init(): Promise<void>;
58
- getConfiguration(): ResolvedWebSQLOpenOptions;
58
+ getConfiguration(): WebDBAdapterConfiguration;
59
59
  protected waitForInitialized(): Promise<void>;
60
60
  shareConnection(): Promise<SharedConnectionWorker>;
61
61
  /**
@@ -137,7 +137,11 @@ export class LockedAsyncDatabaseAdapter extends BaseObserver {
137
137
  if (!this._config) {
138
138
  throw new Error(`Cannot get config before initialization is completed`);
139
139
  }
140
- return this._config;
140
+ return {
141
+ ...this._config,
142
+ // This can be overridden by the adapter later
143
+ requiresPersistentTriggers: false
144
+ };
141
145
  }
142
146
  async waitForInitialized() {
143
147
  // Awaiting this will expose errors on function calls like .execute etc
@@ -4,6 +4,9 @@ export type SharedConnectionWorker = {
4
4
  identifier: string;
5
5
  port: MessagePort;
6
6
  };
7
+ export type WebDBAdapterConfiguration = ResolvedWebSQLOpenOptions & {
8
+ requiresPersistentTriggers: boolean;
9
+ };
7
10
  export interface WebDBAdapter extends DBAdapter {
8
11
  /**
9
12
  * Get a MessagePort which can be used to share the internals of this connection.
@@ -13,5 +16,5 @@ export interface WebDBAdapter extends DBAdapter {
13
16
  * Get the config options used to open this connection.
14
17
  * This is useful for sharing connections.
15
18
  */
16
- getConfiguration(): ResolvedWebSQLOpenOptions;
19
+ getConfiguration(): WebDBAdapterConfiguration;
17
20
  }
@@ -0,0 +1,12 @@
1
+ import { LockedAsyncDatabaseAdapter } from '../LockedAsyncDatabaseAdapter.js';
2
+ import { WebDBAdapterConfiguration } from '../WebDBAdapter.js';
3
+ /**
4
+ * @internal
5
+ * An intermediary implementation of WASQLiteDBAdapter, which takes the same
6
+ * constructor arguments as {@link LockedAsyncDatabaseAdapter}, but provides some
7
+ * basic WA-SQLite specific functionality.
8
+ * This base class is used to avoid requiring overloading the constructor of {@link WASQLiteDBAdapter}
9
+ */
10
+ export declare class InternalWASQLiteDBAdapter extends LockedAsyncDatabaseAdapter {
11
+ getConfiguration(): WebDBAdapterConfiguration;
12
+ }
@@ -0,0 +1,19 @@
1
+ import { LockedAsyncDatabaseAdapter } from '../LockedAsyncDatabaseAdapter.js';
2
+ import { WASQLiteVFS } from './WASQLiteConnection.js';
3
+ /**
4
+ * @internal
5
+ * An intermediary implementation of WASQLiteDBAdapter, which takes the same
6
+ * constructor arguments as {@link LockedAsyncDatabaseAdapter}, but provides some
7
+ * basic WA-SQLite specific functionality.
8
+ * This base class is used to avoid requiring overloading the constructor of {@link WASQLiteDBAdapter}
9
+ */
10
+ export class InternalWASQLiteDBAdapter extends LockedAsyncDatabaseAdapter {
11
+ getConfiguration() {
12
+ // This is valid since we only handle WASQLite connections
13
+ const baseConfig = super.getConfiguration();
14
+ return {
15
+ ...super.getConfiguration(),
16
+ requiresPersistentTriggers: baseConfig.vfs == WASQLiteVFS.OPFSCoopSyncVFS || baseConfig.vfs == WASQLiteVFS.AccessHandlePoolVFS
17
+ };
18
+ }
19
+ }
@@ -1,6 +1,6 @@
1
1
  import { type PowerSyncOpenFactoryOptions } from '@powersync/common';
2
- import { LockedAsyncDatabaseAdapter } from '../LockedAsyncDatabaseAdapter.js';
3
2
  import { ResolvedWebSQLOpenOptions, TemporaryStorageOption, WebSQLFlags } from '../web-sql-flags.js';
3
+ import { InternalWASQLiteDBAdapter } from './InternalWASQLiteDBAdapter.js';
4
4
  import { WASQLiteVFS } from './WASQLiteConnection.js';
5
5
  /**
6
6
  * These flags are the same as {@link WebSQLFlags}.
@@ -27,6 +27,6 @@ export interface WASQLiteDBAdapterOptions extends Omit<PowerSyncOpenFactoryOptio
27
27
  /**
28
28
  * Adapter for WA-SQLite SQLite connections.
29
29
  */
30
- export declare class WASQLiteDBAdapter extends LockedAsyncDatabaseAdapter {
30
+ export declare class WASQLiteDBAdapter extends InternalWASQLiteDBAdapter {
31
31
  constructor(options: WASQLiteDBAdapterOptions);
32
32
  }
@@ -1,13 +1,13 @@
1
1
  import * as Comlink from 'comlink';
2
2
  import { resolveWebPowerSyncFlags } from '../../PowerSyncDatabase.js';
3
- import { LockedAsyncDatabaseAdapter } from '../LockedAsyncDatabaseAdapter.js';
4
3
  import { DEFAULT_CACHE_SIZE_KB, TemporaryStorageOption } from '../web-sql-flags.js';
5
4
  import { WorkerWrappedAsyncDatabaseConnection } from '../WorkerWrappedAsyncDatabaseConnection.js';
5
+ import { InternalWASQLiteDBAdapter } from './InternalWASQLiteDBAdapter.js';
6
6
  import { WASQLiteOpenFactory } from './WASQLiteOpenFactory.js';
7
7
  /**
8
8
  * Adapter for WA-SQLite SQLite connections.
9
9
  */
10
- export class WASQLiteDBAdapter extends LockedAsyncDatabaseAdapter {
10
+ export class WASQLiteDBAdapter extends InternalWASQLiteDBAdapter {
11
11
  constructor(options) {
12
12
  super({
13
13
  name: options.dbFilename,
@@ -1,9 +1,9 @@
1
1
  import * as Comlink from 'comlink';
2
2
  import { openWorkerDatabasePort, resolveWorkerDatabasePortFactory } from '../../../worker/db/open-worker-database.js';
3
3
  import { AbstractWebSQLOpenFactory } from '../AbstractWebSQLOpenFactory.js';
4
- import { LockedAsyncDatabaseAdapter } from '../LockedAsyncDatabaseAdapter.js';
5
4
  import { WorkerWrappedAsyncDatabaseConnection } from '../WorkerWrappedAsyncDatabaseConnection.js';
6
5
  import { DEFAULT_CACHE_SIZE_KB, TemporaryStorageOption } from '../web-sql-flags.js';
6
+ import { InternalWASQLiteDBAdapter } from './InternalWASQLiteDBAdapter.js';
7
7
  import { WASQLiteVFS, WASqliteConnection } from './WASQLiteConnection.js';
8
8
  /**
9
9
  * Opens a SQLite connection using WA-SQLite.
@@ -18,7 +18,7 @@ export class WASQLiteOpenFactory extends AbstractWebSQLOpenFactory {
18
18
  return this.options;
19
19
  }
20
20
  openAdapter() {
21
- return new LockedAsyncDatabaseAdapter({
21
+ return new InternalWASQLiteDBAdapter({
22
22
  name: this.options.dbFilename,
23
23
  openConnection: () => this.openConnection(),
24
24
  debugMode: this.options.debugMode,
@@ -1,4 +1,5 @@
1
1
  export * from '@powersync/common';
2
+ export * from './attachments/IndexDBFileSystemAdapter.js';
2
3
  export * from './db/adapters/AbstractWebPowerSyncDatabaseOpenFactory.js';
3
4
  export * from './db/adapters/AbstractWebSQLOpenFactory.js';
4
5
  export * from './db/adapters/AsyncDatabaseConnection.js';
package/lib/src/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from '@powersync/common';
2
+ export * from './attachments/IndexDBFileSystemAdapter.js';
2
3
  export * from './db/adapters/AbstractWebPowerSyncDatabaseOpenFactory.js';
3
4
  export * from './db/adapters/AbstractWebSQLOpenFactory.js';
4
5
  export * from './db/adapters/AsyncDatabaseConnection.js';