@powersync/web 0.0.0-dev-20241119081147 → 0.0.0-dev-20241203152232

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 (60) hide show
  1. package/dist/24cd027f23123a1360de.wasm +0 -0
  2. package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_IDBBatchAtomicVFS_js-_powersync_co-780aa20.index.umd.js +335 -0
  3. package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_IDBBatchAtomicVFS_js-_powersync_co-780aa20.index.umd.js.map +1 -0
  4. package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_IDBBatchAtomicVFS_js-_powersync_co-780aa21.index.umd.js +335 -0
  5. package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_IDBBatchAtomicVFS_js-_powersync_co-780aa21.index.umd.js.map +1 -0
  6. package/dist/f042552714d86563f127.wasm +0 -0
  7. package/dist/index.umd.js +3493 -623
  8. package/dist/index.umd.js.map +1 -1
  9. package/dist/worker/SharedSyncImplementation.umd.js +272 -2198
  10. package/dist/worker/SharedSyncImplementation.umd.js.map +1 -1
  11. package/dist/worker/WASQLiteDB.umd.js +900 -395
  12. package/dist/worker/WASQLiteDB.umd.js.map +1 -1
  13. package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_wa-sqlite-async_mjs.umd.js +2 -132
  14. package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_wa-sqlite-async_mjs.umd.js.map +1 -1
  15. package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_wa-sqlite_mjs.umd.js +45 -0
  16. package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_wa-sqlite_mjs.umd.js.map +1 -0
  17. package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js.umd.js +1470 -0
  18. package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js.umd.js.map +1 -0
  19. package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_IDBBatchAtomicVFS_js.umd.js +1707 -1372
  20. package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_IDBBatchAtomicVFS_js.umd.js.map +1 -1
  21. package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_OPFSCoopSyncVFS_js.umd.js +1602 -0
  22. package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_OPFSCoopSyncVFS_js.umd.js.map +1 -0
  23. package/lib/package.json +5 -5
  24. package/lib/src/db/PowerSyncDatabase.d.ts +1 -1
  25. package/lib/src/db/PowerSyncDatabase.js +5 -2
  26. package/lib/src/db/adapters/AbstractWebSQLOpenFactory.d.ts +2 -0
  27. package/lib/src/db/adapters/AbstractWebSQLOpenFactory.js +3 -0
  28. package/lib/src/db/adapters/AsyncDatabaseConnection.d.ts +26 -0
  29. package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.d.ts +82 -0
  30. package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.js +239 -0
  31. package/lib/src/db/adapters/WebDBAdapter.d.ts +17 -0
  32. package/lib/src/db/adapters/WebDBAdapter.js +1 -0
  33. package/lib/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.d.ts +38 -0
  34. package/lib/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.js +45 -0
  35. package/lib/src/db/adapters/wa-sqlite/WASQLiteConnection.d.ts +117 -0
  36. package/lib/src/db/adapters/wa-sqlite/WASQLiteConnection.js +289 -0
  37. package/lib/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.d.ts +7 -43
  38. package/lib/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.js +34 -209
  39. package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.d.ts +12 -0
  40. package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.js +57 -4
  41. package/lib/src/db/adapters/web-sql-flags.d.ts +16 -0
  42. package/lib/src/db/adapters/web-sql-flags.js +5 -0
  43. package/lib/src/db/sync/SharedWebStreamingSyncImplementation.d.ts +9 -2
  44. package/lib/src/db/sync/SharedWebStreamingSyncImplementation.js +16 -10
  45. package/lib/src/db/sync/WebStreamingSyncImplementation.d.ts +0 -5
  46. package/lib/src/index.d.ts +8 -7
  47. package/lib/src/index.js +8 -7
  48. package/lib/src/worker/db/WASQLiteDB.worker.js +38 -20
  49. package/lib/src/worker/db/open-worker-database.d.ts +5 -4
  50. package/lib/src/worker/db/open-worker-database.js +5 -3
  51. package/lib/src/worker/sync/AbstractSharedSyncClientProvider.d.ts +1 -0
  52. package/lib/src/worker/sync/SharedSyncImplementation.d.ts +20 -3
  53. package/lib/src/worker/sync/SharedSyncImplementation.js +40 -11
  54. package/lib/tsconfig.tsbuildinfo +1 -1
  55. package/package.json +6 -6
  56. package/dist/5fe5ed837a91c836c24f.wasm +0 -0
  57. package/lib/src/shared/open-db.d.ts +0 -5
  58. package/lib/src/shared/open-db.js +0 -192
  59. package/lib/src/shared/types.d.ts +0 -22
  60. /package/lib/src/{shared/types.js → db/adapters/AsyncDatabaseConnection.js} +0 -0
