@slimr/dbsync 0.0.5 → 0.0.7
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/README.md +5 -5
- package/cjs/DbSync.d.ts +47 -3
- package/cjs/DbSync.js +54 -18
- package/cjs/DbSync.js.map +1 -1
- package/cjs/adapters/RestAdapter.d.ts +17 -0
- package/cjs/adapters/RestAdapter.js +13 -0
- package/cjs/adapters/RestAdapter.js.map +1 -1
- package/cjs/adapters/types.d.ts +13 -0
- package/cjs/internal/AuthManager.d.ts +17 -2
- package/cjs/internal/AuthManager.js +19 -4
- package/cjs/internal/AuthManager.js.map +1 -1
- package/cjs/internal/EventBus.d.ts +12 -0
- package/cjs/internal/EventBus.js +12 -0
- package/cjs/internal/EventBus.js.map +1 -1
- package/cjs/internal/StorageManager.d.ts +21 -0
- package/cjs/internal/StorageManager.js +21 -0
- package/cjs/internal/StorageManager.js.map +1 -1
- package/cjs/internal/SyncEngine.d.ts +29 -3
- package/cjs/internal/SyncEngine.js +31 -5
- package/cjs/internal/SyncEngine.js.map +1 -1
- package/cjs/useDbQuery.js +2 -0
- package/cjs/useDbQuery.js.map +1 -1
- package/cjs/util/promiseWithResolvers.js +3 -0
- package/cjs/util/promiseWithResolvers.js.map +1 -1
- package/docs/Adapters.md +58 -0
- package/docs/LocalAdapter.md +7 -0
- package/docs/RestAdapter.md +69 -0
- package/esm/DbSync.d.ts +47 -3
- package/esm/DbSync.js +54 -18
- package/esm/DbSync.js.map +1 -1
- package/esm/adapters/RestAdapter.d.ts +17 -0
- package/esm/adapters/RestAdapter.js +13 -0
- package/esm/adapters/RestAdapter.js.map +1 -1
- package/esm/adapters/types.d.ts +13 -0
- package/esm/internal/AuthManager.d.ts +17 -2
- package/esm/internal/AuthManager.js +19 -4
- package/esm/internal/AuthManager.js.map +1 -1
- package/esm/internal/EventBus.d.ts +12 -0
- package/esm/internal/EventBus.js +12 -0
- package/esm/internal/EventBus.js.map +1 -1
- package/esm/internal/StorageManager.d.ts +21 -0
- package/esm/internal/StorageManager.js +21 -0
- package/esm/internal/StorageManager.js.map +1 -1
- package/esm/internal/SyncEngine.d.ts +29 -3
- package/esm/internal/SyncEngine.js +31 -5
- package/esm/internal/SyncEngine.js.map +1 -1
- package/esm/useDbQuery.js +2 -0
- package/esm/useDbQuery.js.map +1 -1
- package/esm/util/promiseWithResolvers.js +3 -0
- package/esm/util/promiseWithResolvers.js.map +1 -1
- package/package.json +2 -1
|
@@ -1,20 +1,41 @@
|
|
|
1
1
|
import type { DbSyncConfig } from "../DbSync.js";
|
|
2
2
|
import { DbTransaction } from "./DbTransaction.js";
|
|
3
3
|
import type { EventBus } from "./EventBus.js";
|
|
4
|
+
/**
|
|
5
|
+
* Owns IndexedDB initialization, transactions, and record access.
|
|
6
|
+
*/
|
|
4
7
|
export declare class StorageManager {
|
|
5
8
|
private config;
|
|
6
9
|
private events;
|
|
7
10
|
private onSchemaChange;
|
|
11
|
+
/** The active IndexedDB database instance. */
|
|
8
12
|
db: IDBDatabase;
|
|
13
|
+
/** Whether the storage layer has finished initializing. */
|
|
9
14
|
initted: boolean;
|
|
15
|
+
/** The IndexedDB database name used by dbsync. */
|
|
10
16
|
private dbName;
|
|
17
|
+
/**
|
|
18
|
+
* Creates a storage manager for the provided dbsync configuration and event bus.
|
|
19
|
+
*
|
|
20
|
+
* @param config The full dbsync configuration object.
|
|
21
|
+
* @param events The event bus used to broadcast store updates.
|
|
22
|
+
* @param onSchemaChange Callback fired when the IndexedDB schema changes.
|
|
23
|
+
*/
|
|
11
24
|
constructor(config: DbSyncConfig, events: EventBus, onSchemaChange: () => void);
|
|
25
|
+
/** Computes a deterministic schema signature from the configured tables and indexes. */
|
|
12
26
|
private get schemaSignature();
|
|
27
|
+
/** Creates a transaction wrapper used by the sync engine and public facade. */
|
|
13
28
|
getTransaction(): DbTransaction;
|
|
29
|
+
/** Opens IndexedDB and creates the configured stores when needed. */
|
|
14
30
|
init(): Promise<void>;
|
|
31
|
+
/** Executes a batch of writes inside a single IndexedDB transaction. */
|
|
15
32
|
executeTransaction(operations: any[]): Promise<void>;
|
|
33
|
+
/** Reads a typed record by primary key from the requested store. */
|
|
16
34
|
get<T>(storeName: string, id: string | number): Promise<T | undefined>;
|
|
35
|
+
/** Returns every record from the requested store. */
|
|
17
36
|
findAll<T>(storeName: string): Promise<T[]>;
|
|
37
|
+
/** Clears every object store managed by the database. */
|
|
18
38
|
clearAllStores(): Promise<void>;
|
|
39
|
+
/** Closes the underlying IndexedDB connection. */
|
|
19
40
|
dispose(): void;
|
|
20
41
|
}
|
|
@@ -3,18 +3,32 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.StorageManager = void 0;
|
|
4
4
|
const promiseWithResolvers_js_1 = require("../util/promiseWithResolvers.js");
|
|
5
5
|
const DbTransaction_js_1 = require("./DbTransaction.js");
|
|
6
|
+
/**
|
|
7
|
+
* Owns IndexedDB initialization, transactions, and record access.
|
|
8
|
+
*/
|
|
6
9
|
class StorageManager {
|
|
7
10
|
config;
|
|
8
11
|
events;
|
|
9
12
|
onSchemaChange;
|
|
13
|
+
/** The active IndexedDB database instance. */
|
|
10
14
|
db;
|
|
15
|
+
/** Whether the storage layer has finished initializing. */
|
|
11
16
|
initted = false;
|
|
17
|
+
/** The IndexedDB database name used by dbsync. */
|
|
12
18
|
dbName = "dbsync";
|
|
19
|
+
/**
|
|
20
|
+
* Creates a storage manager for the provided dbsync configuration and event bus.
|
|
21
|
+
*
|
|
22
|
+
* @param config The full dbsync configuration object.
|
|
23
|
+
* @param events The event bus used to broadcast store updates.
|
|
24
|
+
* @param onSchemaChange Callback fired when the IndexedDB schema changes.
|
|
25
|
+
*/
|
|
13
26
|
constructor(config, events, onSchemaChange) {
|
|
14
27
|
this.config = config;
|
|
15
28
|
this.events = events;
|
|
16
29
|
this.onSchemaChange = onSchemaChange;
|
|
17
30
|
}
|
|
31
|
+
/** Computes a deterministic schema signature from the configured tables and indexes. */
|
|
18
32
|
get schemaSignature() {
|
|
19
33
|
const tables = Object.keys(this.config.tables)
|
|
20
34
|
.sort()
|
|
@@ -26,9 +40,11 @@ class StorageManager {
|
|
|
26
40
|
});
|
|
27
41
|
return JSON.stringify(tables);
|
|
28
42
|
}
|
|
43
|
+
/** Creates a transaction wrapper used by the sync engine and public facade. */
|
|
29
44
|
getTransaction() {
|
|
30
45
|
return new DbTransaction_js_1.DbTransaction((operations) => this.executeTransaction(operations));
|
|
31
46
|
}
|
|
47
|
+
/** Opens IndexedDB and creates the configured stores when needed. */
|
|
32
48
|
async init() {
|
|
33
49
|
const { promise, resolve, reject } = (0, promiseWithResolvers_js_1.promiseWithResolvers)();
|
|
34
50
|
const upgradeFn = (e) => {
|
|
@@ -71,6 +87,7 @@ class StorageManager {
|
|
|
71
87
|
req.onerror = () => reject(req.error);
|
|
72
88
|
return promise;
|
|
73
89
|
}
|
|
90
|
+
/** Executes a batch of writes inside a single IndexedDB transaction. */
|
|
74
91
|
async executeTransaction(operations) {
|
|
75
92
|
const storeNames = Array.from(new Set(operations.map((o) => o.storeName))).concat([
|
|
76
93
|
"dirtyQueue",
|
|
@@ -114,6 +131,7 @@ class StorageManager {
|
|
|
114
131
|
});
|
|
115
132
|
return promise;
|
|
116
133
|
}
|
|
134
|
+
/** Reads a typed record by primary key from the requested store. */
|
|
117
135
|
async get(storeName, id) {
|
|
118
136
|
const { promise, resolve, reject } = (0, promiseWithResolvers_js_1.promiseWithResolvers)();
|
|
119
137
|
const tx = this.db.transaction(storeName, "readonly");
|
|
@@ -122,6 +140,7 @@ class StorageManager {
|
|
|
122
140
|
req.onerror = () => reject(req.error);
|
|
123
141
|
return promise;
|
|
124
142
|
}
|
|
143
|
+
/** Returns every record from the requested store. */
|
|
125
144
|
async findAll(storeName) {
|
|
126
145
|
const { promise, resolve, reject } = (0, promiseWithResolvers_js_1.promiseWithResolvers)();
|
|
127
146
|
const tx = this.db.transaction(storeName, "readonly");
|
|
@@ -130,6 +149,7 @@ class StorageManager {
|
|
|
130
149
|
req.onerror = () => reject(req.error);
|
|
131
150
|
return promise;
|
|
132
151
|
}
|
|
152
|
+
/** Clears every object store managed by the database. */
|
|
133
153
|
async clearAllStores() {
|
|
134
154
|
const tx = this.db.transaction(Array.from(this.db.objectStoreNames), "readwrite");
|
|
135
155
|
Array.from(this.db.objectStoreNames).forEach((name) => tx.objectStore(name).clear());
|
|
@@ -138,6 +158,7 @@ class StorageManager {
|
|
|
138
158
|
tx.onerror = () => reject(tx.error);
|
|
139
159
|
});
|
|
140
160
|
}
|
|
161
|
+
/** Closes the underlying IndexedDB connection. */
|
|
141
162
|
dispose() {
|
|
142
163
|
if (this.db) {
|
|
143
164
|
this.db.close();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StorageManager.js","sourceRoot":"","sources":["../../src/internal/StorageManager.ts"],"names":[],"mappings":";;;AACA,6EAAsE;AACtE,yDAAkD;AAGlD,MAAa,cAAc;
|
|
1
|
+
{"version":3,"file":"StorageManager.js","sourceRoot":"","sources":["../../src/internal/StorageManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,9 @@ import type { DbSyncConfig } from "../DbSync.js";
|
|
|
3
3
|
import type { AuthManager } from "./AuthManager.js";
|
|
4
4
|
import type { EventBus } from "./EventBus.js";
|
|
5
5
|
import type { StorageManager } from "./StorageManager.js";
|
|
6
|
+
/**
|
|
7
|
+
* Coordinates periodic pull/push sync cycles against the configured backend.
|
|
8
|
+
*/
|
|
6
9
|
export declare class SyncEngine {
|
|
7
10
|
private config;
|
|
8
11
|
private syncInterval;
|
|
@@ -11,17 +14,40 @@ export declare class SyncEngine {
|
|
|
11
14
|
private auth;
|
|
12
15
|
private adapter;
|
|
13
16
|
private onSchemaChange;
|
|
17
|
+
/** The active interval handle, or `null` when sync is disabled. */
|
|
14
18
|
private syncSetInterval;
|
|
19
|
+
/**
|
|
20
|
+
* Creates a sync engine bound to the given storage, auth, and adapter instances.
|
|
21
|
+
*
|
|
22
|
+
* @param config The active dbsync configuration.
|
|
23
|
+
* @param syncInterval The polling interval in milliseconds.
|
|
24
|
+
* @param events The event bus used for sync state notifications.
|
|
25
|
+
* @param storage The storage manager used to read and write records.
|
|
26
|
+
* @param auth The auth manager used to update authentication state.
|
|
27
|
+
* @param adapter The backend adapter used for pull and push requests.
|
|
28
|
+
* @param onSchemaChange Callback fired when schema versions diverge.
|
|
29
|
+
*/
|
|
15
30
|
constructor(config: DbSyncConfig, syncInterval: number, events: EventBus, storage: StorageManager, auth: AuthManager, adapter: BackendAdapter, onSchemaChange: () => void);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
31
|
+
/** Starts periodic synchronization if it is not already running. */
|
|
32
|
+
start(): void;
|
|
33
|
+
/** Stops periodic synchronization if it is currently running. */
|
|
34
|
+
stop(): void;
|
|
35
|
+
/** Whether the sync timer is currently active. */
|
|
36
|
+
get isStarted(): boolean;
|
|
37
|
+
/** Whether the last successful sync is still considered fresh. */
|
|
19
38
|
get isLive(): boolean;
|
|
39
|
+
/** Waits until the engine reports a live connection or rejects if disabled. */
|
|
20
40
|
waitForLive(): Promise<void>;
|
|
41
|
+
/** Triggers a single sync cycle immediately. */
|
|
21
42
|
triggerSync(): Promise<void>;
|
|
43
|
+
/** Runs one sync pass, optionally under a Web Locks leader lock. */
|
|
22
44
|
private sync;
|
|
45
|
+
/** Performs pull, push, and sync-state bookkeeping for one cycle. */
|
|
23
46
|
private performSync;
|
|
47
|
+
/** Computes the local schema signature used for version handshakes. */
|
|
24
48
|
private get schemaSignature();
|
|
49
|
+
/** Pulls remote changes and applies them to IndexedDB. */
|
|
25
50
|
private syncPull;
|
|
51
|
+
/** Pushes queued local mutations to the backend and clears the queues. */
|
|
26
52
|
private syncPush;
|
|
27
53
|
}
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SyncEngine = void 0;
|
|
4
4
|
const promiseWithResolvers_js_1 = require("../util/promiseWithResolvers.js");
|
|
5
|
+
/**
|
|
6
|
+
* Coordinates periodic pull/push sync cycles against the configured backend.
|
|
7
|
+
*/
|
|
5
8
|
class SyncEngine {
|
|
6
9
|
config;
|
|
7
10
|
syncInterval;
|
|
@@ -10,7 +13,19 @@ class SyncEngine {
|
|
|
10
13
|
auth;
|
|
11
14
|
adapter;
|
|
12
15
|
onSchemaChange;
|
|
16
|
+
/** The active interval handle, or `null` when sync is disabled. */
|
|
13
17
|
syncSetInterval = null;
|
|
18
|
+
/**
|
|
19
|
+
* Creates a sync engine bound to the given storage, auth, and adapter instances.
|
|
20
|
+
*
|
|
21
|
+
* @param config The active dbsync configuration.
|
|
22
|
+
* @param syncInterval The polling interval in milliseconds.
|
|
23
|
+
* @param events The event bus used for sync state notifications.
|
|
24
|
+
* @param storage The storage manager used to read and write records.
|
|
25
|
+
* @param auth The auth manager used to update authentication state.
|
|
26
|
+
* @param adapter The backend adapter used for pull and push requests.
|
|
27
|
+
* @param onSchemaChange Callback fired when schema versions diverge.
|
|
28
|
+
*/
|
|
14
29
|
constructor(config, syncInterval, events, storage, auth, adapter, onSchemaChange) {
|
|
15
30
|
this.config = config;
|
|
16
31
|
this.syncInterval = syncInterval;
|
|
@@ -20,29 +35,34 @@ class SyncEngine {
|
|
|
20
35
|
this.adapter = adapter;
|
|
21
36
|
this.onSchemaChange = onSchemaChange;
|
|
22
37
|
}
|
|
23
|
-
|
|
38
|
+
/** Starts periodic synchronization if it is not already running. */
|
|
39
|
+
start() {
|
|
24
40
|
if (!this.syncSetInterval) {
|
|
25
41
|
this.syncSetInterval = setInterval(() => this.sync(), this.syncInterval);
|
|
26
42
|
}
|
|
27
43
|
}
|
|
28
|
-
|
|
44
|
+
/** Stops periodic synchronization if it is currently running. */
|
|
45
|
+
stop() {
|
|
29
46
|
if (this.syncSetInterval) {
|
|
30
47
|
clearInterval(this.syncSetInterval);
|
|
31
48
|
this.syncSetInterval = null;
|
|
32
49
|
}
|
|
33
50
|
}
|
|
34
|
-
|
|
51
|
+
/** Whether the sync timer is currently active. */
|
|
52
|
+
get isStarted() {
|
|
35
53
|
return !!this.syncSetInterval;
|
|
36
54
|
}
|
|
55
|
+
/** Whether the last successful sync is still considered fresh. */
|
|
37
56
|
get isLive() {
|
|
38
57
|
const lastSuccess = localStorage.getItem("dbsync-lastSuccessAt");
|
|
39
58
|
if (!lastSuccess)
|
|
40
59
|
return false;
|
|
41
60
|
return Date.now() - new Date(lastSuccess).getTime() < this.syncInterval * 4;
|
|
42
61
|
}
|
|
62
|
+
/** Waits until the engine reports a live connection or rejects if disabled. */
|
|
43
63
|
async waitForLive() {
|
|
44
64
|
const { promise, resolve, reject } = (0, promiseWithResolvers_js_1.promiseWithResolvers)();
|
|
45
|
-
if (!this.
|
|
65
|
+
if (!this.isStarted) {
|
|
46
66
|
reject(new Error("Sync disabled"));
|
|
47
67
|
return promise;
|
|
48
68
|
}
|
|
@@ -54,9 +74,11 @@ class SyncEngine {
|
|
|
54
74
|
}, this.syncInterval);
|
|
55
75
|
return promise;
|
|
56
76
|
}
|
|
77
|
+
/** Triggers a single sync cycle immediately. */
|
|
57
78
|
async triggerSync() {
|
|
58
79
|
await this.sync();
|
|
59
80
|
}
|
|
81
|
+
/** Runs one sync pass, optionally under a Web Locks leader lock. */
|
|
60
82
|
async sync() {
|
|
61
83
|
if (typeof navigator !== "undefined" && navigator.locks) {
|
|
62
84
|
await navigator.locks.request("dbsync-leader", async () => {
|
|
@@ -67,6 +89,7 @@ class SyncEngine {
|
|
|
67
89
|
await this.performSync();
|
|
68
90
|
}
|
|
69
91
|
}
|
|
92
|
+
/** Performs pull, push, and sync-state bookkeeping for one cycle. */
|
|
70
93
|
async performSync() {
|
|
71
94
|
this.events.setState("syncing");
|
|
72
95
|
try {
|
|
@@ -79,11 +102,12 @@ class SyncEngine {
|
|
|
79
102
|
catch (err) {
|
|
80
103
|
if (err.status === 401) {
|
|
81
104
|
this.auth.isAuth = false;
|
|
82
|
-
this.
|
|
105
|
+
this.stop();
|
|
83
106
|
}
|
|
84
107
|
this.events.setState("error");
|
|
85
108
|
}
|
|
86
109
|
}
|
|
110
|
+
/** Computes the local schema signature used for version handshakes. */
|
|
87
111
|
get schemaSignature() {
|
|
88
112
|
const tables = Object.keys(this.config.tables)
|
|
89
113
|
.sort()
|
|
@@ -95,6 +119,7 @@ class SyncEngine {
|
|
|
95
119
|
});
|
|
96
120
|
return JSON.stringify(tables);
|
|
97
121
|
}
|
|
122
|
+
/** Pulls remote changes and applies them to IndexedDB. */
|
|
98
123
|
async syncPull() {
|
|
99
124
|
let hasMore = true;
|
|
100
125
|
while (hasMore) {
|
|
@@ -130,6 +155,7 @@ class SyncEngine {
|
|
|
130
155
|
hasMore = data.hasMore;
|
|
131
156
|
}
|
|
132
157
|
}
|
|
158
|
+
/** Pushes queued local mutations to the backend and clears the queues. */
|
|
133
159
|
async syncPush() {
|
|
134
160
|
const dirty = await this.storage.findAll("dirtyQueue");
|
|
135
161
|
const deleted = await this.storage.findAll("deletedQueue");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SyncEngine.js","sourceRoot":"","sources":["../../src/internal/SyncEngine.ts"],"names":[],"mappings":";;;AAEA,6EAAsE;AAKtE,MAAa,UAAU;
|
|
1
|
+
{"version":3,"file":"SyncEngine.js","sourceRoot":"","sources":["../../src/internal/SyncEngine.ts"],"names":[],"mappings":"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"}
|
package/cjs/useDbQuery.js
CHANGED
|
@@ -14,7 +14,9 @@ const react_1 = require("react");
|
|
|
14
14
|
* @returns The resolved data of the `queryFn`, or `undefined` while the initial fetch evaluates.
|
|
15
15
|
*/
|
|
16
16
|
function useDbQuery(db, stores, queryFn, deps = []) {
|
|
17
|
+
/** Holds the latest query result. */
|
|
17
18
|
const [data, setData] = (0, react_1.useState)(undefined);
|
|
19
|
+
/** Normalizes the store input into an array for matching. */
|
|
18
20
|
const storeArray = Array.isArray(stores) ? stores : [stores];
|
|
19
21
|
(0, react_1.useEffect)(() => {
|
|
20
22
|
let isMounted = true;
|
package/cjs/useDbQuery.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDbQuery.js","sourceRoot":"","sources":["../src/useDbQuery.ts"],"names":[],"mappings":";;AAcA,
|
|
1
|
+
{"version":3,"file":"useDbQuery.js","sourceRoot":"","sources":["../src/useDbQuery.ts"],"names":[],"mappings":";;AAcA,gCAqDC;AAnED,iCAA2C;AAG3C;;;;;;;;;;GAUG;AACH,SAAgB,UAAU,CACzB,EAAU,EACV,MAAyB,EACzB,OAAyB,EACzB,OAAc,EAAE;IAEhB,qCAAqC;IACrC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,IAAA,gBAAQ,EAAgB,SAAS,CAAC,CAAA;IAC1D,6DAA6D;IAC7D,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;IAE5D,IAAA,iBAAS,EAAC,GAAG,EAAE;QACd,IAAI,SAAS,GAAG,IAAI,CAAA;QAEpB,MAAM,SAAS,GAAG,KAAK,IAAI,EAAE;YAC5B,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC;gBACjB,oDAAoD;gBACpD,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;oBACnC,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;wBAC9B,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;4BAC9B,aAAa,CAAC,KAAK,CAAC,CAAA;4BACpB,OAAO,EAAE,CAAA;wBACV,CAAC;oBACF,CAAC,EAAE,EAAE,CAAC,CAAA;gBACP,CAAC,CAAC,CAAA;YACH,CAAC;YACD,IAAI,CAAC;gBACJ,MAAM,MAAM,GAAG,MAAM,OAAO,EAAE,CAAA;gBAC9B,IAAI,SAAS;oBAAE,OAAO,CAAC,MAAM,CAAC,CAAA;YAC/B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAA;YACxD,CAAC;QACF,CAAC,CAAA;QAED,gBAAgB;QAChB,SAAS,EAAE,CAAA;QAEX,+BAA+B;QAC/B,MAAM,GAAG,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,aAAa,EAAE,EAAE;YAC1C,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;YACtE,IAAI,YAAY,EAAE,CAAC;gBAClB,SAAS,EAAE,CAAA;YACZ,CAAC;QACF,CAAC,CAAC,CAAA;QAEF,OAAO,GAAG,EAAE;YACX,SAAS,GAAG,KAAK,CAAA;YACjB,GAAG,CAAC,KAAK,EAAE,CAAA;QACZ,CAAC,CAAA;QACD,uDAAuD;IACxD,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAA;IAE7C,OAAO,IAAI,CAAA;AACZ,CAAC"}
|
|
@@ -8,8 +8,11 @@ exports.promiseWithResolvers = promiseWithResolvers;
|
|
|
8
8
|
* the built-in helper yet.
|
|
9
9
|
*/
|
|
10
10
|
function promiseWithResolvers() {
|
|
11
|
+
/** Resolves the created promise. */
|
|
11
12
|
let resolve;
|
|
13
|
+
/** Rejects the created promise. */
|
|
12
14
|
let reject;
|
|
15
|
+
/** The promise instance returned to the caller. */
|
|
13
16
|
const promise = new Promise((res, rej) => {
|
|
14
17
|
resolve = res;
|
|
15
18
|
reject = rej;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"promiseWithResolvers.js","sourceRoot":"","sources":["../../src/util/promiseWithResolvers.ts"],"names":[],"mappings":";;AAMA,
|
|
1
|
+
{"version":3,"file":"promiseWithResolvers.js","sourceRoot":"","sources":["../../src/util/promiseWithResolvers.ts"],"names":[],"mappings":";;AAMA,oDAWC;AAjBD;;;;;GAKG;AACH,SAAgB,oBAAoB;IACnC,oCAAoC;IACpC,IAAI,OAA6C,CAAA;IACjD,mCAAmC;IACnC,IAAI,MAA+B,CAAA;IACnC,mDAAmD;IACnD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC3C,OAAO,GAAG,GAAG,CAAA;QACb,MAAM,GAAG,GAAG,CAAA;IACb,CAAC,CAAC,CAAA;IACF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAA;AACpC,CAAC"}
|
package/docs/Adapters.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Backend Adapters
|
|
2
|
+
|
|
3
|
+
`@slimr/dbsync` relies on a modular `BackendAdapter` architecture to handle remote synchronization. By default, it expects you to use `RestAdapter`, but the interface is designed to let you plug your local IndexedDB database into any backend (like Firebase, GraphQL, or websockets).
|
|
4
|
+
|
|
5
|
+
## The `BackendAdapter` Interface
|
|
6
|
+
|
|
7
|
+
When writing a custom adapter, you simply need to implement the following TypeScript interface:
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
export interface SyncPullResult {
|
|
11
|
+
items: any[]
|
|
12
|
+
hasMore: boolean
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface BackendAdapter {
|
|
16
|
+
checkAuth(): Promise<boolean>
|
|
17
|
+
login(email: string, code: string): Promise<boolean>
|
|
18
|
+
logout(): Promise<void>
|
|
19
|
+
pull(cursor: string): Promise<SyncPullResult>
|
|
20
|
+
push(payload: any[]): Promise<void>
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Authentication Contract
|
|
25
|
+
|
|
26
|
+
- **`checkAuth()`**: Resolves to `true` if the user has an active session, otherwise `false`.
|
|
27
|
+
- **`login(email, code)`**: Validates the login against your backend and resolves to `true` on success.
|
|
28
|
+
- **`logout()`**: Destroys the remote session. (Note: `DbSync` will automatically handle clearing the local IndexedDB database when logout occurs).
|
|
29
|
+
|
|
30
|
+
### Synchronization Contract
|
|
31
|
+
|
|
32
|
+
The sync engine handles pushing queued modifications and pulling new global data independently of your adapter. Your adapter's job is simply to broker the JSON.
|
|
33
|
+
|
|
34
|
+
- **`pull(cursor: string)`**: Responsible for fetching newly updated records from your backend. It receives a `cursor` (typically an ISO timestamp) indicating the newest record the client already has. It must return a `SyncPullResult` containing the rows, and a `hasMore` boolean to let the SyncEngine loop handle pagination.
|
|
35
|
+
- **`push(payload)`**: Responsible for taking an array of mutated records and executing their writes to the backend database.
|
|
36
|
+
|
|
37
|
+
### Schema Versioning Records
|
|
38
|
+
|
|
39
|
+
Because `@slimr/dbsync` handles local schema migrations automatically via signature diffing, it must occasionally send a "System Record" in the `push()` payload to alert other tabs and devices of the schema change.
|
|
40
|
+
|
|
41
|
+
These records arrive in `push(payload)` formatted roughly like this:
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"id": "version",
|
|
45
|
+
"variant": "__dbsync_system",
|
|
46
|
+
"content": "{\"signature\":\"[[schema hash]]\"}",
|
|
47
|
+
"isDeleted": false,
|
|
48
|
+
"updatedAt": "2026-05-17T12:00:00.000Z"
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
**Your custom backend adapter must save these records securely alongside the rest of your user data,** as they must be returned in future `pull()` queries so other clients remain fully in sync.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
### Included Adapters
|
|
56
|
+
|
|
57
|
+
- [LocalAdapter](./LocalAdapter.md) — A no-op adapter if you just want to use the IndexedDB ORM features without any backend syncing.
|
|
58
|
+
- [RestAdapter](./RestAdapter.md) — The default REST adapter built to pair seamlessly with `swift-crud`.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# LocalAdapter
|
|
2
|
+
|
|
3
|
+
`LocalAdapter` is the no-op backend adapter shipped with `@slimr/dbsync`.
|
|
4
|
+
|
|
5
|
+
It exists for consumer apps that want the full IndexedDB ORM, reactive updates, repositories, and transactions without any remote sync backend. It satisfies the `BackendAdapter` contract but intentionally never talks to a server.
|
|
6
|
+
|
|
7
|
+
Use it when your app is local-only or when you want to disable sync in certain environments.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# RestAdapter
|
|
2
|
+
|
|
3
|
+
The `RestAdapter` is the default backend adapter shipped with `@slimr/dbsync`.
|
|
4
|
+
|
|
5
|
+
It maps the offline-first IndexedDB synchronizer to a very specific set of REST JSON endpoints. The easiest way to satisfy these expectations on your server is to use the officially supported backend, [swift-crud](https://github.com/bdombro/swift-crud) — a ready-made Go + SQLite API built specifically for this architecture.
|
|
6
|
+
|
|
7
|
+
You can instantiate `RestAdapter` by providing your API's base URL:
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { RestAdapter } from "@slimr/dbsync/adapters";
|
|
11
|
+
|
|
12
|
+
const adapter = new RestAdapter({ url: "https://api.myapp.com" });
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## API Expectations
|
|
18
|
+
|
|
19
|
+
If you are building your own backend instead of using `swift-crud`, your server must implement the following endpoints and JSON shapes for `RestAdapter` to function without throwing errors.
|
|
20
|
+
|
|
21
|
+
### 1. Data Pull: `GET /api/posts`
|
|
22
|
+
|
|
23
|
+
Used to fetch remote changes and sync them to the local IndexedDB.
|
|
24
|
+
|
|
25
|
+
**Query Parameters:**
|
|
26
|
+
- `after`: A cursor (an ISO 8601 timestamp string) representing the `updatedAt` of the last synced record on the client.
|
|
27
|
+
- `limit`: The maximum number of records to return per page.
|
|
28
|
+
|
|
29
|
+
**Response Shape:**
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"items": [
|
|
33
|
+
{
|
|
34
|
+
"id": "uuid-string",
|
|
35
|
+
"variant": "tableName",
|
|
36
|
+
"content": "{\"field\": \"value\"}",
|
|
37
|
+
"isDeleted": false,
|
|
38
|
+
"updatedAt": "2026-05-17T12:00:00.000Z"
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"hasMore": false
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 2. Data Push: `POST /api/posts/upsert-many`
|
|
46
|
+
|
|
47
|
+
Used to push queued local changes (both inserts/updates and deletes) to the backend.
|
|
48
|
+
|
|
49
|
+
**Request Body:**
|
|
50
|
+
An array of mutated records stringified exactly like the Pull response:
|
|
51
|
+
```json
|
|
52
|
+
[
|
|
53
|
+
{
|
|
54
|
+
"id": "uuid-string",
|
|
55
|
+
"variant": "tableName",
|
|
56
|
+
"content": "{\"field\": \"value\"}",
|
|
57
|
+
"isDeleted": false,
|
|
58
|
+
"updatedAt": "2026-05-17T12:00:00.000Z"
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 3. Session Endpoints
|
|
64
|
+
|
|
65
|
+
The session endpoints expect basic HTTP Cookie-based authentication mechanisms.
|
|
66
|
+
|
|
67
|
+
- **Check Auth:** `GET /api/session` (Returns 200 OK if the browser cookie is an authenticated session, 4xx otherwise)
|
|
68
|
+
- **Login:** `POST /api/session/login` (Expects JSON body `{ "email": "...", "code": "..." }` and should set the auth cookie here)
|
|
69
|
+
- **Logout:** `POST /api/session/logout` (Destroys the session cookie)
|
package/esm/DbSync.d.ts
CHANGED
|
@@ -2,50 +2,94 @@ import type { BackendAdapter } from "./adapters/types.js";
|
|
|
2
2
|
import { type SyncState } from "./internal/EventBus.js";
|
|
3
3
|
import { StorageManager } from "./internal/StorageManager.js";
|
|
4
4
|
export interface DbSyncConfig {
|
|
5
|
+
/** The backend adapter used for authentication and synchronization. */
|
|
5
6
|
adapter: BackendAdapter;
|
|
7
|
+
/** Optional fixed IndexedDB version. */
|
|
6
8
|
version?: number;
|
|
9
|
+
/** The object stores and their index definitions. */
|
|
7
10
|
tables: Record<string, {
|
|
8
11
|
indexes?: string[];
|
|
9
12
|
}>;
|
|
10
13
|
}
|
|
11
14
|
export type { SyncState };
|
|
15
|
+
/**
|
|
16
|
+
* The public facade for the dbsync engine.
|
|
17
|
+
*/
|
|
12
18
|
export declare class DbSync {
|
|
19
|
+
/** The polling interval used by the sync engine in milliseconds. */
|
|
13
20
|
syncInterval: number;
|
|
21
|
+
/** The active configuration passed by the consumer. */
|
|
14
22
|
config: DbSyncConfig;
|
|
23
|
+
/** The event bus used for local and cross-tab notifications. */
|
|
15
24
|
private events;
|
|
25
|
+
/** The storage manager handling IndexedDB state and transactions. */
|
|
16
26
|
storage: StorageManager;
|
|
27
|
+
/** The engine responsible for network synchronization. */
|
|
17
28
|
private syncEngine;
|
|
29
|
+
/** The manager handling authentication and logout/reset behavior. */
|
|
18
30
|
private authManager;
|
|
31
|
+
/**
|
|
32
|
+
* Creates a new `DbSync` instance using the supplied configuration.
|
|
33
|
+
*
|
|
34
|
+
* @param config The backend adapter, schema version, and table definitions.
|
|
35
|
+
*/
|
|
19
36
|
constructor(config: DbSyncConfig);
|
|
37
|
+
/** Returns a fresh RFC-4122 UUID. */
|
|
20
38
|
genUuid(): `${string}-${string}-${string}-${string}-${string}`;
|
|
39
|
+
/** Whether the storage layer has finished initializing. */
|
|
21
40
|
get initted(): boolean;
|
|
41
|
+
/** Initializes the underlying IndexedDB stores. */
|
|
22
42
|
init(): Promise<void>;
|
|
43
|
+
/** Returns a queued transaction object for batched writes. */
|
|
23
44
|
getTransaction(): import("./internal/DbTransaction.js").DbTransaction;
|
|
45
|
+
/** Reads a typed record by primary key. */
|
|
24
46
|
get<T>(storeName: string, id: string | number): Promise<T | undefined>;
|
|
47
|
+
/** Reads all records from the given object store. */
|
|
25
48
|
findAll<T>(storeName: string): Promise<T[]>;
|
|
49
|
+
/** Inserts a new record into the given object store. */
|
|
26
50
|
add<T>(storeName: string, value: any, key?: string | number): Promise<T>;
|
|
51
|
+
/** Upserts a record into the given object store. */
|
|
27
52
|
put<T>(storeName: string, value: any, key?: string | number): Promise<T>;
|
|
53
|
+
/** Deletes a record from the given object store. */
|
|
28
54
|
delete(storeName: string, key: string | number): Promise<void>;
|
|
55
|
+
/** Clears all records from the given object store. */
|
|
29
56
|
clear(storeName: string): Promise<void>;
|
|
57
|
+
/** Subscribes to store update notifications. */
|
|
30
58
|
subscribe(callback: (stores: string[]) => void): {
|
|
31
59
|
close: () => boolean;
|
|
32
60
|
};
|
|
61
|
+
/** Subscribes to sync state changes. */
|
|
33
62
|
onSyncStateChange(callback: (state: SyncState) => void): {
|
|
34
63
|
close: () => boolean;
|
|
35
64
|
};
|
|
65
|
+
/** Whether the current backend session is authenticated. */
|
|
36
66
|
get isAuth(): boolean;
|
|
67
|
+
/** Verifies authentication against the backend adapter. */
|
|
37
68
|
checkAuth(): Promise<boolean>;
|
|
69
|
+
/** Logs in with the given credentials. */
|
|
38
70
|
login(email: string, code: string): Promise<void>;
|
|
71
|
+
/** Logs out and clears auth state. */
|
|
39
72
|
logout(): Promise<void>;
|
|
73
|
+
/** Logs out and clears the local database. */
|
|
40
74
|
reset(): Promise<void>;
|
|
41
|
-
|
|
75
|
+
/** Whether background sync is currently enabled. */
|
|
76
|
+
get isStarted(): boolean;
|
|
77
|
+
/** Whether the sync engine has recently connected successfully. */
|
|
42
78
|
get isLive(): boolean;
|
|
43
|
-
|
|
44
|
-
|
|
79
|
+
/** Starts periodic background synchronization. */
|
|
80
|
+
start(): Promise<void>;
|
|
81
|
+
/** Stops periodic background synchronization. */
|
|
82
|
+
stop(): Promise<void>;
|
|
83
|
+
/** Waits until the sync engine reports a live connection. */
|
|
45
84
|
waitForLive(): Promise<void>;
|
|
85
|
+
/** Triggers a single sync cycle immediately. */
|
|
46
86
|
triggerSync(): Promise<void>;
|
|
87
|
+
/** Legacy alias for `enable()`. */
|
|
47
88
|
startSyncInterval(): void;
|
|
89
|
+
/** Legacy alias for `disable()`. */
|
|
48
90
|
stopSyncInterval(): void;
|
|
91
|
+
/** Responds to schema changes by disposing state and reloading the page. */
|
|
49
92
|
protected onSchemaChangeDetected(): void;
|
|
93
|
+
/** Disposes all background resources and event listeners. */
|
|
50
94
|
dispose(): void;
|
|
51
95
|
}
|