@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.
@@ -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 };