@evolu/sqlite-wasm 2.2.4 → 3.53.4-build1
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 +55 -218
- package/dist/src/CApi.d.ts +2108 -0
- package/dist/src/CApi.d.ts.map +1 -0
- package/dist/src/CApi.js +1919 -0
- package/dist/src/Constants.d.ts +868 -0
- package/dist/src/Constants.d.ts.map +1 -0
- package/dist/src/Constants.js +602 -0
- package/dist/src/Database.d.ts +641 -0
- package/dist/src/Database.d.ts.map +1 -0
- package/dist/src/Database.js +1177 -0
- package/dist/src/Memory.d.ts +119 -0
- package/dist/src/Memory.d.ts.map +1 -0
- package/dist/src/Memory.js +207 -0
- package/dist/src/Pointer.d.ts +100 -0
- package/dist/src/Pointer.d.ts.map +1 -0
- package/dist/src/Pointer.js +15 -0
- package/dist/src/SahPool.d.ts +744 -0
- package/dist/src/SahPool.d.ts.map +1 -0
- package/dist/src/SahPool.js +1985 -0
- package/dist/src/Wasm.d.ts +315 -0
- package/dist/src/Wasm.d.ts.map +1 -0
- package/dist/src/Wasm.js +756 -0
- package/dist/src/WasmUrl.d.ts +21 -0
- package/dist/src/WasmUrl.d.ts.map +1 -0
- package/dist/src/WasmUrl.js +20 -0
- package/dist/src/c-api/index.d.ts +9 -0
- package/dist/src/c-api/index.d.ts.map +1 -0
- package/dist/src/c-api/index.js +8 -0
- package/dist/src/index.d.ts +15 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +13 -0
- package/dist/wasm/sqlite3.wasm +0 -0
- package/package.json +60 -60
- package/src/CApi.test.ts +217 -0
- package/src/CApi.ts +3294 -0
- package/src/Constants.ts +803 -0
- package/src/Database.ts +1714 -0
- package/src/Memory.test.ts +319 -0
- package/src/Memory.ts +237 -0
- package/src/Pointer.ts +121 -0
- package/src/SahPool.test.ts +180 -0
- package/src/SahPool.ts +2627 -0
- package/src/Wasm.test.ts +444 -0
- package/src/Wasm.ts +1026 -0
- package/src/WasmUrl.ts +26 -0
- package/src/c-api/index.ts +9 -0
- package/src/index.ts +15 -0
- package/bin/index.js +0 -110
- package/index.d.ts +0 -8118
- package/index.mjs +0 -7
- package/node.mjs +0 -3
- package/sqlite-wasm/jswasm/sqlite3-bundler-friendly.mjs +0 -13659
- package/sqlite-wasm/jswasm/sqlite3-node.mjs +0 -11671
- package/sqlite-wasm/jswasm/sqlite3-opfs-async-proxy.js +0 -691
- package/sqlite-wasm/jswasm/sqlite3-worker1-bundler-friendly.mjs +0 -35
- package/sqlite-wasm/jswasm/sqlite3-worker1-promiser.js +0 -193
- package/sqlite-wasm/jswasm/sqlite3-worker1-promiser.mjs +0 -187
- package/sqlite-wasm/jswasm/sqlite3-worker1.js +0 -46
- package/sqlite-wasm/jswasm/sqlite3.js +0 -13697
- package/sqlite-wasm/jswasm/sqlite3.mjs +0 -13661
- package/sqlite-wasm/jswasm/sqlite3.wasm +0 -0
|
@@ -0,0 +1,641 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Evolu's SQLite API: databases and statements over the CApi functions, with
|
|
3
|
+
* typed errors and explicit resource management.
|
|
4
|
+
*
|
|
5
|
+
* Status: {@link createSqliteDatabase} opens Memory databases, and File and
|
|
6
|
+
* EncryptedFile databases on a {@link SqliteVfs} or {@link SqliteEncryptingVfs},
|
|
7
|
+
* which a {@link SahPool} is, and {@link createEncryptedSqliteDatabase} also
|
|
8
|
+
* opens the encrypted databases `@evolu/web` 3 created with
|
|
9
|
+
* `@evolu/sqlite-wasm` 2.2.4 in a pool. The pool's own encryption is tested in
|
|
10
|
+
* Node.js over a fake OPFS against 2.2.4, which creates databases as
|
|
11
|
+
* `@evolu/web` does and leaves a hot journal the pool rolls back, and in
|
|
12
|
+
* Chromium, Firefox and WebKit on real OPFS against 2.2.4.
|
|
13
|
+
*
|
|
14
|
+
* ## Calls
|
|
15
|
+
*
|
|
16
|
+
* - Synchronous. Every call returns when SQLite returns. The only asynchronous
|
|
17
|
+
* step, deriving a legacy key with WebCrypto, runs between the two opens of
|
|
18
|
+
* {@link createEncryptedSqliteDatabase}.
|
|
19
|
+
* - Bound once per database. {@link createSqliteDatabase} binds the C functions
|
|
20
|
+
* and memory helpers it needs and allocates one {@link SqliteScratch}; running
|
|
21
|
+
* a statement then calls wasm exports directly.
|
|
22
|
+
* - Every fallible call returns a Result. {@link SqliteError} copies
|
|
23
|
+
* `sqlite3_errmsg` and `sqlite3_extended_errcode` right after the failing
|
|
24
|
+
* call, before any other call on the connection replaces them. It copies
|
|
25
|
+
* `sqlite3_error_offset` only for SQLITE_ERROR from prepare, exec or step,
|
|
26
|
+
* the code of the parser errors that set it, because SQLite keeps an offset
|
|
27
|
+
* until a later prepare succeeds or a statement resets.
|
|
28
|
+
* - The VFS records the first failure since the last top-level call (open,
|
|
29
|
+
* prepare, run, exec, export), and {@link SqliteError.cause} carries it. The
|
|
30
|
+
* database clears the record before each such call. A call that runs inside
|
|
31
|
+
* another call of a database on the same VFS, as a query a callback runs
|
|
32
|
+
* does, is not top-level, so it leaves the record to the outer call.
|
|
33
|
+
* - Every call, disposal included, enters wasm through {@link SqliteWasm.call}. An
|
|
34
|
+
* exception or trap that escapes wasm, such as from a call through a disposed
|
|
35
|
+
* function pointer, is a defect: it is rethrown, and every later call on any
|
|
36
|
+
* database of the instance throws without entering wasm, because the C stack
|
|
37
|
+
* and SQLite's state are left inconsistent. A trap after a File or
|
|
38
|
+
* EncryptedFile connection opened reaches the caller of the open as a
|
|
39
|
+
* `SuppressedError` whose `suppressed` is the trap, because the open's
|
|
40
|
+
* deferred close and the free of its scratch memory are refused as it
|
|
41
|
+
* unwinds.
|
|
42
|
+
*
|
|
43
|
+
* ## Opening
|
|
44
|
+
*
|
|
45
|
+
* - A Memory database opens `:memory:` on the default VFS.
|
|
46
|
+
* - A File or EncryptedFile database's path is a {@link SqliteVfsPath}, a
|
|
47
|
+
* canonical path, which SQLite passes to the VFS as it is, never as a URI or
|
|
48
|
+
* an in-memory database, followed by the name of the VFS.
|
|
49
|
+
* - A File or EncryptedFile database opens its path on its VFS, an EncryptedFile
|
|
50
|
+
* database keyed as the next section describes. Either then prepares a query
|
|
51
|
+
* of `sqlite_schema`, because SQLite reads a file only when a statement needs
|
|
52
|
+
* it. So the open rolls back a hot journal, and fails for a file that is not
|
|
53
|
+
* a database, with SQLITE_NOTADB, or for a hot journal that cannot be rolled
|
|
54
|
+
* back.
|
|
55
|
+
* - The database uses its VFS only through {@link SqliteVfs} or
|
|
56
|
+
* {@link SqliteEncryptingVfs}, so any VFS that implements them can hold it,
|
|
57
|
+
* and a driver can open each database on the VFS that has it, as
|
|
58
|
+
* {@link SqliteVfs.getPaths} tells.
|
|
59
|
+
* - Flags are READWRITE, CREATE and EXRESCODE, so failures during the open
|
|
60
|
+
* already carry extended codes.
|
|
61
|
+
* - When the open fails, the message is read first and then the handle SQLite
|
|
62
|
+
* returned anyway is closed with `sqlite3_close_v2`. Without a handle, as
|
|
63
|
+
* when memory runs out, the error is the open's result code.
|
|
64
|
+
*
|
|
65
|
+
* ## Encryption
|
|
66
|
+
*
|
|
67
|
+
* - The VFS encrypts an EncryptedFile database itself, and a {@link SahPool} does
|
|
68
|
+
* it as SQLite3 Multiple Ciphers' `sqlcipher` scheme did with its default
|
|
69
|
+
* parameters, those of SQLCipher 4, which `PRAGMA cipher = 'sqlcipher'`
|
|
70
|
+
* selected in `@evolu/web` 3 with 2.2.4. The open registers the key for the
|
|
71
|
+
* path with {@link SqliteEncryptingVfs.registerKey} before it enters wasm and
|
|
72
|
+
* disposes the registration when it returns, by when the VFS has taken the
|
|
73
|
+
* key for the database file; the module documentation of `SahPool.ts`
|
|
74
|
+
* describes the pool's format. The key never appears in SQL, a URI, an error
|
|
75
|
+
* or SQLite's memory, and the caller's key is never modified.
|
|
76
|
+
* - Then `sqlite3_file_control` with SQLITE_FCNTL_RESERVE_BYTES asks for 80 bytes
|
|
77
|
+
* at the end of each page, where the pool keeps the page's IV and HMAC, which
|
|
78
|
+
* takes effect for a new database, and `PRAGMA secure_delete = ON` makes
|
|
79
|
+
* deletes overwrite freed content, as SQLite3 Multiple Ciphers did for every
|
|
80
|
+
* encrypted connection. A {@link SahPool} refuses to turn it off for an
|
|
81
|
+
* encrypted database, because a freed page SQLite does not write would fail
|
|
82
|
+
* to authenticate, as `SahPool.ts` describes.
|
|
83
|
+
* - Registering validates nothing, so the read of `sqlite_schema` checks the key.
|
|
84
|
+
* A wrong key fails there with SQLITE_NOTADB, from page 1, or with
|
|
85
|
+
* SQLITE_CORRUPT when the first page of a hot journal is another page, and
|
|
86
|
+
* {@link SqliteError.cause} is the VFS's {@link SqlitePageAuthenticationError}.
|
|
87
|
+
* The rollback stops at that first page, which fails to authenticate, so it
|
|
88
|
+
* writes no page of the journal and keeps the journal for the right key.
|
|
89
|
+
* Before that page, SQLite truncates the database to the size the journal
|
|
90
|
+
* records, as the right key's rollback does too. It would extend a shorter
|
|
91
|
+
* database by one zeroed page, encrypted with the wrong key, but a commit
|
|
92
|
+
* shrinks the file only after it deletes the journal, and a pool refuses a
|
|
93
|
+
* VACUUM that would change an encrypted database's page size, so no database
|
|
94
|
+
* is shorter than its hot journal records.
|
|
95
|
+
* - `@evolu/web` with 2.2.4 ran `PRAGMA key = "x'<hex>'"`, SQLCipher's notation
|
|
96
|
+
* for a raw key, which SQLite3 Multiple Ciphers 2.2.4 took as a passphrase
|
|
97
|
+
* because of a bug
|
|
98
|
+
* (https://github.com/utelle/SQLite3MultipleCiphers/issues/218, fixed in
|
|
99
|
+
* 2.2.5), deriving the key with the `sqlcipher` scheme, so those databases
|
|
100
|
+
* fail as with a wrong key. {@link createEncryptedSqliteDatabase} then opens
|
|
101
|
+
* them with the key {@link deriveLegacySqliteKey} derives through
|
|
102
|
+
* {@link SubtleCryptoDep}, and {@link SqliteEncryptedDatabase.keyDerivation}
|
|
103
|
+
* says which key opened the database. Nothing rekeys a database.
|
|
104
|
+
* - `@evolu/web` 1.0.1-preview.6 to 2.4.0 also ran `PRAGMA legacy = 4`, so the
|
|
105
|
+
* databases it encrypted fail with SQLITE_NOTADB, as with a wrong key, since
|
|
106
|
+
* page 1 is encrypted from byte 16; they have not opened since `@evolu/web`
|
|
107
|
+
* 3.0.0 (see `SahPool.ts`).
|
|
108
|
+
* - Only page 1 of the database or a record of its journal that failed to
|
|
109
|
+
* authenticate counts as a wrong key. Another page of the database that fails
|
|
110
|
+
* means that page 1 proved the key and the page is damaged, so it fails with
|
|
111
|
+
* SQLITE_CORRUPT and that page as the cause, also with the key 2.2.4 derived.
|
|
112
|
+
* An I/O error fails with its own code, and the VFS's record as its cause,
|
|
113
|
+
* and a database whose pages authenticate but whose content is malformed
|
|
114
|
+
* fails with SQLite's code and no cause.
|
|
115
|
+
*
|
|
116
|
+
* ## Statements
|
|
117
|
+
*
|
|
118
|
+
* - SQL is copied into its own memory, which is freed when the call returns,
|
|
119
|
+
* because SQLite parses it in place and copies a statement's SQL, which a
|
|
120
|
+
* schema change prepares again, only after the parse. Meanwhile a callback,
|
|
121
|
+
* such as a collation-needed callback during the parse or a function during a
|
|
122
|
+
* step of {@link SqliteDatabase.exec}, can run a query on the same database,
|
|
123
|
+
* and that query reuses the scratch memory.
|
|
124
|
+
* - `sqlite3_prepare_v3` gets the SQL's byte length, counting a NUL terminator,
|
|
125
|
+
* which spares SQLite a copy, and, for statements
|
|
126
|
+
* {@link SqliteDatabase.prepare} returns, SQLITE_PREPARE_PERSISTENT. Empty SQL
|
|
127
|
+
* and SQL with more than one statement are errors, so nothing after the first
|
|
128
|
+
* statement is silently ignored. SQLite reads SQL only up to a NUL character,
|
|
129
|
+
* and UTF-8 cannot encode a lone surrogate, which encoding would replace with
|
|
130
|
+
* U+FFFD, so SQL that contains either fails with
|
|
131
|
+
* {@link SqliteInvalidSqlTextError} before SQLite sees it, in
|
|
132
|
+
* {@link SqliteDatabase.exec} too.
|
|
133
|
+
* - A second statement is found by scanning the rest of the SQL as SQLite
|
|
134
|
+
* 3.53.4's tokenizer reads it, not by preparing it, because SQLite applies
|
|
135
|
+
* many pragmas, such as `foreign_keys`, when it prepares them, so SQL that
|
|
136
|
+
* fails with {@link SqliteMultipleStatementsError} would still change the
|
|
137
|
+
* connection. Only semicolons, whitespace, UTF-8 byte order marks and
|
|
138
|
+
* comments may follow the first statement. A pragma in the first statement
|
|
139
|
+
* still takes effect when the SQL then fails, as SQLite documents for prepare
|
|
140
|
+
* (https://sqlite.org/pragma.html).
|
|
141
|
+
* - {@link SqliteDatabase.exec} prepares each statement where the previous one
|
|
142
|
+
* ended and steps it to completion, so {@link SqliteError.sqlOffset} counts
|
|
143
|
+
* from the start of the whole SQL.
|
|
144
|
+
* - Parameters are positional. Their number is read once at prepare and a run
|
|
145
|
+
* with a different number fails, so no binding leaks from a previous run.
|
|
146
|
+
* {@link SqliteDatabase.exec} binds none, so a statement with a parameter
|
|
147
|
+
* fails there without running, rather than run with NULL.
|
|
148
|
+
* - Binding: null binds NULL; a 32-bit integer binds with `sqlite3_bind_int`;
|
|
149
|
+
* another safe integer with `sqlite3_bind_int64`, so it stays INTEGER; any
|
|
150
|
+
* other number with `sqlite3_bind_double`. Text is encoded with `encodeInto`
|
|
151
|
+
* and bytes are copied into the scratch memory, both bound with
|
|
152
|
+
* SQLITE_TRANSIENT and an explicit byte length, so embedded NUL characters
|
|
153
|
+
* survive and an empty value stays non-NULL. A value that can take more than
|
|
154
|
+
* 64 KiB, counting 3 bytes per UTF-16 code unit of text, is allocated exactly
|
|
155
|
+
* and handed over with SQLITE_WASM_DEALLOC instead, so the scratch memory
|
|
156
|
+
* does not keep the size of the largest value, and SQLite does not copy it
|
|
157
|
+
* twice. Such text is encoded into a new array first, and when JavaScript
|
|
158
|
+
* cannot allocate it, the run fails with SQLITE_NOMEM and the operation
|
|
159
|
+
* `bind`, while the instance keeps working, because the encoding runs no
|
|
160
|
+
* wasm. {@link SqliteDatabase.exec} copies its SQL the same way and fails with
|
|
161
|
+
* the operation `exec`. SQLite keeps a bound value until its parameter is
|
|
162
|
+
* bound again, so a run that handed a value over clears the bindings before
|
|
163
|
+
* it returns, also when it fails, and a prepared statement keeps no large
|
|
164
|
+
* value between runs, while smaller ones keep the buffers SQLite reuses for
|
|
165
|
+
* them. A {@link SqliteValue} string may contain a lone surrogate, which UTF-8
|
|
166
|
+
* cannot encode, so text binds it as U+FFFD, as better-sqlite3 does.
|
|
167
|
+
* - Reading: `sqlite3_column_type` first. INTEGER and FLOAT read with
|
|
168
|
+
* `sqlite3_column_double`, so no BigInt is created; integers beyond 2^53 lose
|
|
169
|
+
* precision, as in better-sqlite3. TEXT reads the pointer, then the byte
|
|
170
|
+
* length, and decodes keeping a leading byte order mark. A BLOB is one copy
|
|
171
|
+
* into its own `ArrayBuffer`, so it can be transferred. With the type read
|
|
172
|
+
* first, a NULL pointer is never SQL NULL: for TEXT it is SQLITE_NOMEM, and
|
|
173
|
+
* for a BLOB it is an empty value unless `sqlite3_errcode`, read right after,
|
|
174
|
+
* returns SQLITE_NOMEM. A NULL column name is SQLITE_NOMEM too, and so is a
|
|
175
|
+
* TEXT or BLOB that JavaScript cannot allocate a copy of, whatever error the
|
|
176
|
+
* engine throws then, because the copy runs no wasm, so the instance keeps
|
|
177
|
+
* working. Each fails the run with the operation `step`. Rows are
|
|
178
|
+
* null-prototype objects, so a column named `__proto__` is an ordinary
|
|
179
|
+
* property, and of columns with the same name, the last one wins.
|
|
180
|
+
* - Column names are read after the first row and cached with the statement's
|
|
181
|
+
* SQLITE_STMTSTATUS_REPREPARE counter. A schema change re-prepares the
|
|
182
|
+
* statement, and `SELECT *` then returns other columns, so the names are read
|
|
183
|
+
* again when the counter changed.
|
|
184
|
+
* - {@link SqliteStatement.run} always resets the statement, so it is reusable
|
|
185
|
+
* after an error, and ignores the result: SQLITE_OK after SQLITE_DONE, and a
|
|
186
|
+
* failed step's error again after it. A deferred constraint or commit failure
|
|
187
|
+
* comes from the last step, so it is not lost. A run whose read fails is cut
|
|
188
|
+
* short, and its reset completes the statement, so a write with RETURNING is
|
|
189
|
+
* committed although the run fails.
|
|
190
|
+
* - `changes` compares `sqlite3_total_changes64` before and after the run: 0 when
|
|
191
|
+
* it did not move, `sqlite3_changes64` otherwise, as in better-sqlite3, and
|
|
192
|
+
* unlike it also 0 when `sqlite3_stmt_readonly` is true, as for a SELECT
|
|
193
|
+
* whose function writes. SQLite keeps one count per connection, of the last
|
|
194
|
+
* INSERT, UPDATE or DELETE that finished, so reading it alone would report a
|
|
195
|
+
* stale count after a SELECT or DDL. {@link SqliteRunResult.changes} says
|
|
196
|
+
* which writes the count can come from.
|
|
197
|
+
* - A callback may run queries on the database, but SQLite forbids resetting or
|
|
198
|
+
* finalizing a statement that is stepping and closing a connection while it
|
|
199
|
+
* runs. So running or disposing a statement during its own run, and disposing
|
|
200
|
+
* the database while one of its operations runs, throw before wasm is
|
|
201
|
+
* entered, and the instance keeps working. A callback installed with
|
|
202
|
+
* `installWasmFunctions` then fails as a defect.
|
|
203
|
+
*
|
|
204
|
+
* ## Exporting and closing
|
|
205
|
+
*
|
|
206
|
+
* - {@link SqliteDatabase.export} calls `sqlite3_serialize(db, NULL, &size, 0)`
|
|
207
|
+
* for the main schema, copies the pages into their own `ArrayBuffer` and
|
|
208
|
+
* frees SQLite's copy. The size has its own memory, because SQLite writes it
|
|
209
|
+
* before it finalizes its query, whose trace callback can run a query on the
|
|
210
|
+
* same database. `sqlite3_serialize` does not report a failed allocation to
|
|
211
|
+
* the connection, so the connection's error is cleared with
|
|
212
|
+
* `sqlite3_set_errmsg` first, and NULL then fails with the error the
|
|
213
|
+
* connection reports, or else SQLITE_NOMEM, as when JavaScript cannot
|
|
214
|
+
* allocate the copy of the pages, which still frees SQLite's copy. SQLite
|
|
215
|
+
* gives an empty database its first page before copying, so NULL with a size
|
|
216
|
+
* of 0 and no error is only a database that has no pages and cannot get one,
|
|
217
|
+
* such as a read-only empty one, which exports as zero bytes. Pages come
|
|
218
|
+
* through the pager, so an encrypted database exports as plaintext. SQLite
|
|
219
|
+
* zero-fills a page that fails to read and reports success, so the export of
|
|
220
|
+
* a File or EncryptedFile database fails when its VFS recorded a failure
|
|
221
|
+
* during it, caused by the VFS's record: with SQLITE_CORRUPT for a page that
|
|
222
|
+
* failed to authenticate, a {@link SqlitePageAuthenticationError}, and with
|
|
223
|
+
* SQLITE_IOERR otherwise.
|
|
224
|
+
* - Disposing a database finalizes its statements that are still open and then
|
|
225
|
+
* calls `sqlite3_close_v2`, so no deferred close keeps the VFS's files open.
|
|
226
|
+
*
|
|
227
|
+
* @module
|
|
228
|
+
*/
|
|
229
|
+
import { type EncryptionKey, type Result, type SqliteRow, type SqliteValue, type Task, type Typed, type TypeError } from "@evolu/common";
|
|
230
|
+
import { type SqlitePrimaryResultCode, type SqliteResultCode } from "./Constants.ts";
|
|
231
|
+
import { type SahPool } from "./SahPool.ts";
|
|
232
|
+
import type { SqliteWasmDep } from "./Wasm.ts";
|
|
233
|
+
/**
|
|
234
|
+
* An open SQLite database. Disposing it while one of its operations runs, as
|
|
235
|
+
* from a callback, throws.
|
|
236
|
+
*/
|
|
237
|
+
export interface SqliteDatabase extends Disposable {
|
|
238
|
+
/** Prepares one statement for repeated runs. */
|
|
239
|
+
readonly prepare: (sql: string) => Result<SqliteStatement, SqlitePrepareError>;
|
|
240
|
+
/**
|
|
241
|
+
* Prepares one statement, runs it once as {@link SqliteStatement.run} does and
|
|
242
|
+
* finalizes it.
|
|
243
|
+
*
|
|
244
|
+
* Without SQLITE_PREPARE_PERSISTENT, SQLite prepares it from its lookaside
|
|
245
|
+
* memory, so a statement that runs once is faster than one from
|
|
246
|
+
* {@link SqliteDatabase.prepare}: about 20% for a typical query in Node.js
|
|
247
|
+
* 24.
|
|
248
|
+
*/
|
|
249
|
+
readonly run: (sql: string, parameters: ReadonlyArray<SqliteValue>) => Result<SqliteRunResult, SqlitePrepareError | SqliteRunError>;
|
|
250
|
+
/**
|
|
251
|
+
* Runs SQL that can hold several statements, without parameters, and discards
|
|
252
|
+
* any rows. Meant for schema changes and pragmas.
|
|
253
|
+
*
|
|
254
|
+
* It runs the statements in order and stops at the first that fails. A
|
|
255
|
+
* statement with a parameter fails with {@link SqliteParameterCountError}
|
|
256
|
+
* without running, so no parameter silently binds NULL.
|
|
257
|
+
*/
|
|
258
|
+
readonly exec: (sql: string) => Result<void, SqliteExecError>;
|
|
259
|
+
/**
|
|
260
|
+
* Returns the whole database as bytes backed by their own `ArrayBuffer`, so
|
|
261
|
+
* they can be transferred to another worker.
|
|
262
|
+
*/
|
|
263
|
+
readonly export: () => Result<Uint8Array<ArrayBuffer>, SqliteError>;
|
|
264
|
+
/**
|
|
265
|
+
* Whether no transaction is open.
|
|
266
|
+
*
|
|
267
|
+
* After errors such as SQLITE_FULL, SQLITE_IOERR or SQLITE_NOMEM, SQLite may
|
|
268
|
+
* roll back the transaction itself, and a ROLLBACK then fails. A transaction
|
|
269
|
+
* helper checks this before rolling back.
|
|
270
|
+
*/
|
|
271
|
+
readonly isAutocommit: () => boolean;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* A prepared statement. Running or disposing it during its own run, as from a
|
|
275
|
+
* callback, throws.
|
|
276
|
+
*/
|
|
277
|
+
export interface SqliteStatement extends Disposable {
|
|
278
|
+
/** The number of SQL parameters, which each run must supply exactly. */
|
|
279
|
+
readonly parameterCount: number;
|
|
280
|
+
/**
|
|
281
|
+
* Binds the parameters, steps to completion, collects the rows and resets the
|
|
282
|
+
* statement, also when a step fails.
|
|
283
|
+
*/
|
|
284
|
+
readonly run: (parameters: ReadonlyArray<SqliteValue>) => Result<SqliteRunResult, SqliteRunError>;
|
|
285
|
+
}
|
|
286
|
+
/** The result of {@link SqliteStatement.run}. */
|
|
287
|
+
export interface SqliteRunResult {
|
|
288
|
+
readonly rows: ReadonlyArray<SqliteRow>;
|
|
289
|
+
/**
|
|
290
|
+
* 0 for a read-only statement or a run that changed no rows, and otherwise
|
|
291
|
+
* SQLite's `sqlite3_changes64`: the rows the connection's last INSERT, UPDATE
|
|
292
|
+
* or DELETE that finished changed, without those of triggers, foreign key
|
|
293
|
+
* actions or REPLACE. For an INSERT, UPDATE or DELETE, that is its own count,
|
|
294
|
+
* unless a write on the same connection finished after it within the run, as
|
|
295
|
+
* one its profile trace callback runs. For another statement, it is the count
|
|
296
|
+
* of the last write that finished during the run, as one by a function it
|
|
297
|
+
* calls or by its trace callback.
|
|
298
|
+
*/
|
|
299
|
+
readonly changes: number;
|
|
300
|
+
}
|
|
301
|
+
/** An error SQLite reported. */
|
|
302
|
+
export interface SqliteError extends Typed<"SqliteError"> {
|
|
303
|
+
readonly operation: SqliteOperation;
|
|
304
|
+
/**
|
|
305
|
+
* The extended result code, whose primary result code
|
|
306
|
+
* {@link sqliteResultCodeToPrimary} returns.
|
|
307
|
+
*/
|
|
308
|
+
readonly extendedCode: SqliteResultCode;
|
|
309
|
+
/**
|
|
310
|
+
* From `sqlite3_errmsg`, or from `sqlite3_errstr` of the code when SQLite did
|
|
311
|
+
* not report the failure to the connection, as for an open without a handle,
|
|
312
|
+
* an allocation that failed, or an export whose VFS failed to read a page.
|
|
313
|
+
*/
|
|
314
|
+
readonly message: string;
|
|
315
|
+
/**
|
|
316
|
+
* The byte offset in the UTF-8 SQL where SQLite detected the error, from
|
|
317
|
+
* `sqlite3_error_offset` for a parser error (SQLITE_ERROR from prepare, exec
|
|
318
|
+
* or step); null for any other error or when the error has no position.
|
|
319
|
+
*/
|
|
320
|
+
readonly sqlOffset: number | null;
|
|
321
|
+
/**
|
|
322
|
+
* The first VFS failure since the top-level operation started, such as the
|
|
323
|
+
* `QuotaExceededError` behind SQLITE_FULL; null when the VFS reported none.
|
|
324
|
+
*/
|
|
325
|
+
readonly cause: SqliteVfsFailure | null;
|
|
326
|
+
}
|
|
327
|
+
/** The operation a {@link SqliteError} comes from. */
|
|
328
|
+
export type SqliteOperation = "open" | "prepare" | "bind" | "step" | "exec" | "export";
|
|
329
|
+
/**
|
|
330
|
+
* Returns the primary result code of a result code, its low 8 bits, such as
|
|
331
|
+
* SQLITE_CONSTRAINT for SQLITE_CONSTRAINT_NOTNULL. A primary result code
|
|
332
|
+
* returns itself.
|
|
333
|
+
*/
|
|
334
|
+
export declare const sqliteResultCodeToPrimary: (code: SqliteResultCode) => SqlitePrimaryResultCode;
|
|
335
|
+
/** A failure a VFS method recorded before returning an error code. */
|
|
336
|
+
export interface SqliteVfsFailure {
|
|
337
|
+
readonly method: SqliteVfsMethod;
|
|
338
|
+
/**
|
|
339
|
+
* The path of the file, or null for a method without one or a name that maps
|
|
340
|
+
* to no path.
|
|
341
|
+
*/
|
|
342
|
+
readonly path: string | null;
|
|
343
|
+
/**
|
|
344
|
+
* What the browser threw, such as a `DOMException`, or what the VFS found
|
|
345
|
+
* wrong, such as a {@link SqliteShortWriteError}, a
|
|
346
|
+
* {@link SqlitePageAuthenticationError}, a {@link SahPoolFullError}, a
|
|
347
|
+
* {@link SahPoolInvalidPathError}, or a
|
|
348
|
+
* {@link SahPoolEncryptionUnsupportedError}.
|
|
349
|
+
*/
|
|
350
|
+
readonly error: unknown;
|
|
351
|
+
}
|
|
352
|
+
/** A VFS or I/O method that can record a {@link SqliteVfsFailure}. */
|
|
353
|
+
export type SqliteVfsMethod = "xOpen" | "xDelete" | "xAccess" | "xClose" | "xRead" | "xWrite" | "xTruncate" | "xSync" | "xFileSize" | "xLock" | "xUnlock" | "xCheckReservedLock" | "xFileControl";
|
|
354
|
+
/**
|
|
355
|
+
* A write that stored fewer or more bytes than requested.
|
|
356
|
+
*
|
|
357
|
+
* Firefox reports a full disk with a short count, and Chromium's off-the-record
|
|
358
|
+
* storage has reported impossible counts; either way the data is not all there,
|
|
359
|
+
* so the write fails with SQLITE_FULL.
|
|
360
|
+
*/
|
|
361
|
+
export interface SqliteShortWriteError extends Typed<"SqliteShortWrite"> {
|
|
362
|
+
readonly requested: number;
|
|
363
|
+
readonly written: number;
|
|
364
|
+
}
|
|
365
|
+
/** Why {@link SqliteDatabase.prepare} failed. */
|
|
366
|
+
export type SqlitePrepareError = SqliteError | SqliteEmptySqlError | SqliteMultipleStatementsError | SqliteInvalidSqlTextError;
|
|
367
|
+
/** The SQL contains no statement, only whitespace or comments. */
|
|
368
|
+
export interface SqliteEmptySqlError extends Typed<"SqliteEmptySqlError"> {
|
|
369
|
+
}
|
|
370
|
+
/** The SQL contains more than one statement. */
|
|
371
|
+
export interface SqliteMultipleStatementsError extends Typed<"SqliteMultipleStatementsError"> {
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* The SQL is text SQLite would read as other SQL, so it fails before SQLite
|
|
375
|
+
* sees it: it contains a NUL character, which SQLite reads SQL only up to, so
|
|
376
|
+
* it would silently ignore the rest, or a lone surrogate, which UTF-8 cannot
|
|
377
|
+
* encode, so it would run with U+FFFD in its place.
|
|
378
|
+
*/
|
|
379
|
+
export interface SqliteInvalidSqlTextError extends Typed<"SqliteInvalidSqlText"> {
|
|
380
|
+
}
|
|
381
|
+
/** Why {@link SqliteDatabase.exec} failed. */
|
|
382
|
+
export type SqliteExecError = SqliteError | SqliteInvalidSqlTextError | SqliteParameterCountError;
|
|
383
|
+
/** Why {@link SqliteStatement.run} failed. */
|
|
384
|
+
export type SqliteRunError = SqliteError | SqliteParameterCountError;
|
|
385
|
+
/**
|
|
386
|
+
* A run supplied a different number of parameters than the SQL has, or
|
|
387
|
+
* {@link SqliteDatabase.exec}, which supplies none, met a statement with
|
|
388
|
+
* parameters.
|
|
389
|
+
*/
|
|
390
|
+
export interface SqliteParameterCountError extends Typed<"SqliteParameterCountError"> {
|
|
391
|
+
readonly expected: number;
|
|
392
|
+
readonly actual: number;
|
|
393
|
+
}
|
|
394
|
+
/** How to open a database. */
|
|
395
|
+
export type SqliteDatabaseOptions = SqliteMemoryDatabaseOptions | SqliteFileDatabaseOptions | SqliteEncryptedFileDatabaseOptions;
|
|
396
|
+
/**
|
|
397
|
+
* An in-memory database on the default VFS, which never touches OPFS. Temporary
|
|
398
|
+
* tables and indexes stay in memory in every mode.
|
|
399
|
+
*/
|
|
400
|
+
export interface SqliteMemoryDatabaseOptions extends Typed<"Memory"> {
|
|
401
|
+
}
|
|
402
|
+
/** An unencrypted database file on a {@link SqliteVfs}, such as a {@link SahPool}. */
|
|
403
|
+
export interface SqliteFileDatabaseOptions extends Typed<"File"> {
|
|
404
|
+
readonly vfs: SqliteVfs;
|
|
405
|
+
/**
|
|
406
|
+
* The canonical path of the file on the VFS, such as `/evolu1.db`, by which
|
|
407
|
+
* the VFS also lists and deletes it.
|
|
408
|
+
*/
|
|
409
|
+
readonly path: SqliteVfsPath;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* A database file on a {@link SqliteEncryptingVfs}, which encrypts it, as a
|
|
413
|
+
* {@link SahPool} does in the format of SQLite3 Multiple Ciphers' `sqlcipher`
|
|
414
|
+
* scheme.
|
|
415
|
+
*
|
|
416
|
+
* Only the database file and its journal are encrypted. `VACUUM INTO` and
|
|
417
|
+
* `ATTACH` open their file as a database of its own, which is encrypted only
|
|
418
|
+
* when a key is registered for its path with
|
|
419
|
+
* {@link SqliteEncryptingVfs.registerKey} while they open it. Otherwise they
|
|
420
|
+
* write it unencrypted, because SQLite ignores the `KEY` clause of `ATTACH` and
|
|
421
|
+
* `PRAGMA key`, `rekey` and `cipher`, where 2.2.4 encrypted both with the
|
|
422
|
+
* database's key, or with the `KEY` of `ATTACH`. A file that `ATTACH` creates
|
|
423
|
+
* cannot be encrypted, because SQLite reserves no bytes in it, so with a key
|
|
424
|
+
* registered its first write fails with SQLITE_IOERR_WRITE. `VACUUM INTO` keeps
|
|
425
|
+
* the reserved bytes, so it can create an encrypted copy, which `ATTACH` then
|
|
426
|
+
* opens with its key registered.
|
|
427
|
+
*/
|
|
428
|
+
export interface SqliteEncryptedFileDatabaseOptions extends Typed<"EncryptedFile"> {
|
|
429
|
+
readonly vfs: SqliteEncryptingVfs;
|
|
430
|
+
/**
|
|
431
|
+
* The path of the file on the VFS, as {@link SqliteFileDatabaseOptions.path}
|
|
432
|
+
* describes.
|
|
433
|
+
*/
|
|
434
|
+
readonly path: SqliteVfsPath;
|
|
435
|
+
/**
|
|
436
|
+
* The raw key, which {@link SqliteEncryptingVfs.registerKey} gets while the
|
|
437
|
+
* file opens.
|
|
438
|
+
*/
|
|
439
|
+
readonly key: EncryptionKey;
|
|
440
|
+
}
|
|
441
|
+
/** Error returned when a string is not a valid {@link SqliteVfsPath}. */
|
|
442
|
+
export interface SqliteVfsPathError extends TypeError<"SqliteVfsPath"> {
|
|
443
|
+
readonly value: string;
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* The canonical path of a database file on a {@link SqliteVfs}, such as
|
|
447
|
+
* `/evolu1.db`, one spelling per file, as {@link SqliteVfs.getPaths} lists it.
|
|
448
|
+
*
|
|
449
|
+
* A path is canonical when it is its own `new URL(path,
|
|
450
|
+
* "file://localhost/").pathname`, the path a {@link SahPool} maps a name to, so
|
|
451
|
+
* the VFS opens, lists and deletes the file by the path the database opened it
|
|
452
|
+
* with, and an EncryptedFile database registers its key for that file. A
|
|
453
|
+
* canonical path starts with `/` and is printable ASCII without `?` or `#`, so
|
|
454
|
+
* SQLite passes it to the VFS as it is, and the paths SQLite derives from it by
|
|
455
|
+
* appending a suffix, as for the journal, are canonical too. It rejects:
|
|
456
|
+
*
|
|
457
|
+
* - Another spelling of a path, such as `evolu1.db`, `/x/../evolu1.db`,
|
|
458
|
+
* `FILE:evolu1.db` or `/a b.db` for `/a%20b.db`, and a name with a scheme,
|
|
459
|
+
* such as `db:evolu1.db`, which a pool would map to the relative path
|
|
460
|
+
* `evolu1.db`.
|
|
461
|
+
* - A path SQLite reads itself: an empty path and `:memory:`, which open an
|
|
462
|
+
* in-memory database, `:localStorage:` and `:sessionStorage:`, which SQLite
|
|
463
|
+
* opens on its kvvfs, and a `file:` URI, whose query and fragment SQLite
|
|
464
|
+
* strips and whose escapes it decodes, so the VFS would get another name, and
|
|
465
|
+
* an EncryptedFile database would be written without its key.
|
|
466
|
+
* - A path longer than {@link sahPoolMaxDatabasePathSize}, 498 bytes, because a
|
|
467
|
+
* pool slot's header holds a path of up to 510 bytes, and SQLite names a
|
|
468
|
+
* super-journal by appending 12 bytes to the database's path.
|
|
469
|
+
*/
|
|
470
|
+
export declare const SqliteVfsPath: import("@evolu/common").BrandType<import("@evolu/common").Type<"String", string, string, import("@evolu/common").TypeOfError<"String">, null, import("@evolu/common").TypeOfError<"String">, never, string, true>, "SqliteVfsPath", SqliteVfsPathError>;
|
|
471
|
+
export type SqliteVfsPath = typeof SqliteVfsPath.Output;
|
|
472
|
+
/**
|
|
473
|
+
* What a database needs from the VFS it opens a file on, and what a driver
|
|
474
|
+
* needs to tell which databases the VFS has and to delete them. A
|
|
475
|
+
* {@link SahPool} is one.
|
|
476
|
+
*/
|
|
477
|
+
export interface SqliteVfs {
|
|
478
|
+
/** The name of the VFS, which a database opens its path with. */
|
|
479
|
+
readonly vfsName: string;
|
|
480
|
+
/**
|
|
481
|
+
* Returns the first failure a method of the VFS recorded since the last
|
|
482
|
+
* {@link SqliteVfs.clearFailure}, which a {@link SqliteError} carries as its
|
|
483
|
+
* cause.
|
|
484
|
+
*/
|
|
485
|
+
readonly getFailure: () => SqliteVfsFailure | null;
|
|
486
|
+
/**
|
|
487
|
+
* Forgets the recorded failure; a database calls it before each operation
|
|
488
|
+
* that does not run inside another operation on the VFS.
|
|
489
|
+
*/
|
|
490
|
+
readonly clearFailure: () => void;
|
|
491
|
+
/**
|
|
492
|
+
* Returns the canonical paths of the files the VFS has, databases and their
|
|
493
|
+
* journals, such as `/evolu1.db`, so a database opened at a
|
|
494
|
+
* {@link SqliteVfsPath} is listed by that path. A VFS may derive a file's
|
|
495
|
+
* canonical path from the name SQLite opened it with, as a {@link SahPool}
|
|
496
|
+
* lists a file SQLite's opfs-sahpool opened as `evolu1.db` as `/evolu1.db`.
|
|
497
|
+
*/
|
|
498
|
+
readonly getPaths: () => ReadonlyArray<string>;
|
|
499
|
+
/**
|
|
500
|
+
* Deletes the file with a canonical path, as {@link SqliteVfs.getPaths}
|
|
501
|
+
* returns it, and the files SQLite keeps beside it, such as its `-journal`.
|
|
502
|
+
* The file goes first, so a failure never leaves a database without the
|
|
503
|
+
* journal that would roll it back. Returns false when the VFS has no file
|
|
504
|
+
* with the path, as for a path that is not canonical, and throws when a
|
|
505
|
+
* connection has one of the files open.
|
|
506
|
+
*/
|
|
507
|
+
readonly unlink: (path: string) => Result<boolean, SqliteVfsIoError>;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* A {@link SqliteVfs} that encrypts a database file whose path has a key
|
|
511
|
+
* registered while the file opens, as an EncryptedFile database needs.
|
|
512
|
+
*
|
|
513
|
+
* The database asks SQLite to leave the last 80 bytes of each page of a new
|
|
514
|
+
* database unused, so the VFS can store data of its own there, as a
|
|
515
|
+
* {@link SahPool} stores the page's IV and HMAC.
|
|
516
|
+
*
|
|
517
|
+
* A read of a page that fails to authenticate fails with SQLITE_NOTADB for page
|
|
518
|
+
* 1 and SQLITE_CORRUPT for any other page, and records a
|
|
519
|
+
* {@link SqlitePageAuthenticationError}, by which the database tells it from
|
|
520
|
+
* other failures, so an export that reads the page fails with SQLITE_CORRUPT
|
|
521
|
+
* rather than SQLITE_IOERR.
|
|
522
|
+
*/
|
|
523
|
+
export interface SqliteEncryptingVfs extends SqliteVfs {
|
|
524
|
+
/**
|
|
525
|
+
* Registers a raw key for a path until the registration is disposed, as an
|
|
526
|
+
* EncryptedFile database does while it opens. The path is the one spelling by
|
|
527
|
+
* which the VFS opens the file, so it is registered as it is. When the VFS
|
|
528
|
+
* opens the path as a main database, it copies the key and encrypts that file
|
|
529
|
+
* and its journal with it until the file closes, also for the file of an
|
|
530
|
+
* `ATTACH` or `VACUUM INTO` that opens it meanwhile. The caller's key is
|
|
531
|
+
* never modified.
|
|
532
|
+
*/
|
|
533
|
+
readonly registerKey: (path: SqliteVfsPath, key: EncryptionKey) => Disposable;
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* The storage of a VFS failed outside SQLite, as when {@link SqliteVfs.unlink}
|
|
537
|
+
* deletes a file.
|
|
538
|
+
*/
|
|
539
|
+
export interface SqliteVfsIoError extends Typed<"SqliteVfsIoError"> {
|
|
540
|
+
/**
|
|
541
|
+
* What the storage threw, such as a `DOMException`, or a
|
|
542
|
+
* {@link SqliteShortWriteError} for a write that stored a different number of
|
|
543
|
+
* bytes.
|
|
544
|
+
*/
|
|
545
|
+
readonly cause: unknown;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* A page of an encrypted file that failed to authenticate, because the key is
|
|
549
|
+
* wrong or the page was altered or cut short, as a {@link SqliteEncryptingVfs}
|
|
550
|
+
* records it.
|
|
551
|
+
*/
|
|
552
|
+
export interface SqlitePageAuthenticationError extends Typed<"SqlitePageAuthenticationError"> {
|
|
553
|
+
/**
|
|
554
|
+
* The number of the database page, counting from 1, also for a page in a
|
|
555
|
+
* journal.
|
|
556
|
+
*/
|
|
557
|
+
readonly pageNumber: number;
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Opens a database.
|
|
561
|
+
*
|
|
562
|
+
* With a wrong key or a file that is not a database, it fails with
|
|
563
|
+
* SQLITE_NOTADB, or with SQLITE_CORRUPT for a wrong key and a hot journal whose
|
|
564
|
+
* first record is not page 1. On a {@link SahPool}, an encrypted database opened
|
|
565
|
+
* without its key while it has a hot journal that records pages fails with
|
|
566
|
+
* SQLITE_CANTOPEN, and the journal stays for the key. A leftover journal that
|
|
567
|
+
* is not hot, such as one `journal_mode = PERSIST` or TRUNCATE keeps, gives
|
|
568
|
+
* SQLITE_NOTADB, as no journal does. For encrypted databases that 2.2.4 may
|
|
569
|
+
* have keyed, use {@link createEncryptedSqliteDatabase}.
|
|
570
|
+
*/
|
|
571
|
+
export declare const createSqliteDatabase: (deps: SqliteWasmDep) => (options: SqliteDatabaseOptions) => Result<SqliteDatabase, SqliteError>;
|
|
572
|
+
/**
|
|
573
|
+
* Options for {@link createEncryptedSqliteDatabase}: an EncryptedFile database
|
|
574
|
+
* on a {@link SahPool}, because 2.2.4 wrote only pool files, and the fallback to
|
|
575
|
+
* its key reads the salt with {@link SahPool.read}.
|
|
576
|
+
*/
|
|
577
|
+
export interface SqliteEncryptedDatabaseOptions extends SqliteEncryptedFileDatabaseOptions {
|
|
578
|
+
readonly vfs: SahPool;
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Opens an EncryptedFile database on a pool, falling back to the key
|
|
582
|
+
* `@evolu/sqlite-wasm` 2.2.4 derived.
|
|
583
|
+
*
|
|
584
|
+
* `@evolu/web` passed 2.2.4 the key as the SQL text `x'<hex>'`, SQLCipher's
|
|
585
|
+
* notation for a raw key, which SQLite3 Multiple Ciphers 2.2.4 treated as a
|
|
586
|
+
* passphrase because of a bug
|
|
587
|
+
* (https://github.com/utelle/SQLite3MultipleCiphers/issues/218, fixed in
|
|
588
|
+
* 2.2.5). So every database it encrypted is keyed with PBKDF2-HMAC-SHA512 of
|
|
589
|
+
* that text, not with the key itself. This Task:
|
|
590
|
+
*
|
|
591
|
+
* 1. Opens with the raw key. A new or empty file always accepts it.
|
|
592
|
+
* 2. Only when a wrong key failed it, so page 1 of the database or a record of its
|
|
593
|
+
* hot journal failed to authenticate, which the pool records as a
|
|
594
|
+
* {@link SqlitePageAuthenticationError}, reads the first 16 bytes of the file
|
|
595
|
+
* through {@link SahPool.read}: the unencrypted cipher salt. Another page of
|
|
596
|
+
* the database that fails to authenticate is damaged, because page 1 proved
|
|
597
|
+
* the key, so the open fails with SQLITE_CORRUPT.
|
|
598
|
+
* 3. Derives the legacy key with {@link deriveLegacySqliteKey}, opens again with it
|
|
599
|
+
* as the raw key, and zeroes it.
|
|
600
|
+
*
|
|
601
|
+
* The result says which key opened the database. When neither key opens it, the
|
|
602
|
+
* error is the raw key's, unless the second open failed otherwise. Rekeying a
|
|
603
|
+
* legacy database to the raw key is a separate decision: it rewrites every
|
|
604
|
+
* page, needs space, and makes the database unreadable to 2.2.4 tabs that share
|
|
605
|
+
* the pool.
|
|
606
|
+
*/
|
|
607
|
+
export declare const createEncryptedSqliteDatabase: (options: SqliteEncryptedDatabaseOptions) => Task<SqliteEncryptedDatabase, SqliteError | SqliteVfsIoError, SqliteWasmDep & SubtleCryptoDep>;
|
|
608
|
+
/** The result of {@link createEncryptedSqliteDatabase}. */
|
|
609
|
+
export interface SqliteEncryptedDatabase {
|
|
610
|
+
readonly database: SqliteDatabase;
|
|
611
|
+
readonly keyDerivation: SqliteKeyDerivation;
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Which key opened an encrypted database: the raw key, or the key 2.2.4 derived
|
|
615
|
+
* from it because of a bug in SQLite3 Multiple Ciphers, which
|
|
616
|
+
* {@link deriveLegacySqliteKey} describes.
|
|
617
|
+
*/
|
|
618
|
+
export type SqliteKeyDerivation = "Raw" | "Legacy224";
|
|
619
|
+
/**
|
|
620
|
+
* Derives the key `@evolu/sqlite-wasm` 2.2.4 used: PBKDF2-HMAC-SHA512 with
|
|
621
|
+
* 256000 iterations and a 32-byte output, over the UTF-8 text `x'` followed by
|
|
622
|
+
* the key in lowercase hex and `'`, salted with the database's first 16 bytes.
|
|
623
|
+
*
|
|
624
|
+
* It exists because of a bug in SQLite3 Multiple Ciphers 2.2.4, which 2.2.4
|
|
625
|
+
* packaged. `x'<hex>'` is SQLCipher's notation for a raw key, which
|
|
626
|
+
* `@evolu/web` used, but that version took it as a passphrase and derived the
|
|
627
|
+
* key from the text
|
|
628
|
+
* (https://github.com/utelle/SQLite3MultipleCiphers/issues/218, fixed in
|
|
629
|
+
* 2.2.5). So the databases it encrypted are keyed with this derivation, and
|
|
630
|
+
* opening them needs it for as long as they exist, because nothing rekeys
|
|
631
|
+
* them.
|
|
632
|
+
*
|
|
633
|
+
* The text is built byte by byte, so no string holds the key, and zeroed once
|
|
634
|
+
* WebCrypto has imported it.
|
|
635
|
+
*/
|
|
636
|
+
export declare const deriveLegacySqliteKey: (key: EncryptionKey, salt: Uint8Array) => Task<EncryptionKey, never, SubtleCryptoDep>;
|
|
637
|
+
/** WebCrypto, which derives legacy keys. */
|
|
638
|
+
export interface SubtleCryptoDep {
|
|
639
|
+
readonly subtleCrypto: SubtleCrypto;
|
|
640
|
+
}
|
|
641
|
+
//# sourceMappingURL=Database.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Database.d.ts","sourceRoot":"","sources":["../../src/Database.ts"],"names":[],"mappings":"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"}
|