@mauryasumit/driftdb 3.0.0 → 7.0.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/README.md +47 -19
- package/dist/db.d.ts +4 -2
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +38 -7
- package/dist/db.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/sync/engine.d.ts +1 -0
- package/dist/sync/engine.d.ts.map +1 -1
- package/dist/sync/engine.js +50 -0
- package/dist/sync/engine.js.map +1 -1
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/db.ts +68 -24
- package/src/index.ts +4 -2
- package/src/sync/engine.ts +123 -61
- package/src/types.ts +13 -0
package/README.md
CHANGED
|
@@ -108,17 +108,21 @@ npm install driftdb
|
|
|
108
108
|
|
|
109
109
|
### Schema-based API (recommended)
|
|
110
110
|
|
|
111
|
-
```typescript
|
|
111
|
+
```typescript
|
|
112
112
|
import { DB, Column } from 'driftdb';
|
|
113
113
|
|
|
114
|
-
const db =
|
|
114
|
+
const db = await DB.open({
|
|
115
115
|
dbName: 'myapp-prod',
|
|
116
116
|
sqlitePath: './data/myapp.sqlite',
|
|
117
|
+
autoRestore: true,
|
|
117
118
|
s3Config: {
|
|
118
119
|
bucket: 'my-app-backups',
|
|
119
|
-
region: 'us-east-1',
|
|
120
|
-
},
|
|
121
|
-
|
|
120
|
+
region: 'us-east-1',
|
|
121
|
+
},
|
|
122
|
+
logger: (event) => {
|
|
123
|
+
console.log(`[${event.scope}] ${event.message}`, event.metadata ?? '');
|
|
124
|
+
},
|
|
125
|
+
});
|
|
122
126
|
|
|
123
127
|
// Define a model
|
|
124
128
|
const Users = db.define('users', {
|
|
@@ -181,11 +185,13 @@ await User.update({ id: alice.id }, { name: 'Alice Smith' });
|
|
|
181
185
|
|
|
182
186
|
### DB
|
|
183
187
|
|
|
184
|
-
The main entry point. Manages the SQLite connection, ORM registrations, and sync engine.
|
|
185
|
-
|
|
186
|
-
```typescript
|
|
187
|
-
const db = new DB(config: DBConfig);
|
|
188
|
-
```
|
|
188
|
+
The main entry point. Manages the SQLite connection, ORM registrations, and sync engine.
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
const db = new DB(config: DBConfig);
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Use `await DB.open(config)` when `autoRestore: true` is enabled and the local SQLite file may be missing on startup.
|
|
189
195
|
|
|
190
196
|
| Method | Description |
|
|
191
197
|
|---|---|
|
|
@@ -478,6 +484,8 @@ Current releases use a database-scoped layout so multiple logical databases can
|
|
|
478
484
|
- isolate each application database under `databases/{dbName}`
|
|
479
485
|
- restore the latest snapshot after a local SQLite file is deleted
|
|
480
486
|
- persist the local `nodeId` for that selected database so restarts reuse the same node identity
|
|
487
|
+
|
|
488
|
+
If you want that restore to happen automatically on application restart, initialize with `await DB.open(...)` instead of `new DB(...)`.
|
|
481
489
|
|
|
482
490
|
**Log batch example:**
|
|
483
491
|
```json
|
|
@@ -680,13 +688,17 @@ interface DBConfig {
|
|
|
680
688
|
key: string; // 64-char hex = 32-byte AES-256 key
|
|
681
689
|
};
|
|
682
690
|
|
|
683
|
-
retryConfig?: {
|
|
684
|
-
maxRetries: number; // Max retry attempts (default: 5)
|
|
685
|
-
baseDelayMs: number; // Base delay for exponential backoff (default: 500)
|
|
686
|
-
maxDelayMs: number; // Max delay cap (default: 30000)
|
|
687
|
-
};
|
|
688
|
-
|
|
689
|
-
|
|
691
|
+
retryConfig?: {
|
|
692
|
+
maxRetries: number; // Max retry attempts (default: 5)
|
|
693
|
+
baseDelayMs: number; // Base delay for exponential backoff (default: 500)
|
|
694
|
+
maxDelayMs: number; // Max delay cap (default: 30000)
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
autoRestore?: boolean; // Restore latest snapshot on startup when using DB.open(...)
|
|
698
|
+
restoreFromS3?: boolean; // Legacy alias for autoRestore
|
|
699
|
+
logger?: (event) => void; // Optional hook for restore/sync logs
|
|
700
|
+
}
|
|
701
|
+
```
|
|
690
702
|
|
|
691
703
|
---
|
|
692
704
|
|
|
@@ -725,8 +737,24 @@ const db = new DB({
|
|
|
725
737
|
await Users.create({ name: 'Alice', email: 'alice@example.com' });
|
|
726
738
|
|
|
727
739
|
// Flush when ready
|
|
728
|
-
await db.flush();
|
|
729
|
-
```
|
|
740
|
+
await db.flush();
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
### Restore deleted local DB on startup
|
|
744
|
+
|
|
745
|
+
```typescript
|
|
746
|
+
const db = await DB.open({
|
|
747
|
+
dbName: 'manual-sync-demo',
|
|
748
|
+
sqlitePath: './data.sqlite',
|
|
749
|
+
autoRestore: true,
|
|
750
|
+
s3Config: { bucket: 'my-bucket', region: 'us-east-1' },
|
|
751
|
+
logger: (event) => {
|
|
752
|
+
console.log(`[${event.scope}] ${event.message}`, event.metadata ?? '');
|
|
753
|
+
},
|
|
754
|
+
});
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
If `./data.sqlite` was deleted locally, DriftDB checks S3 for the latest snapshot for `manual-sync-demo`, restores it, and logs the restore activity through `logger`.
|
|
730
758
|
|
|
731
759
|
### Monitoring sync metrics
|
|
732
760
|
|
package/dist/db.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export declare class DB {
|
|
|
13
13
|
/**
|
|
14
14
|
* Async factory — use this instead of `new DB()` when you need S3 restore on startup.
|
|
15
15
|
*
|
|
16
|
-
* - If `
|
|
16
|
+
* - If `autoRestore: true` and the local SQLite file does not exist, it downloads
|
|
17
17
|
* the latest snapshot from S3 before opening the database.
|
|
18
18
|
* - `dbName` is required and namespaces each logical database in S3.
|
|
19
19
|
* - `nodeId` identifies the current local node within that logical database.
|
|
@@ -23,12 +23,14 @@ export declare class DB {
|
|
|
23
23
|
* dbName: 'my-app-db',
|
|
24
24
|
* sqlitePath: './data/app.sqlite',
|
|
25
25
|
* nodeId: 'server-1',
|
|
26
|
-
*
|
|
26
|
+
* autoRestore: true, // auto-restore if local file is missing
|
|
27
27
|
* s3Config: { bucket: '...', region: '...' },
|
|
28
28
|
* });
|
|
29
29
|
*/
|
|
30
30
|
static open(config: DBConfig): Promise<DB>;
|
|
31
31
|
private static restoreSnapshot;
|
|
32
|
+
private static emitLog;
|
|
33
|
+
private static shouldAutoRestore;
|
|
32
34
|
private getOrCreateNodeId;
|
|
33
35
|
define<S extends ModelSchema>(tableName: string, schema: S): Repository<BaseRecord & {
|
|
34
36
|
[K in keyof S]: unknown;
|
package/dist/db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAG3C,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAG3C,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAgB,WAAW,EAAE,MAAM,YAAY,CAAC;AACnF,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAIjD,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAa7C,qBAAa,EAAE;IACb,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAW;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;IACxC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA6C;gBAEvD,MAAM,EAAE,QAAQ;IAgD5B;;;;;;;;;;;;;;;;OAgBG;WACU,IAAI,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,EAAE,CAAC;mBA+B3B,eAAe;IAqBpC,OAAO,CAAC,MAAM,CAAC,OAAO;IAItB,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAIhC,OAAO,CAAC,iBAAiB;IAuBzB,MAAM,CAAC,CAAC,SAAS,WAAW,EAC1B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,CAAC,GACR,UAAU,CAAC,UAAU,GAAG;SAAG,CAAC,IAAI,MAAM,CAAC,GAAG,OAAO;KAAE,CAAC;IAWvD,aAAa,CAAC,CAAC,SAAS,KAAK,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI;IAmBhE,SAAS,IAAI,MAAM;IAInB,UAAU,IAAI,QAAQ,CAAC,WAAW,CAAC;IAI7B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B,SAAS,IAAI,IAAI;IAIjB,QAAQ,IAAI,IAAI;IAIhB,GAAG,IAAI,QAAQ,CAAC,QAAQ;IAIxB,KAAK,IAAI,IAAI;IAKb,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC;IAI9B,MAAM,IAAI,IAAI;IAId,cAAc,IAAI,OAAO;CAM1B"}
|
package/dist/db.js
CHANGED
|
@@ -11,7 +11,7 @@ const repository_js_1 = require("./orm/repository.js");
|
|
|
11
11
|
const engine_js_1 = require("./sync/engine.js");
|
|
12
12
|
const s3_adapter_js_1 = require("./storage/s3-adapter.js");
|
|
13
13
|
const id_js_1 = require("./utils/id.js");
|
|
14
|
-
const META_SCHEMA = `
|
|
14
|
+
const META_SCHEMA = `
|
|
15
15
|
CREATE TABLE IF NOT EXISTS _driftdb_meta (
|
|
16
16
|
key TEXT PRIMARY KEY,
|
|
17
17
|
value TEXT NOT NULL
|
|
@@ -20,14 +20,22 @@ const META_SCHEMA = `
|
|
|
20
20
|
class DB {
|
|
21
21
|
constructor(config) {
|
|
22
22
|
this.repos = new Map();
|
|
23
|
+
const internalConfig = config;
|
|
23
24
|
const dbName = config.dbName.trim();
|
|
24
25
|
if (!dbName) {
|
|
25
26
|
throw new Error('DBConfig.dbName is required');
|
|
26
27
|
}
|
|
27
28
|
this.config = {
|
|
28
|
-
...
|
|
29
|
+
...internalConfig,
|
|
29
30
|
dbName,
|
|
30
31
|
};
|
|
32
|
+
if (DB.shouldAutoRestore(this.config) &&
|
|
33
|
+
this.config.s3Config &&
|
|
34
|
+
this.config.sqlitePath !== ':memory:' &&
|
|
35
|
+
!(0, fs_1.existsSync)(this.config.sqlitePath) &&
|
|
36
|
+
!internalConfig.__skipRestoreGuard) {
|
|
37
|
+
throw new Error(`Local database "${this.config.sqlitePath}" does not exist. Use await DB.open(...) when autoRestore is enabled.`);
|
|
38
|
+
}
|
|
31
39
|
if (this.config.sqlitePath !== ':memory:') {
|
|
32
40
|
const dir = (0, path_1.dirname)(this.config.sqlitePath);
|
|
33
41
|
if (dir && dir !== '.') {
|
|
@@ -50,7 +58,7 @@ class DB {
|
|
|
50
58
|
/**
|
|
51
59
|
* Async factory — use this instead of `new DB()` when you need S3 restore on startup.
|
|
52
60
|
*
|
|
53
|
-
* - If `
|
|
61
|
+
* - If `autoRestore: true` and the local SQLite file does not exist, it downloads
|
|
54
62
|
* the latest snapshot from S3 before opening the database.
|
|
55
63
|
* - `dbName` is required and namespaces each logical database in S3.
|
|
56
64
|
* - `nodeId` identifies the current local node within that logical database.
|
|
@@ -60,18 +68,35 @@ class DB {
|
|
|
60
68
|
* dbName: 'my-app-db',
|
|
61
69
|
* sqlitePath: './data/app.sqlite',
|
|
62
70
|
* nodeId: 'server-1',
|
|
63
|
-
*
|
|
71
|
+
* autoRestore: true, // auto-restore if local file is missing
|
|
64
72
|
* s3Config: { bucket: '...', region: '...' },
|
|
65
73
|
* });
|
|
66
74
|
*/
|
|
67
75
|
static async open(config) {
|
|
68
|
-
if (config
|
|
76
|
+
if (DB.shouldAutoRestore(config) &&
|
|
69
77
|
config.s3Config &&
|
|
70
78
|
config.sqlitePath !== ':memory:' &&
|
|
71
79
|
!(0, fs_1.existsSync)(config.sqlitePath)) {
|
|
72
|
-
|
|
80
|
+
DB.emitLog(config, {
|
|
81
|
+
level: 'info',
|
|
82
|
+
scope: 'restore',
|
|
83
|
+
message: `Local database missing at "${config.sqlitePath}". Attempting restore from S3.`,
|
|
84
|
+
dbName: config.dbName,
|
|
85
|
+
});
|
|
86
|
+
const restored = await DB.restoreSnapshot(config);
|
|
87
|
+
DB.emitLog(config, {
|
|
88
|
+
level: 'info',
|
|
89
|
+
scope: 'restore',
|
|
90
|
+
message: restored
|
|
91
|
+
? `Restored database "${config.dbName}" from S3 snapshot.`
|
|
92
|
+
: `No remote snapshot found for database "${config.dbName}". Starting with a new local database.`,
|
|
93
|
+
dbName: config.dbName,
|
|
94
|
+
});
|
|
73
95
|
}
|
|
74
|
-
return new DB(
|
|
96
|
+
return new DB({
|
|
97
|
+
...config,
|
|
98
|
+
__skipRestoreGuard: true,
|
|
99
|
+
});
|
|
75
100
|
}
|
|
76
101
|
static async restoreSnapshot(config) {
|
|
77
102
|
const s3 = new s3_adapter_js_1.S3Adapter(config.s3Config);
|
|
@@ -91,6 +116,12 @@ class DB {
|
|
|
91
116
|
(0, fs_1.writeFileSync)(config.sqlitePath, data);
|
|
92
117
|
return true;
|
|
93
118
|
}
|
|
119
|
+
static emitLog(config, event) {
|
|
120
|
+
config.logger?.(event);
|
|
121
|
+
}
|
|
122
|
+
static shouldAutoRestore(config) {
|
|
123
|
+
return config.autoRestore === true || config.restoreFromS3 === true;
|
|
124
|
+
}
|
|
94
125
|
getOrCreateNodeId(preferred) {
|
|
95
126
|
const metaKey = `nodeId:${this.config.dbName}`;
|
|
96
127
|
if (preferred) {
|
package/dist/db.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":";;;;;;AAAA,oEAA2C;AAE3C,2BAA0D;AAC1D,+BAA+B;AAE/B,uDAAiD;AACjD,gDAA8C;AAC9C,2DAAoD;AACpD,yCAA+C;AAI/C,MAAM,WAAW,GAAG;;;;;CAKnB,CAAC;
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,5 +4,5 @@ export type { ModelStatic } from './orm/model.js';
|
|
|
4
4
|
export { Repository } from './orm/repository.js';
|
|
5
5
|
export { Column } from './orm/schema.js';
|
|
6
6
|
export type { RecordOf } from './orm/repository.js';
|
|
7
|
-
export type { DBConfig, S3Config, ModelSchema, ColumnDef, ColumnType, BaseRecord, WhereClause, FindOptions, SyncMetrics, RetryConfig, EncryptionConfig, LogBatch, ChangeLogEntry, SyncJob, SyncManifest, } from './types.js';
|
|
7
|
+
export type { DBConfig, S3Config, ModelSchema, ColumnDef, ColumnType, BaseRecord, WhereClause, FindOptions, SyncMetrics, RetryConfig, EncryptionConfig, SyncLogEvent, SyncLogger, LogBatch, ChangeLogEntry, SyncJob, SyncManifest, } from './types.js';
|
|
8
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,YAAY,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,YAAY,EACV,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,SAAS,EACT,UAAU,EACV,UAAU,EACV,WAAW,EACX,WAAW,EACX,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,QAAQ,EACR,cAAc,EACd,OAAO,EACP,YAAY,GACb,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,YAAY,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,YAAY,EACV,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,SAAS,EACT,UAAU,EACV,UAAU,EACV,WAAW,EACX,WAAW,EACX,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,cAAc,EACd,OAAO,EACP,YAAY,GACb,MAAM,YAAY,CAAC"}
|
package/dist/sync/engine.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/sync/engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/sync/engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EACV,QAAQ,EAGR,WAAW,EAGZ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAW5C,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAoB;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAW;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAyB;IACzD,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAmB;IAEtC,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,YAAY,CAAS;IAE7B,OAAO,CAAC,OAAO,CAQb;gBAEU,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ;IA6BnE,YAAY,IAAI,SAAS;IAIzB,QAAQ,IAAI,SAAS;IAIrB,KAAK,IAAI,IAAI;IAgBb,IAAI,IAAI,IAAI;IASN,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,UAAU,IAAI,QAAQ,CAAC,WAAW,CAAC;IAQnC,OAAO,CAAC,cAAc;YAUR,IAAI;YAiBJ,kBAAkB;YA6BlB,YAAY;YAUZ,UAAU;YAqFV,aAAa;IAkBrB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBtC,OAAO,CAAC,GAAG;CAcZ"}
|
package/dist/sync/engine.js
CHANGED
|
@@ -54,6 +54,7 @@ class SyncEngine {
|
|
|
54
54
|
return;
|
|
55
55
|
this.metrics.isRunning = true;
|
|
56
56
|
this.queue.resetStuck();
|
|
57
|
+
this.log('info', 'Started background sync engine.');
|
|
57
58
|
const intervalMs = this.config.syncIntervalMs ?? DEFAULT_SYNC_INTERVAL_MS;
|
|
58
59
|
this.timer = setInterval(() => {
|
|
59
60
|
void this.tick();
|
|
@@ -68,6 +69,7 @@ class SyncEngine {
|
|
|
68
69
|
this.timer = null;
|
|
69
70
|
}
|
|
70
71
|
this.metrics.isRunning = false;
|
|
72
|
+
this.log('info', 'Stopped background sync engine.');
|
|
71
73
|
}
|
|
72
74
|
async flush() {
|
|
73
75
|
await this.tick();
|
|
@@ -100,6 +102,9 @@ class SyncEngine {
|
|
|
100
102
|
}
|
|
101
103
|
catch (err) {
|
|
102
104
|
this.metrics.syncErrors++;
|
|
105
|
+
this.log('error', 'Sync tick failed.', {
|
|
106
|
+
error: err instanceof Error ? err.message : String(err),
|
|
107
|
+
});
|
|
103
108
|
}
|
|
104
109
|
finally {
|
|
105
110
|
this.isProcessing = false;
|
|
@@ -120,6 +125,11 @@ class SyncEngine {
|
|
|
120
125
|
s3Key,
|
|
121
126
|
};
|
|
122
127
|
this.queue.enqueue('upload_log', { ...payload, batch });
|
|
128
|
+
this.log('info', 'Queued log batch for upload.', {
|
|
129
|
+
fromSequence: batch.fromSequence,
|
|
130
|
+
toSequence: batch.toSequence,
|
|
131
|
+
s3Key,
|
|
132
|
+
});
|
|
123
133
|
}
|
|
124
134
|
}
|
|
125
135
|
async processQueue() {
|
|
@@ -138,6 +148,11 @@ class SyncEngine {
|
|
|
138
148
|
if (job.type === 'upload_log') {
|
|
139
149
|
const p = JSON.parse(job.payload);
|
|
140
150
|
const batchBuffer = Buffer.from(JSON.stringify(p.batch), 'utf8');
|
|
151
|
+
this.log('info', 'Uploading log batch to S3.', {
|
|
152
|
+
fromSequence: p.fromSequence,
|
|
153
|
+
toSequence: p.toSequence,
|
|
154
|
+
s3Key: p.s3Key,
|
|
155
|
+
});
|
|
141
156
|
await this.s3.upload(p.s3Key, batchBuffer, uploadOptions);
|
|
142
157
|
this.changeLog.markSynced(p.fromSequence, p.toSequence);
|
|
143
158
|
const manifest = await this.s3.getManifest(this.config.dbName);
|
|
@@ -152,11 +167,19 @@ class SyncEngine {
|
|
|
152
167
|
});
|
|
153
168
|
this.metrics.totalSynced += (p.toSequence - p.fromSequence + 1);
|
|
154
169
|
this.metrics.lastSyncAt = Date.now();
|
|
170
|
+
this.log('info', 'Uploaded log batch to S3.', {
|
|
171
|
+
fromSequence: p.fromSequence,
|
|
172
|
+
toSequence: p.toSequence,
|
|
173
|
+
s3Key: p.s3Key,
|
|
174
|
+
});
|
|
155
175
|
await this.maybeSnapshot(latestSeq);
|
|
156
176
|
}
|
|
157
177
|
else if (job.type === 'upload_snapshot') {
|
|
158
178
|
const p = JSON.parse(job.payload);
|
|
159
179
|
if (this.snapshotManager) {
|
|
180
|
+
this.log('info', 'Uploading snapshot to S3.', {
|
|
181
|
+
s3Key: p.s3Key,
|
|
182
|
+
});
|
|
160
183
|
const { key, timestamp } = await this.snapshotManager.takeAndUpload();
|
|
161
184
|
const manifest = await this.s3.getManifest(this.config.dbName);
|
|
162
185
|
await this.s3.putManifest(this.config.dbName, {
|
|
@@ -168,6 +191,10 @@ class SyncEngine {
|
|
|
168
191
|
updatedAt: Date.now(),
|
|
169
192
|
});
|
|
170
193
|
this.metrics.lastSnapshotAt = Date.now();
|
|
194
|
+
this.log('info', 'Uploaded snapshot to S3.', {
|
|
195
|
+
s3Key: key,
|
|
196
|
+
timestamp,
|
|
197
|
+
});
|
|
171
198
|
}
|
|
172
199
|
void p;
|
|
173
200
|
}
|
|
@@ -178,6 +205,11 @@ class SyncEngine {
|
|
|
178
205
|
const msg = err instanceof Error ? err.message : String(err);
|
|
179
206
|
this.queue.markFailed(job.id, msg);
|
|
180
207
|
this.metrics.syncErrors++;
|
|
208
|
+
this.log('error', 'Sync job failed.', {
|
|
209
|
+
jobId: job.id,
|
|
210
|
+
jobType: job.type,
|
|
211
|
+
error: msg,
|
|
212
|
+
});
|
|
181
213
|
}
|
|
182
214
|
}
|
|
183
215
|
async maybeSnapshot(latestSequence) {
|
|
@@ -190,6 +222,10 @@ class SyncEngine {
|
|
|
190
222
|
dbPath: this.config.sqlitePath,
|
|
191
223
|
};
|
|
192
224
|
this.queue.enqueue('upload_snapshot', payload);
|
|
225
|
+
this.log('info', 'Queued snapshot upload.', {
|
|
226
|
+
s3Key: payload.s3Key,
|
|
227
|
+
timestamp: payload.timestamp,
|
|
228
|
+
});
|
|
193
229
|
}
|
|
194
230
|
}
|
|
195
231
|
}
|
|
@@ -207,6 +243,20 @@ class SyncEngine {
|
|
|
207
243
|
updatedAt: Date.now(),
|
|
208
244
|
});
|
|
209
245
|
this.metrics.lastSnapshotAt = Date.now();
|
|
246
|
+
this.log('info', 'Triggered snapshot upload.', {
|
|
247
|
+
s3Key: key,
|
|
248
|
+
timestamp,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
log(level, message, metadata) {
|
|
252
|
+
this.config.logger?.({
|
|
253
|
+
level,
|
|
254
|
+
scope: 'sync',
|
|
255
|
+
message,
|
|
256
|
+
dbName: this.config.dbName,
|
|
257
|
+
nodeId: this.nodeId,
|
|
258
|
+
metadata,
|
|
259
|
+
});
|
|
210
260
|
}
|
|
211
261
|
}
|
|
212
262
|
exports.SyncEngine = SyncEngine;
|
package/dist/sync/engine.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/sync/engine.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/sync/engine.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -47,6 +47,15 @@ export interface RetryConfig {
|
|
|
47
47
|
export interface EncryptionConfig {
|
|
48
48
|
key: string;
|
|
49
49
|
}
|
|
50
|
+
export interface SyncLogEvent {
|
|
51
|
+
level: 'info' | 'error';
|
|
52
|
+
scope: 'restore' | 'sync';
|
|
53
|
+
message: string;
|
|
54
|
+
dbName: string;
|
|
55
|
+
nodeId?: string;
|
|
56
|
+
metadata?: Record<string, unknown>;
|
|
57
|
+
}
|
|
58
|
+
export type SyncLogger = (event: SyncLogEvent) => void;
|
|
50
59
|
export interface DBConfig {
|
|
51
60
|
dbName: string;
|
|
52
61
|
sqlitePath: string;
|
|
@@ -59,7 +68,9 @@ export interface DBConfig {
|
|
|
59
68
|
encryption?: EncryptionConfig;
|
|
60
69
|
retryConfig?: RetryConfig;
|
|
61
70
|
autoSync?: boolean;
|
|
71
|
+
autoRestore?: boolean;
|
|
62
72
|
restoreFromS3?: boolean;
|
|
73
|
+
logger?: SyncLogger;
|
|
63
74
|
}
|
|
64
75
|
export interface ChangeLogEntry {
|
|
65
76
|
sequence: number;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1E,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IAC3C,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAEpD,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,UAAU,CAAC,CAAC,IACpB,CAAC,GACD;IAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,CAAC,CAAA;CAAE,CAAC;AAEjF,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;KAC1B,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAClC,CAAC;AAEF,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,KAAK,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/db.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import BetterSqlite3 from 'better-sqlite3';
|
|
2
2
|
import type Database from 'better-sqlite3';
|
|
3
3
|
import { mkdirSync, existsSync, writeFileSync } from 'fs';
|
|
4
|
-
import { dirname } from 'path';
|
|
5
|
-
import type { DBConfig, ModelSchema, SyncMetrics } from './types.js';
|
|
4
|
+
import { dirname } from 'path';
|
|
5
|
+
import type { DBConfig, ModelSchema, SyncLogEvent, SyncMetrics } from './types.js';
|
|
6
6
|
import { Repository } from './orm/repository.js';
|
|
7
7
|
import { SyncEngine } from './sync/engine.js';
|
|
8
8
|
import { S3Adapter } from './storage/s3-adapter.js';
|
|
@@ -10,13 +10,17 @@ import { generateNodeId } from './utils/id.js';
|
|
|
10
10
|
import type { Model, ModelStatic } from './orm/model.js';
|
|
11
11
|
import type { BaseRecord } from './types.js';
|
|
12
12
|
|
|
13
|
-
const META_SCHEMA = `
|
|
13
|
+
const META_SCHEMA = `
|
|
14
14
|
CREATE TABLE IF NOT EXISTS _driftdb_meta (
|
|
15
15
|
key TEXT PRIMARY KEY,
|
|
16
16
|
value TEXT NOT NULL
|
|
17
17
|
);
|
|
18
|
-
`;
|
|
19
|
-
|
|
18
|
+
`;
|
|
19
|
+
|
|
20
|
+
type InternalDBConfig = DBConfig & {
|
|
21
|
+
__skipRestoreGuard?: boolean;
|
|
22
|
+
};
|
|
23
|
+
|
|
20
24
|
export class DB {
|
|
21
25
|
private readonly sqliteDb: Database.Database;
|
|
22
26
|
private readonly config: DBConfig;
|
|
@@ -25,16 +29,29 @@ export class DB {
|
|
|
25
29
|
private readonly repos = new Map<string, Repository<BaseRecord>>();
|
|
26
30
|
|
|
27
31
|
constructor(config: DBConfig) {
|
|
32
|
+
const internalConfig = config as InternalDBConfig;
|
|
28
33
|
const dbName = config.dbName.trim();
|
|
29
34
|
if (!dbName) {
|
|
30
35
|
throw new Error('DBConfig.dbName is required');
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
this.config = {
|
|
34
|
-
...
|
|
39
|
+
...internalConfig,
|
|
35
40
|
dbName,
|
|
36
41
|
};
|
|
37
42
|
|
|
43
|
+
if (
|
|
44
|
+
DB.shouldAutoRestore(this.config) &&
|
|
45
|
+
this.config.s3Config &&
|
|
46
|
+
this.config.sqlitePath !== ':memory:' &&
|
|
47
|
+
!existsSync(this.config.sqlitePath) &&
|
|
48
|
+
!internalConfig.__skipRestoreGuard
|
|
49
|
+
) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`Local database "${this.config.sqlitePath}" does not exist. Use await DB.open(...) when autoRestore is enabled.`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
38
55
|
if (this.config.sqlitePath !== ':memory:') {
|
|
39
56
|
const dir = dirname(this.config.sqlitePath);
|
|
40
57
|
if (dir && dir !== '.') {
|
|
@@ -62,8 +79,8 @@ export class DB {
|
|
|
62
79
|
/**
|
|
63
80
|
* Async factory — use this instead of `new DB()` when you need S3 restore on startup.
|
|
64
81
|
*
|
|
65
|
-
* - If `
|
|
66
|
-
* the latest snapshot from S3 before opening the database.
|
|
82
|
+
* - If `autoRestore: true` and the local SQLite file does not exist, it downloads
|
|
83
|
+
* the latest snapshot from S3 before opening the database.
|
|
67
84
|
* - `dbName` is required and namespaces each logical database in S3.
|
|
68
85
|
* - `nodeId` identifies the current local node within that logical database.
|
|
69
86
|
*
|
|
@@ -72,21 +89,40 @@ export class DB {
|
|
|
72
89
|
* dbName: 'my-app-db',
|
|
73
90
|
* sqlitePath: './data/app.sqlite',
|
|
74
91
|
* nodeId: 'server-1',
|
|
75
|
-
*
|
|
92
|
+
* autoRestore: true, // auto-restore if local file is missing
|
|
76
93
|
* s3Config: { bucket: '...', region: '...' },
|
|
77
94
|
* });
|
|
78
|
-
*/
|
|
79
|
-
static async open(config: DBConfig): Promise<DB> {
|
|
80
|
-
if (
|
|
81
|
-
config
|
|
82
|
-
config.s3Config &&
|
|
83
|
-
config.sqlitePath !== ':memory:' &&
|
|
84
|
-
!existsSync(config.sqlitePath)
|
|
85
|
-
) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
95
|
+
*/
|
|
96
|
+
static async open(config: DBConfig): Promise<DB> {
|
|
97
|
+
if (
|
|
98
|
+
DB.shouldAutoRestore(config) &&
|
|
99
|
+
config.s3Config &&
|
|
100
|
+
config.sqlitePath !== ':memory:' &&
|
|
101
|
+
!existsSync(config.sqlitePath)
|
|
102
|
+
) {
|
|
103
|
+
DB.emitLog(config, {
|
|
104
|
+
level: 'info',
|
|
105
|
+
scope: 'restore',
|
|
106
|
+
message: `Local database missing at "${config.sqlitePath}". Attempting restore from S3.`,
|
|
107
|
+
dbName: config.dbName,
|
|
108
|
+
});
|
|
109
|
+
const restored = await DB.restoreSnapshot(config);
|
|
110
|
+
DB.emitLog(config, {
|
|
111
|
+
level: 'info',
|
|
112
|
+
scope: 'restore',
|
|
113
|
+
message: restored
|
|
114
|
+
? `Restored database "${config.dbName}" from S3 snapshot.`
|
|
115
|
+
: `No remote snapshot found for database "${config.dbName}". Starting with a new local database.`,
|
|
116
|
+
dbName: config.dbName,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
return new DB(
|
|
120
|
+
{
|
|
121
|
+
...(config as InternalDBConfig),
|
|
122
|
+
__skipRestoreGuard: true,
|
|
123
|
+
} as InternalDBConfig
|
|
124
|
+
);
|
|
125
|
+
}
|
|
90
126
|
|
|
91
127
|
private static async restoreSnapshot(config: DBConfig): Promise<boolean> {
|
|
92
128
|
const s3 = new S3Adapter(config.s3Config!);
|
|
@@ -105,9 +141,17 @@ export class DB {
|
|
|
105
141
|
if (dir && dir !== '.') {
|
|
106
142
|
mkdirSync(dir, { recursive: true });
|
|
107
143
|
}
|
|
108
|
-
writeFileSync(config.sqlitePath, data);
|
|
109
|
-
return true;
|
|
110
|
-
}
|
|
144
|
+
writeFileSync(config.sqlitePath, data);
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private static emitLog(config: DBConfig, event: SyncLogEvent): void {
|
|
149
|
+
config.logger?.(event);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private static shouldAutoRestore(config: DBConfig): boolean {
|
|
153
|
+
return config.autoRestore === true || config.restoreFromS3 === true;
|
|
154
|
+
}
|
|
111
155
|
|
|
112
156
|
private getOrCreateNodeId(preferred?: string): string {
|
|
113
157
|
const metaKey = `nodeId:${this.config.dbName}`;
|
package/src/index.ts
CHANGED
package/src/sync/engine.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import type Database from 'better-sqlite3';
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
DBConfig,
|
|
4
|
+
SyncJob,
|
|
5
|
+
SyncLogEvent,
|
|
6
|
+
SyncMetrics,
|
|
7
|
+
UploadLogPayload,
|
|
8
|
+
UploadSnapshotPayload,
|
|
9
|
+
} from '../types.js';
|
|
3
10
|
import { SyncQueue } from '../queue/queue.js';
|
|
4
11
|
import { ChangeLog } from './change-log.js';
|
|
5
12
|
import { SnapshotManager } from './snapshot-manager.js';
|
|
@@ -71,12 +78,13 @@ export class SyncEngine {
|
|
|
71
78
|
return this.queue;
|
|
72
79
|
}
|
|
73
80
|
|
|
74
|
-
start(): void {
|
|
75
|
-
if (this.timer) return;
|
|
76
|
-
this.metrics.isRunning = true;
|
|
77
|
-
this.queue.resetStuck();
|
|
78
|
-
|
|
79
|
-
|
|
81
|
+
start(): void {
|
|
82
|
+
if (this.timer) return;
|
|
83
|
+
this.metrics.isRunning = true;
|
|
84
|
+
this.queue.resetStuck();
|
|
85
|
+
this.log('info', 'Started background sync engine.');
|
|
86
|
+
|
|
87
|
+
const intervalMs = this.config.syncIntervalMs ?? DEFAULT_SYNC_INTERVAL_MS;
|
|
80
88
|
this.timer = setInterval(() => {
|
|
81
89
|
void this.tick();
|
|
82
90
|
}, intervalMs);
|
|
@@ -86,13 +94,14 @@ export class SyncEngine {
|
|
|
86
94
|
}
|
|
87
95
|
}
|
|
88
96
|
|
|
89
|
-
stop(): void {
|
|
97
|
+
stop(): void {
|
|
90
98
|
if (this.timer) {
|
|
91
99
|
clearInterval(this.timer);
|
|
92
100
|
this.timer = null;
|
|
93
|
-
}
|
|
94
|
-
this.metrics.isRunning = false;
|
|
95
|
-
|
|
101
|
+
}
|
|
102
|
+
this.metrics.isRunning = false;
|
|
103
|
+
this.log('info', 'Stopped background sync engine.');
|
|
104
|
+
}
|
|
96
105
|
|
|
97
106
|
async flush(): Promise<void> {
|
|
98
107
|
await this.tick();
|
|
@@ -120,14 +129,17 @@ export class SyncEngine {
|
|
|
120
129
|
if (this.isProcessing || !this.s3) return;
|
|
121
130
|
this.isProcessing = true;
|
|
122
131
|
|
|
123
|
-
try {
|
|
124
|
-
await this.enqueuePendingLogs();
|
|
125
|
-
await this.processQueue();
|
|
126
|
-
} catch (err) {
|
|
127
|
-
this.metrics.syncErrors++;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
132
|
+
try {
|
|
133
|
+
await this.enqueuePendingLogs();
|
|
134
|
+
await this.processQueue();
|
|
135
|
+
} catch (err) {
|
|
136
|
+
this.metrics.syncErrors++;
|
|
137
|
+
this.log('error', 'Sync tick failed.', {
|
|
138
|
+
error: err instanceof Error ? err.message : String(err),
|
|
139
|
+
});
|
|
140
|
+
} finally {
|
|
141
|
+
this.isProcessing = false;
|
|
142
|
+
}
|
|
131
143
|
}
|
|
132
144
|
|
|
133
145
|
private async enqueuePendingLogs(): Promise<void> {
|
|
@@ -144,15 +156,20 @@ export class SyncEngine {
|
|
|
144
156
|
);
|
|
145
157
|
|
|
146
158
|
const alreadyQueued = this.queue.hasPendingOfType('upload_log');
|
|
147
|
-
if (!alreadyQueued) {
|
|
148
|
-
const payload: UploadLogPayload = {
|
|
149
|
-
fromSequence: batch.fromSequence,
|
|
150
|
-
toSequence: batch.toSequence,
|
|
151
|
-
s3Key,
|
|
152
|
-
};
|
|
153
|
-
this.queue.enqueue('upload_log', { ...payload, batch });
|
|
154
|
-
|
|
155
|
-
|
|
159
|
+
if (!alreadyQueued) {
|
|
160
|
+
const payload: UploadLogPayload = {
|
|
161
|
+
fromSequence: batch.fromSequence,
|
|
162
|
+
toSequence: batch.toSequence,
|
|
163
|
+
s3Key,
|
|
164
|
+
};
|
|
165
|
+
this.queue.enqueue('upload_log', { ...payload, batch });
|
|
166
|
+
this.log('info', 'Queued log batch for upload.', {
|
|
167
|
+
fromSequence: batch.fromSequence,
|
|
168
|
+
toSequence: batch.toSequence,
|
|
169
|
+
s3Key,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
156
173
|
|
|
157
174
|
private async processQueue(): Promise<void> {
|
|
158
175
|
const jobs = this.queue.dequeue(3);
|
|
@@ -174,11 +191,16 @@ export class SyncEngine {
|
|
|
174
191
|
try {
|
|
175
192
|
await withRetry(
|
|
176
193
|
async () => {
|
|
177
|
-
if (job.type === 'upload_log') {
|
|
178
|
-
const p = JSON.parse(job.payload) as UploadLogPayload & { batch: unknown };
|
|
179
|
-
const batchBuffer = Buffer.from(JSON.stringify(p.batch), 'utf8');
|
|
180
|
-
|
|
181
|
-
|
|
194
|
+
if (job.type === 'upload_log') {
|
|
195
|
+
const p = JSON.parse(job.payload) as UploadLogPayload & { batch: unknown };
|
|
196
|
+
const batchBuffer = Buffer.from(JSON.stringify(p.batch), 'utf8');
|
|
197
|
+
this.log('info', 'Uploading log batch to S3.', {
|
|
198
|
+
fromSequence: p.fromSequence,
|
|
199
|
+
toSequence: p.toSequence,
|
|
200
|
+
s3Key: p.s3Key,
|
|
201
|
+
});
|
|
202
|
+
await this.s3!.upload(p.s3Key, batchBuffer, uploadOptions);
|
|
203
|
+
this.changeLog.markSynced(p.fromSequence, p.toSequence);
|
|
182
204
|
|
|
183
205
|
const manifest = await this.s3!.getManifest(this.config.dbName);
|
|
184
206
|
const latestSeq = Math.max(
|
|
@@ -193,14 +215,22 @@ export class SyncEngine {
|
|
|
193
215
|
latestLogSequence: latestSeq,
|
|
194
216
|
updatedAt: Date.now(),
|
|
195
217
|
});
|
|
196
|
-
|
|
197
|
-
this.metrics.totalSynced += (p.toSequence - p.fromSequence + 1);
|
|
198
|
-
this.metrics.lastSyncAt = Date.now();
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
218
|
+
|
|
219
|
+
this.metrics.totalSynced += (p.toSequence - p.fromSequence + 1);
|
|
220
|
+
this.metrics.lastSyncAt = Date.now();
|
|
221
|
+
this.log('info', 'Uploaded log batch to S3.', {
|
|
222
|
+
fromSequence: p.fromSequence,
|
|
223
|
+
toSequence: p.toSequence,
|
|
224
|
+
s3Key: p.s3Key,
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
await this.maybeSnapshot(latestSeq);
|
|
228
|
+
} else if (job.type === 'upload_snapshot') {
|
|
229
|
+
const p = JSON.parse(job.payload) as UploadSnapshotPayload;
|
|
230
|
+
if (this.snapshotManager) {
|
|
231
|
+
this.log('info', 'Uploading snapshot to S3.', {
|
|
232
|
+
s3Key: p.s3Key,
|
|
233
|
+
});
|
|
204
234
|
const { key, timestamp } = await this.snapshotManager.takeAndUpload();
|
|
205
235
|
const manifest = await this.s3!.getManifest(this.config.dbName);
|
|
206
236
|
await this.s3!.putManifest(this.config.dbName, {
|
|
@@ -209,23 +239,32 @@ export class SyncEngine {
|
|
|
209
239
|
latestSnapshotKey: key,
|
|
210
240
|
latestSnapshotTimestamp: timestamp,
|
|
211
241
|
latestLogSequence: manifest?.latestLogSequence ?? 0,
|
|
212
|
-
updatedAt: Date.now(),
|
|
213
|
-
});
|
|
214
|
-
this.metrics.lastSnapshotAt = Date.now();
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
242
|
+
updatedAt: Date.now(),
|
|
243
|
+
});
|
|
244
|
+
this.metrics.lastSnapshotAt = Date.now();
|
|
245
|
+
this.log('info', 'Uploaded snapshot to S3.', {
|
|
246
|
+
s3Key: key,
|
|
247
|
+
timestamp,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
void p;
|
|
251
|
+
}
|
|
218
252
|
},
|
|
219
253
|
retryConfig
|
|
220
254
|
);
|
|
221
255
|
|
|
222
256
|
this.queue.markDone(job.id);
|
|
223
|
-
} catch (err) {
|
|
224
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
225
|
-
this.queue.markFailed(job.id, msg);
|
|
226
|
-
this.metrics.syncErrors++;
|
|
227
|
-
|
|
228
|
-
|
|
257
|
+
} catch (err) {
|
|
258
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
259
|
+
this.queue.markFailed(job.id, msg);
|
|
260
|
+
this.metrics.syncErrors++;
|
|
261
|
+
this.log('error', 'Sync job failed.', {
|
|
262
|
+
jobId: job.id,
|
|
263
|
+
jobType: job.type,
|
|
264
|
+
error: msg,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
229
268
|
|
|
230
269
|
private async maybeSnapshot(latestSequence: number): Promise<void> {
|
|
231
270
|
const threshold = this.config.snapshotEveryNLogs ?? DEFAULT_SNAPSHOT_EVERY_N_LOGS;
|
|
@@ -236,10 +275,14 @@ export class SyncEngine {
|
|
|
236
275
|
s3Key: this.s3!.snapshotKey(this.config.dbName, this.nodeId, Date.now()),
|
|
237
276
|
dbPath: this.config.sqlitePath,
|
|
238
277
|
};
|
|
239
|
-
this.queue.enqueue('upload_snapshot', payload);
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
278
|
+
this.queue.enqueue('upload_snapshot', payload);
|
|
279
|
+
this.log('info', 'Queued snapshot upload.', {
|
|
280
|
+
s3Key: payload.s3Key,
|
|
281
|
+
timestamp: payload.timestamp,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
243
286
|
|
|
244
287
|
async triggerSnapshot(): Promise<void> {
|
|
245
288
|
if (!this.snapshotManager || !this.s3) return;
|
|
@@ -252,7 +295,26 @@ export class SyncEngine {
|
|
|
252
295
|
latestSnapshotTimestamp: timestamp,
|
|
253
296
|
latestLogSequence: manifest?.latestLogSequence ?? 0,
|
|
254
297
|
updatedAt: Date.now(),
|
|
255
|
-
});
|
|
256
|
-
this.metrics.lastSnapshotAt = Date.now();
|
|
257
|
-
|
|
258
|
-
|
|
298
|
+
});
|
|
299
|
+
this.metrics.lastSnapshotAt = Date.now();
|
|
300
|
+
this.log('info', 'Triggered snapshot upload.', {
|
|
301
|
+
s3Key: key,
|
|
302
|
+
timestamp,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
private log(
|
|
307
|
+
level: SyncLogEvent['level'],
|
|
308
|
+
message: string,
|
|
309
|
+
metadata?: Record<string, unknown>
|
|
310
|
+
): void {
|
|
311
|
+
this.config.logger?.({
|
|
312
|
+
level,
|
|
313
|
+
scope: 'sync',
|
|
314
|
+
message,
|
|
315
|
+
dbName: this.config.dbName,
|
|
316
|
+
nodeId: this.nodeId,
|
|
317
|
+
metadata,
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -51,6 +51,17 @@ export interface EncryptionConfig {
|
|
|
51
51
|
key: string;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
export interface SyncLogEvent {
|
|
55
|
+
level: 'info' | 'error';
|
|
56
|
+
scope: 'restore' | 'sync';
|
|
57
|
+
message: string;
|
|
58
|
+
dbName: string;
|
|
59
|
+
nodeId?: string;
|
|
60
|
+
metadata?: Record<string, unknown>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type SyncLogger = (event: SyncLogEvent) => void;
|
|
64
|
+
|
|
54
65
|
export interface DBConfig {
|
|
55
66
|
dbName: string;
|
|
56
67
|
sqlitePath: string;
|
|
@@ -63,7 +74,9 @@ export interface DBConfig {
|
|
|
63
74
|
encryption?: EncryptionConfig;
|
|
64
75
|
retryConfig?: RetryConfig;
|
|
65
76
|
autoSync?: boolean;
|
|
77
|
+
autoRestore?: boolean;
|
|
66
78
|
restoreFromS3?: boolean;
|
|
79
|
+
logger?: SyncLogger;
|
|
67
80
|
}
|
|
68
81
|
|
|
69
82
|
export interface ChangeLogEntry {
|