@evolu/common 6.0.1-preview.2 → 6.0.1-preview.21
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/dist/src/Assert.d.ts +6 -3
- package/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Assert.js +7 -4
- package/dist/src/Brand.d.ts +75 -0
- package/dist/src/Brand.d.ts.map +1 -0
- package/dist/src/Brand.js +1 -0
- package/dist/src/Buffer.d.ts +1 -1
- package/dist/src/Buffer.d.ts.map +1 -1
- package/dist/src/Buffer.js +1 -1
- package/dist/src/CallbackRegistry.d.ts +53 -0
- package/dist/src/CallbackRegistry.d.ts.map +1 -0
- package/dist/src/CallbackRegistry.js +25 -0
- package/dist/src/Console.d.ts +31 -6
- package/dist/src/Console.d.ts.map +1 -1
- package/dist/src/Console.js +72 -9
- package/dist/src/Crypto.d.ts +61 -34
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +29 -42
- package/dist/src/Evolu/Db.d.ts +159 -66
- package/dist/src/Evolu/Db.d.ts.map +1 -1
- package/dist/src/Evolu/Db.js +300 -705
- package/dist/src/Evolu/Diff.d.ts +3 -3
- package/dist/src/Evolu/Diff.d.ts.map +1 -1
- package/dist/src/Evolu/Diff.js +7 -5
- package/dist/src/Evolu/Evolu.d.ts +200 -115
- package/dist/src/Evolu/Evolu.d.ts.map +1 -1
- package/dist/src/Evolu/Evolu.js +287 -157
- package/dist/src/Evolu/Internal.d.ts +0 -2
- package/dist/src/Evolu/Internal.d.ts.map +1 -1
- package/dist/src/Evolu/Internal.js +0 -2
- package/dist/src/Evolu/LocalAuth.d.ts +144 -0
- package/dist/src/Evolu/LocalAuth.d.ts.map +1 -0
- package/dist/src/Evolu/LocalAuth.js +171 -0
- package/dist/src/Evolu/Owner.d.ts +209 -124
- package/dist/src/Evolu/Owner.d.ts.map +1 -1
- package/dist/src/Evolu/Owner.js +118 -104
- package/dist/src/Evolu/Platform.d.ts +9 -7
- package/dist/src/Evolu/Platform.d.ts.map +1 -1
- package/dist/src/Evolu/Protocol.d.ts +256 -211
- package/dist/src/Evolu/Protocol.d.ts.map +1 -1
- package/dist/src/Evolu/Protocol.js +558 -359
- package/dist/src/Evolu/Public.d.ts +6 -8
- package/dist/src/Evolu/Public.d.ts.map +1 -1
- package/dist/src/Evolu/Public.js +2 -3
- package/dist/src/Evolu/PublicKysely.js +3 -3
- package/dist/src/Evolu/Query.d.ts +2 -1
- package/dist/src/Evolu/Query.d.ts.map +1 -1
- package/dist/src/Evolu/Relay.d.ts +72 -4
- package/dist/src/Evolu/Relay.d.ts.map +1 -1
- package/dist/src/Evolu/Relay.js +124 -13
- package/dist/src/Evolu/Schema.d.ts +129 -73
- package/dist/src/Evolu/Schema.d.ts.map +1 -1
- package/dist/src/Evolu/Schema.js +169 -89
- package/dist/src/Evolu/Storage.d.ts +159 -14
- package/dist/src/Evolu/Storage.d.ts.map +1 -1
- package/dist/src/Evolu/Storage.js +42 -32
- package/dist/src/Evolu/Sync.d.ts +68 -13
- package/dist/src/Evolu/Sync.d.ts.map +1 -1
- package/dist/src/Evolu/Sync.js +414 -20
- package/dist/src/Evolu/Timestamp.d.ts +35 -27
- package/dist/src/Evolu/Timestamp.d.ts.map +1 -1
- package/dist/src/Evolu/Timestamp.js +27 -18
- package/dist/src/ManyToManyMap.d.ts +74 -10
- package/dist/src/ManyToManyMap.d.ts.map +1 -1
- package/dist/src/ManyToManyMap.js +41 -6
- package/dist/src/Number.d.ts +2 -1
- package/dist/src/Number.d.ts.map +1 -1
- package/dist/src/Random.d.ts +3 -2
- package/dist/src/Random.d.ts.map +1 -1
- package/dist/src/RefCountedResourceManager.d.ts +119 -0
- package/dist/src/RefCountedResourceManager.d.ts.map +1 -0
- package/dist/src/RefCountedResourceManager.js +197 -0
- package/dist/src/Result.d.ts +176 -51
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +30 -241
- package/dist/src/Sqlite.d.ts +21 -4
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +50 -8
- package/dist/src/Task.d.ts +511 -0
- package/dist/src/Task.d.ts.map +1 -0
- package/dist/src/Task.js +410 -0
- package/dist/src/Time.d.ts +59 -0
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +87 -4
- package/dist/src/Type.d.ts +474 -327
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +502 -436
- package/dist/src/Types.d.ts +0 -74
- package/dist/src/Types.d.ts.map +1 -1
- package/dist/src/WebSocket.d.ts +5 -2
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/WebSocket.js +12 -13
- package/dist/src/Worker.d.ts +39 -11
- package/dist/src/Worker.d.ts.map +1 -1
- package/dist/src/Worker.js +22 -4
- package/dist/src/index.d.ts +3 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -3
- package/package.json +14 -13
- package/src/Assert.ts +8 -7
- package/src/Brand.ts +75 -0
- package/src/Buffer.ts +1 -1
- package/src/CallbackRegistry.ts +84 -0
- package/src/Console.ts +91 -11
- package/src/Crypto.ts +94 -79
- package/src/Evolu/Db.ts +528 -1027
- package/src/Evolu/Diff.ts +7 -5
- package/src/Evolu/Evolu.ts +682 -329
- package/src/Evolu/Internal.ts +0 -2
- package/src/Evolu/LocalAuth.ts +422 -0
- package/src/Evolu/Owner.ts +282 -227
- package/src/Evolu/Platform.ts +9 -9
- package/src/Evolu/Protocol.ts +788 -640
- package/src/Evolu/Public.ts +7 -14
- package/src/Evolu/PublicKysely.ts +3 -3
- package/src/Evolu/Query.ts +2 -1
- package/src/Evolu/Relay.ts +238 -18
- package/src/Evolu/Schema.ts +391 -191
- package/src/Evolu/Storage.ts +275 -55
- package/src/Evolu/Sync.ts +708 -37
- package/src/Evolu/Timestamp.ts +38 -35
- package/src/ManyToManyMap.ts +127 -24
- package/src/Number.ts +2 -6
- package/src/Random.ts +3 -2
- package/src/RefCountedResourceManager.ts +368 -0
- package/src/Result.ts +183 -53
- package/src/Sqlite.ts +59 -23
- package/src/Task.ts +779 -0
- package/src/Time.ts +168 -4
- package/src/Type.ts +708 -660
- package/src/Types.ts +0 -76
- package/src/WebSocket.ts +23 -17
- package/src/Worker.ts +72 -23
- package/src/index.ts +3 -3
- package/dist/src/Callbacks.d.ts +0 -20
- package/dist/src/Callbacks.d.ts.map +0 -1
- package/dist/src/Callbacks.js +0 -18
- package/dist/src/Evolu/Config.d.ts +0 -69
- package/dist/src/Evolu/Config.d.ts.map +0 -1
- package/dist/src/Evolu/Config.js +0 -9
- package/dist/src/Evolu/Kysely.d.ts +0 -6
- package/dist/src/Evolu/Kysely.d.ts.map +0 -1
- package/dist/src/Evolu/Kysely.js +0 -21
- package/dist/src/NanoId.d.ts +0 -27
- package/dist/src/NanoId.d.ts.map +0 -1
- package/dist/src/NanoId.js +0 -6
- package/dist/src/Promise.d.ts +0 -180
- package/dist/src/Promise.d.ts.map +0 -1
- package/dist/src/Promise.js +0 -176
- package/src/Callbacks.ts +0 -43
- package/src/Evolu/Config.ts +0 -83
- package/src/Evolu/Kysely.ts +0 -38
- package/src/NanoId.ts +0 -39
- package/src/Promise.ts +0 -295
package/dist/src/Result.js
CHANGED
|
@@ -1,242 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 🛡️ Type-safe errors
|
|
3
|
-
*
|
|
4
|
-
* ## Intro
|
|
5
|
-
*
|
|
6
|
-
* The problem with throwing an exception in JavaScript is that the caught error
|
|
7
|
-
* is always of an unknown type. The unknown type is a problem because we can't
|
|
8
|
-
* be sure all errors have been handled because the TypeScript compiler can't
|
|
9
|
-
* help us.
|
|
10
|
-
*
|
|
11
|
-
* Some other languages like Rust 🦀 or Haskell 📚 use a type-safe approach to
|
|
12
|
-
* error handling, where errors are explicitly represented as part of the return
|
|
13
|
-
* type, such as Result or Either, allowing the developer to handle all errors
|
|
14
|
-
* safely. ✅
|
|
15
|
-
*
|
|
16
|
-
* ✨ Evolu uses {@link Result}, and it looks like this:
|
|
17
|
-
*
|
|
18
|
-
* ```ts
|
|
19
|
-
* type Result<T, E> = Ok<T> | Err<E>;
|
|
20
|
-
*
|
|
21
|
-
* interface Ok<T> {
|
|
22
|
-
* readonly ok: true;
|
|
23
|
-
* readonly value: T;
|
|
24
|
-
* }
|
|
25
|
-
*
|
|
26
|
-
* interface Err<E> {
|
|
27
|
-
* readonly ok: false;
|
|
28
|
-
* readonly error: E;
|
|
29
|
-
* }
|
|
30
|
-
*
|
|
31
|
-
* const ok = <T>(value: T): Ok<T> => ({ ok: true, value });
|
|
32
|
-
* const err = <E>(error: E): Err<E> => ({ ok: false, error });
|
|
33
|
-
* ```
|
|
34
|
-
*
|
|
35
|
-
* Now let's look at how `Result` can be used for safe JSON parsing:
|
|
36
|
-
*
|
|
37
|
-
* ```ts
|
|
38
|
-
* interface ParseJsonError {
|
|
39
|
-
* readonly type: "ParseJsonError";
|
|
40
|
-
* readonly message: string;
|
|
41
|
-
* }
|
|
42
|
-
*
|
|
43
|
-
* const parseJson = (value: string): Result<unknown, ParseJsonError> => {
|
|
44
|
-
* try {
|
|
45
|
-
* return ok(JSON.parse(value));
|
|
46
|
-
* } catch (error) {
|
|
47
|
-
* return err({ type: "ParseJsonError", message: String(error) });
|
|
48
|
-
* }
|
|
49
|
-
* };
|
|
50
|
-
*
|
|
51
|
-
* // Result<unknown, ParseJsonError>
|
|
52
|
-
* const json = parseJson('{"key": "value"}');
|
|
53
|
-
*
|
|
54
|
-
* // Fail fast to handle errors early.
|
|
55
|
-
* if (!json.ok) return json; // Err<ParseJsonError>
|
|
56
|
-
*
|
|
57
|
-
* // Now, we have access to the json.value.
|
|
58
|
-
* expectTypeOf(json.value).toBeUnknown();
|
|
59
|
-
* ```
|
|
60
|
-
*
|
|
61
|
-
* Note how we didn't have to use the try/catch, just `if (!json.ok)`, and how
|
|
62
|
-
* the error isn't unknown but has a type.
|
|
63
|
-
*
|
|
64
|
-
* But we had to use `try/catch` in the `parseJson` function. For such a case,
|
|
65
|
-
* wrapping unsafe code, Evolu provides the {@link trySync} helper:
|
|
66
|
-
*
|
|
67
|
-
* ```ts
|
|
68
|
-
* const parseJson = (value: string): Result<unknown, ParseJsonError> =>
|
|
69
|
-
* trySync(
|
|
70
|
-
* () => JSON.parse(value) as unknown,
|
|
71
|
-
* (error) => ({ type: "ParseJsonError", message: String(error) }),
|
|
72
|
-
* );
|
|
73
|
-
* ```
|
|
74
|
-
*
|
|
75
|
-
* ✨ {@link trySync} helper makes unsafe (can throw) synchronous code safe; for
|
|
76
|
-
* unsafe asynchronous code, use {@link tryAsync}.
|
|
77
|
-
*
|
|
78
|
-
* Let's summarize it:
|
|
79
|
-
*
|
|
80
|
-
* - For synchronous safe code, use `ok` and `err`.
|
|
81
|
-
* - For unsafe code, use `trySync` or `tryAsync`.
|
|
82
|
-
* - For asynchronous safe code, use `Promise` with {@link Result}.
|
|
83
|
-
*
|
|
84
|
-
* Asynchronous safe (because of a Promise using Result) code is
|
|
85
|
-
* straightforward:
|
|
86
|
-
*
|
|
87
|
-
* ```ts
|
|
88
|
-
* const fetchUser = async (
|
|
89
|
-
* userId: string,
|
|
90
|
-
* ): Promise<Result<User, FetchUserError>> => {
|
|
91
|
-
* // Simulate an API call
|
|
92
|
-
* return new Promise((resolve) => {
|
|
93
|
-
* setTimeout(() => {
|
|
94
|
-
* if (userId === "1") {
|
|
95
|
-
* resolve(ok({ id: "1", name: "Alice" }));
|
|
96
|
-
* } else {
|
|
97
|
-
* resolve(
|
|
98
|
-
* err({ type: "FetchUserError", reason: "user not found" }),
|
|
99
|
-
* );
|
|
100
|
-
* }
|
|
101
|
-
* }, 1000);
|
|
102
|
-
* });
|
|
103
|
-
* };
|
|
104
|
-
* ```
|
|
105
|
-
*
|
|
106
|
-
* ## Examples
|
|
107
|
-
*
|
|
108
|
-
* ### Sequential Operations with Short-Circuiting
|
|
109
|
-
*
|
|
110
|
-
* When performing a sequence of operations where any failure should stop
|
|
111
|
-
* further processing, use the `Result` type with early returns.
|
|
112
|
-
*
|
|
113
|
-
* Here's an example of a database reset operation that drops tables, restores a
|
|
114
|
-
* schema, and initializes the database, stopping on the first error:
|
|
115
|
-
*
|
|
116
|
-
* ```ts
|
|
117
|
-
* const resetResult = deps.sqlite.transaction(() => {
|
|
118
|
-
* const dropAllTablesResult = dropAllTables(deps);
|
|
119
|
-
* if (!dropAllTablesResult.ok) return dropAllTablesResult;
|
|
120
|
-
*
|
|
121
|
-
* if (message.restore) {
|
|
122
|
-
* const dbSchema = getDbSchema(deps)();
|
|
123
|
-
* if (!dbSchema.ok) return dbSchema;
|
|
124
|
-
*
|
|
125
|
-
* const ensureDbSchemaResult = ensureDbSchema(deps)(
|
|
126
|
-
* message.restore.dbSchema,
|
|
127
|
-
* dbSchema.value,
|
|
128
|
-
* );
|
|
129
|
-
* if (!ensureDbSchemaResult.ok) return ensureDbSchemaResult;
|
|
130
|
-
*
|
|
131
|
-
* const initializeDbResult = initializeDb(deps)(
|
|
132
|
-
* message.restore.mnemonic,
|
|
133
|
-
* );
|
|
134
|
-
* if (!initializeDbResult.ok) return initializeDbResult;
|
|
135
|
-
* }
|
|
136
|
-
* return ok();
|
|
137
|
-
* });
|
|
138
|
-
*
|
|
139
|
-
* if (!resetResult.ok) {
|
|
140
|
-
* deps.postMessage({ type: "onError", error: resetResult.error });
|
|
141
|
-
* return;
|
|
142
|
-
* }
|
|
143
|
-
* ```
|
|
144
|
-
*
|
|
145
|
-
* In this pattern:
|
|
146
|
-
*
|
|
147
|
-
* - Each operation returns a `Result` (e.g., `Result<void, E>` or `Result<T,
|
|
148
|
-
* E>`).
|
|
149
|
-
* - After each operation, check `if (!result.ok)` and return the `Err` to
|
|
150
|
-
* short-circuit.
|
|
151
|
-
* - If all operations succeed, return `ok()` (or another value if needed).
|
|
152
|
-
* - Outside the transaction, handle the final `Result` to report success or
|
|
153
|
-
* failure.
|
|
154
|
-
*
|
|
155
|
-
* This approach ensures type-safe error handling, avoids nested try/catch
|
|
156
|
-
* blocks, and clearly communicates the control flow.
|
|
157
|
-
*
|
|
158
|
-
* ### A function with two different errors:
|
|
159
|
-
*
|
|
160
|
-
* ```ts
|
|
161
|
-
* const example = (value: string): Result<number, FooError | BarError> => {
|
|
162
|
-
* const foo = getFoo(value);
|
|
163
|
-
* if (!foo.ok) return foo;
|
|
164
|
-
*
|
|
165
|
-
* const bar = barize(foo.value);
|
|
166
|
-
* if (!bar.ok) return bar;
|
|
167
|
-
*
|
|
168
|
-
* return ok(barToNumber(bar.value));
|
|
169
|
-
* };
|
|
170
|
-
* ```
|
|
171
|
-
*
|
|
172
|
-
* ## FAQ
|
|
173
|
-
*
|
|
174
|
-
* ### What if my function doesn't return a value on success?
|
|
175
|
-
*
|
|
176
|
-
* If your function performs an operation but doesn't need to return a value on
|
|
177
|
-
* success, you can use `Result<void, E>`. Using `Result<void, E>` is clearer
|
|
178
|
-
* than using `Result<true, E>` or `Result<null, E>` because it communicates
|
|
179
|
-
* that the function doesn't produce a value but can produce errors.
|
|
180
|
-
*
|
|
181
|
-
* ### How do I short-circuit processing of an array on the first error?
|
|
182
|
-
*
|
|
183
|
-
* If you want to stop processing as soon as an error occurs (short-circuit),
|
|
184
|
-
* you should produce and check each `Result` inside a loop:
|
|
185
|
-
*
|
|
186
|
-
* ```ts
|
|
187
|
-
* for (const query of [
|
|
188
|
-
* sql`drop table evolu_owner;`,
|
|
189
|
-
* sql`drop table evolu_message;`,
|
|
190
|
-
* ]) {
|
|
191
|
-
* const result = deps.sqlite.exec(query);
|
|
192
|
-
* if (!result.ok) return result;
|
|
193
|
-
* }
|
|
194
|
-
* // All queries succeeded
|
|
195
|
-
* ```
|
|
196
|
-
*
|
|
197
|
-
* ### How do I handle an array of operations and short-circuit on the first error?
|
|
198
|
-
*
|
|
199
|
-
* If you have an array of operations (not results), you should make them
|
|
200
|
-
* _lazy_—that is, represent each operation as a function (see `LazyValue` in
|
|
201
|
-
* `Function.ts`). This way, you only execute each operation as needed, and can
|
|
202
|
-
* stop on the first error:
|
|
203
|
-
*
|
|
204
|
-
* ```ts
|
|
205
|
-
* import type { LazyValue } from "./Function";
|
|
206
|
-
*
|
|
207
|
-
* const operations: LazyValue<Result<void, MyError>>[] = [
|
|
208
|
-
* () => doSomething(),
|
|
209
|
-
* () => doSomethingElse(),
|
|
210
|
-
* ];
|
|
211
|
-
*
|
|
212
|
-
* for (const op of operations) {
|
|
213
|
-
* const result = op();
|
|
214
|
-
* if (!result.ok) return result;
|
|
215
|
-
* }
|
|
216
|
-
* // All operations succeeded
|
|
217
|
-
* ```
|
|
218
|
-
*
|
|
219
|
-
* If you already have an array of `Result`s, the processing has already
|
|
220
|
-
* happened, so you can't short-circuit. In that case, you can check for the
|
|
221
|
-
* first error:
|
|
222
|
-
*
|
|
223
|
-
* ```ts
|
|
224
|
-
* const firstError = results.find((r) => !r.ok);
|
|
225
|
-
* if (firstError) return firstError;
|
|
226
|
-
* // All results are Ok
|
|
227
|
-
* ```
|
|
228
|
-
*
|
|
229
|
-
* ### Why doesn't Evolu provide "handy helpers"?
|
|
230
|
-
*
|
|
231
|
-
* Evolu intentionally favors imperative patterns (like the `for...of` loop
|
|
232
|
-
* above) over monadic helpers. Imperative code is generally more readable,
|
|
233
|
-
* easier to debug, and more familiar to most JavaScript and TypeScript
|
|
234
|
-
* developers. While monads and functional helpers can be powerful, they often
|
|
235
|
-
* obscure control flow and make debugging harder. Evolu's approach keeps error
|
|
236
|
-
* handling explicit and straightforward.
|
|
237
|
-
*
|
|
238
|
-
* @module
|
|
239
|
-
*/
|
|
240
1
|
export function ok(value = undefined) {
|
|
241
2
|
return { ok: true, value: value };
|
|
242
3
|
}
|
|
@@ -269,15 +30,40 @@ export const err = (error) => ({ ok: false, error });
|
|
|
269
30
|
* const config = getOrThrow(loadConfig());
|
|
270
31
|
* // Safe to use config here
|
|
271
32
|
* ```
|
|
33
|
+
*
|
|
34
|
+
* Throws: `Error` with the original error attached as `cause`.
|
|
272
35
|
*/
|
|
273
36
|
export const getOrThrow = (result) => {
|
|
274
37
|
if (result.ok) {
|
|
275
38
|
return result.value;
|
|
276
39
|
}
|
|
277
40
|
else {
|
|
278
|
-
throw new Error(
|
|
41
|
+
throw new Error("getOrThrow", { cause: result.error });
|
|
279
42
|
}
|
|
280
43
|
};
|
|
44
|
+
/**
|
|
45
|
+
* Extracts the value from a {@link Result} if it is an `Ok`, or returns `null`
|
|
46
|
+
* if it is an `Err`.
|
|
47
|
+
*
|
|
48
|
+
* **Intended usage:**
|
|
49
|
+
*
|
|
50
|
+
* - When you need to convert a `Result` to a nullable value for APIs that expect
|
|
51
|
+
* `T | null`.
|
|
52
|
+
* - When the error is not important and you just want the value or nothing.
|
|
53
|
+
*
|
|
54
|
+
* ### Example
|
|
55
|
+
*
|
|
56
|
+
* ```ts
|
|
57
|
+
* const parseResult = parseJson('{"key": "value"}');
|
|
58
|
+
* const value = getOrNull(parseResult);
|
|
59
|
+
* // value is unknown | null
|
|
60
|
+
*
|
|
61
|
+
* if (value != null) {
|
|
62
|
+
* console.log("Parsed value:", value);
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export const getOrNull = (result) => result.ok ? result.value : null;
|
|
281
67
|
/**
|
|
282
68
|
* Wraps synchronous functions that may throw exceptions, returning a
|
|
283
69
|
* {@link Result}.
|
|
@@ -298,7 +84,10 @@ export const getOrThrow = (result) => {
|
|
|
298
84
|
* const parseJson = (value: string): Result<unknown, ParseJsonError> =>
|
|
299
85
|
* trySync(
|
|
300
86
|
* () => JSON.parse(value) as unknown,
|
|
301
|
-
* (error)
|
|
87
|
+
* (error): ParseJsonError => ({
|
|
88
|
+
* type: "ParseJsonError",
|
|
89
|
+
* message: String(error),
|
|
90
|
+
* }),
|
|
302
91
|
* );
|
|
303
92
|
* ```
|
|
304
93
|
*/
|
package/dist/src/Sqlite.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { Brand } from "./Brand.js";
|
|
1
2
|
import { ConsoleDep } from "./Console.js";
|
|
3
|
+
import { EncryptionKey } from "./Crypto.js";
|
|
2
4
|
import { TransferableError } from "./Error.js";
|
|
3
5
|
import { Result } from "./Result.js";
|
|
4
6
|
import { SimpleName } from "./Type.js";
|
|
5
|
-
import {
|
|
7
|
+
import { Predicate } from "./Types.js";
|
|
6
8
|
/**
|
|
7
9
|
* SQLite driver interface. This is the minimal interface that platform-specific
|
|
8
10
|
* drivers must implement.
|
|
@@ -17,6 +19,7 @@ export interface CreateSqliteDriverDep {
|
|
|
17
19
|
}
|
|
18
20
|
export interface SqliteDriverOptions {
|
|
19
21
|
memory?: boolean;
|
|
22
|
+
encryptionKey?: EncryptionKey | undefined;
|
|
20
23
|
}
|
|
21
24
|
/**
|
|
22
25
|
* Cross-platform SQLite abstraction.
|
|
@@ -124,11 +127,25 @@ export interface SqliteQueryPlanRow {
|
|
|
124
127
|
export declare const explainSqliteQueryPlan: (deps: SqliteDep) => (query: SqliteQuery) => Result<void, SqliteError>;
|
|
125
128
|
/**
|
|
126
129
|
* SQLite represents boolean values using `0` (false) and `1` (true) instead of
|
|
127
|
-
* a dedicated boolean type.
|
|
128
|
-
*
|
|
130
|
+
* a dedicated boolean type.
|
|
131
|
+
*
|
|
132
|
+
* Use {@link sqliteTrue} and {@link sqliteFalse} constants for better
|
|
133
|
+
* readability.
|
|
129
134
|
*
|
|
130
135
|
* See: https://www.sqlite.org/quirks.html#no_separate_boolean_datatype
|
|
131
136
|
*/
|
|
132
|
-
export declare const SqliteBoolean: import("./Type.js").
|
|
137
|
+
export declare const SqliteBoolean: import("./Type.js").UnionType<[import("./Type.js").LiteralType<0>, import("./Type.js").LiteralType<1>]>;
|
|
133
138
|
export type SqliteBoolean = typeof SqliteBoolean.Type;
|
|
139
|
+
/**
|
|
140
|
+
* Represents the {@link SqliteBoolean} value for `true`.
|
|
141
|
+
*
|
|
142
|
+
* See {@link SqliteBoolean}.
|
|
143
|
+
*/
|
|
144
|
+
export declare const sqliteTrue = 1;
|
|
145
|
+
/**
|
|
146
|
+
* Represents the {@link SqliteBoolean} value for `false`.
|
|
147
|
+
*
|
|
148
|
+
* See {@link SqliteBoolean}.
|
|
149
|
+
*/
|
|
150
|
+
export declare const sqliteFalse = 0;
|
|
134
151
|
//# sourceMappingURL=Sqlite.d.ts.map
|
package/dist/src/Sqlite.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sqlite.d.ts","sourceRoot":"","sources":["../../src/Sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAA2B,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EAAW,MAAM,EAAqB,MAAM,aAAa,CAAC;AACjE,OAAO,
|
|
1
|
+
{"version":3,"file":"Sqlite.d.ts","sourceRoot":"","sources":["../../src/Sqlite.ts"],"names":[],"mappings":"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"}
|
package/dist/src/Sqlite.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createTransferableError } from "./Error.js";
|
|
2
2
|
import { err, ok, tryAsync, trySync } from "./Result.js";
|
|
3
|
-
import {
|
|
3
|
+
import { Null, Number, String, Uint8Array, union } from "./Type.js";
|
|
4
4
|
/**
|
|
5
5
|
* A value that can be stored in Sqlite.
|
|
6
6
|
*
|
|
@@ -21,9 +21,9 @@ export const createSqlite = (deps) => async (name, options) => tryAsync(async ()
|
|
|
21
21
|
}, createSqliteError);
|
|
22
22
|
const sqlite = {
|
|
23
23
|
exec: (query) => trySync(() => {
|
|
24
|
-
deps.console?.log("[sql]", query);
|
|
24
|
+
deps.console?.log("[sql]", { query });
|
|
25
25
|
const result = maybeLogSqliteQueryExecutionTime(query, () => driver.exec(query, isSqlMutation(query.sql)));
|
|
26
|
-
deps.console?.log("[sql]", result);
|
|
26
|
+
deps.console?.log("[sql]", { result });
|
|
27
27
|
return result;
|
|
28
28
|
}, (error) => ({
|
|
29
29
|
type: "SqliteError",
|
|
@@ -172,7 +172,35 @@ const isSqlMutationRegEx = new RegExp(`\\b(${[
|
|
|
172
172
|
"pragma",
|
|
173
173
|
"vacuum",
|
|
174
174
|
].join("|")})\\b`, "i");
|
|
175
|
-
|
|
175
|
+
/**
|
|
176
|
+
* Removes SQL line comments (--) from a SQL string without using regex to avoid
|
|
177
|
+
* ReDoS vulnerabilities.
|
|
178
|
+
*/
|
|
179
|
+
const removeSqlComments = (sql) => {
|
|
180
|
+
let result = "";
|
|
181
|
+
let i = 0;
|
|
182
|
+
while (i < sql.length) {
|
|
183
|
+
// Check for comment start
|
|
184
|
+
if (i < sql.length - 1 && sql[i] === "-" && sql[i + 1] === "-") {
|
|
185
|
+
// Skip until end of line or end of string
|
|
186
|
+
i += 2;
|
|
187
|
+
while (i < sql.length && sql[i] !== "\n") {
|
|
188
|
+
i++;
|
|
189
|
+
}
|
|
190
|
+
// Keep the newline if present
|
|
191
|
+
if (i < sql.length && sql[i] === "\n") {
|
|
192
|
+
result += "\n";
|
|
193
|
+
i++;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
result += sql[i];
|
|
198
|
+
i++;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return result;
|
|
202
|
+
};
|
|
203
|
+
export const isSqlMutation = (sql) => isSqlMutationRegEx.test(removeSqlComments(sql));
|
|
176
204
|
export const explainSqliteQueryPlan = (deps) => (query) => {
|
|
177
205
|
const result = deps.sqlite.exec({
|
|
178
206
|
...query,
|
|
@@ -181,7 +209,7 @@ export const explainSqliteQueryPlan = (deps) => (query) => {
|
|
|
181
209
|
if (!result.ok)
|
|
182
210
|
return result;
|
|
183
211
|
// eslint-disable-next-line no-console
|
|
184
|
-
console.log("
|
|
212
|
+
console.log("[explainSqliteQueryPlan]", query);
|
|
185
213
|
// eslint-disable-next-line no-console
|
|
186
214
|
console.log(drawSqliteQueryPlan(result.value.rows));
|
|
187
215
|
return ok();
|
|
@@ -203,9 +231,23 @@ const drawSqliteQueryPlan = (rows) => rows
|
|
|
203
231
|
.join("\n");
|
|
204
232
|
/**
|
|
205
233
|
* SQLite represents boolean values using `0` (false) and `1` (true) instead of
|
|
206
|
-
* a dedicated boolean type.
|
|
207
|
-
*
|
|
234
|
+
* a dedicated boolean type.
|
|
235
|
+
*
|
|
236
|
+
* Use {@link sqliteTrue} and {@link sqliteFalse} constants for better
|
|
237
|
+
* readability.
|
|
208
238
|
*
|
|
209
239
|
* See: https://www.sqlite.org/quirks.html#no_separate_boolean_datatype
|
|
210
240
|
*/
|
|
211
|
-
export const SqliteBoolean =
|
|
241
|
+
export const SqliteBoolean = union(0, 1);
|
|
242
|
+
/**
|
|
243
|
+
* Represents the {@link SqliteBoolean} value for `true`.
|
|
244
|
+
*
|
|
245
|
+
* See {@link SqliteBoolean}.
|
|
246
|
+
*/
|
|
247
|
+
export const sqliteTrue = 1;
|
|
248
|
+
/**
|
|
249
|
+
* Represents the {@link SqliteBoolean} value for `false`.
|
|
250
|
+
*
|
|
251
|
+
* See {@link SqliteBoolean}.
|
|
252
|
+
*/
|
|
253
|
+
export const sqliteFalse = 0;
|