@rivetkit/sqlite-wasm 2.2.1-pr.4600.b74ff3b
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 +203 -0
- package/dist/schemas/file-meta/v1.ts +43 -0
- package/dist/tsup/index.cjs +1557 -0
- package/dist/tsup/index.cjs.map +1 -0
- package/dist/tsup/index.d.cts +253 -0
- package/dist/tsup/index.d.ts +253 -0
- package/dist/tsup/index.js +1557 -0
- package/dist/tsup/index.js.map +1 -0
- package/package.json +49 -0
- package/schemas/file-meta/mod.ts +2 -0
- package/schemas/file-meta/v1.bare +7 -0
- package/schemas/file-meta/versioned.ts +25 -0
- package/src/generated/empty-db-page.ts +23 -0
- package/src/index.ts +5 -0
- package/src/kv.ts +116 -0
- package/src/pool.ts +502 -0
- package/src/types.ts +20 -0
- package/src/vfs.ts +1646 -0
- package/src/wasm.d.ts +60 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { Factory } from '@rivetkit/sqlite';
|
|
2
|
+
|
|
3
|
+
interface KvVfsOptions {
|
|
4
|
+
/** Get a single value by key. Returns null if missing. */
|
|
5
|
+
get: (key: Uint8Array) => Promise<Uint8Array | null>;
|
|
6
|
+
/** Get multiple values by keys. Returns null for missing keys. */
|
|
7
|
+
getBatch: (keys: Uint8Array[]) => Promise<(Uint8Array | null)[]>;
|
|
8
|
+
/** Put a single key-value pair */
|
|
9
|
+
put: (key: Uint8Array, value: Uint8Array) => Promise<void>;
|
|
10
|
+
/** Put multiple key-value pairs */
|
|
11
|
+
putBatch: (entries: [Uint8Array, Uint8Array][]) => Promise<void>;
|
|
12
|
+
/** Delete multiple keys */
|
|
13
|
+
deleteBatch: (keys: Uint8Array[]) => Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Called when a KV operation fails inside a VFS callback. The VFS must
|
|
16
|
+
* return a generic SQLite error code to the pager, so the original error
|
|
17
|
+
* is lost unless the caller captures it through this callback.
|
|
18
|
+
*/
|
|
19
|
+
onError?: (error: unknown) => void;
|
|
20
|
+
/** Delete all keys in the half-open range [start, end). */
|
|
21
|
+
deleteRange: (start: Uint8Array, end: Uint8Array) => Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* SQLite raw database with KV storage backend
|
|
26
|
+
*
|
|
27
|
+
* This module provides a SQLite API that uses a KV-backed VFS
|
|
28
|
+
* for storage. Each SqliteVfs instance is independent and can be
|
|
29
|
+
* used concurrently with other instances.
|
|
30
|
+
*
|
|
31
|
+
* Keep this VFS on direct VFS.Base callbacks for minimal wrapper overhead.
|
|
32
|
+
* Use @rivetkit/sqlite/src/FacadeVFS.js as the reference implementation for
|
|
33
|
+
* callback ABI and pointer/data conversion behavior.
|
|
34
|
+
* This implementation is optimized for single-writer semantics because each
|
|
35
|
+
* actor owns one SQLite database.
|
|
36
|
+
* SQLite invokes this VFS with byte-range file operations. This VFS maps those
|
|
37
|
+
* ranges onto fixed-size KV chunks keyed by file tag and chunk index.
|
|
38
|
+
* We intentionally rely on SQLite's pager cache for hot page reuse and do not
|
|
39
|
+
* add a second cache in this VFS. This avoids duplicate cache invalidation
|
|
40
|
+
* logic and keeps memory usage predictable for each actor.
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Common interface for database handles returned by ISqliteVfs.open().
|
|
45
|
+
* Both the concrete Database class and the pool's TrackedDatabase wrapper
|
|
46
|
+
* implement this, so consumers can use either interchangeably.
|
|
47
|
+
*/
|
|
48
|
+
interface IDatabase {
|
|
49
|
+
exec(sql: string, callback?: (row: unknown[], columns: string[]) => void): Promise<void>;
|
|
50
|
+
run(sql: string, params?: SqliteBindings): Promise<void>;
|
|
51
|
+
query(sql: string, params?: SqliteBindings): Promise<{
|
|
52
|
+
rows: unknown[][];
|
|
53
|
+
columns: string[];
|
|
54
|
+
}>;
|
|
55
|
+
close(): Promise<void>;
|
|
56
|
+
readonly fileName: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Common interface for SQLite VFS backends. Both standalone SqliteVfs and
|
|
60
|
+
* PooledSqliteHandle implement this so callers can use either interchangeably.
|
|
61
|
+
*/
|
|
62
|
+
interface ISqliteVfs {
|
|
63
|
+
open(fileName: string, options: KvVfsOptions): Promise<IDatabase>;
|
|
64
|
+
destroy(): Promise<void>;
|
|
65
|
+
}
|
|
66
|
+
type SQLite3Api = ReturnType<typeof Factory>;
|
|
67
|
+
type SqliteBindings = Parameters<SQLite3Api["bind_collection"]>[1];
|
|
68
|
+
/**
|
|
69
|
+
* Simple async mutex for serializing database operations
|
|
70
|
+
* @rivetkit/sqlite calls are not safe to run concurrently on one module instance
|
|
71
|
+
*/
|
|
72
|
+
declare class AsyncMutex {
|
|
73
|
+
#private;
|
|
74
|
+
acquire(): Promise<void>;
|
|
75
|
+
release(): void;
|
|
76
|
+
run<T>(fn: () => Promise<T>): Promise<T>;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Database wrapper that provides a simplified SQLite API
|
|
80
|
+
*/
|
|
81
|
+
declare class Database implements IDatabase {
|
|
82
|
+
#private;
|
|
83
|
+
constructor(sqlite3: SQLite3Api, handle: number, fileName: string, onClose: () => Promise<void>, sqliteMutex: AsyncMutex);
|
|
84
|
+
/**
|
|
85
|
+
* Execute SQL with optional row callback
|
|
86
|
+
* @param sql - SQL statement to execute
|
|
87
|
+
* @param callback - Called for each result row with (row, columns)
|
|
88
|
+
*/
|
|
89
|
+
exec(sql: string, callback?: (row: unknown[], columns: string[]) => void): Promise<void>;
|
|
90
|
+
/**
|
|
91
|
+
* Execute a parameterized SQL statement (no result rows)
|
|
92
|
+
* @param sql - SQL statement with ? placeholders
|
|
93
|
+
* @param params - Parameter values to bind
|
|
94
|
+
*/
|
|
95
|
+
run(sql: string, params?: SqliteBindings): Promise<void>;
|
|
96
|
+
/**
|
|
97
|
+
* Execute a parameterized SQL query and return results
|
|
98
|
+
* @param sql - SQL query with ? placeholders
|
|
99
|
+
* @param params - Parameter values to bind
|
|
100
|
+
* @returns Object with rows (array of arrays) and columns (column names)
|
|
101
|
+
*/
|
|
102
|
+
query(sql: string, params?: SqliteBindings): Promise<{
|
|
103
|
+
rows: unknown[][];
|
|
104
|
+
columns: string[];
|
|
105
|
+
}>;
|
|
106
|
+
/**
|
|
107
|
+
* Close the database
|
|
108
|
+
*/
|
|
109
|
+
close(): Promise<void>;
|
|
110
|
+
/**
|
|
111
|
+
* Get the database file name
|
|
112
|
+
*/
|
|
113
|
+
get fileName(): string;
|
|
114
|
+
/**
|
|
115
|
+
* Get the raw @rivetkit/sqlite API (for advanced usage)
|
|
116
|
+
*/
|
|
117
|
+
get sqlite3(): SQLite3Api;
|
|
118
|
+
/**
|
|
119
|
+
* Get the raw database handle (for advanced usage)
|
|
120
|
+
*/
|
|
121
|
+
get handle(): number;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* SQLite VFS backed by KV storage.
|
|
125
|
+
*
|
|
126
|
+
* Each instance is independent and has its own @rivetkit/sqlite WASM module.
|
|
127
|
+
* This allows multiple instances to operate concurrently without interference.
|
|
128
|
+
*/
|
|
129
|
+
declare class SqliteVfs implements ISqliteVfs {
|
|
130
|
+
#private;
|
|
131
|
+
constructor(wasmModule?: WebAssembly.Module);
|
|
132
|
+
/**
|
|
133
|
+
* Open a SQLite database using KV storage backend
|
|
134
|
+
*
|
|
135
|
+
* @param fileName - The database file name (typically the actor ID)
|
|
136
|
+
* @param options - KV storage operations for this database
|
|
137
|
+
* @returns A Database instance
|
|
138
|
+
*/
|
|
139
|
+
open(fileName: string, options: KvVfsOptions): Promise<IDatabase>;
|
|
140
|
+
/**
|
|
141
|
+
* Force-close all Database handles whose fileName exactly matches the
|
|
142
|
+
* given name. Snapshots the set to an array before iterating to avoid
|
|
143
|
+
* mutation during async iteration.
|
|
144
|
+
*
|
|
145
|
+
* Uses exact file name match because short names are numeric strings
|
|
146
|
+
* ('0', '1', ..., '10', '11', ...) and a prefix match like
|
|
147
|
+
* startsWith('1') would incorrectly match '10', '11', etc., causing
|
|
148
|
+
* cross-actor corruption. Sidecar files (-journal, -wal, -shm) are not
|
|
149
|
+
* tracked as separate Database handles, so prefix matching for sidecars
|
|
150
|
+
* is not needed.
|
|
151
|
+
*/
|
|
152
|
+
forceCloseByFileName(fileName: string): Promise<{
|
|
153
|
+
allSucceeded: boolean;
|
|
154
|
+
}>;
|
|
155
|
+
/**
|
|
156
|
+
* Force-close all open Database handles. Best-effort: errors are
|
|
157
|
+
* swallowed so this is safe to call during instance teardown.
|
|
158
|
+
*/
|
|
159
|
+
forceCloseAll(): Promise<void>;
|
|
160
|
+
/**
|
|
161
|
+
* Tears down this VFS instance and releases internal references.
|
|
162
|
+
*/
|
|
163
|
+
destroy(): Promise<void>;
|
|
164
|
+
/**
|
|
165
|
+
* Alias for destroy to align with DB-style lifecycle naming.
|
|
166
|
+
*/
|
|
167
|
+
close(): Promise<void>;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* SQLite VFS Pool - shares WASM SQLite instances across actors to reduce
|
|
172
|
+
* memory overhead. Instead of one WASM module per actor, multiple actors
|
|
173
|
+
* share a single instance, with short file names routing to separate KV
|
|
174
|
+
* namespaces.
|
|
175
|
+
*/
|
|
176
|
+
|
|
177
|
+
interface SqliteVfsPoolConfig {
|
|
178
|
+
actorsPerInstance: number;
|
|
179
|
+
idleDestroyMs?: number;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Manages a pool of SqliteVfs instances, assigning actors to instances using
|
|
183
|
+
* bin-packing to maximize density. The WASM module is compiled once and
|
|
184
|
+
* reused across all instances.
|
|
185
|
+
*/
|
|
186
|
+
declare class SqliteVfsPool {
|
|
187
|
+
#private;
|
|
188
|
+
constructor(config: SqliteVfsPoolConfig);
|
|
189
|
+
/** Number of live WASM instances in the pool. */
|
|
190
|
+
get instanceCount(): number;
|
|
191
|
+
/** Number of actors currently assigned to pool instances. */
|
|
192
|
+
get actorCount(): number;
|
|
193
|
+
/**
|
|
194
|
+
* Acquire a pooled VFS handle for the given actor. Returns a
|
|
195
|
+
* PooledSqliteHandle with sticky assignment. If the actor is already
|
|
196
|
+
* assigned, the existing handle is returned.
|
|
197
|
+
*
|
|
198
|
+
* Bin-packing: picks the instance with the most actors that still has
|
|
199
|
+
* capacity. If all instances are full, creates a new one using the
|
|
200
|
+
* cached WASM module.
|
|
201
|
+
*/
|
|
202
|
+
acquire(actorId: string): Promise<PooledSqliteHandle>;
|
|
203
|
+
/**
|
|
204
|
+
* Release an actor's assignment from the pool. Force-closes all database
|
|
205
|
+
* handles for the actor, recycles or poisons the short name, and
|
|
206
|
+
* decrements the instance refcount.
|
|
207
|
+
*/
|
|
208
|
+
release(actorId: string): Promise<void>;
|
|
209
|
+
/**
|
|
210
|
+
* Open a database on behalf of an actor, tracked as an in-flight
|
|
211
|
+
* operation. Used by PooledSqliteHandle to avoid exposing PoolInstance.
|
|
212
|
+
*/
|
|
213
|
+
openForActor(actorId: string, shortName: string, options: KvVfsOptions): Promise<IDatabase>;
|
|
214
|
+
/**
|
|
215
|
+
* Track an in-flight database operation for the given actor. Resolves the
|
|
216
|
+
* actor's pool instance and wraps the operation with opsInFlight tracking.
|
|
217
|
+
* If the actor has already been released, the operation runs without
|
|
218
|
+
* tracking since the instance may already be destroyed.
|
|
219
|
+
*/
|
|
220
|
+
trackOpForActor<T>(actorId: string, fn: () => Promise<T>): Promise<T>;
|
|
221
|
+
/**
|
|
222
|
+
* Graceful shutdown. Rejects new acquire() calls, cancels idle timers,
|
|
223
|
+
* force-closes all databases, destroys all VFS instances, and clears pool
|
|
224
|
+
* state.
|
|
225
|
+
*/
|
|
226
|
+
shutdown(): Promise<void>;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* A pooled VFS handle for a single actor. Implements ISqliteVfs so callers
|
|
230
|
+
* can use it interchangeably with a standalone SqliteVfs. The short name
|
|
231
|
+
* assigned by the pool is used as the VFS file path, while the caller's
|
|
232
|
+
* KvVfsOptions routes data to the correct KV namespace.
|
|
233
|
+
*/
|
|
234
|
+
declare class PooledSqliteHandle implements ISqliteVfs {
|
|
235
|
+
#private;
|
|
236
|
+
constructor(shortName: string, actorId: string, pool: SqliteVfsPool);
|
|
237
|
+
/**
|
|
238
|
+
* Open a database on the shared instance. Uses the pool-assigned short
|
|
239
|
+
* name as the VFS file path, with the caller's KvVfsOptions for KV
|
|
240
|
+
* routing. The open call itself is tracked as an in-flight operation,
|
|
241
|
+
* and the returned Database is wrapped so that exec(), run(), query(),
|
|
242
|
+
* and close() are also tracked via opsInFlight.
|
|
243
|
+
*/
|
|
244
|
+
open(_fileName: string, options: KvVfsOptions): Promise<IDatabase>;
|
|
245
|
+
/**
|
|
246
|
+
* Release this actor's assignment back to the pool. Idempotent: calling
|
|
247
|
+
* destroy() more than once is a no-op, preventing double-release from
|
|
248
|
+
* decrementing the instance refcount below actual.
|
|
249
|
+
*/
|
|
250
|
+
destroy(): Promise<void>;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export { Database, type IDatabase, type ISqliteVfs, type KvVfsOptions, PooledSqliteHandle, SqliteVfs, SqliteVfsPool, type SqliteVfsPoolConfig };
|