remult-sqlite-s3 0.1.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/LICENSE +21 -0
- package/README.md +145 -0
- package/dist/index.cjs +1117 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +285 -0
- package/dist/index.d.ts +285 -0
- package/dist/index.js +1109 -0
- package/dist/index.js.map +1 -0
- package/package.json +67 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { SqlDatabase } from 'remult';
|
|
2
|
+
import { Options, Database } from 'better-sqlite3';
|
|
3
|
+
import { SqliteCoreDataProvider } from 'remult/remult-sqlite-core-js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Public types for BetterSqlite3S3DataProvider
|
|
7
|
+
*/
|
|
8
|
+
interface BetterSqlite3S3Options {
|
|
9
|
+
/** Path to SQLite database file */
|
|
10
|
+
file: string;
|
|
11
|
+
/** better-sqlite3 options (optional) */
|
|
12
|
+
sqliteOptions?: {
|
|
13
|
+
readonly?: boolean;
|
|
14
|
+
fileMustExist?: boolean;
|
|
15
|
+
timeout?: number;
|
|
16
|
+
verbose?: (message?: unknown, ...additionalArgs: unknown[]) => void;
|
|
17
|
+
nativeBinding?: string;
|
|
18
|
+
};
|
|
19
|
+
s3: {
|
|
20
|
+
/** S3 bucket name */
|
|
21
|
+
bucket: string;
|
|
22
|
+
/**
|
|
23
|
+
* Unique database name (required)
|
|
24
|
+
* Used to namespace all S3 keys for this database.
|
|
25
|
+
* Must be unique per database to prevent data conflicts.
|
|
26
|
+
* Example: "myapp-users", "myapp-orders", "prod-main"
|
|
27
|
+
*/
|
|
28
|
+
databaseName: string;
|
|
29
|
+
/** Optional key prefix prepended to all S3 keys (e.g., "databases/") */
|
|
30
|
+
keyPrefix?: string;
|
|
31
|
+
/** AWS region (default: "us-east-1") */
|
|
32
|
+
region?: string;
|
|
33
|
+
/** Custom endpoint for S3-compatible storage (MinIO, R2, Backblaze, etc.) */
|
|
34
|
+
endpoint?: string;
|
|
35
|
+
/** Explicit credentials (optional - uses AWS SDK default chain if not provided) */
|
|
36
|
+
credentials?: {
|
|
37
|
+
accessKeyId: string;
|
|
38
|
+
secretAccessKey: string;
|
|
39
|
+
};
|
|
40
|
+
/** Force path style for S3-compatible storage like MinIO */
|
|
41
|
+
forcePathStyle?: boolean;
|
|
42
|
+
};
|
|
43
|
+
sync?: {
|
|
44
|
+
/**
|
|
45
|
+
* Sync mode:
|
|
46
|
+
* - 'async': Fast writes, eventual durability (default)
|
|
47
|
+
* - 'sync': Wait for S3 confirmation on every write
|
|
48
|
+
*/
|
|
49
|
+
mode?: 'async' | 'sync';
|
|
50
|
+
/** Sync WAL to S3 when it reaches this size in bytes (default: 1MB) */
|
|
51
|
+
walThreshold?: number;
|
|
52
|
+
/** Create full snapshot every N milliseconds (default: 5 minutes) */
|
|
53
|
+
snapshotInterval?: number;
|
|
54
|
+
/** S3 operation retry count (default: 3) */
|
|
55
|
+
maxRetries?: number;
|
|
56
|
+
/** Lock TTL in milliseconds (default: 60000) */
|
|
57
|
+
lockTtl?: number;
|
|
58
|
+
/** Lock refresh interval in milliseconds (default: 30000) */
|
|
59
|
+
lockRefresh?: number;
|
|
60
|
+
/** Force acquire lock even if another process holds it (use only in development) */
|
|
61
|
+
forceLock?: boolean;
|
|
62
|
+
};
|
|
63
|
+
/** Called on sync events (uploads, recoveries, errors) */
|
|
64
|
+
onEvent?: (event: S3SyncEvent) => void;
|
|
65
|
+
/** Enable verbose logging */
|
|
66
|
+
verbose?: boolean;
|
|
67
|
+
}
|
|
68
|
+
type S3SyncEvent = {
|
|
69
|
+
type: 'wal_uploaded';
|
|
70
|
+
generation: string;
|
|
71
|
+
index: number;
|
|
72
|
+
size: number;
|
|
73
|
+
} | {
|
|
74
|
+
type: 'snapshot_uploaded';
|
|
75
|
+
generation: string;
|
|
76
|
+
size: number;
|
|
77
|
+
} | {
|
|
78
|
+
type: 'recovery_started';
|
|
79
|
+
generation: string;
|
|
80
|
+
} | {
|
|
81
|
+
type: 'recovery_completed';
|
|
82
|
+
generation: string;
|
|
83
|
+
segments: number;
|
|
84
|
+
} | {
|
|
85
|
+
type: 'lock_acquired';
|
|
86
|
+
lockId: string;
|
|
87
|
+
} | {
|
|
88
|
+
type: 'lock_lost';
|
|
89
|
+
reason: string;
|
|
90
|
+
} | {
|
|
91
|
+
type: 'sync_error';
|
|
92
|
+
error: Error;
|
|
93
|
+
context: string;
|
|
94
|
+
willRetry: boolean;
|
|
95
|
+
} | {
|
|
96
|
+
type: 'initialized';
|
|
97
|
+
generation: string;
|
|
98
|
+
recovered: boolean;
|
|
99
|
+
};
|
|
100
|
+
interface S3Config {
|
|
101
|
+
bucket: string;
|
|
102
|
+
databaseName: string;
|
|
103
|
+
keyPrefix: string;
|
|
104
|
+
region: string;
|
|
105
|
+
endpoint?: string;
|
|
106
|
+
credentials?: {
|
|
107
|
+
accessKeyId: string;
|
|
108
|
+
secretAccessKey: string;
|
|
109
|
+
};
|
|
110
|
+
forcePathStyle?: boolean;
|
|
111
|
+
}
|
|
112
|
+
interface SyncConfig {
|
|
113
|
+
mode: 'async' | 'sync';
|
|
114
|
+
walThreshold: number;
|
|
115
|
+
snapshotInterval: number;
|
|
116
|
+
maxRetries: number;
|
|
117
|
+
lockTtl: number;
|
|
118
|
+
lockRefresh: number;
|
|
119
|
+
forceLock: boolean;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* S3 Sync Manager
|
|
124
|
+
* Coordinates lock, WAL, and snapshot operations
|
|
125
|
+
*/
|
|
126
|
+
|
|
127
|
+
interface S3SyncManagerOptions {
|
|
128
|
+
dbPath: string;
|
|
129
|
+
sqliteOptions?: Options;
|
|
130
|
+
s3: S3Config;
|
|
131
|
+
sync: SyncConfig;
|
|
132
|
+
onEvent: (event: S3SyncEvent) => void;
|
|
133
|
+
verbose: boolean;
|
|
134
|
+
}
|
|
135
|
+
declare class S3SyncManager {
|
|
136
|
+
private s3;
|
|
137
|
+
private lock;
|
|
138
|
+
private walManager;
|
|
139
|
+
private recoveryManager;
|
|
140
|
+
private db;
|
|
141
|
+
private dbPath;
|
|
142
|
+
private sqliteOptions?;
|
|
143
|
+
private syncConfig;
|
|
144
|
+
private onEvent;
|
|
145
|
+
private verbose;
|
|
146
|
+
private generation;
|
|
147
|
+
private snapshotTimer;
|
|
148
|
+
private closed;
|
|
149
|
+
constructor(options: S3SyncManagerOptions);
|
|
150
|
+
/**
|
|
151
|
+
* Initialize the sync manager
|
|
152
|
+
* - Acquire lock
|
|
153
|
+
* - Recover from S3 if needed
|
|
154
|
+
* - Open database
|
|
155
|
+
* - Start sync timers
|
|
156
|
+
*/
|
|
157
|
+
initialize(): Promise<Database>;
|
|
158
|
+
/**
|
|
159
|
+
* Called after write operations
|
|
160
|
+
*/
|
|
161
|
+
onWrite(): Promise<void>;
|
|
162
|
+
/**
|
|
163
|
+
* Force sync WAL to S3
|
|
164
|
+
*/
|
|
165
|
+
syncWal(): Promise<void>;
|
|
166
|
+
/**
|
|
167
|
+
* Force full sync (WAL + check for snapshot)
|
|
168
|
+
*/
|
|
169
|
+
sync(): Promise<void>;
|
|
170
|
+
/**
|
|
171
|
+
* Create a full snapshot
|
|
172
|
+
*/
|
|
173
|
+
snapshot(): Promise<void>;
|
|
174
|
+
/**
|
|
175
|
+
* Close the sync manager
|
|
176
|
+
*/
|
|
177
|
+
close(): Promise<void>;
|
|
178
|
+
/**
|
|
179
|
+
* Get the current generation
|
|
180
|
+
*/
|
|
181
|
+
getGeneration(): string;
|
|
182
|
+
private createGenerationInfo;
|
|
183
|
+
private updateGenerationInfo;
|
|
184
|
+
private startSnapshotTimer;
|
|
185
|
+
private stopSnapshotTimer;
|
|
186
|
+
private log;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* BetterSqlite3S3DataProvider
|
|
191
|
+
* A Remult data provider that wraps better-sqlite3 with automatic S3 synchronization
|
|
192
|
+
*/
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* BetterSqlite3S3DataProvider
|
|
196
|
+
*
|
|
197
|
+
* A drop-in replacement for BetterSqlite3DataProvider with automatic S3 synchronization.
|
|
198
|
+
*
|
|
199
|
+
* Usage:
|
|
200
|
+
* ```typescript
|
|
201
|
+
* const provider = new BetterSqlite3S3DataProvider({
|
|
202
|
+
* file: './mydb.sqlite',
|
|
203
|
+
* s3: {
|
|
204
|
+
* bucket: 'my-bucket',
|
|
205
|
+
* databaseName: 'myapp-main', // Required: unique name for this database
|
|
206
|
+
* keyPrefix: 'databases/', // Optional: prefix for all keys
|
|
207
|
+
* },
|
|
208
|
+
* });
|
|
209
|
+
* await provider.init();
|
|
210
|
+
* const dataProvider = new SqlDatabase(provider);
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
declare class BetterSqlite3S3DataProvider extends SqliteCoreDataProvider {
|
|
214
|
+
private db;
|
|
215
|
+
private syncManager;
|
|
216
|
+
private options;
|
|
217
|
+
private initialized;
|
|
218
|
+
private initPromise;
|
|
219
|
+
constructor(options: BetterSqlite3S3Options);
|
|
220
|
+
/**
|
|
221
|
+
* Async initialization - must be called before use
|
|
222
|
+
*/
|
|
223
|
+
init(): Promise<void>;
|
|
224
|
+
private doInit;
|
|
225
|
+
/**
|
|
226
|
+
* Get the underlying database (for advanced use cases)
|
|
227
|
+
*/
|
|
228
|
+
get rawDatabase(): Database;
|
|
229
|
+
/**
|
|
230
|
+
* Get the sync manager (for manual sync control)
|
|
231
|
+
*/
|
|
232
|
+
get sync(): S3SyncManager;
|
|
233
|
+
/**
|
|
234
|
+
* Force sync to S3
|
|
235
|
+
*/
|
|
236
|
+
forceSync(): Promise<void>;
|
|
237
|
+
/**
|
|
238
|
+
* Force a full snapshot
|
|
239
|
+
*/
|
|
240
|
+
snapshot(): Promise<void>;
|
|
241
|
+
/**
|
|
242
|
+
* Close the database and release resources
|
|
243
|
+
*/
|
|
244
|
+
close(): Promise<void>;
|
|
245
|
+
/**
|
|
246
|
+
* Check if the provider is initialized
|
|
247
|
+
*/
|
|
248
|
+
get isInitialized(): boolean;
|
|
249
|
+
/**
|
|
250
|
+
* Get the current generation ID
|
|
251
|
+
*/
|
|
252
|
+
get generation(): string;
|
|
253
|
+
private ensureInitialized;
|
|
254
|
+
private applyDefaults;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* remult-sqlite-s3
|
|
259
|
+
* A Remult data provider that syncs SQLite to S3 for serverless deployments
|
|
260
|
+
*/
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Creates an S3-synced SQLite data provider for Remult.
|
|
264
|
+
* Handles initialization and graceful shutdown automatically.
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* ```typescript
|
|
268
|
+
* import { remultApi } from 'remult/remult-express'
|
|
269
|
+
* import { createS3DataProvider } from 'remult-sqlite-s3'
|
|
270
|
+
*
|
|
271
|
+
* export const api = remultApi({
|
|
272
|
+
* dataProvider: createS3DataProvider({
|
|
273
|
+
* file: './mydb.sqlite',
|
|
274
|
+
* s3: {
|
|
275
|
+
* bucket: 'my-bucket',
|
|
276
|
+
* databaseName: 'my-database',
|
|
277
|
+
* },
|
|
278
|
+
* }),
|
|
279
|
+
* entities: [Task],
|
|
280
|
+
* })
|
|
281
|
+
* ```
|
|
282
|
+
*/
|
|
283
|
+
declare function createS3DataProvider(options: BetterSqlite3S3Options): () => Promise<SqlDatabase>;
|
|
284
|
+
|
|
285
|
+
export { BetterSqlite3S3DataProvider, type BetterSqlite3S3Options, type S3Config, type S3SyncEvent, S3SyncManager, type SyncConfig, createS3DataProvider };
|