@powersync/web 0.0.0-dev-20260311103504 → 0.0.0-dev-20260503073249
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.
- package/dist/2075a31bb151adbb9767.wasm +0 -0
- package/dist/3322bc84de986b63c2cd.wasm +0 -0
- package/dist/8e97452e297be23b5e50.wasm +0 -0
- package/dist/fbc178b70d530e8ce02b.wasm +0 -0
- package/dist/index.umd.js +5341 -1279
- package/dist/index.umd.js.map +1 -1
- package/dist/worker/SharedSyncImplementation.umd.js +1113 -3526
- package/dist/worker/SharedSyncImplementation.umd.js.map +1 -1
- package/dist/worker/WASQLiteDB.umd.js +1397 -1332
- package/dist/worker/WASQLiteDB.umd.js.map +1 -1
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_dist_mc-wa-s-9af0a7.umd.js +31 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_dist_mc-wa-s-9af0a7.umd.js.map +1 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_dist_mc-wa-s-bbf5a9.umd.js +31 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_dist_mc-wa-s-bbf5a9.umd.js.map +1 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_dist_wa-sqli-c26e0f.umd.js +31 -0
- package/dist/worker/{node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_dist_wa-sqli-cc5fcc.umd.js.map → node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_dist_wa-sqli-c26e0f.umd.js.map} +1 -1
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_dist_wa-sqlite_mjs.umd.js +31 -0
- package/dist/worker/{node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_dist_wa-sqlite_mjs.umd.js.map → node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_dist_wa-sqlite_mjs.umd.js.map} +1 -1
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_src_examples-2fb422.umd.js +3562 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_src_examples-2fb422.umd.js.map +1 -0
- package/dist/worker/{node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_src_examples-0df390.umd.js → node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_src_examples-96fb23.umd.js} +16 -16
- package/dist/worker/{node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_src_examples-0df390.umd.js.map → node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_src_examples-96fb23.umd.js.map} +1 -1
- package/dist/worker/{node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_src_examples-151024.umd.js → node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_src_examples-c89911.umd.js} +12 -12
- package/dist/worker/{node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_src_examples-151024.umd.js.map → node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_src_examples-c89911.umd.js.map} +1 -1
- package/dist/worker/{node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_src_examples-c01ef0.umd.js → node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_src_examples-ec4eb1.umd.js} +14 -14
- package/dist/worker/{node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_src_examples-c01ef0.umd.js.map → node_modules_pnpm_journeyapps_wa-sqlite_1_7_0_node_modules_journeyapps_wa-sqlite_src_examples-ec4eb1.umd.js.map} +1 -1
- package/lib/package.json +4 -5
- package/lib/src/db/PowerSyncDatabase.d.ts +2 -3
- package/lib/src/db/PowerSyncDatabase.js +3 -12
- package/lib/src/db/adapters/AsyncWebAdapter.d.ts +50 -0
- package/lib/src/db/adapters/AsyncWebAdapter.js +163 -0
- package/lib/src/db/adapters/SSRDBAdapter.d.ts +1 -2
- package/lib/src/db/adapters/SSRDBAdapter.js +5 -6
- package/lib/src/db/adapters/wa-sqlite/ConcurrentConnection.d.ts +56 -0
- package/lib/src/db/adapters/wa-sqlite/ConcurrentConnection.js +121 -0
- package/lib/src/db/adapters/wa-sqlite/DatabaseClient.d.ts +54 -0
- package/lib/src/db/adapters/wa-sqlite/DatabaseClient.js +227 -0
- package/lib/src/db/adapters/wa-sqlite/DatabaseServer.d.ts +47 -0
- package/lib/src/db/adapters/wa-sqlite/DatabaseServer.js +145 -0
- package/lib/src/db/adapters/wa-sqlite/RawSqliteConnection.d.ts +46 -0
- package/lib/src/db/adapters/wa-sqlite/RawSqliteConnection.js +147 -0
- package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.d.ts +28 -6
- package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.js +104 -55
- package/lib/src/db/adapters/wa-sqlite/vfs.d.ts +50 -0
- package/lib/src/db/adapters/wa-sqlite/vfs.js +76 -0
- package/lib/src/db/adapters/web-sql-flags.d.ts +5 -0
- package/lib/src/db/sync/SSRWebStreamingSyncImplementation.d.ts +5 -2
- package/lib/src/db/sync/SSRWebStreamingSyncImplementation.js +6 -3
- package/lib/src/db/sync/SharedWebStreamingSyncImplementation.js +4 -19
- package/lib/src/index.d.ts +1 -4
- package/lib/src/index.js +1 -4
- package/lib/src/shared/tab_close_signal.d.ts +11 -0
- package/lib/src/shared/tab_close_signal.js +26 -0
- package/lib/src/worker/db/MultiDatabaseServer.d.ts +17 -0
- package/lib/src/worker/db/MultiDatabaseServer.js +89 -0
- package/lib/src/worker/db/WASQLiteDB.worker.js +9 -48
- package/lib/src/worker/db/open-worker-database.d.ts +3 -3
- package/lib/src/worker/db/open-worker-database.js +2 -2
- package/lib/src/worker/sync/SharedSyncImplementation.d.ts +5 -6
- package/lib/src/worker/sync/SharedSyncImplementation.js +88 -54
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -6
- package/src/db/PowerSyncDatabase.ts +4 -12
- package/src/db/adapters/AsyncWebAdapter.ts +207 -0
- package/src/db/adapters/SSRDBAdapter.ts +7 -7
- package/src/db/adapters/wa-sqlite/ConcurrentConnection.ts +137 -0
- package/src/db/adapters/wa-sqlite/DatabaseClient.ts +325 -0
- package/src/db/adapters/wa-sqlite/DatabaseServer.ts +203 -0
- package/src/db/adapters/wa-sqlite/RawSqliteConnection.ts +194 -0
- package/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.ts +152 -63
- package/src/db/adapters/wa-sqlite/vfs.ts +96 -0
- package/src/db/adapters/web-sql-flags.ts +6 -0
- package/src/db/sync/SSRWebStreamingSyncImplementation.ts +7 -3
- package/src/db/sync/SharedWebStreamingSyncImplementation.ts +4 -20
- package/src/index.ts +1 -4
- package/src/shared/tab_close_signal.ts +28 -0
- package/src/worker/db/MultiDatabaseServer.ts +107 -0
- package/src/worker/db/WASQLiteDB.worker.ts +10 -57
- package/src/worker/db/open-worker-database.ts +4 -4
- package/src/worker/sync/SharedSyncImplementation.ts +114 -58
- package/dist/26d61ca9f5694d064635.wasm +0 -0
- package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-89f0ba.index.umd.js +0 -1878
- package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-89f0ba.index.umd.js.map +0 -1
- package/dist/_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapps_wa-sqlite_src_example-97ebe9.index.umd.js +0 -555
- package/dist/_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapps_wa-sqlite_src_example-97ebe9.index.umd.js.map +0 -1
- package/dist/b4c6283dc473b6b3fd24.wasm +0 -0
- package/dist/c78985091a0b22aaef03.wasm +0 -0
- package/dist/ca59e199e1138b553fad.wasm +0 -0
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_dist_mc-wa-s-b9c070.umd.js +0 -31
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_dist_mc-wa-s-b9c070.umd.js.map +0 -1
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_dist_mc-wa-s-c99c07.umd.js +0 -31
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_dist_mc-wa-s-c99c07.umd.js.map +0 -1
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_dist_wa-sqli-cc5fcc.umd.js +0 -31
- package/dist/worker/node_modules_pnpm_journeyapps_wa-sqlite_1_5_0_node_modules_journeyapps_wa-sqlite_dist_wa-sqlite_mjs.umd.js +0 -31
- package/lib/src/db/adapters/AbstractWebSQLOpenFactory.d.ts +0 -17
- package/lib/src/db/adapters/AbstractWebSQLOpenFactory.js +0 -33
- package/lib/src/db/adapters/AsyncDatabaseConnection.d.ts +0 -49
- package/lib/src/db/adapters/AsyncDatabaseConnection.js +0 -1
- package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.d.ts +0 -109
- package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.js +0 -401
- package/lib/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.d.ts +0 -59
- package/lib/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.js +0 -147
- package/lib/src/db/adapters/wa-sqlite/InternalWASQLiteDBAdapter.d.ts +0 -12
- package/lib/src/db/adapters/wa-sqlite/InternalWASQLiteDBAdapter.js +0 -19
- package/lib/src/db/adapters/wa-sqlite/WASQLiteConnection.d.ts +0 -155
- package/lib/src/db/adapters/wa-sqlite/WASQLiteConnection.js +0 -401
- package/lib/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.d.ts +0 -32
- package/lib/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.js +0 -49
- package/lib/src/worker/db/SharedWASQLiteConnection.d.ts +0 -42
- package/lib/src/worker/db/SharedWASQLiteConnection.js +0 -90
- package/lib/src/worker/db/WorkerWASQLiteConnection.d.ts +0 -9
- package/lib/src/worker/db/WorkerWASQLiteConnection.js +0 -12
- package/src/db/adapters/AbstractWebSQLOpenFactory.ts +0 -48
- package/src/db/adapters/AsyncDatabaseConnection.ts +0 -55
- package/src/db/adapters/LockedAsyncDatabaseAdapter.ts +0 -490
- package/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.ts +0 -201
- package/src/db/adapters/wa-sqlite/InternalWASQLiteDBAdapter.ts +0 -23
- package/src/db/adapters/wa-sqlite/WASQLiteConnection.ts +0 -497
- package/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.ts +0 -86
- package/src/worker/db/SharedWASQLiteConnection.ts +0 -131
- package/src/worker/db/WorkerWASQLiteConnection.ts +0 -14
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { Factory as WaSqliteFactory, SQLITE_ROW } from '@journeyapps/wa-sqlite';
|
|
2
|
+
|
|
3
|
+
import { DEFAULT_MODULE_FACTORIES, WASQLiteModuleFactory } from './vfs.js';
|
|
4
|
+
import { ResolvedWASQLiteOpenFactoryOptions } from './WASQLiteOpenFactory.js';
|
|
5
|
+
|
|
6
|
+
export interface RawResultSet {
|
|
7
|
+
columns: string[];
|
|
8
|
+
rows: SQLiteCompatibleType[][];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface RawQueryResult {
|
|
12
|
+
changes: number;
|
|
13
|
+
lastInsertRowId: number;
|
|
14
|
+
autocommit: boolean;
|
|
15
|
+
resultSet: RawResultSet | undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A small wrapper around WA-sqlite to help with opening databases and running statements by preparing them internally.
|
|
20
|
+
*
|
|
21
|
+
* This is an internal class, and it must never be used directly. Wrappers are required to ensure raw connections aren't
|
|
22
|
+
* used concurrently across tabs.
|
|
23
|
+
*/
|
|
24
|
+
export class RawSqliteConnection {
|
|
25
|
+
private _sqliteAPI: SQLiteAPI | null = null;
|
|
26
|
+
/**
|
|
27
|
+
* The `sqlite3*` connection pointer.
|
|
28
|
+
*/
|
|
29
|
+
private db: number = 0;
|
|
30
|
+
private _moduleFactory: WASQLiteModuleFactory;
|
|
31
|
+
|
|
32
|
+
constructor(readonly options: ResolvedWASQLiteOpenFactoryOptions) {
|
|
33
|
+
this._moduleFactory = DEFAULT_MODULE_FACTORIES[this.options.vfs];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
get isOpen(): boolean {
|
|
37
|
+
return this.db != 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async init() {
|
|
41
|
+
const api = (this._sqliteAPI = await this.openSQLiteAPI());
|
|
42
|
+
this.db = await api.open_v2(
|
|
43
|
+
this.options.dbFilename,
|
|
44
|
+
this.options.isReadOnly ? 1 /* SQLITE_OPEN_READONLY */ : 6 /* SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE */
|
|
45
|
+
);
|
|
46
|
+
await this.executeRaw(`PRAGMA temp_store = ${this.options.temporaryStorage};`);
|
|
47
|
+
if (this.options.encryptionKey) {
|
|
48
|
+
const escapedKey = this.options.encryptionKey.replace("'", "''");
|
|
49
|
+
await this.executeRaw(`PRAGMA key = '${escapedKey}'`);
|
|
50
|
+
}
|
|
51
|
+
await this.executeRaw(`PRAGMA cache_size = -${this.options.cacheSizeKb};`);
|
|
52
|
+
|
|
53
|
+
await this.executeRaw(`SELECT powersync_update_hooks('install');`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private async openSQLiteAPI(): Promise<SQLiteAPI> {
|
|
57
|
+
const { module, vfs } = await this._moduleFactory({
|
|
58
|
+
dbFileName: this.options.dbFilename,
|
|
59
|
+
encryptionKey: this.options.encryptionKey
|
|
60
|
+
});
|
|
61
|
+
const sqlite3 = WaSqliteFactory(module);
|
|
62
|
+
sqlite3.vfs_register(vfs, true);
|
|
63
|
+
/**
|
|
64
|
+
* Register the PowerSync core SQLite extension
|
|
65
|
+
*/
|
|
66
|
+
module.ccall('powersync_init_static', 'int', []);
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Create the multiple cipher vfs if an encryption key is provided
|
|
70
|
+
*/
|
|
71
|
+
if (this.options.encryptionKey) {
|
|
72
|
+
const createResult = module.ccall('sqlite3mc_vfs_create', 'int', ['string', 'int'], [this.options.dbFilename, 1]);
|
|
73
|
+
if (createResult !== 0) {
|
|
74
|
+
throw new Error('Failed to create multiple cipher vfs, Database encryption will not work');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return sqlite3;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
requireSqlite(): SQLiteAPI {
|
|
82
|
+
if (!this._sqliteAPI) {
|
|
83
|
+
throw new Error(`Initialization has not completed`);
|
|
84
|
+
}
|
|
85
|
+
return this._sqliteAPI;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Checks if the database connection is in autocommit mode.
|
|
90
|
+
* @returns true if in autocommit mode, false if in a transaction
|
|
91
|
+
*/
|
|
92
|
+
isAutoCommit(): boolean {
|
|
93
|
+
return this.requireSqlite().get_autocommit(this.db) != 0;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async execute(sql: string, bindings?: any[]): Promise<RawQueryResult> {
|
|
97
|
+
const resultSet = await this.executeSingleStatementRaw(sql, bindings);
|
|
98
|
+
return this.wrapQueryResults(this.requireSqlite(), resultSet);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async executeBatch(sql: string, bindings: any[][]): Promise<RawQueryResult[]> {
|
|
102
|
+
const results = [];
|
|
103
|
+
const api = this.requireSqlite();
|
|
104
|
+
for await (const stmt of api.statements(this.db, sql)) {
|
|
105
|
+
let columns;
|
|
106
|
+
|
|
107
|
+
for (const parameterSet of bindings) {
|
|
108
|
+
const rs = await this.stepThroughStatement(api, stmt, parameterSet, columns, false);
|
|
109
|
+
results.push(this.wrapQueryResults(api, rs));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// executeBatch can only use a single statement
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return results;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private wrapQueryResults(api: SQLiteAPI, rs: RawResultSet | undefined): RawQueryResult {
|
|
120
|
+
return {
|
|
121
|
+
changes: api.changes(this.db),
|
|
122
|
+
lastInsertRowId: api.last_insert_id(this.db),
|
|
123
|
+
autocommit: api.get_autocommit(this.db) != 0,
|
|
124
|
+
resultSet: rs
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* This executes a single statement using SQLite3 and returns the results as a {@link RawResultSet}.
|
|
130
|
+
*/
|
|
131
|
+
private async executeSingleStatementRaw(sql: string, bindings?: any[]): Promise<RawResultSet | undefined> {
|
|
132
|
+
const results = await this.executeRaw(sql, bindings);
|
|
133
|
+
return results.length ? results[0] : undefined;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async executeRaw(sql: string, bindings?: any[]): Promise<RawResultSet[]> {
|
|
137
|
+
const results = [];
|
|
138
|
+
const api = this.requireSqlite();
|
|
139
|
+
for await (const stmt of api.statements(this.db, sql)) {
|
|
140
|
+
let columns;
|
|
141
|
+
|
|
142
|
+
const rs = await this.stepThroughStatement(api, stmt, bindings ?? [], columns);
|
|
143
|
+
columns = rs.columns;
|
|
144
|
+
if (columns.length) {
|
|
145
|
+
results.push(rs);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// When binding parameters, only a single statement is executed.
|
|
149
|
+
if (bindings) {
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return results;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private async stepThroughStatement(
|
|
158
|
+
api: SQLiteAPI,
|
|
159
|
+
stmt: number,
|
|
160
|
+
bindings: any[],
|
|
161
|
+
knownColumns: string[] | undefined,
|
|
162
|
+
includeResults: boolean = true
|
|
163
|
+
): Promise<RawResultSet> {
|
|
164
|
+
// TODO not sure why this is needed currently, but booleans break
|
|
165
|
+
bindings.forEach((b, index, arr) => {
|
|
166
|
+
if (typeof b == 'boolean') {
|
|
167
|
+
arr[index] = b ? 1 : 0;
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
api.reset(stmt);
|
|
172
|
+
if (bindings) {
|
|
173
|
+
api.bind_collection(stmt, bindings);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const rows = [];
|
|
177
|
+
while ((await api.step(stmt)) === SQLITE_ROW) {
|
|
178
|
+
if (includeResults) {
|
|
179
|
+
const row = api.row(stmt);
|
|
180
|
+
rows.push(row);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
knownColumns ??= api.column_names(stmt);
|
|
185
|
+
return { columns: knownColumns, rows };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async close() {
|
|
189
|
+
if (this.isOpen) {
|
|
190
|
+
await this.requireSqlite().close(this.db);
|
|
191
|
+
this.db = 0;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -1,38 +1,65 @@
|
|
|
1
|
-
import { DBAdapter, type ILogLevel } from '@powersync/common';
|
|
1
|
+
import { createLogger, DBAdapter, ILogger, SQLOpenFactory, type ILogLevel } from '@powersync/common';
|
|
2
2
|
import * as Comlink from 'comlink';
|
|
3
3
|
import { openWorkerDatabasePort, resolveWorkerDatabasePortFactory } from '../../../worker/db/open-worker-database.js';
|
|
4
|
-
import { AbstractWebSQLOpenFactory } from '../AbstractWebSQLOpenFactory.js';
|
|
5
|
-
import { AsyncDatabaseConnection, OpenAsyncDatabaseConnection } from '../AsyncDatabaseConnection.js';
|
|
6
|
-
import { WorkerWrappedAsyncDatabaseConnection } from '../WorkerWrappedAsyncDatabaseConnection.js';
|
|
7
4
|
import {
|
|
8
5
|
DEFAULT_CACHE_SIZE_KB,
|
|
6
|
+
isServerSide,
|
|
7
|
+
ResolvedWebSQLFlags,
|
|
9
8
|
ResolvedWebSQLOpenOptions,
|
|
9
|
+
resolveWebSQLFlags,
|
|
10
10
|
TemporaryStorageOption,
|
|
11
11
|
WebSQLOpenFactoryOptions
|
|
12
12
|
} from '../web-sql-flags.js';
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
13
|
+
import { SSRDBAdapter } from '../SSRDBAdapter.js';
|
|
14
|
+
import { vfsRequiresDedicatedWorkers, WASQLiteVFS } from './vfs.js';
|
|
15
|
+
import { MultiDatabaseServer } from '../../../worker/db/MultiDatabaseServer.js';
|
|
16
|
+
import { DatabaseClient, OpenWorkerConnection } from './DatabaseClient.js';
|
|
17
|
+
import { generateTabCloseSignal } from '../../../shared/tab_close_signal.js';
|
|
18
|
+
import { AsyncDbAdapter, PoolConnection } from '../AsyncWebAdapter.js';
|
|
15
19
|
|
|
16
20
|
export interface WASQLiteOpenFactoryOptions extends WebSQLOpenFactoryOptions {
|
|
17
21
|
vfs?: WASQLiteVFS;
|
|
22
|
+
/**
|
|
23
|
+
* If the {@link vfs} supports it, an additional amount of read-only connections to open. Using additional read
|
|
24
|
+
* connections can speed up queries by dispatching them to multiple workers running them concurrently.
|
|
25
|
+
*
|
|
26
|
+
* {@link WASQLiteVFS.OPFSWriteAheadVFS} is the only VFS with support for multiple connections, so this option is
|
|
27
|
+
* ignored for other VFS implementations.
|
|
28
|
+
*
|
|
29
|
+
* Defaults to 1.
|
|
30
|
+
*/
|
|
31
|
+
additionalReaders?: number;
|
|
18
32
|
}
|
|
19
33
|
|
|
20
34
|
export interface ResolvedWASQLiteOpenFactoryOptions extends ResolvedWebSQLOpenOptions {
|
|
21
35
|
vfs: WASQLiteVFS;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Whether this is a read-only connection opened for the `OPFSWriteAheadVFS` file system.
|
|
39
|
+
*/
|
|
40
|
+
isReadOnly: boolean;
|
|
22
41
|
}
|
|
23
42
|
|
|
24
43
|
export interface WorkerDBOpenerOptions extends ResolvedWASQLiteOpenFactoryOptions {
|
|
25
44
|
logLevel: ILogLevel;
|
|
45
|
+
/**
|
|
46
|
+
* A lock that is currently held by the client. When the lock is returned, we know the client is gone and that we need
|
|
47
|
+
* to clean up resources.
|
|
48
|
+
*/
|
|
49
|
+
lockName: string;
|
|
26
50
|
}
|
|
27
51
|
|
|
28
52
|
/**
|
|
29
53
|
* Opens a SQLite connection using WA-SQLite.
|
|
30
54
|
*/
|
|
31
|
-
export class WASQLiteOpenFactory
|
|
32
|
-
|
|
33
|
-
|
|
55
|
+
export class WASQLiteOpenFactory implements SQLOpenFactory {
|
|
56
|
+
private resolvedFlags: ResolvedWebSQLFlags;
|
|
57
|
+
private logger: ILogger;
|
|
34
58
|
|
|
59
|
+
constructor(private options: WASQLiteOpenFactoryOptions) {
|
|
35
60
|
assertValidWASQLiteOpenFactoryOptions(options);
|
|
61
|
+
this.resolvedFlags = resolveWebSQLFlags(options.flags);
|
|
62
|
+
this.logger = options.logger ?? createLogger(`WASQLiteOpenFactory - ${this.options.dbFilename}`);
|
|
36
63
|
}
|
|
37
64
|
|
|
38
65
|
get waOptions(): WASQLiteOpenFactoryOptions {
|
|
@@ -41,15 +68,36 @@ export class WASQLiteOpenFactory extends AbstractWebSQLOpenFactory {
|
|
|
41
68
|
}
|
|
42
69
|
|
|
43
70
|
protected openAdapter(): DBAdapter {
|
|
44
|
-
return new
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
71
|
+
return new AsyncDbAdapter(this.openConnection(), this.options.dbFilename);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
openDB(): DBAdapter {
|
|
75
|
+
const {
|
|
76
|
+
resolvedFlags: { disableSSRWarning, enableMultiTabs, ssrMode = isServerSide() }
|
|
77
|
+
} = this;
|
|
78
|
+
if (ssrMode) {
|
|
79
|
+
if (!disableSSRWarning) {
|
|
80
|
+
this.logger.warn(
|
|
81
|
+
`
|
|
82
|
+
Running PowerSync in SSR mode.
|
|
83
|
+
Only empty query results will be returned.
|
|
84
|
+
Disable this warning by setting 'disableSSRWarning: true' in options.`
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return new SSRDBAdapter();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (!enableMultiTabs) {
|
|
92
|
+
this.logger.warn(
|
|
93
|
+
'Multiple tab support is not enabled. Using this site across multiple tabs may not function correctly.'
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return this.openAdapter();
|
|
50
98
|
}
|
|
51
99
|
|
|
52
|
-
async openConnection(): Promise<
|
|
100
|
+
async openConnection(): Promise<PoolConnection> {
|
|
53
101
|
const { enableMultiTabs, useWebWorker } = this.resolvedFlags;
|
|
54
102
|
const {
|
|
55
103
|
vfs = WASQLiteVFS.IDBBatchAtomicVFS,
|
|
@@ -62,59 +110,100 @@ export class WASQLiteOpenFactory extends AbstractWebSQLOpenFactory {
|
|
|
62
110
|
this.logger.warn('Multiple tabs are not enabled in this browser');
|
|
63
111
|
}
|
|
64
112
|
|
|
113
|
+
const resolveOptions = (isReadOnly: boolean): ResolvedWASQLiteOpenFactoryOptions => ({
|
|
114
|
+
dbFilename: this.options.dbFilename,
|
|
115
|
+
dbLocation: this.options.dbLocation,
|
|
116
|
+
debugMode: this.options.debugMode,
|
|
117
|
+
vfs,
|
|
118
|
+
temporaryStorage,
|
|
119
|
+
cacheSizeKb,
|
|
120
|
+
flags: this.resolvedFlags,
|
|
121
|
+
encryptionKey: encryptionKey,
|
|
122
|
+
isReadOnly
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
let client: DatabaseClient;
|
|
126
|
+
let additionalReaders: DatabaseClient[] = [];
|
|
127
|
+
let requiresPersistentTriggers = vfsRequiresDedicatedWorkers(vfs);
|
|
128
|
+
|
|
65
129
|
if (useWebWorker) {
|
|
66
130
|
const optionsDbWorker = this.options.worker;
|
|
67
131
|
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
132
|
+
const openDatabaseWorker = async (
|
|
133
|
+
resolvedOptions: ResolvedWASQLiteOpenFactoryOptions
|
|
134
|
+
): Promise<DatabaseClient> => {
|
|
135
|
+
const workerPort =
|
|
136
|
+
typeof optionsDbWorker == 'function'
|
|
137
|
+
? resolveWorkerDatabasePortFactory(() =>
|
|
138
|
+
optionsDbWorker({
|
|
139
|
+
...this.options,
|
|
140
|
+
temporaryStorage,
|
|
141
|
+
cacheSizeKb,
|
|
142
|
+
flags: this.resolvedFlags,
|
|
143
|
+
encryptionKey
|
|
144
|
+
})
|
|
145
|
+
)
|
|
146
|
+
: openWorkerDatabasePort(this.options.dbFilename, enableMultiTabs, optionsDbWorker, this.waOptions.vfs);
|
|
147
|
+
|
|
148
|
+
const source = Comlink.wrap<OpenWorkerConnection>(workerPort);
|
|
149
|
+
const closeSignal = new AbortController();
|
|
150
|
+
const connection = await source.connect({
|
|
151
|
+
...resolvedOptions,
|
|
152
|
+
logLevel: this.logger.getLevel(),
|
|
153
|
+
lockName: await generateTabCloseSignal(closeSignal.signal)
|
|
154
|
+
});
|
|
155
|
+
const clientOptions = {
|
|
156
|
+
connection,
|
|
157
|
+
source,
|
|
158
|
+
// This tab owns the worker, so we're guaranteed to outlive it.
|
|
159
|
+
remoteCanCloseUnexpectedly: false,
|
|
160
|
+
onClose: () => {
|
|
161
|
+
closeSignal.abort();
|
|
162
|
+
if (workerPort instanceof Worker) {
|
|
163
|
+
workerPort.terminate();
|
|
164
|
+
} else {
|
|
165
|
+
workerPort.close();
|
|
166
|
+
}
|
|
102
167
|
}
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
return new DatabaseClient(clientOptions, {
|
|
171
|
+
...resolvedOptions,
|
|
172
|
+
requiresPersistentTriggers
|
|
173
|
+
});
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
client = await openDatabaseWorker(resolveOptions(false));
|
|
177
|
+
|
|
178
|
+
if (vfs == WASQLiteVFS.OPFSWriteAheadVFS) {
|
|
179
|
+
// This VFS supports concurrent reads, so we can open additional workers to host read-only connections for
|
|
180
|
+
// concurrent reads / writes.
|
|
181
|
+
const additionalReadersCount = this.options.additionalReaders ?? 1;
|
|
182
|
+
for (let i = 0; i < additionalReadersCount; i++) {
|
|
183
|
+
const reader = await openDatabaseWorker(resolveOptions(true));
|
|
184
|
+
additionalReaders.push(reader);
|
|
103
185
|
}
|
|
104
|
-
}
|
|
186
|
+
}
|
|
105
187
|
} else {
|
|
106
|
-
// Don't use a web worker
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
188
|
+
// Don't use a web worker. Instead, open the MultiDatabaseServer a worker would use locally.
|
|
189
|
+
const localServer = new MultiDatabaseServer(this.logger);
|
|
190
|
+
requiresPersistentTriggers = true;
|
|
191
|
+
|
|
192
|
+
const resolvedOptions = resolveOptions(false);
|
|
193
|
+
const connection = await localServer.openConnectionLocally(resolvedOptions);
|
|
194
|
+
client = new DatabaseClient(
|
|
195
|
+
{ connection, source: null, remoteCanCloseUnexpectedly: false },
|
|
196
|
+
{
|
|
197
|
+
...resolvedOptions,
|
|
198
|
+
requiresPersistentTriggers
|
|
199
|
+
}
|
|
200
|
+
);
|
|
117
201
|
}
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
writer: client,
|
|
205
|
+
additionalReaders
|
|
206
|
+
};
|
|
118
207
|
}
|
|
119
208
|
}
|
|
120
209
|
|
|
@@ -125,7 +214,7 @@ function assertValidWASQLiteOpenFactoryOptions(options: WASQLiteOpenFactoryOptio
|
|
|
125
214
|
// The OPFS VFS only works in dedicated web workers.
|
|
126
215
|
if ('vfs' in options && 'flags' in options) {
|
|
127
216
|
const { vfs, flags = {} } = options;
|
|
128
|
-
if (vfs
|
|
217
|
+
if (vfs && vfsRequiresDedicatedWorkers(vfs) && 'useWebWorker' in flags && !flags.useWebWorker) {
|
|
129
218
|
throw new Error(
|
|
130
219
|
`Invalid configuration: The 'useWebWorker' flag must be true when using an OPFS-based VFS (${vfs}).`
|
|
131
220
|
);
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type * as SQLite from '@journeyapps/wa-sqlite';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* List of currently tested virtual filesystems
|
|
5
|
+
*/
|
|
6
|
+
export enum WASQLiteVFS {
|
|
7
|
+
IDBBatchAtomicVFS = 'IDBBatchAtomicVFS',
|
|
8
|
+
OPFSCoopSyncVFS = 'OPFSCoopSyncVFS',
|
|
9
|
+
AccessHandlePoolVFS = 'AccessHandlePoolVFS',
|
|
10
|
+
OPFSWriteAheadVFS = 'OPFSWriteAheadVFS'
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function vfsRequiresDedicatedWorkers(vfs: WASQLiteVFS) {
|
|
14
|
+
return vfs != WASQLiteVFS.IDBBatchAtomicVFS;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
export type WASQLiteModuleFactoryOptions = { dbFileName: string; encryptionKey?: string };
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
export type SQLiteModule = Parameters<typeof SQLite.Factory>[0];
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @internal
|
|
29
|
+
*/
|
|
30
|
+
export type WASQLiteModuleFactory = (
|
|
31
|
+
options: WASQLiteModuleFactoryOptions
|
|
32
|
+
) => Promise<{ module: SQLiteModule; vfs: SQLiteVFS }>;
|
|
33
|
+
|
|
34
|
+
async function asyncModuleFactory(encryptionKey: unknown) {
|
|
35
|
+
if (encryptionKey) {
|
|
36
|
+
const { default: factory } = await import('@journeyapps/wa-sqlite/dist/mc-wa-sqlite-async.mjs');
|
|
37
|
+
return factory();
|
|
38
|
+
} else {
|
|
39
|
+
const { default: factory } = await import('@journeyapps/wa-sqlite/dist/wa-sqlite-async.mjs');
|
|
40
|
+
return factory();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function syncModuleFactory(encryptionKey: unknown) {
|
|
45
|
+
if (encryptionKey) {
|
|
46
|
+
const { default: factory } = await import('@journeyapps/wa-sqlite/dist/mc-wa-sqlite.mjs');
|
|
47
|
+
return factory();
|
|
48
|
+
} else {
|
|
49
|
+
const { default: factory } = await import('@journeyapps/wa-sqlite/dist/wa-sqlite.mjs');
|
|
50
|
+
return factory();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @internal
|
|
56
|
+
*/
|
|
57
|
+
export const DEFAULT_MODULE_FACTORIES = {
|
|
58
|
+
[WASQLiteVFS.IDBBatchAtomicVFS]: async (options: WASQLiteModuleFactoryOptions) => {
|
|
59
|
+
const module = await asyncModuleFactory(options.encryptionKey);
|
|
60
|
+
const { IDBBatchAtomicVFS } = await import('@journeyapps/wa-sqlite/src/examples/IDBBatchAtomicVFS.js');
|
|
61
|
+
return {
|
|
62
|
+
module,
|
|
63
|
+
// @ts-expect-error The types for this static method are missing upstream
|
|
64
|
+
vfs: await IDBBatchAtomicVFS.create(options.dbFileName, module, { lockPolicy: 'exclusive' })
|
|
65
|
+
};
|
|
66
|
+
},
|
|
67
|
+
[WASQLiteVFS.AccessHandlePoolVFS]: async (options: WASQLiteModuleFactoryOptions) => {
|
|
68
|
+
const module = await syncModuleFactory(options.encryptionKey);
|
|
69
|
+
// @ts-expect-error The types for this static method are missing upstream
|
|
70
|
+
const { AccessHandlePoolVFS } = await import('@journeyapps/wa-sqlite/src/examples/AccessHandlePoolVFS.js');
|
|
71
|
+
return {
|
|
72
|
+
module,
|
|
73
|
+
vfs: await AccessHandlePoolVFS.create(options.dbFileName, module)
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
[WASQLiteVFS.OPFSCoopSyncVFS]: async (options: WASQLiteModuleFactoryOptions) => {
|
|
77
|
+
const module = await syncModuleFactory(options.encryptionKey);
|
|
78
|
+
// @ts-expect-error The types for this static method are missing upstream
|
|
79
|
+
const { OPFSCoopSyncVFS } = await import('@journeyapps/wa-sqlite/src/examples/OPFSCoopSyncVFS.js');
|
|
80
|
+
const vfs = await OPFSCoopSyncVFS.create(options.dbFileName, module);
|
|
81
|
+
return {
|
|
82
|
+
module,
|
|
83
|
+
vfs
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
[WASQLiteVFS.OPFSWriteAheadVFS]: async (options: WASQLiteModuleFactoryOptions) => {
|
|
87
|
+
const module = await syncModuleFactory(options.encryptionKey);
|
|
88
|
+
// @ts-expect-error The types for this static method are missing upstream
|
|
89
|
+
const { OPFSWriteAheadVFS } = await import('@journeyapps/wa-sqlite/src/examples/OPFSWriteAheadVFS.js');
|
|
90
|
+
const vfs = await OPFSWriteAheadVFS.create(options.dbFileName, module, {});
|
|
91
|
+
return {
|
|
92
|
+
module,
|
|
93
|
+
vfs
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
};
|
|
@@ -76,6 +76,12 @@ export interface WebSQLOpenFactoryOptions extends SQLOpenOptions {
|
|
|
76
76
|
*/
|
|
77
77
|
worker?: string | URL | ((options: ResolvedWebSQLOpenOptions) => Worker | SharedWorker);
|
|
78
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Use an existing port to an initialized worker.
|
|
81
|
+
* A worker will be initialized if none is provided
|
|
82
|
+
*/
|
|
83
|
+
workerPort?: MessagePort;
|
|
84
|
+
|
|
79
85
|
logger?: ILogger;
|
|
80
86
|
|
|
81
87
|
/**
|
|
@@ -3,13 +3,12 @@ import {
|
|
|
3
3
|
BaseObserver,
|
|
4
4
|
LockOptions,
|
|
5
5
|
LockType,
|
|
6
|
+
Mutex,
|
|
6
7
|
PowerSyncConnectionOptions,
|
|
7
8
|
StreamingSyncImplementation,
|
|
8
|
-
SubscribedStream,
|
|
9
9
|
SyncStatus,
|
|
10
10
|
SyncStatusOptions
|
|
11
11
|
} from '@powersync/common';
|
|
12
|
-
import { Mutex } from 'async-mutex';
|
|
13
12
|
|
|
14
13
|
export class SSRStreamingSyncImplementation extends BaseObserver implements StreamingSyncImplementation {
|
|
15
14
|
syncMutex: Mutex;
|
|
@@ -29,7 +28,7 @@ export class SSRStreamingSyncImplementation extends BaseObserver implements Stre
|
|
|
29
28
|
|
|
30
29
|
obtainLock<T>(lockOptions: LockOptions<T>): Promise<T> {
|
|
31
30
|
const mutex = lockOptions.type == LockType.CRUD ? this.crudMutex : this.syncMutex;
|
|
32
|
-
return mutex.runExclusive(lockOptions.callback);
|
|
31
|
+
return mutex.runExclusive(lockOptions.callback, lockOptions.signal);
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
/**
|
|
@@ -86,4 +85,9 @@ export class SSRStreamingSyncImplementation extends BaseObserver implements Stre
|
|
|
86
85
|
* No-op in SSR mode.
|
|
87
86
|
*/
|
|
88
87
|
updateSubscriptions(): void {}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* No-op in SSR mode.
|
|
91
|
+
*/
|
|
92
|
+
markConnectionMayHaveChanged(): void {}
|
|
89
93
|
}
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
WebStreamingSyncImplementation,
|
|
16
16
|
WebStreamingSyncImplementationOptions
|
|
17
17
|
} from './WebStreamingSyncImplementation.js';
|
|
18
|
+
import { generateTabCloseSignal } from '../../shared/tab_close_signal.js';
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* The shared worker will trigger methods on this side of the message port
|
|
@@ -192,26 +193,9 @@ export class SharedWebStreamingSyncImplementation extends WebStreamingSyncImplem
|
|
|
192
193
|
* - We resolve the top-level promise after the lock has been registered with the shared worker.
|
|
193
194
|
* - The client sends the params to the shared worker after locks have been registered.
|
|
194
195
|
*/
|
|
195
|
-
await
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
// to free resources associated with this tab.
|
|
199
|
-
// We take hold of this lock as soon-as-possible in order to cater for potentially closed tabs.
|
|
200
|
-
getNavigatorLocks().request(`tab-close-signal-${crypto.randomUUID()}`, async (lock) => {
|
|
201
|
-
if (this.abortOnClose.signal.aborted) {
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
// Awaiting here ensures the worker is waiting for the lock
|
|
205
|
-
await this.syncManager.addLockBasedCloseSignal(lock!.name);
|
|
206
|
-
|
|
207
|
-
// The lock has been registered, we can continue with the initialization
|
|
208
|
-
resolve();
|
|
209
|
-
|
|
210
|
-
await new Promise<void>((r) => {
|
|
211
|
-
this.abortOnClose.signal.onabort = () => r();
|
|
212
|
-
});
|
|
213
|
-
});
|
|
214
|
-
});
|
|
196
|
+
const closeSignal = await generateTabCloseSignal(this.abortOnClose.signal);
|
|
197
|
+
// Awaiting here ensures the worker is waiting for the lock
|
|
198
|
+
await this.syncManager.addLockBasedCloseSignal(closeSignal);
|
|
215
199
|
|
|
216
200
|
const { crudUploadThrottleMs, identifier, retryDelayMs } = this.options;
|
|
217
201
|
const flags = { ...this.webOptions.flags, workers: undefined };
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
export * from '@powersync/common';
|
|
2
2
|
export * from './attachments/IndexDBFileSystemAdapter.js';
|
|
3
3
|
export * from './db/adapters/AbstractWebPowerSyncDatabaseOpenFactory.js';
|
|
4
|
-
export
|
|
5
|
-
export * from './db/adapters/AsyncDatabaseConnection.js';
|
|
6
|
-
export * from './db/adapters/wa-sqlite/WASQLiteConnection.js';
|
|
7
|
-
export * from './db/adapters/wa-sqlite/WASQLiteDBAdapter.js';
|
|
4
|
+
export { WASQLiteVFS } from './db/adapters/wa-sqlite/vfs.js';
|
|
8
5
|
export * from './db/adapters/wa-sqlite/WASQLiteOpenFactory.js';
|
|
9
6
|
export * from './db/adapters/wa-sqlite/WASQLitePowerSyncDatabaseOpenFactory.js';
|
|
10
7
|
export * from './db/adapters/web-sql-flags.js';
|