@powersync/web 0.0.0-dev-20250916075127 → 0.0.0-dev-20250922105207
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/2dcb8a60ed4b341d3046.wasm +0 -0
- package/dist/50eaffc7435d7a77ffb5.wasm +0 -0
- package/dist/88ca2d3820062df8ea26.wasm +0 -0
- package/dist/efe40e50208db1807722.wasm +0 -0
- package/dist/index.umd.js +95 -16
- package/dist/index.umd.js.map +1 -1
- package/dist/worker/SharedSyncImplementation.umd.js +10 -10
- package/dist/worker/SharedSyncImplementation.umd.js.map +1 -1
- package/dist/worker/WASQLiteDB.umd.js +152 -41
- package/dist/worker/WASQLiteDB.umd.js.map +1 -1
- package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_mc-wa-sqlite-async_mjs.umd.js +15 -3
- package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_mc-wa-sqlite-async_mjs.umd.js.map +1 -1
- package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_mc-wa-sqlite_mjs.umd.js +15 -3
- package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_mc-wa-sqlite_mjs.umd.js.map +1 -1
- package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_wa-sqlite-async_mjs.umd.js +15 -3
- package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_wa-sqlite-async_mjs.umd.js.map +1 -1
- package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_wa-sqlite_mjs.umd.js +15 -3
- package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_wa-sqlite_mjs.umd.js.map +1 -1
- package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js.umd.js +46 -218
- package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js.umd.js.map +1 -1
- package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_IDBBatchAtomicVFS_js.umd.js +46 -218
- package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_IDBBatchAtomicVFS_js.umd.js.map +1 -1
- package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_OPFSCoopSyncVFS_js.umd.js +46 -218
- package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_OPFSCoopSyncVFS_js.umd.js.map +1 -1
- package/lib/package.json +4 -4
- package/lib/src/db/PowerSyncDatabase.js +1 -0
- package/lib/src/db/adapters/AsyncDatabaseConnection.d.ts +13 -1
- package/lib/src/db/adapters/wa-sqlite/WASQLiteConnection.d.ts +3 -1
- package/lib/src/db/adapters/wa-sqlite/WASQLiteConnection.js +28 -2
- package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.d.ts +1 -1
- package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.js +6 -2
- package/lib/src/worker/db/LogHandler.d.ts +12 -0
- package/lib/src/worker/db/LogHandler.js +6 -0
- package/lib/src/worker/db/WASQLiteDB.worker.js +80 -17
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/dist/31ba59416bad61e8fb1f.wasm +0 -0
- package/dist/d0a1e43030b814ed322f.wasm +0 -0
- package/dist/f4ad8bfeb6e6e5326142.wasm +0 -0
- package/dist/fbde47713220d7baec73.wasm +0 -0
|
@@ -59,6 +59,7 @@ export const DEFAULT_MODULE_FACTORIES = {
|
|
|
59
59
|
},
|
|
60
60
|
[WASQLiteVFS.AccessHandlePoolVFS]: async (options) => {
|
|
61
61
|
let module;
|
|
62
|
+
options.logger?.debug(`Opening VFS with options`, JSON.stringify(options));
|
|
62
63
|
if (options.encryptionKey) {
|
|
63
64
|
module = await MultiCipherSyncWASQLiteModuleFactory();
|
|
64
65
|
}
|
|
@@ -67,9 +68,26 @@ export const DEFAULT_MODULE_FACTORIES = {
|
|
|
67
68
|
}
|
|
68
69
|
// @ts-expect-error The types for this static method are missing upstream
|
|
69
70
|
const { AccessHandlePoolVFS } = await import('@journeyapps/wa-sqlite/src/examples/AccessHandlePoolVFS.js');
|
|
71
|
+
const vfs = new AccessHandlePoolVFS(options.dbFileName, module);
|
|
72
|
+
// Allow extra logs
|
|
73
|
+
const proxiedVFS = new Proxy(vfs, {
|
|
74
|
+
get(target, prop, receiver) {
|
|
75
|
+
const value = Reflect.get(target, prop, receiver);
|
|
76
|
+
// Only wrap methods, not properties
|
|
77
|
+
if (typeof value === 'function') {
|
|
78
|
+
return function (...args) {
|
|
79
|
+
options.logger?.debug(`VFS: Called ${String(prop)} with:`, args);
|
|
80
|
+
return value.apply(vfs, args);
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
await vfs.isReady();
|
|
87
|
+
// const vfs = await AccessHandlePoolVFS.create(options.dbFileName, module);
|
|
70
88
|
return {
|
|
71
89
|
module,
|
|
72
|
-
vfs:
|
|
90
|
+
vfs: proxiedVFS
|
|
73
91
|
};
|
|
74
92
|
},
|
|
75
93
|
[WASQLiteVFS.OPFSCoopSyncVFS]: async (options) => {
|
|
@@ -142,7 +160,9 @@ export class WASqliteConnection extends BaseObserver {
|
|
|
142
160
|
async openSQLiteAPI() {
|
|
143
161
|
const { module, vfs } = await this._moduleFactory({
|
|
144
162
|
dbFileName: this.options.dbFilename,
|
|
145
|
-
encryptionKey: this.options.encryptionKey
|
|
163
|
+
encryptionKey: this.options.encryptionKey,
|
|
164
|
+
debugMode: this.options.debugMode,
|
|
165
|
+
logger: this.options.logger
|
|
146
166
|
});
|
|
147
167
|
const sqlite3 = SQLite.Factory(module);
|
|
148
168
|
sqlite3.vfs_register(vfs, true);
|
|
@@ -180,6 +200,7 @@ export class WASqliteConnection extends BaseObserver {
|
|
|
180
200
|
}
|
|
181
201
|
}
|
|
182
202
|
async init() {
|
|
203
|
+
this.options.logger?.debug('Opening WASQLite connection for', this.options.dbFilename);
|
|
183
204
|
this._sqliteAPI = await this.openSQLiteAPI();
|
|
184
205
|
await this.openDB();
|
|
185
206
|
this.registerBroadcastListeners();
|
|
@@ -277,6 +298,7 @@ export class WASqliteConnection extends BaseObserver {
|
|
|
277
298
|
});
|
|
278
299
|
}
|
|
279
300
|
async close() {
|
|
301
|
+
this.options.logger?.debug('Closing WASQLite connection', this.options.dbFilename);
|
|
280
302
|
this.broadcastChannel?.close();
|
|
281
303
|
await this.sqliteAPI.close(this.dbP);
|
|
282
304
|
}
|
|
@@ -325,6 +347,10 @@ export class WASqliteConnection extends BaseObserver {
|
|
|
325
347
|
return results.flatMap((resultset) => resultset.rows.map((row) => resultset.columns.map((_, index) => row[index])));
|
|
326
348
|
}
|
|
327
349
|
async _execute(sql, bindings) {
|
|
350
|
+
// TODO, this might be redundant
|
|
351
|
+
if (this.options.debugMode) {
|
|
352
|
+
this.options.logger?.debug(`Executing SQL: ${sql}`);
|
|
353
|
+
}
|
|
328
354
|
const results = [];
|
|
329
355
|
for await (const stmt of this.sqliteAPI.statements(this.dbP, sql)) {
|
|
330
356
|
let columns;
|
|
@@ -9,7 +9,7 @@ export interface WASQLiteOpenFactoryOptions extends WebSQLOpenFactoryOptions {
|
|
|
9
9
|
export interface ResolvedWASQLiteOpenFactoryOptions extends ResolvedWebSQLOpenOptions {
|
|
10
10
|
vfs: WASQLiteVFS;
|
|
11
11
|
}
|
|
12
|
-
export interface WorkerDBOpenerOptions extends ResolvedWASQLiteOpenFactoryOptions {
|
|
12
|
+
export interface WorkerDBOpenerOptions extends Omit<ResolvedWASQLiteOpenFactoryOptions, 'logger'> {
|
|
13
13
|
logLevel: ILogLevel;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
@@ -52,8 +52,12 @@ export class WASQLiteOpenFactory extends AbstractWebSQLOpenFactory {
|
|
|
52
52
|
cacheSizeKb,
|
|
53
53
|
flags: this.resolvedFlags,
|
|
54
54
|
encryptionKey: encryptionKey,
|
|
55
|
-
logLevel: this.logger.getLevel()
|
|
56
|
-
|
|
55
|
+
logLevel: this.logger.getLevel(),
|
|
56
|
+
debugMode: this.options.debugMode
|
|
57
|
+
}, Comlink.proxy((event) => {
|
|
58
|
+
// TODO
|
|
59
|
+
this.logger[event.logLevel.toLocaleLowerCase()]('[DB Worker] ', ...event.messages);
|
|
60
|
+
})),
|
|
57
61
|
identifier: this.options.dbFilename,
|
|
58
62
|
onClose: () => {
|
|
59
63
|
if (workerPort instanceof Worker) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BaseListener, BaseObserver } from '@powersync/common';
|
|
2
|
+
export type LogEvent = {
|
|
3
|
+
loggerName: string;
|
|
4
|
+
logLevel: string;
|
|
5
|
+
messages: string[];
|
|
6
|
+
};
|
|
7
|
+
export interface LogHandlerListener extends BaseListener {
|
|
8
|
+
onLog: (event: LogEvent) => void;
|
|
9
|
+
}
|
|
10
|
+
export declare class LogHandler extends BaseObserver<LogHandlerListener> {
|
|
11
|
+
pushLog(entry: LogEvent): void;
|
|
12
|
+
}
|
|
@@ -2,21 +2,70 @@
|
|
|
2
2
|
* Supports both shared and dedicated workers, based on how the worker is constructed (new SharedWorker vs new Worker()).
|
|
3
3
|
*/
|
|
4
4
|
import '@journeyapps/wa-sqlite';
|
|
5
|
-
import { createBaseLogger, createLogger } from '@powersync/common';
|
|
5
|
+
import { createBaseLogger, createLogger, LogLevel } from '@powersync/common';
|
|
6
6
|
import * as Comlink from 'comlink';
|
|
7
7
|
import { WASqliteConnection } from '../../db/adapters/wa-sqlite/WASQLiteConnection';
|
|
8
8
|
import { getNavigatorLocks } from '../../shared/navigator';
|
|
9
|
-
|
|
10
|
-
baseLogger.useDefaults();
|
|
11
|
-
const logger = createLogger('db-worker');
|
|
9
|
+
import { LogHandler } from './LogHandler';
|
|
12
10
|
const DBMap = new Map();
|
|
13
11
|
const OPEN_DB_LOCK = 'open-wasqlite-db';
|
|
12
|
+
function logToAll(logLevel, ...messages) {
|
|
13
|
+
for (const dbFilename of DBMap.keys()) {
|
|
14
|
+
logBroadcaster.pushLog({
|
|
15
|
+
loggerName: dbFilename,
|
|
16
|
+
logLevel,
|
|
17
|
+
messages
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
14
21
|
let nextClientId = 1;
|
|
22
|
+
function logUnhandledException(error) {
|
|
23
|
+
const errorMessage = `
|
|
24
|
+
Name: ${error.name}
|
|
25
|
+
Cause: ${error.cause}
|
|
26
|
+
Message: ${error.message}
|
|
27
|
+
Stack: ${error.stack}`.trim();
|
|
28
|
+
logToAll(LogLevel.ERROR.name, 'Uncaught Exception in DB worker', errorMessage);
|
|
29
|
+
}
|
|
30
|
+
// Report unhandled exceptions to all loggers
|
|
31
|
+
addEventListener('unhandledrejection', (event) => {
|
|
32
|
+
logUnhandledException(event.reason);
|
|
33
|
+
});
|
|
34
|
+
addEventListener('error', (event) => {
|
|
35
|
+
logUnhandledException(event.error);
|
|
36
|
+
});
|
|
37
|
+
addEventListener('unload', () => {
|
|
38
|
+
logToAll(LogLevel.INFO.name, 'DB worker is unloading');
|
|
39
|
+
Array.from(DBMap.values()).forEach(async (dbConnection) => {
|
|
40
|
+
const { db, clientIds } = dbConnection;
|
|
41
|
+
logToAll(LogLevel.INFO.name, `closing db with ids ${clientIds}`);
|
|
42
|
+
db.close();
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
const baseLogger = createBaseLogger();
|
|
46
|
+
const logBroadcaster = new LogHandler();
|
|
47
|
+
const defaultHandler = baseLogger.createDefaultHandler();
|
|
48
|
+
const logHandler = (messages, context) => {
|
|
49
|
+
logBroadcaster.pushLog({
|
|
50
|
+
loggerName: context.name ?? 'unknown',
|
|
51
|
+
logLevel: context.level.name,
|
|
52
|
+
messages: messages.map((m) => String(m))
|
|
53
|
+
});
|
|
54
|
+
defaultHandler(messages, context);
|
|
55
|
+
};
|
|
56
|
+
baseLogger.useDefaults({
|
|
57
|
+
formatter: logHandler
|
|
58
|
+
});
|
|
59
|
+
const workerLogger = createLogger('db-worker');
|
|
15
60
|
const openWorkerConnection = async (options) => {
|
|
16
61
|
const connection = new WASqliteConnection(options);
|
|
17
62
|
return {
|
|
18
63
|
init: Comlink.proxy(() => connection.init()),
|
|
19
|
-
getConfig: Comlink.proxy(() =>
|
|
64
|
+
getConfig: Comlink.proxy(async () => {
|
|
65
|
+
// Can't send the logger over
|
|
66
|
+
const { logger, ...rest } = await connection.getConfig();
|
|
67
|
+
return rest;
|
|
68
|
+
}),
|
|
20
69
|
close: Comlink.proxy(() => connection.close()),
|
|
21
70
|
execute: Comlink.proxy(async (sql, params) => connection.execute(sql, params)),
|
|
22
71
|
executeRaw: Comlink.proxy(async (sql, params) => connection.executeRaw(sql, params)),
|
|
@@ -27,15 +76,34 @@ const openWorkerConnection = async (options) => {
|
|
|
27
76
|
})
|
|
28
77
|
};
|
|
29
78
|
};
|
|
30
|
-
const openDBShared = async (options) => {
|
|
79
|
+
const openDBShared = async (options, logHandler) => {
|
|
31
80
|
// Prevent multiple simultaneous opens from causing race conditions
|
|
32
81
|
return getNavigatorLocks().request(OPEN_DB_LOCK, async () => {
|
|
33
82
|
const clientId = nextClientId++;
|
|
34
83
|
const { dbFilename, logLevel } = options;
|
|
35
|
-
|
|
84
|
+
logToAll(`Worker opening DB connection for`, JSON.stringify(options));
|
|
85
|
+
// This updates the log level for the worker-level logger
|
|
86
|
+
// The DB connection logger will automatically track the main context logger
|
|
87
|
+
// since it passes logs to it.
|
|
88
|
+
workerLogger.setLevel(logLevel);
|
|
89
|
+
let disposeLogListener = logHandler
|
|
90
|
+
? logBroadcaster.registerListener({
|
|
91
|
+
onLog: (event) => {
|
|
92
|
+
if (event.loggerName !== dbFilename) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
logHandler(event);
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
: null;
|
|
36
99
|
if (!DBMap.has(dbFilename)) {
|
|
37
100
|
const clientIds = new Set();
|
|
38
|
-
const
|
|
101
|
+
const logger = createLogger(dbFilename);
|
|
102
|
+
logger.debug(`Worker opened a new connection`);
|
|
103
|
+
const connection = await openWorkerConnection({
|
|
104
|
+
...options,
|
|
105
|
+
logger
|
|
106
|
+
});
|
|
39
107
|
await connection.init();
|
|
40
108
|
DBMap.set(dbFilename, {
|
|
41
109
|
clientIds,
|
|
@@ -52,14 +120,15 @@ const openDBShared = async (options) => {
|
|
|
52
120
|
}),
|
|
53
121
|
close: Comlink.proxy(async () => {
|
|
54
122
|
const { clientIds } = dbEntry;
|
|
55
|
-
|
|
123
|
+
disposeLogListener?.();
|
|
124
|
+
workerLogger.debug(`Close requested from client ${clientId} of ${[...clientIds]}`);
|
|
56
125
|
clientIds.delete(clientId);
|
|
57
126
|
if (clientIds.size == 0) {
|
|
58
|
-
|
|
127
|
+
workerLogger.debug(`Closing connection to ${dbFilename}.`);
|
|
59
128
|
DBMap.delete(dbFilename);
|
|
60
129
|
return db.close?.();
|
|
61
130
|
}
|
|
62
|
-
|
|
131
|
+
workerLogger.debug(`Connection to ${dbFilename} not closed yet due to active clients.`);
|
|
63
132
|
return;
|
|
64
133
|
})
|
|
65
134
|
};
|
|
@@ -78,9 +147,3 @@ else {
|
|
|
78
147
|
// A dedicated worker can be shared externally
|
|
79
148
|
Comlink.expose(openDBShared);
|
|
80
149
|
}
|
|
81
|
-
addEventListener('unload', () => {
|
|
82
|
-
Array.from(DBMap.values()).forEach(async (dbConnection) => {
|
|
83
|
-
const { db } = dbConnection;
|
|
84
|
-
db.close?.();
|
|
85
|
-
});
|
|
86
|
-
});
|