@@ -1,219 +1,44 @@
1
- import { BaseObserver } from '@powersync/common';
2
1
  import * as Comlink from 'comlink';
3
- import Logger from 'js-logger';
4
- import { _openDB } from '../../../shared/open-db';
5
- import { getWorkerDatabaseOpener, resolveWorkerDatabasePortFactory } from '../../../worker/db/open-worker-database';
6
- import { resolveWebSQLFlags } from '../web-sql-flags';
7
- import { getNavigatorLocks } from '../../../shared/navigator';
2
+ import { resolveWebPowerSyncFlags } from '../../PowerSyncDatabase';
3
+ import { LockedAsyncDatabaseAdapter } from '../LockedAsyncDatabaseAdapter';
4
+ import { TemporaryStorageOption } from '../web-sql-flags';
5
+ import { WorkerWrappedAsyncDatabaseConnection } from '../WorkerWrappedAsyncDatabaseConnection';
6
+ import { WASQLiteOpenFactory } from './WASQLiteOpenFactory';
8
7
  /**
9
8
  * Adapter for WA-SQLite SQLite connections.
10
9
  */
11
- export class WASQLiteDBAdapter extends BaseObserver {
12
- options;
13
- initialized;
14
- logger;
15
- dbGetHelpers;
16
- methods;
17
- debugMode;
10
+ export class WASQLiteDBAdapter extends LockedAsyncDatabaseAdapter {
18
11
  constructor(options) {
19
- super();
20
- this.options = options;
21
- this.logger = Logger.get('WASQLite');
22
- this.dbGetHelpers = null;
23
- this.methods = null;
24
- this.debugMode = options.debugMode ?? false;
25
- if (this.debugMode) {
26
- const originalExecute = this._execute.bind(this);
27
- this._execute = async (sql, bindings) => {
28
- const start = performance.now();
29
- try {
30
- const r = await originalExecute(sql, bindings);
31
- performance.measure(`[SQL] ${sql}`, { start });
32
- return r;
12
+ super({
13
+ name: options.dbFilename,
14
+ openConnection: async () => {
15
+ const { workerPort, temporaryStorage } = options;
16
+ if (workerPort) {
17
+ const remote = Comlink.wrap(workerPort);
18
+ return new WorkerWrappedAsyncDatabaseConnection({
19
+ remote,
20
+ identifier: options.dbFilename,
21
+ baseConnection: await remote({
22
+ ...options,
23
+ temporaryStorage: temporaryStorage ?? TemporaryStorageOption.MEMORY,
24
+ flags: resolveWebPowerSyncFlags(options.flags)
25
+ })
26
+ });
33
27
  }
34
- catch (e) {
35
- performance.measure(`[SQL] [ERROR: ${e.message}] ${sql}`, { start });
36
- throw e;
37
- }
38
- };
39
- }
40
- this.initialized = this.init();
41
- this.dbGetHelpers = this.generateDBHelpers({
42
- execute: (query, params) => this.acquireLock(() => this._execute(query, params))
43
- });
44
- }
45
- get name() {
46
- return this.options.dbFilename;
47
- }
48
- get flags() {
49
- return resolveWebSQLFlags(this.options.flags ?? {});
50
- }
51
- getWorker() { }
52
- async init() {
53
- const { enableMultiTabs, useWebWorker } = this.flags;
54
- if (!enableMultiTabs) {
55
- this.logger.warn('Multiple tabs are not enabled in this browser');
56
- }
57
- if (useWebWorker) {
58
- const optionsDbWorker = this.options.worker;
59
- const dbOpener = this.options.workerPort
60
- ? Comlink.wrap(this.options.workerPort)
61
- : typeof optionsDbWorker === 'function'
62
- ? Comlink.wrap(resolveWorkerDatabasePortFactory(() => optionsDbWorker({
63
- ...this.options,
64
- flags: this.flags
65
- })))
66
- : getWorkerDatabaseOpener(this.options.dbFilename, enableMultiTabs, optionsDbWorker);
67
- this.methods = await dbOpener(this.options.dbFilename);
68
- this.methods.registerOnTableChange(Comlink.proxy((event) => {
69
- this.iterateListeners((cb) => cb.tablesUpdated?.(event));
70
- }));
71
- return;
72
- }
73
- this.methods = await _openDB(this.options.dbFilename, { useWebWorker: false });
74
- this.methods.registerOnTableChange((event) => {
75
- this.iterateListeners((cb) => cb.tablesUpdated?.(event));
76
- });
77
- }
78
- async execute(query, params) {
79
- return this.writeLock((ctx) => ctx.execute(query, params));
80
- }
81
- async executeBatch(query, params) {
82
- return this.writeLock((ctx) => this._executeBatch(query, params));
83
- }
84
- /**
85
- * Wraps the worker execute function, awaiting for it to be available
86
- */
87
- _execute = async (sql, bindings) => {
88
- await this.initialized;
89
- const result = await this.methods.execute(sql, bindings);
90
- return {
91
- ...result,
92
- rows: {
93
- ...result.rows,
94
- item: (idx) => result.rows._array[idx]
95
- }
96
- };
97
- };
98
- /**
99
- * Wraps the worker executeBatch function, awaiting for it to be available
100
- */
101
- _executeBatch = async (query, params) => {
102
- await this.initialized;
103
- const result = await this.methods.executeBatch(query, params);
104
- return {
105
- ...result,
106
- rows: undefined
107
- };
108
- };
109
- /**
110
- * Attempts to close the connection.
111
- * Shared workers might not actually close the connection if other
112
- * tabs are still using it.
113
- */
114
- close() {
115
- this.methods?.close?.();
116
- }
117
- async getAll(sql, parameters) {
118
- await this.initialized;
119
- return this.dbGetHelpers.getAll(sql, parameters);
120
- }
121
- async getOptional(sql, parameters) {
122
- await this.initialized;
123
- return this.dbGetHelpers.getOptional(sql, parameters);
124
- }
125
- async get(sql, parameters) {
126
- await this.initialized;
127
- return this.dbGetHelpers.get(sql, parameters);
128
- }
129
- async readLock(fn, options) {
130
- await this.initialized;
131
- return this.acquireLock(async () => fn(this.generateDBHelpers({ execute: this._execute })));
132
- }
133
- async writeLock(fn, options) {
134
- await this.initialized;
135
- return this.acquireLock(async () => fn(this.generateDBHelpers({ execute: this._execute })));
136
- }
137
- acquireLock(callback) {
138
- return getNavigatorLocks().request(`db-lock-${this.options.dbFilename}`, callback);
139
- }
140
- async readTransaction(fn, options) {
141
- return this.readLock(this.wrapTransaction(fn));
142
- }
143
- writeTransaction(fn, options) {
144
- return this.writeLock(this.wrapTransaction(fn));
145
- }
146
- /**
147
- * Wraps a lock context into a transaction context
148
- */
149
- wrapTransaction(cb) {
150
- return async (tx) => {
151
- await this._execute('BEGIN TRANSACTION');
152
- let finalized = false;
153
- const commit = async () => {
154
- if (finalized) {
155
- return { rowsAffected: 0 };
156
- }
157
- finalized = true;
158
- return this._execute('COMMIT');
159
- };
160
- const rollback = () => {
161
- finalized = true;
162
- return this._execute('ROLLBACK');
163
- };
164
- try {
165
- const result = await cb({
166
- ...tx,
167
- commit,
168
- rollback
28
+ const openFactory = new WASQLiteOpenFactory({
29
+ dbFilename: options.dbFilename,
30
+ dbLocation: options.dbLocation,
31
+ debugMode: options.debugMode,
32
+ flags: options.flags,
33
+ temporaryStorage,
34
+ logger: options.logger,
35
+ vfs: options.vfs,
36
+ worker: options.worker
169
37
  });
170
- if (!finalized) {
171
- await commit();
172
- }
173
- return result;
174
- }
175
- catch (ex) {
176
- this.logger.debug('Caught ex in transaction', ex);
177
- try {
178
- await rollback();
179
- }
180
- catch (ex2) {
181
- // In rare cases, a rollback may fail.
182
- // Safe to ignore.
183
- }
184
- throw ex;
185
- }
186
- };
187
- }
188
- generateDBHelpers(tx) {
189
- return {
190
- ...tx,
191
- /**
192
- * Execute a read-only query and return results
193
- */
194
- async getAll(sql, parameters) {
195
- const res = await tx.execute(sql, parameters);
196
- return res.rows?._array ?? [];
38
+ return openFactory.openConnection();
197
39
  },
198
- /**
199
- * Execute a read-only query and return the first result, or null if the ResultSet is empty.
200
- */
201
- async getOptional(sql, parameters) {
202
- const res = await tx.execute(sql, parameters);
203
- return res.rows?.item(0) ?? null;
204
- },
205
- /**
206
- * Execute a read-only query and return the first result, error if the ResultSet is empty.
207
- */
208
- async get(sql, parameters) {
209
- const res = await tx.execute(sql, parameters);
210
- const first = res.rows?.item(0);
211
- if (!first) {
212
- throw new Error('Result set is empty');
213
- }
214
- return first;
215
- }
216
- };
40
+ debugMode: options.debugMode,
41
+ logger: options.logger
42
+ });
217
43
  }
218
- async refreshSchema() { }
219
44
  }
@@ -1,8 +1,20 @@
1
1
  import { DBAdapter } from '@powersync/common';
2
2
  import { AbstractWebSQLOpenFactory } from '../AbstractWebSQLOpenFactory';
3
+ import { AsyncDatabaseConnection } from '../AsyncDatabaseConnection';
4
+ import { ResolvedWebSQLOpenOptions, WebSQLOpenFactoryOptions } from '../web-sql-flags';
5
+ import { WASQLiteVFS } from './WASQLiteConnection';
6
+ export interface WASQLiteOpenFactoryOptions extends WebSQLOpenFactoryOptions {
7
+ vfs?: WASQLiteVFS;
8
+ }
9
+ export interface ResolvedWASQLiteOpenFactoryOptions extends ResolvedWebSQLOpenOptions {
10
+ vfs: WASQLiteVFS;
11
+ }
3
12
  /**
4
13
  * Opens a SQLite connection using WA-SQLite.
5
14
  */
6
15
  export declare class WASQLiteOpenFactory extends AbstractWebSQLOpenFactory {
16
+ constructor(options: WASQLiteOpenFactoryOptions);
17
+ get waOptions(): WASQLiteOpenFactoryOptions;
7
18
  protected openAdapter(): DBAdapter;
19
+ openConnection(): Promise<AsyncDatabaseConnection>;
8
20
  }
@@ -1,13 +1,66 @@
1
- import { WASQLiteDBAdapter } from './WASQLiteDBAdapter';
1
+ import * as Comlink from 'comlink';
2
+ import { openWorkerDatabasePort, resolveWorkerDatabasePortFactory } from '../../../worker/db/open-worker-database';
2
3
  import { AbstractWebSQLOpenFactory } from '../AbstractWebSQLOpenFactory';
4
+ import { LockedAsyncDatabaseAdapter } from '../LockedAsyncDatabaseAdapter';
5
+ import { TemporaryStorageOption } from '../web-sql-flags';
6
+ import { WorkerWrappedAsyncDatabaseConnection } from '../WorkerWrappedAsyncDatabaseConnection';
7
+ import { WASqliteConnection, WASQLiteVFS } from './WASQLiteConnection';
3
8
  /**
4
9
  * Opens a SQLite connection using WA-SQLite.
5
10
  */
6
11
  export class WASQLiteOpenFactory extends AbstractWebSQLOpenFactory {
12
+ constructor(options) {
13
+ super(options);
14
+ }
15
+ get waOptions() {
16
+ // Cast to extended type
17
+ return this.options;
18
+ }
7
19
  openAdapter() {
8
- return new WASQLiteDBAdapter({
9
- ...this.options,
10
- flags: this.resolvedFlags
20
+ return new LockedAsyncDatabaseAdapter({
21
+ name: this.options.dbFilename,
22
+ openConnection: () => this.openConnection(),
23
+ debugMode: this.options.debugMode,
24
+ logger: this.logger
11
25
  });
12
26
  }
27
+ async openConnection() {
28
+ const { enableMultiTabs, useWebWorker } = this.resolvedFlags;
29
+ const { vfs = WASQLiteVFS.IDBBatchAtomicVFS, temporaryStorage = TemporaryStorageOption.MEMORY } = this.waOptions;
30
+ if (!enableMultiTabs) {
31
+ this.logger.warn('Multiple tabs are not enabled in this browser');
32
+ }
33
+ if (useWebWorker) {
34
+ const optionsDbWorker = this.options.worker;
35
+ const workerPort = typeof optionsDbWorker == 'function'
36
+ ? resolveWorkerDatabasePortFactory(() => optionsDbWorker({
37
+ ...this.options,
38
+ temporaryStorage,
39
+ flags: this.resolvedFlags
40
+ }))
41
+ : openWorkerDatabasePort(this.options.dbFilename, enableMultiTabs, optionsDbWorker, this.waOptions.vfs);
42
+ const workerDBOpener = Comlink.wrap(workerPort);
43
+ return new WorkerWrappedAsyncDatabaseConnection({
44
+ remote: workerDBOpener,
45
+ baseConnection: await workerDBOpener({
46
+ dbFilename: this.options.dbFilename,
47
+ vfs,
48
+ temporaryStorage,
49
+ flags: this.resolvedFlags
50
+ }),
51
+ identifier: this.options.dbFilename
52
+ });
53
+ }
54
+ else {
55
+ // Don't use a web worker
56
+ return new WASqliteConnection({
57
+ dbFilename: this.options.dbFilename,
58
+ dbLocation: this.options.dbLocation,
59
+ debugMode: this.options.debugMode,
60
+ vfs,
61
+ temporaryStorage,
62
+ flags: this.resolvedFlags
63
+ });
64
+ }
65
+ }
13
66
  }
@@ -1,4 +1,5 @@
1
1
  import { SQLOpenOptions } from '@powersync/common';
2
+ import { ILogger } from 'js-logger';
2
3
  /**
3
4
  * Common settings used when creating SQL connections on web.
4
5
  */
@@ -33,6 +34,15 @@ export interface WebSQLFlags {
33
34
  export type ResolvedWebSQLFlags = Required<WebSQLFlags>;
34
35
  export interface ResolvedWebSQLOpenOptions extends SQLOpenOptions {
35
36
  flags: ResolvedWebSQLFlags;
37
+ /**
38
+ * Where to store SQLite temporary files. Defaults to 'MEMORY'.
39
+ * Setting this to `FILESYSTEM` can cause issues with larger queries or datasets.
40
+ */
41
+ temporaryStorage: TemporaryStorageOption;
42
+ }
43
+ export declare enum TemporaryStorageOption {
44
+ MEMORY = "memory",
45
+ FILESYSTEM = "file"
36
46
  }
37
47
  /**
38
48
  * Options for opening a Web SQL connection
@@ -46,6 +56,12 @@ export interface WebSQLOpenFactoryOptions extends SQLOpenOptions {
46
56
  * or a factory method that returns a worker.
47
57
  */
48
58
  worker?: string | URL | ((options: ResolvedWebSQLOpenOptions) => Worker | SharedWorker);
59
+ logger?: ILogger;
60
+ /**
61
+ * Where to store SQLite temporary files. Defaults to 'MEMORY'.
62
+ * Setting this to `FILESYSTEM` can cause issues with larger queries or datasets.
63
+ */
64
+ temporaryStorage?: TemporaryStorageOption;
49
65
  }
50
66
  export declare function isServerSide(): boolean;
51
67
  export declare const DEFAULT_WEB_SQL_FLAGS: ResolvedWebSQLFlags;
@@ -1,3 +1,8 @@
1
+ export var TemporaryStorageOption;
2
+ (function (TemporaryStorageOption) {
3
+ TemporaryStorageOption["MEMORY"] = "memory";
4
+ TemporaryStorageOption["FILESYSTEM"] = "file";
5
+ })(TemporaryStorageOption || (TemporaryStorageOption = {}));
1
6
  export function isServerSide() {
2
7
  return typeof window == 'undefined';
3
8
  }
@@ -2,6 +2,7 @@ import { PowerSyncConnectionOptions, PowerSyncCredentials, SyncStatusOptions } f
2
2
  import * as Comlink from 'comlink';
3
3
  import { AbstractSharedSyncClientProvider } from '../../worker/sync/AbstractSharedSyncClientProvider';
4
4
  import { SharedSyncImplementation } from '../../worker/sync/SharedSyncImplementation';
5
+ import { WebDBAdapter } from '../adapters/WebDBAdapter';
5
6
  import { WebStreamingSyncImplementation, WebStreamingSyncImplementationOptions } from './WebStreamingSyncImplementation';
6
7
  /**
7
8
  * The shared worker will trigger methods on this side of the message port
@@ -10,7 +11,9 @@ import { WebStreamingSyncImplementation, WebStreamingSyncImplementationOptions }
10
11
  declare class SharedSyncClientProvider extends AbstractSharedSyncClientProvider {
11
12
  protected options: WebStreamingSyncImplementationOptions;
12
13
  statusChanged: (status: SyncStatusOptions) => void;
13
- constructor(options: WebStreamingSyncImplementationOptions, statusChanged: (status: SyncStatusOptions) => void);
14
+ protected webDB: WebDBAdapter;
15
+ constructor(options: WebStreamingSyncImplementationOptions, statusChanged: (status: SyncStatusOptions) => void, webDB: WebDBAdapter);
16
+ getDBWorkerPort(): Promise<MessagePort>;
14
17
  fetchCredentials(): Promise<PowerSyncCredentials | null>;
15
18
  uploadCrud(): Promise<void>;
16
19
  get logger(): import("js-logger").ILogger | undefined;
@@ -23,12 +26,16 @@ declare class SharedSyncClientProvider extends AbstractSharedSyncClientProvider
23
26
  time(label: string): void;
24
27
  timeEnd(label: string): void;
25
28
  }
29
+ export interface SharedWebStreamingSyncImplementationOptions extends WebStreamingSyncImplementationOptions {
30
+ db: WebDBAdapter;
31
+ }
26
32
  export declare class SharedWebStreamingSyncImplementation extends WebStreamingSyncImplementation {
27
33
  protected syncManager: Comlink.Remote<SharedSyncImplementation>;
28
34
  protected clientProvider: SharedSyncClientProvider;
29
35
  protected messagePort: MessagePort;
30
36
  protected isInitialized: Promise<void>;
31
- constructor(options: WebStreamingSyncImplementationOptions);
37
+ protected dbAdapter: WebDBAdapter;
38
+ constructor(options: SharedWebStreamingSyncImplementationOptions);
32
39
  /**
33
40
  * Starts the sync process, this effectively acts as a call to
34
41
  * `connect` if not yet connected.
@@ -1,9 +1,8 @@
1
1
  import * as Comlink from 'comlink';
2
- import { openWorkerDatabasePort, resolveWorkerDatabasePortFactory } from '../../worker/db/open-worker-database';
3
2
  import { AbstractSharedSyncClientProvider } from '../../worker/sync/AbstractSharedSyncClientProvider';
4
3
  import { SharedSyncClientEvent } from '../../worker/sync/SharedSyncImplementation';
4
+ import { resolveWebSQLFlags, TemporaryStorageOption } from '../adapters/web-sql-flags';
5
5
  import { WebStreamingSyncImplementation } from './WebStreamingSyncImplementation';
6
- import { resolveWebSQLFlags } from '../adapters/web-sql-flags';
7
6
  /**
8
7
  * The shared worker will trigger methods on this side of the message port
9
8
  * via this client provider.
@@ -11,10 +10,16 @@ import { resolveWebSQLFlags } from '../adapters/web-sql-flags';
11
10
  class SharedSyncClientProvider extends AbstractSharedSyncClientProvider {
12
11
  options;
13
12
  statusChanged;
14
- constructor(options, statusChanged) {
13
+ webDB;
14
+ constructor(options, statusChanged, webDB) {
15
15
  super();
16
16
  this.options = options;
17
17
  this.statusChanged = statusChanged;
18
+ this.webDB = webDB;
19
+ }
20
+ async getDBWorkerPort() {
21
+ const { port } = await this.webDB.shareConnection();
22
+ return Comlink.transfer(port, [port]);
18
23
  }
19
24
  async fetchCredentials() {
20
25
  const credentials = await this.options.remote.getCredentials();
@@ -73,8 +78,10 @@ export class SharedWebStreamingSyncImplementation extends WebStreamingSyncImplem
73
78
  clientProvider;
74
79
  messagePort;
75
80
  isInitialized;
81
+ dbAdapter;
76
82
  constructor(options) {
77
83
  super(options);
84
+ this.dbAdapter = options.db;
78
85
  /**
79
86
  * Configure or connect to the shared sync worker.
80
87
  * This worker will manage all syncing operations remotely.
@@ -82,6 +89,8 @@ export class SharedWebStreamingSyncImplementation extends WebStreamingSyncImplem
82
89
  const resolvedWorkerOptions = {
83
90
  ...options,
84
91
  dbFilename: this.options.identifier,
92
+ // TODO
93
+ temporaryStorage: TemporaryStorageOption.MEMORY,
85
94
  flags: resolveWebSQLFlags(options.flags)
86
95
  };
87
96
  const syncWorker = options.sync?.worker;
@@ -112,13 +121,9 @@ export class SharedWebStreamingSyncImplementation extends WebStreamingSyncImplem
112
121
  * sync worker.
113
122
  */
114
123
  const { crudUploadThrottleMs, identifier, retryDelayMs } = this.options;
115
- const dbWorker = options.database?.options?.worker;
116
- const dbOpenerPort = typeof dbWorker === 'function'
117
- ? resolveWorkerDatabasePortFactory(() => dbWorker(resolvedWorkerOptions))
118
- : openWorkerDatabasePort(this.options.identifier, true, dbWorker);
119
124
  const flags = { ...this.webOptions.flags, workers: undefined };
120
- this.isInitialized = this.syncManager.init(Comlink.transfer(dbOpenerPort, [dbOpenerPort]), {
121
- dbName: this.options.identifier,
125
+ this.isInitialized = this.syncManager.setParams({
126
+ dbParams: this.dbAdapter.getConfiguration(),
122
127
  streamOptions: {
123
128
  crudUploadThrottleMs,
124
129
  identifier,
@@ -131,7 +136,7 @@ export class SharedWebStreamingSyncImplementation extends WebStreamingSyncImplem
131
136
  */
132
137
  this.clientProvider = new SharedSyncClientProvider(this.webOptions, (status) => {
133
138
  this.iterateListeners((l) => this.updateSyncStatus(status));
134
- });
139
+ }, options.db);
135
140
  /**
136
141
  * The sync worker will call this client provider when it needs
137
142
  * to fetch credentials or upload data.
@@ -180,6 +185,7 @@ export class SharedWebStreamingSyncImplementation extends WebStreamingSyncImplem
180
185
  * Used in tests to force a connection states
181
186
  */
182
187
  async _testUpdateStatus(status) {
188
+ await this.isInitialized;
183
189
  return this.syncManager['_testUpdateAllStatuses'](status.toJSON());
184
190
  }
185
191
  }
@@ -2,11 +2,6 @@ import { AbstractStreamingSyncImplementation, AbstractStreamingSyncImplementatio
2
2
  import { ResolvedWebSQLOpenOptions, WebSQLFlags } from '../adapters/web-sql-flags';
3
3
  export interface WebStreamingSyncImplementationOptions extends AbstractStreamingSyncImplementationOptions {
4
4
  flags?: WebSQLFlags;
5
- database?: {
6
- options: {
7
- worker?: string | URL | ((options: ResolvedWebSQLOpenOptions) => Worker | SharedWorker);
8
- };
9
- };
10
5
  sync?: {
11
6
  worker?: string | URL | ((options: ResolvedWebSQLOpenOptions) => SharedWorker);
12
7
  };
@@ -1,11 +1,12 @@
1
1
  export * from '@powersync/common';
2
- export * from './db/PowerSyncDatabase';
3
- export * from './db/sync/WebRemote';
4
- export * from './db/sync/WebStreamingSyncImplementation';
5
- export * from './db/sync/SharedWebStreamingSyncImplementation';
6
- export * from './db/adapters/wa-sqlite/WASQLiteDBAdapter';
7
- export * from './db/adapters/wa-sqlite/WASQLitePowerSyncDatabaseOpenFactory';
8
2
  export * from './db/adapters/AbstractWebPowerSyncDatabaseOpenFactory';
9
- export * from './db/adapters/web-sql-flags';
10
3
  export * from './db/adapters/AbstractWebSQLOpenFactory';
4
+ export * from './db/adapters/wa-sqlite/WASQLiteConnection';
5
+ export * from './db/adapters/wa-sqlite/WASQLiteDBAdapter';
11
6
  export * from './db/adapters/wa-sqlite/WASQLiteOpenFactory';
7
+ export * from './db/adapters/wa-sqlite/WASQLitePowerSyncDatabaseOpenFactory';
8
+ export * from './db/adapters/web-sql-flags';
9
+ export * from './db/PowerSyncDatabase';
10
+ export * from './db/sync/SharedWebStreamingSyncImplementation';
11
+ export * from './db/sync/WebRemote';
12
+ export * from './db/sync/WebStreamingSyncImplementation';
package/lib/src/index.js CHANGED
@@ -1,11 +1,12 @@
1
1
  export * from '@powersync/common';
2
- export * from './db/PowerSyncDatabase';
3
- export * from './db/sync/WebRemote';
4
- export * from './db/sync/WebStreamingSyncImplementation';
5
- export * from './db/sync/SharedWebStreamingSyncImplementation';
6
- export * from './db/adapters/wa-sqlite/WASQLiteDBAdapter';
7
- export * from './db/adapters/wa-sqlite/WASQLitePowerSyncDatabaseOpenFactory';
8
2
  export * from './db/adapters/AbstractWebPowerSyncDatabaseOpenFactory';
9
- export * from './db/adapters/web-sql-flags';
10
3
  export * from './db/adapters/AbstractWebSQLOpenFactory';
4
+ export * from './db/adapters/wa-sqlite/WASQLiteConnection';
5
+ export * from './db/adapters/wa-sqlite/WASQLiteDBAdapter';
11
6
  export * from './db/adapters/wa-sqlite/WASQLiteOpenFactory';
7
+ export * from './db/adapters/wa-sqlite/WASQLitePowerSyncDatabaseOpenFactory';
8
+ export * from './db/adapters/web-sql-flags';
9
+ export * from './db/PowerSyncDatabase';
10
+ export * from './db/sync/SharedWebStreamingSyncImplementation';
11
+ export * from './db/sync/WebRemote';
12
+ export * from './db/sync/WebStreamingSyncImplementation';
@@ -3,46 +3,63 @@
3
3
  */
4
4
  import '@journeyapps/wa-sqlite';
5
5
  import * as Comlink from 'comlink';
6
- import { _openDB } from '../../shared/open-db';
6
+ import { WASqliteConnection } from '../../db/adapters/wa-sqlite/WASQLiteConnection';
7
7
  import { getNavigatorLocks } from '../../shared/navigator';
8
8
  const DBMap = new Map();
9
9
  const OPEN_DB_LOCK = 'open-wasqlite-db';
10
10
  let nextClientId = 1;
11
- const openDBShared = async (dbFileName) => {
11
+ const openWorkerConnection = async (options) => {
12
+ const connection = new WASqliteConnection(options);
13
+ return {
14
+ init: Comlink.proxy(() => connection.init()),
15
+ getConfig: Comlink.proxy(() => connection.getConfig()),
16
+ close: Comlink.proxy(() => connection.close()),
17
+ execute: Comlink.proxy(async (sql, params) => connection.execute(sql, params)),
18
+ executeBatch: Comlink.proxy(async (sql, params) => connection.executeBatch(sql, params)),
19
+ registerOnTableChange: Comlink.proxy(async (callback) => {
20
+ // Proxy the callback remove function
21
+ return Comlink.proxy(await connection.registerOnTableChange(callback));
22
+ })
23
+ };
24
+ };
25
+ const openDBShared = async (options) => {
12
26
  // Prevent multiple simultaneous opens from causing race conditions
13
27
  return getNavigatorLocks().request(OPEN_DB_LOCK, async () => {
14
28
  const clientId = nextClientId++;
15
- if (!DBMap.has(dbFileName)) {
29
+ const { dbFilename } = options;
30
+ if (!DBMap.has(dbFilename)) {
16
31
  const clientIds = new Set();
17
- const connection = await _openDB(dbFileName);
18
- DBMap.set(dbFileName, {
32
+ const connection = await openWorkerConnection(options);
33
+ await connection.init();
34
+ DBMap.set(dbFilename, {
19
35
  clientIds,
20
36
  db: connection
21
37
  });
22
38
  }
23
- const dbEntry = DBMap.get(dbFileName);
39
+ const dbEntry = DBMap.get(dbFilename);
24
40
  dbEntry.clientIds.add(clientId);
25
41
  const { db } = dbEntry;
26
42
  const wrappedConnection = {
27
43
  ...db,
44
+ init: Comlink.proxy(() => {
45
+ // the init has been done automatically
46
+ }),
28
47
  close: Comlink.proxy(() => {
29
48
  const { clientIds } = dbEntry;
49
+ console.debug(`Close requested from client ${clientId} of ${[...clientIds]}`);
30
50
  clientIds.delete(clientId);
31
51
  if (clientIds.size == 0) {
32
- console.debug(`Closing connection to ${dbFileName}.`);
33
- DBMap.delete(dbFileName);
52
+ console.debug(`Closing connection to ${dbFilename}.`);
53
+ DBMap.delete(dbFilename);
34
54
  return db.close?.();
35
55
  }
36
- console.debug(`Connection to ${dbFileName} not closed yet due to active clients.`);
56
+ console.debug(`Connection to ${dbFilename} not closed yet due to active clients.`);
57
+ return;
37
58
  })
38
59
  };
39
60
  return Comlink.proxy(wrappedConnection);
40
61
  });
41
62
  };
42
- const openDBDedicated = async (dbFileName) => {
43
- const connection = await _openDB(dbFileName);
44
- return Comlink.proxy(connection);
45
- };
46
63
  // Check if we're in a SharedWorker context
47
64
  if (typeof SharedWorkerGlobalScope !== 'undefined') {
48
65
  const _self = self;
@@ -51,13 +68,14 @@ if (typeof SharedWorkerGlobalScope !== 'undefined') {
51
68
  console.debug('Exposing shared db on port', port);
52
69
  Comlink.expose(openDBShared, port);
53
70
  };
54
- addEventListener('unload', () => {
55
- Array.from(DBMap.values()).forEach(async (dbConnection) => {
56
- const db = await dbConnection.db;
57
- db.close?.();
58
- });
59
- });
60
71
  }
61
72
  else {
62
- Comlink.expose(openDBDedicated);
73
+ // A dedicated worker can be shared externally
74
+ Comlink.expose(openDBShared);
63
75
  }
76
+ addEventListener('unload', () => {
77
+ Array.from(DBMap.values()).forEach(async (dbConnection) => {
78
+ const { db } = dbConnection;
79
+ db.close?.();
80
+ });
81
+ });