@powersync/web 0.0.0-dev-20240712065121 → 0.0.0-dev-20240715085239

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.
@@ -1,103 +1,90 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  import * as Comlink from 'comlink';
11
2
  import { WebStreamingSyncImplementation } from './WebStreamingSyncImplementation';
12
3
  import { SharedSyncClientEvent } from '../../worker/sync/SharedSyncImplementation';
13
4
  import { AbstractSharedSyncClientProvider } from '../../worker/sync/AbstractSharedSyncClientProvider';
14
5
  import { openWorkerDatabasePort } from '../../worker/db/open-worker-database';
6
+ import SharedSyncImplementationWorker from '../../worker/sync/SharedSyncImplementation.worker?sharedworker&inline';
15
7
  /**
16
8
  * The shared worker will trigger methods on this side of the message port
17
9
  * via this client provider.
18
10
  */
19
11
  class SharedSyncClientProvider extends AbstractSharedSyncClientProvider {
12
+ options;
13
+ statusChanged;
20
14
  constructor(options, statusChanged) {
21
15
  super();
22
16
  this.options = options;
23
17
  this.statusChanged = statusChanged;
24
18
  }
25
- fetchCredentials() {
26
- return __awaiter(this, void 0, void 0, function* () {
27
- const credentials = yield this.options.remote.getCredentials();
28
- if (credentials == null) {
29
- return null;
30
- }
31
- /**
32
- * The credentials need to be serializable.
33
- * Users might extend [PowerSyncCredentials] to contain
34
- * items which are not serializable.
35
- * This returns only the essential fields.
36
- */
37
- return {
38
- endpoint: credentials.endpoint,
39
- token: credentials.token,
40
- expiresAt: credentials.expiresAt
41
- };
42
- });
19
+ async fetchCredentials() {
20
+ const credentials = await this.options.remote.getCredentials();
21
+ if (credentials == null) {
22
+ return null;
23
+ }
24
+ /**
25
+ * The credentials need to be serializable.
26
+ * Users might extend [PowerSyncCredentials] to contain
27
+ * items which are not serializable.
28
+ * This returns only the essential fields.
29
+ */
30
+ return {
31
+ endpoint: credentials.endpoint,
32
+ token: credentials.token,
33
+ expiresAt: credentials.expiresAt
34
+ };
43
35
  }
44
- uploadCrud() {
45
- return __awaiter(this, void 0, void 0, function* () {
46
- /**
47
- * Don't return anything here, just incase something which is not
48
- * serializable is returned from the `uploadCrud` function.
49
- */
50
- yield this.options.uploadCrud();
51
- });
36
+ async uploadCrud() {
37
+ /**
38
+ * Don't return anything here, just incase something which is not
39
+ * serializable is returned from the `uploadCrud` function.
40
+ */
41
+ await this.options.uploadCrud();
52
42
  }
53
43
  get logger() {
54
44
  return this.options.logger;
55
45
  }
56
46
  trace(...x) {
57
- var _a;
58
- (_a = this.logger) === null || _a === void 0 ? void 0 : _a.trace(...x);
47
+ this.logger?.trace(...x);
59
48
  }
60
49
  debug(...x) {
61
- var _a;
62
- (_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug(...x);
50
+ this.logger?.debug(...x);
63
51
  }
64
52
  info(...x) {
65
- var _a;
66
- (_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(...x);
53
+ this.logger?.info(...x);
67
54
  }
68
55
  log(...x) {
69
- var _a;
70
- (_a = this.logger) === null || _a === void 0 ? void 0 : _a.log(...x);
56
+ this.logger?.log(...x);
71
57
  }
72
58
  warn(...x) {
73
- var _a;
74
- (_a = this.logger) === null || _a === void 0 ? void 0 : _a.warn(...x);
59
+ this.logger?.warn(...x);
75
60
  }
76
61
  error(...x) {
77
- var _a;
78
- (_a = this.logger) === null || _a === void 0 ? void 0 : _a.error(...x);
62
+ this.logger?.error(...x);
79
63
  }
80
64
  time(label) {
81
- var _a;
82
- (_a = this.logger) === null || _a === void 0 ? void 0 : _a.time(label);
65
+ this.logger?.time(label);
83
66
  }
84
67
  timeEnd(label) {
85
- var _a;
86
- (_a = this.logger) === null || _a === void 0 ? void 0 : _a.timeEnd(label);
68
+ this.logger?.timeEnd(label);
87
69
  }
88
70
  }
89
71
  export class SharedWebStreamingSyncImplementation extends WebStreamingSyncImplementation {
72
+ syncManager;
73
+ clientProvider;
74
+ messagePort;
75
+ isInitialized;
90
76
  constructor(options) {
91
77
  super(options);
92
78
  /**
93
79
  * Configure or connect to the shared sync worker.
94
80
  * This worker will manage all syncing operations remotely.
95
81
  */
96
- const syncWorker = new SharedWorker(new URL('../../worker/sync/SharedSyncImplementation.worker.js', import.meta.url), {
97
- /* @vite-ignore */
98
- name: `shared-sync-${this.webOptions.identifier}`,
99
- type: 'module'
100
- });
82
+ const syncWorker = new SharedSyncImplementationWorker({ name: `shared-sync-${this.webOptions.identifier}` });
83
+ // new SharedWorker(new URL('../../worker/sync/SharedSyncImplementation.worker.js', import.meta.url), {
84
+ // /* @vite-ignore */
85
+ // name: `shared-sync-${this.webOptions.identifier}`,
86
+ // type: 'module'
87
+ // });
101
88
  this.messagePort = syncWorker.port;
102
89
  this.syncManager = Comlink.wrap(this.messagePort);
103
90
  this.triggerCrudUpload = this.syncManager.triggerCrudUpload;
@@ -135,53 +122,39 @@ export class SharedWebStreamingSyncImplementation extends WebStreamingSyncImplem
135
122
  * Starts the sync process, this effectively acts as a call to
136
123
  * `connect` if not yet connected.
137
124
  */
138
- connect(options) {
139
- return __awaiter(this, void 0, void 0, function* () {
140
- yield this.waitForReady();
141
- return this.syncManager.connect(options);
142
- });
143
- }
144
- disconnect() {
145
- return __awaiter(this, void 0, void 0, function* () {
146
- yield this.waitForReady();
147
- return this.syncManager.disconnect();
148
- });
149
- }
150
- getWriteCheckpoint() {
151
- return __awaiter(this, void 0, void 0, function* () {
152
- yield this.waitForReady();
153
- return this.syncManager.getWriteCheckpoint();
154
- });
155
- }
156
- hasCompletedSync() {
157
- return __awaiter(this, void 0, void 0, function* () {
158
- return this.syncManager.hasCompletedSync();
159
- });
160
- }
161
- dispose() {
162
- return __awaiter(this, void 0, void 0, function* () {
163
- yield this.waitForReady();
164
- // Signal the shared worker that this client is closing its connection to the worker
165
- const closeMessagePayload = {
166
- event: SharedSyncClientEvent.CLOSE_CLIENT,
167
- data: {}
168
- };
169
- this.messagePort.postMessage(closeMessagePayload);
170
- // Release the proxy
171
- this.syncManager[Comlink.releaseProxy]();
172
- });
173
- }
174
- waitForReady() {
175
- return __awaiter(this, void 0, void 0, function* () {
176
- return this.isInitialized;
177
- });
125
+ async connect(options) {
126
+ await this.waitForReady();
127
+ return this.syncManager.connect(options);
128
+ }
129
+ async disconnect() {
130
+ await this.waitForReady();
131
+ return this.syncManager.disconnect();
132
+ }
133
+ async getWriteCheckpoint() {
134
+ await this.waitForReady();
135
+ return this.syncManager.getWriteCheckpoint();
136
+ }
137
+ async hasCompletedSync() {
138
+ return this.syncManager.hasCompletedSync();
139
+ }
140
+ async dispose() {
141
+ await this.waitForReady();
142
+ // Signal the shared worker that this client is closing its connection to the worker
143
+ const closeMessagePayload = {
144
+ event: SharedSyncClientEvent.CLOSE_CLIENT,
145
+ data: {}
146
+ };
147
+ this.messagePort.postMessage(closeMessagePayload);
148
+ // Release the proxy
149
+ this.syncManager[Comlink.releaseProxy]();
150
+ }
151
+ async waitForReady() {
152
+ return this.isInitialized;
178
153
  }
179
154
  /**
180
155
  * Used in tests to force a connection states
181
156
  */
182
- _testUpdateStatus(status) {
183
- return __awaiter(this, void 0, void 0, function* () {
184
- return this.syncManager['_testUpdateAllStatuses'](status.toJSON());
185
- });
157
+ async _testUpdateStatus(status) {
158
+ return this.syncManager['_testUpdateAllStatuses'](status.toJSON());
186
159
  }
187
160
  }
@@ -1,25 +1,15 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  import { AbstractRemote } from '@powersync/common';
11
2
  export class WebRemote extends AbstractRemote {
12
- getBSON() {
13
- return __awaiter(this, void 0, void 0, function* () {
14
- if (this._bson) {
15
- return this._bson;
16
- }
17
- /**
18
- * Dynamic import to be used only when needed.
19
- */
20
- const { BSON } = yield import('bson');
21
- this._bson = BSON;
3
+ _bson;
4
+ async getBSON() {
5
+ if (this._bson) {
22
6
  return this._bson;
23
- });
7
+ }
8
+ /**
9
+ * Dynamic import to be used only when needed.
10
+ */
11
+ const { BSON } = await import('bson');
12
+ this._bson = BSON;
13
+ return this._bson;
24
14
  }
25
15
  }
@@ -1,207 +1,176 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- var __asyncValues = (this && this.__asyncValues) || function (o) {
11
- if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
12
- var m = o[Symbol.asyncIterator], i;
13
- return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
14
- function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
15
- function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
16
- };
17
1
  import * as SQLite from '@journeyapps/wa-sqlite';
18
2
  import '@journeyapps/wa-sqlite';
19
3
  import * as Comlink from 'comlink';
20
4
  let nextId = 1;
21
- export function _openDB(dbFileName_1) {
22
- return __awaiter(this, arguments, void 0, function* (dbFileName, options = { useWebWorker: true }) {
23
- const { default: moduleFactory } = yield import('@journeyapps/wa-sqlite/dist/wa-sqlite-async.mjs');
24
- const module = yield moduleFactory();
25
- const sqlite3 = SQLite.Factory(module);
26
- const { IDBBatchAtomicVFS } = yield import('@journeyapps/wa-sqlite/src/examples/IDBBatchAtomicVFS.js');
27
- const vfs = new IDBBatchAtomicVFS(dbFileName);
28
- sqlite3.vfs_register(vfs, true);
29
- const db = yield sqlite3.open_v2(dbFileName);
30
- /**
31
- * Listeners are exclusive to the DB connection.
32
- */
33
- const listeners = new Map();
34
- sqlite3.register_table_onchange_hook(db, (opType, tableName, rowId) => {
35
- Array.from(listeners.values()).forEach((l) => l(opType, tableName, rowId));
36
- });
37
- /**
38
- * This executes single SQL statements inside a requested lock.
39
- */
40
- const execute = (sql, bindings) => __awaiter(this, void 0, void 0, function* () {
41
- // Running multiple statements on the same connection concurrently should not be allowed
42
- return _acquireExecuteLock(() => __awaiter(this, void 0, void 0, function* () {
43
- return executeSingleStatement(sql, bindings);
44
- }));
5
+ export async function _openDB(dbFileName, options = { useWebWorker: true }) {
6
+ const { default: moduleFactory } = await import('@journeyapps/wa-sqlite/dist/wa-sqlite-async.mjs');
7
+ const module = await moduleFactory();
8
+ const sqlite3 = SQLite.Factory(module);
9
+ const { IDBBatchAtomicVFS } = await import('@journeyapps/wa-sqlite/src/examples/IDBBatchAtomicVFS.js');
10
+ const vfs = new IDBBatchAtomicVFS(dbFileName);
11
+ sqlite3.vfs_register(vfs, true);
12
+ const db = await sqlite3.open_v2(dbFileName);
13
+ /**
14
+ * Listeners are exclusive to the DB connection.
15
+ */
16
+ const listeners = new Map();
17
+ sqlite3.register_table_onchange_hook(db, (opType, tableName, rowId) => {
18
+ Array.from(listeners.values()).forEach((l) => l(opType, tableName, rowId));
19
+ });
20
+ /**
21
+ * This executes single SQL statements inside a requested lock.
22
+ */
23
+ const execute = async (sql, bindings) => {
24
+ // Running multiple statements on the same connection concurrently should not be allowed
25
+ return _acquireExecuteLock(async () => {
26
+ return executeSingleStatement(sql, bindings);
45
27
  });
46
- /**
47
- * This requests a lock for executing statements.
48
- * Should only be used interanlly.
49
- */
50
- const _acquireExecuteLock = (callback) => {
51
- return navigator.locks.request(`db-execute-${dbFileName}`, callback);
28
+ };
29
+ /**
30
+ * This requests a lock for executing statements.
31
+ * Should only be used interanlly.
32
+ */
33
+ const _acquireExecuteLock = (callback) => {
34
+ return navigator.locks.request(`db-execute-${dbFileName}`, callback);
35
+ };
36
+ /**
37
+ * This executes a single statement using SQLite3.
38
+ */
39
+ const executeSingleStatement = async (sql, bindings) => {
40
+ const results = [];
41
+ for await (const stmt of sqlite3.statements(db, sql)) {
42
+ let columns;
43
+ const wrappedBindings = bindings ? [bindings] : [[]];
44
+ for (const binding of wrappedBindings) {
45
+ // TODO not sure why this is needed currently, but booleans break
46
+ binding.forEach((b, index, arr) => {
47
+ if (typeof b == 'boolean') {
48
+ arr[index] = b ? 1 : 0;
49
+ }
50
+ });
51
+ sqlite3.reset(stmt);
52
+ if (bindings) {
53
+ sqlite3.bind_collection(stmt, binding);
54
+ }
55
+ const rows = [];
56
+ while ((await sqlite3.step(stmt)) === SQLite.SQLITE_ROW) {
57
+ const row = sqlite3.row(stmt);
58
+ rows.push(row);
59
+ }
60
+ columns = columns ?? sqlite3.column_names(stmt);
61
+ if (columns.length) {
62
+ results.push({ columns, rows });
63
+ }
64
+ }
65
+ // When binding parameters, only a single statement is executed.
66
+ if (bindings) {
67
+ break;
68
+ }
69
+ }
70
+ const rows = [];
71
+ for (const resultset of results) {
72
+ for (const row of resultset.rows) {
73
+ const outRow = {};
74
+ resultset.columns.forEach((key, index) => {
75
+ outRow[key] = row[index];
76
+ });
77
+ rows.push(outRow);
78
+ }
79
+ }
80
+ const result = {
81
+ insertId: sqlite3.last_insert_id(db),
82
+ rowsAffected: sqlite3.changes(db),
83
+ rows: {
84
+ _array: rows,
85
+ length: rows.length
86
+ }
52
87
  };
53
- /**
54
- * This executes a single statement using SQLite3.
55
- */
56
- const executeSingleStatement = (sql, bindings) => __awaiter(this, void 0, void 0, function* () {
57
- var _a, e_1, _b, _c;
58
- const results = [];
88
+ return result;
89
+ };
90
+ /**
91
+ * This executes SQL statements in a batch.
92
+ */
93
+ const executeBatch = async (sql, bindings) => {
94
+ return _acquireExecuteLock(async () => {
95
+ let affectedRows = 0;
96
+ const str = sqlite3.str_new(db, sql);
97
+ const query = sqlite3.str_value(str);
59
98
  try {
60
- for (var _d = true, _e = __asyncValues(sqlite3.statements(db, sql)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
61
- _c = _f.value;
62
- _d = false;
63
- const stmt = _c;
64
- let columns;
65
- const wrappedBindings = bindings ? [bindings] : [[]];
66
- for (const binding of wrappedBindings) {
67
- // TODO not sure why this is needed currently, but booleans break
68
- binding.forEach((b, index, arr) => {
69
- if (typeof b == 'boolean') {
70
- arr[index] = b ? 1 : 0;
71
- }
72
- });
73
- sqlite3.reset(stmt);
74
- if (bindings) {
75
- sqlite3.bind_collection(stmt, binding);
76
- }
77
- const rows = [];
78
- while ((yield sqlite3.step(stmt)) === SQLite.SQLITE_ROW) {
79
- const row = sqlite3.row(stmt);
80
- rows.push(row);
81
- }
82
- columns = columns !== null && columns !== void 0 ? columns : sqlite3.column_names(stmt);
83
- if (columns.length) {
84
- results.push({ columns, rows });
99
+ await executeSingleStatement('BEGIN TRANSACTION');
100
+ //Prepare statement once
101
+ const prepared = await sqlite3.prepare_v2(db, query);
102
+ if (prepared === null) {
103
+ return {
104
+ rowsAffected: 0
105
+ };
106
+ }
107
+ const wrappedBindings = bindings ? bindings : [];
108
+ for (const binding of wrappedBindings) {
109
+ // TODO not sure why this is needed currently, but booleans break
110
+ for (let i = 0; i < binding.length; i++) {
111
+ const b = binding[i];
112
+ if (typeof b == 'boolean') {
113
+ binding[i] = b ? 1 : 0;
85
114
  }
86
115
  }
87
- // When binding parameters, only a single statement is executed.
116
+ //Reset bindings
117
+ sqlite3.reset(prepared.stmt);
88
118
  if (bindings) {
89
- break;
119
+ sqlite3.bind_collection(prepared.stmt, binding);
120
+ }
121
+ const result = await sqlite3.step(prepared.stmt);
122
+ if (result === SQLite.SQLITE_DONE) {
123
+ //The value returned by sqlite3_changes() immediately after an INSERT, UPDATE or DELETE statement run on a view is always zero.
124
+ affectedRows += sqlite3.changes(db);
90
125
  }
91
126
  }
127
+ //Finalize prepared statement
128
+ await sqlite3.finalize(prepared.stmt);
129
+ await executeSingleStatement('COMMIT');
92
130
  }
93
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
94
- finally {
95
- try {
96
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
97
- }
98
- finally { if (e_1) throw e_1.error; }
131
+ catch (err) {
132
+ await executeSingleStatement('ROLLBACK');
133
+ return {
134
+ rowsAffected: 0
135
+ };
99
136
  }
100
- const rows = [];
101
- for (const resultset of results) {
102
- for (const row of resultset.rows) {
103
- const outRow = {};
104
- resultset.columns.forEach((key, index) => {
105
- outRow[key] = row[index];
106
- });
107
- rows.push(outRow);
108
- }
137
+ finally {
138
+ sqlite3.str_finish(str);
109
139
  }
110
140
  const result = {
111
- insertId: sqlite3.last_insert_id(db),
112
- rowsAffected: sqlite3.changes(db),
113
- rows: {
114
- _array: rows,
115
- length: rows.length
116
- }
141
+ rowsAffected: affectedRows
117
142
  };
118
143
  return result;
119
144
  });
120
- /**
121
- * This executes SQL statements in a batch.
122
- */
123
- const executeBatch = (sql, bindings) => __awaiter(this, void 0, void 0, function* () {
124
- return _acquireExecuteLock(() => __awaiter(this, void 0, void 0, function* () {
125
- let affectedRows = 0;
126
- const str = sqlite3.str_new(db, sql);
127
- const query = sqlite3.str_value(str);
128
- try {
129
- yield executeSingleStatement('BEGIN TRANSACTION');
130
- //Prepare statement once
131
- const prepared = yield sqlite3.prepare_v2(db, query);
132
- if (prepared === null) {
133
- return {
134
- rowsAffected: 0
135
- };
136
- }
137
- const wrappedBindings = bindings ? bindings : [];
138
- for (const binding of wrappedBindings) {
139
- // TODO not sure why this is needed currently, but booleans break
140
- for (let i = 0; i < binding.length; i++) {
141
- const b = binding[i];
142
- if (typeof b == 'boolean') {
143
- binding[i] = b ? 1 : 0;
144
- }
145
- }
146
- //Reset bindings
147
- sqlite3.reset(prepared.stmt);
148
- if (bindings) {
149
- sqlite3.bind_collection(prepared.stmt, binding);
150
- }
151
- const result = yield sqlite3.step(prepared.stmt);
152
- if (result === SQLite.SQLITE_DONE) {
153
- //The value returned by sqlite3_changes() immediately after an INSERT, UPDATE or DELETE statement run on a view is always zero.
154
- affectedRows += sqlite3.changes(db);
155
- }
156
- }
157
- //Finalize prepared statement
158
- yield sqlite3.finalize(prepared.stmt);
159
- yield executeSingleStatement('COMMIT');
160
- }
161
- catch (err) {
162
- yield executeSingleStatement('ROLLBACK');
163
- return {
164
- rowsAffected: 0
165
- };
166
- }
167
- finally {
168
- sqlite3.str_finish(str);
169
- }
170
- const result = {
171
- rowsAffected: affectedRows
172
- };
173
- return result;
174
- }));
175
- });
176
- if (options.useWebWorker) {
177
- const registerOnTableChange = (callback) => {
178
- const id = nextId++;
179
- listeners.set(id, callback);
180
- return Comlink.proxy(() => {
181
- listeners.delete(id);
182
- });
183
- };
184
- return {
185
- execute: Comlink.proxy(execute),
186
- executeBatch: Comlink.proxy(executeBatch),
187
- registerOnTableChange: Comlink.proxy(registerOnTableChange),
188
- close: Comlink.proxy(() => {
189
- sqlite3.close(db);
190
- })
191
- };
192
- }
145
+ };
146
+ if (options.useWebWorker) {
193
147
  const registerOnTableChange = (callback) => {
194
148
  const id = nextId++;
195
149
  listeners.set(id, callback);
196
- return () => {
150
+ return Comlink.proxy(() => {
197
151
  listeners.delete(id);
198
- };
152
+ });
199
153
  };
200
154
  return {
201
- execute: execute,
202
- executeBatch: executeBatch,
203
- registerOnTableChange: registerOnTableChange,
204
- close: () => sqlite3.close(db)
155
+ execute: Comlink.proxy(execute),
156
+ executeBatch: Comlink.proxy(executeBatch),
157
+ registerOnTableChange: Comlink.proxy(registerOnTableChange),
158
+ close: Comlink.proxy(() => {
159
+ sqlite3.close(db);
160
+ })
205
161
  };
206
- });
162
+ }
163
+ const registerOnTableChange = (callback) => {
164
+ const id = nextId++;
165
+ listeners.set(id, callback);
166
+ return () => {
167
+ listeners.delete(id);
168
+ };
169
+ };
170
+ return {
171
+ execute: execute,
172
+ executeBatch: executeBatch,
173
+ registerOnTableChange: registerOnTableChange,
174
+ close: () => sqlite3.close(db)
175
+ };
207
176
  }