@powersync/web 1.32.0 → 1.33.0
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/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-89f0ba.index.umd.js +21 -10
- package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-89f0ba.index.umd.js.map +1 -1
- package/dist/index.umd.js +177 -45
- package/dist/index.umd.js.map +1 -1
- package/dist/worker/SharedSyncImplementation.umd.js +1268 -349
- package/dist/worker/SharedSyncImplementation.umd.js.map +1 -1
- package/dist/worker/WASQLiteDB.umd.js +1268 -360
- package/dist/worker/WASQLiteDB.umd.js.map +1 -1
- package/lib/package.json +2 -2
- package/lib/src/attachments/IndexDBFileSystemAdapter.d.ts +25 -0
- package/lib/src/attachments/IndexDBFileSystemAdapter.js +104 -0
- package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.js +21 -10
- package/lib/src/index.d.ts +1 -0
- package/lib/src/index.js +1 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/attachments/IndexDBFileSystemAdapter.ts +117 -0
- package/src/db/adapters/LockedAsyncDatabaseAdapter.ts +19 -11
- package/src/index.ts +1 -0
package/lib/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powersync/web",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.33.0",
|
|
4
4
|
"description": "PowerSync Web SDK",
|
|
5
5
|
"main": "lib/src/index.js",
|
|
6
6
|
"module": "lib/src/index.js",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"license": "Apache-2.0",
|
|
68
68
|
"peerDependencies": {
|
|
69
69
|
"@journeyapps/wa-sqlite": "catalog:",
|
|
70
|
-
"@powersync/common": "workspace:^1.
|
|
70
|
+
"@powersync/common": "workspace:^1.47.0"
|
|
71
71
|
},
|
|
72
72
|
"dependencies": {
|
|
73
73
|
"@powersync/common": "workspace:*",
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { AttachmentData, EncodingType, LocalStorageAdapter } from '@powersync/common';
|
|
2
|
+
/**
|
|
3
|
+
* IndexDBFileSystemStorageAdapter implements LocalStorageAdapter using IndexedDB.
|
|
4
|
+
* Suitable for web browsers and web-based environments.
|
|
5
|
+
*/
|
|
6
|
+
export declare class IndexDBFileSystemStorageAdapter implements LocalStorageAdapter {
|
|
7
|
+
private databaseName;
|
|
8
|
+
private dbPromise;
|
|
9
|
+
constructor(databaseName?: string);
|
|
10
|
+
initialize(): Promise<void>;
|
|
11
|
+
clear(): Promise<void>;
|
|
12
|
+
getLocalUri(filename: string): string;
|
|
13
|
+
private getStore;
|
|
14
|
+
saveFile(filePath: string, data: AttachmentData): Promise<number>;
|
|
15
|
+
readFile(fileUri: string, options?: {
|
|
16
|
+
encoding?: EncodingType;
|
|
17
|
+
mediaType?: string;
|
|
18
|
+
}): Promise<ArrayBuffer>;
|
|
19
|
+
deleteFile(uri: string, options?: {
|
|
20
|
+
filename?: string;
|
|
21
|
+
}): Promise<void>;
|
|
22
|
+
fileExists(fileUri: string): Promise<boolean>;
|
|
23
|
+
makeDir(path: string): Promise<void>;
|
|
24
|
+
rmDir(path: string): Promise<void>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IndexDBFileSystemStorageAdapter implements LocalStorageAdapter using IndexedDB.
|
|
3
|
+
* Suitable for web browsers and web-based environments.
|
|
4
|
+
*/
|
|
5
|
+
export class IndexDBFileSystemStorageAdapter {
|
|
6
|
+
databaseName;
|
|
7
|
+
dbPromise;
|
|
8
|
+
constructor(databaseName = 'PowerSyncFiles') {
|
|
9
|
+
this.databaseName = databaseName;
|
|
10
|
+
}
|
|
11
|
+
async initialize() {
|
|
12
|
+
this.dbPromise = new Promise((resolve, reject) => {
|
|
13
|
+
const request = indexedDB.open(this.databaseName, 1);
|
|
14
|
+
request.onupgradeneeded = () => {
|
|
15
|
+
request.result.createObjectStore('files');
|
|
16
|
+
};
|
|
17
|
+
request.onsuccess = () => resolve(request.result);
|
|
18
|
+
request.onerror = () => reject(request.error);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
async clear() {
|
|
22
|
+
const db = await this.dbPromise;
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
const tx = db.transaction('files', 'readwrite');
|
|
25
|
+
const store = tx.objectStore('files');
|
|
26
|
+
const req = store.clear();
|
|
27
|
+
req.onsuccess = () => resolve();
|
|
28
|
+
req.onerror = () => reject(req.error);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
getLocalUri(filename) {
|
|
32
|
+
return `indexeddb://${this.databaseName}/files/${filename}`;
|
|
33
|
+
}
|
|
34
|
+
async getStore(mode = 'readonly') {
|
|
35
|
+
const db = await this.dbPromise;
|
|
36
|
+
const tx = db.transaction('files', mode);
|
|
37
|
+
return tx.objectStore('files');
|
|
38
|
+
}
|
|
39
|
+
async saveFile(filePath, data) {
|
|
40
|
+
const store = await this.getStore('readwrite');
|
|
41
|
+
let dataToStore;
|
|
42
|
+
let size;
|
|
43
|
+
if (typeof data === 'string') {
|
|
44
|
+
const binaryString = atob(data);
|
|
45
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
46
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
47
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
48
|
+
}
|
|
49
|
+
dataToStore = bytes.buffer;
|
|
50
|
+
size = bytes.byteLength;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
dataToStore = data;
|
|
54
|
+
size = dataToStore.byteLength;
|
|
55
|
+
}
|
|
56
|
+
return await new Promise((resolve, reject) => {
|
|
57
|
+
const req = store.put(dataToStore, filePath);
|
|
58
|
+
req.onsuccess = () => resolve(size);
|
|
59
|
+
req.onerror = () => reject(req.error);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
async readFile(fileUri, options) {
|
|
63
|
+
const store = await this.getStore();
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
const req = store.get(fileUri);
|
|
66
|
+
req.onsuccess = async () => {
|
|
67
|
+
if (!req.result) {
|
|
68
|
+
reject(new Error('File not found'));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
resolve(req.result);
|
|
72
|
+
};
|
|
73
|
+
req.onerror = () => reject(req.error);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
async deleteFile(uri, options) {
|
|
77
|
+
const store = await this.getStore('readwrite');
|
|
78
|
+
await new Promise((resolve, reject) => {
|
|
79
|
+
const req = store.delete(uri);
|
|
80
|
+
req.onsuccess = () => resolve();
|
|
81
|
+
req.onerror = () => reject(req.error);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
async fileExists(fileUri) {
|
|
85
|
+
const store = await this.getStore();
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
const req = store.get(fileUri);
|
|
88
|
+
req.onsuccess = () => resolve(!!req.result);
|
|
89
|
+
req.onerror = () => reject(req.error);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
async makeDir(path) {
|
|
93
|
+
// No-op for IndexedDB as it does not have a directory structure
|
|
94
|
+
}
|
|
95
|
+
async rmDir(path) {
|
|
96
|
+
const store = await this.getStore('readwrite');
|
|
97
|
+
const range = IDBKeyRange.bound(path + '/', path + '/\uffff', false, false);
|
|
98
|
+
await new Promise((resolve, reject) => {
|
|
99
|
+
const req = store.delete(range);
|
|
100
|
+
req.onsuccess = () => resolve();
|
|
101
|
+
req.onerror = () => reject(req.error);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -104,13 +104,17 @@ export class LockedAsyncDatabaseAdapter extends BaseObserver {
|
|
|
104
104
|
* Returns a pending operation if one is already in progress.
|
|
105
105
|
*/
|
|
106
106
|
async reOpenInternalDB() {
|
|
107
|
-
if (!this.options.reOpenOnConnectionClosed) {
|
|
108
|
-
|
|
107
|
+
if (this.closing || !this.options.reOpenOnConnectionClosed) {
|
|
108
|
+
// No-op
|
|
109
|
+
return;
|
|
109
110
|
}
|
|
110
|
-
if (this.databaseOpenPromise) {
|
|
111
|
+
else if (this.databaseOpenPromise) {
|
|
112
|
+
// Already busy opening
|
|
111
113
|
return this.databaseOpenPromise;
|
|
112
114
|
}
|
|
113
|
-
|
|
115
|
+
else {
|
|
116
|
+
return this._reOpen();
|
|
117
|
+
}
|
|
114
118
|
}
|
|
115
119
|
async _init() {
|
|
116
120
|
/**
|
|
@@ -241,10 +245,19 @@ export class LockedAsyncDatabaseAdapter extends BaseObserver {
|
|
|
241
245
|
}
|
|
242
246
|
async acquireLock(callback, options) {
|
|
243
247
|
await this.waitForInitialized();
|
|
244
|
-
// The database is being opened in the background. Wait for it here.
|
|
248
|
+
// The database is being (re)opened in the background. Wait for it here.
|
|
245
249
|
if (this.databaseOpenPromise) {
|
|
246
250
|
await this.databaseOpenPromise;
|
|
247
251
|
}
|
|
252
|
+
else if (!this._db) {
|
|
253
|
+
/**
|
|
254
|
+
* The database is not open anymore, we might need to re-open it.
|
|
255
|
+
* Typically, _db, can be `null` if we tried to reOpen the database, but failed to succeed in re-opening.
|
|
256
|
+
* This can happen when disconnecting the client.
|
|
257
|
+
* Note: It is safe to re-enter this method multiple times.
|
|
258
|
+
*/
|
|
259
|
+
await this.reOpenInternalDB();
|
|
260
|
+
}
|
|
248
261
|
return this._acquireLock(async () => {
|
|
249
262
|
let holdId = null;
|
|
250
263
|
try {
|
|
@@ -262,11 +275,9 @@ export class LockedAsyncDatabaseAdapter extends BaseObserver {
|
|
|
262
275
|
}
|
|
263
276
|
catch (ex) {
|
|
264
277
|
if (ConnectionClosedError.MATCHES(ex)) {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
this.reOpenInternalDB();
|
|
269
|
-
}
|
|
278
|
+
// Immediately re-open the database. We need to miss as little table updates as possible.
|
|
279
|
+
// Note, don't await this since it uses the same lock as we're in now.
|
|
280
|
+
this.reOpenInternalDB();
|
|
270
281
|
}
|
|
271
282
|
throw ex;
|
|
272
283
|
}
|
package/lib/src/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from '@powersync/common';
|
|
2
|
+
export * from './attachments/IndexDBFileSystemAdapter.js';
|
|
2
3
|
export * from './db/adapters/AbstractWebPowerSyncDatabaseOpenFactory.js';
|
|
3
4
|
export * from './db/adapters/AbstractWebSQLOpenFactory.js';
|
|
4
5
|
export * from './db/adapters/AsyncDatabaseConnection.js';
|
package/lib/src/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from '@powersync/common';
|
|
2
|
+
export * from './attachments/IndexDBFileSystemAdapter.js';
|
|
2
3
|
export * from './db/adapters/AbstractWebPowerSyncDatabaseOpenFactory.js';
|
|
3
4
|
export * from './db/adapters/AbstractWebSQLOpenFactory.js';
|
|
4
5
|
export * from './db/adapters/AsyncDatabaseConnection.js';
|