@evolu/common 8.0.0-next.4 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/Array.d.ts +279 -173
- package/dist/src/Array.d.ts.map +1 -1
- package/dist/src/Array.js +105 -101
- package/dist/src/Assert.d.ts +44 -44
- package/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Assert.js +44 -32
- package/dist/src/BigInt.d.ts +6 -3
- package/dist/src/BigInt.d.ts.map +1 -1
- package/dist/src/BigInt.js +5 -2
- package/dist/src/Brand.d.ts +27 -40
- package/dist/src/Brand.d.ts.map +1 -1
- package/dist/src/Buffer.d.ts +27 -11
- package/dist/src/Buffer.d.ts.map +1 -1
- package/dist/src/Cache.d.ts +9 -4
- package/dist/src/Cache.d.ts.map +1 -1
- package/dist/src/Cache.js +8 -3
- package/dist/src/Callbacks.d.ts +30 -19
- package/dist/src/Callbacks.d.ts.map +1 -1
- package/dist/src/Console.d.ts +145 -66
- package/dist/src/Console.d.ts.map +1 -1
- package/dist/src/Console.js +91 -43
- package/dist/src/Crypto.d.ts +85 -42
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +44 -20
- package/dist/src/Eq.d.ts +87 -21
- package/dist/src/Eq.d.ts.map +1 -1
- package/dist/src/Eq.js +67 -19
- package/dist/src/Error.d.ts +5 -3
- package/dist/src/Error.d.ts.map +1 -1
- package/dist/src/Error.js +16 -0
- package/dist/src/Function.d.ts +119 -58
- package/dist/src/Function.d.ts.map +1 -1
- package/dist/src/Function.js +86 -43
- package/dist/src/Http.d.ts +394 -0
- package/dist/src/Http.d.ts.map +1 -0
- package/dist/src/Http.js +102 -0
- package/dist/src/Identicon.d.ts +16 -7
- package/dist/src/Identicon.d.ts.map +1 -1
- package/dist/src/Identicon.js +14 -5
- package/dist/src/LeakDetector.d.ts +88 -0
- package/dist/src/LeakDetector.d.ts.map +1 -0
- package/dist/src/LeakDetector.js +86 -0
- package/dist/src/LockManager.d.ts +18 -9
- package/dist/src/LockManager.d.ts.map +1 -1
- package/dist/src/LockManager.js +7 -8
- package/dist/src/Lookup.d.ts +43 -13
- package/dist/src/Lookup.d.ts.map +1 -1
- package/dist/src/Lookup.js +28 -8
- package/dist/src/Microtask.d.ts +1 -1
- package/dist/src/Microtask.d.ts.map +1 -1
- package/dist/src/Microtask.js +3 -7
- package/dist/src/Number.d.ts +49 -13
- package/dist/src/Number.d.ts.map +1 -1
- package/dist/src/Number.js +34 -5
- package/dist/src/Object.d.ts +160 -40
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/Object.js +92 -46
- package/dist/src/Option.d.ts +10 -7
- package/dist/src/Option.d.ts.map +1 -1
- package/dist/src/Option.js +9 -6
- package/dist/src/Order.d.ts +21 -21
- package/dist/src/Order.d.ts.map +1 -1
- package/dist/src/Order.js +18 -21
- package/dist/src/Platform.d.ts +31 -0
- package/dist/src/Platform.d.ts.map +1 -1
- package/dist/src/Platform.js +98 -0
- package/dist/src/Random.d.ts +32 -17
- package/dist/src/Random.d.ts.map +1 -1
- package/dist/src/Random.js +12 -8
- package/dist/src/Redacted.d.ts +43 -29
- package/dist/src/Redacted.d.ts.map +1 -1
- package/dist/src/Redacted.js +14 -3
- package/dist/src/Ref.d.ts +11 -3
- package/dist/src/Ref.d.ts.map +1 -1
- package/dist/src/Ref.js +2 -2
- package/dist/src/RefCount.d.ts +2 -6
- package/dist/src/RefCount.d.ts.map +1 -1
- package/dist/src/RefCount.js +33 -90
- package/dist/src/Relation.d.ts +70 -5
- package/dist/src/Relation.d.ts.map +1 -1
- package/dist/src/Relation.js +77 -2
- package/dist/src/Resource.d.ts +590 -155
- package/dist/src/Resource.d.ts.map +1 -1
- package/dist/src/Resource.js +592 -343
- package/dist/src/Result.d.ts +838 -191
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +163 -102
- package/dist/src/Schedule.d.ts +684 -231
- package/dist/src/Schedule.d.ts.map +1 -1
- package/dist/src/Schedule.js +766 -295
- package/dist/src/Set.d.ts +89 -40
- package/dist/src/Set.d.ts.map +1 -1
- package/dist/src/Set.js +50 -29
- package/dist/src/Sqlite.d.ts +29 -72
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +41 -46
- package/dist/src/StackTrace.d.ts +40 -0
- package/dist/src/StackTrace.d.ts.map +1 -0
- package/dist/src/StackTrace.js +140 -0
- package/dist/src/Store.d.ts +5 -4
- package/dist/src/Store.d.ts.map +1 -1
- package/dist/src/Store.js +5 -4
- package/dist/src/String.d.ts +7 -1
- package/dist/src/String.d.ts.map +1 -1
- package/dist/src/String.js +20 -7
- package/dist/src/Task.d.ts +3572 -1770
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +1879 -1274
- package/dist/src/Test.d.ts +17 -125
- package/dist/src/Test.d.ts.map +1 -1
- package/dist/src/Test.js +17 -68
- package/dist/src/Time.d.ts +108 -49
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +172 -73
- package/dist/src/Type.d.ts +3542 -1926
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +3070 -1784
- package/dist/src/Types.d.ts +200 -108
- package/dist/src/Types.d.ts.map +1 -1
- package/dist/src/Types.js +39 -8
- package/dist/src/WebSocket.d.ts +48 -23
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/WebSocket.js +15 -6
- package/dist/src/Worker.d.ts +94 -36
- package/dist/src/Worker.d.ts.map +1 -1
- package/dist/src/Worker.js +58 -24
- package/dist/src/index.d.ts +55 -52
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -1
- package/dist/src/intl/cs.d.ts +94 -0
- package/dist/src/intl/cs.d.ts.map +1 -0
- package/dist/src/intl/cs.js +220 -0
- package/dist/src/intl/index.d.ts +7 -0
- package/dist/src/intl/index.d.ts.map +1 -0
- package/dist/src/intl/index.js +6 -0
- package/dist/src/local-first/Db.d.ts +12 -8
- package/dist/src/local-first/Db.d.ts.map +1 -1
- package/dist/src/local-first/Db.js +109 -132
- package/dist/src/local-first/Error.d.ts +4 -4
- package/dist/src/local-first/Evolu.d.ts +338 -92
- package/dist/src/local-first/Evolu.d.ts.map +1 -1
- package/dist/src/local-first/Evolu.js +47 -55
- package/dist/src/local-first/LocalAuth.d.ts +4 -4
- package/dist/src/local-first/LocalAuth.d.ts.map +1 -1
- package/dist/src/local-first/Owner.d.ts +61 -24
- package/dist/src/local-first/Owner.d.ts.map +1 -1
- package/dist/src/local-first/Owner.js +45 -8
- package/dist/src/local-first/Protocol.d.ts +44 -31
- package/dist/src/local-first/Protocol.d.ts.map +1 -1
- package/dist/src/local-first/Protocol.js +36 -13
- package/dist/src/local-first/Query.d.ts +147 -62
- package/dist/src/local-first/Query.d.ts.map +1 -1
- package/dist/src/local-first/Query.js +112 -58
- package/dist/src/local-first/Relay.d.ts +44 -14
- package/dist/src/local-first/Relay.d.ts.map +1 -1
- package/dist/src/local-first/Schema.d.ts +92 -41
- package/dist/src/local-first/Schema.d.ts.map +1 -1
- package/dist/src/local-first/Schema.js +25 -8
- package/dist/src/local-first/Shared.d.ts +23 -21
- package/dist/src/local-first/Shared.d.ts.map +1 -1
- package/dist/src/local-first/Shared.js +100 -57
- package/dist/src/local-first/Storage.d.ts +53 -32
- package/dist/src/local-first/Storage.d.ts.map +1 -1
- package/dist/src/local-first/Storage.js +194 -234
- package/dist/src/local-first/Timestamp.d.ts +21 -21
- package/dist/src/local-first/Timestamp.d.ts.map +1 -1
- package/dist/src/local-first/Timestamp.js +2 -2
- package/dist/src/local-first/index.d.ts +11 -11
- package/package.json +14 -13
- package/src/Array.ts +306 -205
- package/src/Assert.ts +54 -69
- package/src/BigInt.ts +6 -3
- package/src/Brand.ts +27 -40
- package/src/Buffer.ts +28 -12
- package/src/Cache.ts +9 -4
- package/src/Callbacks.ts +30 -19
- package/src/Console.ts +156 -84
- package/src/Crypto.ts +83 -41
- package/src/Eq.ts +95 -22
- package/src/Error.ts +8 -4
- package/src/Function.ts +167 -59
- package/src/Http.ts +549 -0
- package/src/Identicon.ts +16 -7
- package/src/LeakDetector.ts +182 -0
- package/src/LockManager.ts +43 -39
- package/src/Lookup.ts +62 -28
- package/src/Microtask.ts +19 -23
- package/src/Number.ts +64 -12
- package/src/Object.ts +173 -49
- package/src/Option.ts +10 -7
- package/src/Order.ts +23 -21
- package/src/Platform.ts +136 -0
- package/src/Polyfills.ts +6 -12
- package/src/Random.ts +32 -19
- package/src/Redacted.ts +44 -30
- package/src/Ref.ts +14 -6
- package/src/RefCount.ts +38 -80
- package/src/Relation.ts +202 -10
- package/src/Resource.ts +1199 -591
- package/src/Result.ts +930 -271
- package/src/Schedule.ts +859 -343
- package/src/Set.ts +89 -40
- package/src/Sqlite.ts +144 -138
- package/src/StackTrace.ts +230 -0
- package/src/Store.ts +8 -7
- package/src/String.ts +22 -5
- package/src/Task.ts +5101 -2832
- package/src/Test.ts +20 -168
- package/src/Time.ts +293 -90
- package/src/Type.ts +10034 -4117
- package/src/Types.ts +227 -110
- package/src/WebSocket.ts +64 -36
- package/src/Worker.ts +180 -72
- package/src/index.ts +55 -52
- package/src/intl/cs.ts +388 -0
- package/src/intl/index.ts +7 -0
- package/src/local-first/Db.ts +152 -179
- package/src/local-first/Error.ts +4 -4
- package/src/local-first/Evolu.ts +495 -250
- package/src/local-first/LocalAuth.ts +6 -12
- package/src/local-first/Owner.ts +58 -21
- package/src/local-first/Protocol.ts +49 -31
- package/src/local-first/Query.ts +146 -61
- package/src/local-first/Relay.ts +51 -21
- package/src/local-first/Schema.ts +109 -51
- package/src/local-first/Shared.ts +266 -226
- package/src/local-first/Storage.ts +266 -264
- package/src/local-first/Timestamp.ts +25 -18
- package/src/local-first/index.ts +11 -11
- package/dist/src/Skiplist.d.ts +0 -28
- package/dist/src/Skiplist.d.ts.map +0 -1
- package/dist/src/Skiplist.js +0 -64
- package/dist/src/Tracer.d.ts +0 -48
- package/dist/src/Tracer.d.ts.map +0 -1
- package/dist/src/Tracer.js +0 -6
- package/src/Skiplist.ts +0 -108
- package/src/Tracer.ts +0 -54
package/src/local-first/Query.ts
CHANGED
|
@@ -21,15 +21,14 @@ import {
|
|
|
21
21
|
TableNode,
|
|
22
22
|
ValueNode,
|
|
23
23
|
} from "kysely";
|
|
24
|
-
import type { Brand } from "../Brand.
|
|
25
|
-
import { createRandomBytes } from "../Crypto.
|
|
26
|
-
import type { ReadonlyRecord } from "../Object.
|
|
27
|
-
import {
|
|
28
|
-
import type { SqliteQueryString } from "../Sqlite.
|
|
29
|
-
import { eqSqliteValue, SqliteValue } from "../Sqlite.
|
|
30
|
-
import { createId, String } from "../Type.
|
|
31
|
-
import type {
|
|
32
|
-
import type { EvoluSchema } from "./Schema.js";
|
|
24
|
+
import type { Brand } from "../Brand.ts";
|
|
25
|
+
import { createRandomBytes } from "../Crypto.ts";
|
|
26
|
+
import type { ReadonlyRecord } from "../Object.ts";
|
|
27
|
+
import { createMutableRecord, isPlainObject } from "../Object.ts";
|
|
28
|
+
import type { SqliteQueryString } from "../Sqlite.ts";
|
|
29
|
+
import { eqSqliteValue, SqliteValue } from "../Sqlite.ts";
|
|
30
|
+
import { createId, String } from "../Type.ts";
|
|
31
|
+
import type { EvoluSchema } from "./Schema.ts";
|
|
33
32
|
|
|
34
33
|
export { sql as kyselySql } from "kysely";
|
|
35
34
|
export type { NotNull as KyselyNotNull } from "kysely";
|
|
@@ -40,9 +39,27 @@ export type { NotNull as KyselyNotNull } from "kysely";
|
|
|
40
39
|
* ### Example
|
|
41
40
|
*
|
|
42
41
|
* ```ts
|
|
42
|
+
* import {
|
|
43
|
+
* createQueryBuilder,
|
|
44
|
+
* id,
|
|
45
|
+
* NonEmptyTrimmedString100,
|
|
46
|
+
* type Query,
|
|
47
|
+
* } from "@evolu/common";
|
|
48
|
+
*
|
|
49
|
+
* const TodoId = id("Todo");
|
|
50
|
+
* type TodoId = typeof TodoId.Output;
|
|
51
|
+
* const Schema = {
|
|
52
|
+
* todo: { id: TodoId, title: NonEmptyTrimmedString100 },
|
|
53
|
+
* };
|
|
43
54
|
* const createQuery = createQueryBuilder(Schema);
|
|
44
55
|
* const allTodos = createQuery((db) => db.selectFrom("todo").selectAll());
|
|
56
|
+
*
|
|
45
57
|
* type AllTodosRow = typeof allTodos.Row;
|
|
58
|
+
* expectTypeOf<typeof allTodos>().toExtend<Query<typeof Schema>>();
|
|
59
|
+
* expectTypeOf<AllTodosRow["id"]>().toEqualTypeOf<TodoId>();
|
|
60
|
+
* expectTypeOf<
|
|
61
|
+
* AllTodosRow["title"]
|
|
62
|
+
* >().toEqualTypeOf<NonEmptyTrimmedString100 | null>();
|
|
46
63
|
* ```
|
|
47
64
|
*/
|
|
48
65
|
export type Query<
|
|
@@ -59,11 +76,25 @@ export type Query<
|
|
|
59
76
|
* ### Example
|
|
60
77
|
*
|
|
61
78
|
* ```ts
|
|
79
|
+
* import {
|
|
80
|
+
* createQueryBuilder,
|
|
81
|
+
* id,
|
|
82
|
+
* type InferRow,
|
|
83
|
+
* NonEmptyTrimmedString100,
|
|
84
|
+
* } from "@evolu/common";
|
|
85
|
+
*
|
|
86
|
+
* const Schema = {
|
|
87
|
+
* todo: { id: id("Todo"), title: NonEmptyTrimmedString100 },
|
|
88
|
+
* };
|
|
62
89
|
* const createQuery = createQueryBuilder(Schema);
|
|
63
90
|
* const allTodos = createQuery((db) =>
|
|
64
91
|
* db.selectFrom("todo").selectAll(),
|
|
65
92
|
* );
|
|
93
|
+
*
|
|
66
94
|
* type AllTodosRow = typeof allTodos.Row;
|
|
95
|
+
* expectTypeOf<AllTodosRow>().toEqualTypeOf<
|
|
96
|
+
* InferRow<typeof allTodos>
|
|
97
|
+
* >();
|
|
67
98
|
* ```
|
|
68
99
|
*/
|
|
69
100
|
Row: R;
|
|
@@ -91,25 +122,42 @@ export interface Row {
|
|
|
91
122
|
* ### Example
|
|
92
123
|
*
|
|
93
124
|
* ```ts
|
|
94
|
-
* import {
|
|
125
|
+
* import {
|
|
126
|
+
* createQueryBuilder,
|
|
127
|
+
* evoluJsonArrayFrom,
|
|
128
|
+
* id,
|
|
129
|
+
* NonEmptyTrimmedString100,
|
|
130
|
+
* } from "@evolu/common";
|
|
95
131
|
*
|
|
96
|
-
* const
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
132
|
+
* const PersonId = id("Person");
|
|
133
|
+
* const Schema = {
|
|
134
|
+
* person: { id: PersonId },
|
|
135
|
+
* pet: {
|
|
136
|
+
* id: id("Pet"),
|
|
137
|
+
* name: NonEmptyTrimmedString100,
|
|
138
|
+
* personId: PersonId,
|
|
139
|
+
* },
|
|
140
|
+
* };
|
|
141
|
+
* const createQuery = createQueryBuilder(Schema);
|
|
142
|
+
* const people = createQuery((db) =>
|
|
143
|
+
* db
|
|
144
|
+
* .selectFrom("person")
|
|
145
|
+
* .select(["person.id"])
|
|
146
|
+
* .select((eb) => [
|
|
147
|
+
* evoluJsonArrayFrom(
|
|
148
|
+
* eb
|
|
149
|
+
* .selectFrom("pet")
|
|
150
|
+
* .select(["pet.id as petId", "pet.name"])
|
|
151
|
+
* .whereRef("pet.personId", "=", "person.id")
|
|
152
|
+
* .orderBy("pet.name"),
|
|
153
|
+
* ).as("pets"),
|
|
154
|
+
* ]),
|
|
155
|
+
* );
|
|
109
156
|
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
157
|
+
* expectTypeOf<(typeof people.Row.pets)[number]>().toEqualTypeOf<{
|
|
158
|
+
* petId: typeof Schema.pet.id.Output;
|
|
159
|
+
* name: NonEmptyTrimmedString100 | null;
|
|
160
|
+
* }>();
|
|
113
161
|
* ```
|
|
114
162
|
*/
|
|
115
163
|
export const evoluJsonArrayFrom = <O>(
|
|
@@ -133,25 +181,44 @@ export const evoluJsonArrayFrom = <O>(
|
|
|
133
181
|
* ### Example
|
|
134
182
|
*
|
|
135
183
|
* ```ts
|
|
136
|
-
* import {
|
|
184
|
+
* import {
|
|
185
|
+
* createQueryBuilder,
|
|
186
|
+
* evoluJsonObjectFrom,
|
|
187
|
+
* id,
|
|
188
|
+
* NonEmptyTrimmedString100,
|
|
189
|
+
* SqliteBoolean,
|
|
190
|
+
* } from "@evolu/common";
|
|
137
191
|
*
|
|
138
|
-
* const
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
192
|
+
* const PersonId = id("Person");
|
|
193
|
+
* const Schema = {
|
|
194
|
+
* person: { id: PersonId },
|
|
195
|
+
* pet: {
|
|
196
|
+
* id: id("Pet"),
|
|
197
|
+
* name: NonEmptyTrimmedString100,
|
|
198
|
+
* personId: PersonId,
|
|
199
|
+
* isFavorite: SqliteBoolean,
|
|
200
|
+
* },
|
|
201
|
+
* };
|
|
202
|
+
* const createQuery = createQueryBuilder(Schema);
|
|
203
|
+
* const people = createQuery((db) =>
|
|
204
|
+
* db
|
|
205
|
+
* .selectFrom("person")
|
|
206
|
+
* .select(["person.id"])
|
|
207
|
+
* .select((eb) => [
|
|
208
|
+
* evoluJsonObjectFrom(
|
|
209
|
+
* eb
|
|
210
|
+
* .selectFrom("pet")
|
|
211
|
+
* .select(["pet.id as petId", "pet.name"])
|
|
212
|
+
* .whereRef("pet.personId", "=", "person.id")
|
|
213
|
+
* .where("pet.isFavorite", "=", 1),
|
|
214
|
+
* ).as("favoritePet"),
|
|
215
|
+
* ]),
|
|
216
|
+
* );
|
|
151
217
|
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
218
|
+
* expectTypeOf<typeof people.Row.favoritePet>().toEqualTypeOf<{
|
|
219
|
+
* petId: typeof Schema.pet.id.Output;
|
|
220
|
+
* name: NonEmptyTrimmedString100 | null;
|
|
221
|
+
* } | null>();
|
|
155
222
|
* ```
|
|
156
223
|
*/
|
|
157
224
|
export const evoluJsonObjectFrom = <O>(
|
|
@@ -173,24 +240,42 @@ export const evoluJsonObjectFrom = <O>(
|
|
|
173
240
|
* ### Example
|
|
174
241
|
*
|
|
175
242
|
* ```ts
|
|
176
|
-
* import {
|
|
243
|
+
* import {
|
|
244
|
+
* createQueryBuilder,
|
|
245
|
+
* evoluJsonBuildObject,
|
|
246
|
+
* id,
|
|
247
|
+
* kyselySql,
|
|
248
|
+
* NonEmptyTrimmedString100,
|
|
249
|
+
* } from "@evolu/common";
|
|
177
250
|
*
|
|
178
|
-
* const
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
251
|
+
* const Schema = {
|
|
252
|
+
* person: {
|
|
253
|
+
* id: id("Person"),
|
|
254
|
+
* firstName: NonEmptyTrimmedString100,
|
|
255
|
+
* lastName: NonEmptyTrimmedString100,
|
|
256
|
+
* },
|
|
257
|
+
* };
|
|
258
|
+
* const createQuery = createQueryBuilder(Schema);
|
|
259
|
+
* const people = createQuery((db) =>
|
|
260
|
+
* db
|
|
261
|
+
* .selectFrom("person")
|
|
262
|
+
* .select("person.id")
|
|
263
|
+
* .select((eb) => [
|
|
264
|
+
* evoluJsonBuildObject({
|
|
265
|
+
* first: eb.ref("firstName"),
|
|
266
|
+
* last: eb.ref("lastName"),
|
|
267
|
+
* full: kyselySql<string>`${eb.ref("firstName")} || ' ' || ${eb.ref(
|
|
268
|
+
* "lastName",
|
|
269
|
+
* )}`,
|
|
270
|
+
* }).as("name"),
|
|
271
|
+
* ]),
|
|
272
|
+
* );
|
|
189
273
|
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
274
|
+
* expectTypeOf<typeof people.Row.name>().toEqualTypeOf<{
|
|
275
|
+
* first: NonEmptyTrimmedString100 | null;
|
|
276
|
+
* last: NonEmptyTrimmedString100 | null;
|
|
277
|
+
* full: string;
|
|
278
|
+
* }>();
|
|
194
279
|
* ```
|
|
195
280
|
*/
|
|
196
281
|
export const evoluJsonBuildObject = <
|
|
@@ -232,7 +317,7 @@ export const getJsonObjectArgs = (
|
|
|
232
317
|
|
|
233
318
|
/** Rows returned by a query. */
|
|
234
319
|
export type QueryRows<R extends Row = Row> = ReadonlyArray<
|
|
235
|
-
Readonly<
|
|
320
|
+
Readonly<KyselySimplify<R>>
|
|
236
321
|
>;
|
|
237
322
|
|
|
238
323
|
export type Queries<
|
|
@@ -396,7 +481,7 @@ const parse = (obj: unknown): unknown => {
|
|
|
396
481
|
const parseObject = (
|
|
397
482
|
obj: ReadonlyRecord<string, unknown>,
|
|
398
483
|
): ReadonlyRecord<string, unknown> => {
|
|
399
|
-
const result =
|
|
484
|
+
const result = createMutableRecord();
|
|
400
485
|
for (const key in obj) {
|
|
401
486
|
result[key] = parse(obj[key]);
|
|
402
487
|
}
|
package/src/local-first/Relay.ts
CHANGED
|
@@ -10,35 +10,35 @@ import {
|
|
|
10
10
|
firstInArray,
|
|
11
11
|
isNonEmptyArray,
|
|
12
12
|
mapArray,
|
|
13
|
-
} from "../Array.
|
|
14
|
-
import { assert } from "../Assert.
|
|
15
|
-
import type { TimingSafeEqualDep } from "../Crypto.
|
|
16
|
-
import { err, ok } from "../Result.
|
|
17
|
-
import type { SqliteDep } from "../Sqlite.
|
|
18
|
-
import { sql } from "../Sqlite.
|
|
19
|
-
import { createMutexByKey } from "../Task.
|
|
20
|
-
import { Name, PositiveInt, uint8ArrayToBase64Url } from "../Type.
|
|
21
|
-
import { isPromiseLike, type Awaitable } from "../Types.
|
|
13
|
+
} from "../Array.ts";
|
|
14
|
+
import { assert } from "../Assert.ts";
|
|
15
|
+
import type { TimingSafeEqualDep } from "../Crypto.ts";
|
|
16
|
+
import { err, ok } from "../Result.ts";
|
|
17
|
+
import type { SqliteDep } from "../Sqlite.ts";
|
|
18
|
+
import { sql } from "../Sqlite.ts";
|
|
19
|
+
import { createMutexByKey } from "../Task.ts";
|
|
20
|
+
import { Name, PositiveInt, uint8ArrayToBase64Url } from "../Type.ts";
|
|
21
|
+
import { isPromiseLike, type Awaitable } from "../Types.ts";
|
|
22
22
|
import {
|
|
23
23
|
OwnerId,
|
|
24
24
|
ownerIdBytesToOwnerId,
|
|
25
25
|
// OwnerTransport,
|
|
26
26
|
OwnerWriteKey,
|
|
27
|
-
} from "./Owner.
|
|
27
|
+
} from "./Owner.ts";
|
|
28
28
|
import type {
|
|
29
29
|
EncryptedDbChange,
|
|
30
30
|
SqliteStorageDeps,
|
|
31
31
|
Storage,
|
|
32
32
|
StorageConfig,
|
|
33
33
|
StorageQuotaError,
|
|
34
|
-
} from "./Storage.
|
|
34
|
+
} from "./Storage.ts";
|
|
35
35
|
import {
|
|
36
36
|
createBaseSqliteStorage,
|
|
37
37
|
getTimestampInsertStrategy,
|
|
38
38
|
readOwnerUsageOrDefault,
|
|
39
39
|
updateOwnerUsage,
|
|
40
|
-
} from "./Storage.
|
|
41
|
-
import { timestampToTimestampBytes } from "./Timestamp.
|
|
40
|
+
} from "./Storage.ts";
|
|
41
|
+
import { timestampToTimestampBytes } from "./Timestamp.ts";
|
|
42
42
|
|
|
43
43
|
export interface RelayConfig extends StorageConfig {
|
|
44
44
|
/**
|
|
@@ -77,20 +77,50 @@ export interface RelayConfig extends StorageConfig {
|
|
|
77
77
|
* ### Example
|
|
78
78
|
*
|
|
79
79
|
* ```ts
|
|
80
|
-
*
|
|
80
|
+
* import {
|
|
81
|
+
* AppName,
|
|
82
|
+
* createAppOwner,
|
|
83
|
+
* createEvolu,
|
|
84
|
+
* createOwnerWebSocketTransport,
|
|
85
|
+
* createOwnerSecret,
|
|
86
|
+
* createRandomBytes,
|
|
87
|
+
* id,
|
|
88
|
+
* type AnyTask,
|
|
89
|
+
* } from "@evolu/common";
|
|
90
|
+
* import type { RelayConfig } from "@evolu/common/local-first";
|
|
91
|
+
*
|
|
92
|
+
* // Create once, persist the mnemonic securely, and restore it on later runs.
|
|
93
|
+
* const appOwner = createAppOwner(
|
|
94
|
+
* createOwnerSecret({ randomBytes: createRandomBytes() }),
|
|
95
|
+
* );
|
|
96
|
+
* // Client: include the OwnerId so the relay can authenticate the connection.
|
|
81
97
|
* const transport = createOwnerWebSocketTransport({
|
|
82
98
|
* url: "wss://relay.evolu.dev",
|
|
83
|
-
* ownerId:
|
|
99
|
+
* ownerId: appOwner.id,
|
|
84
100
|
* });
|
|
85
101
|
*
|
|
86
|
-
* const
|
|
87
|
-
*
|
|
88
|
-
*
|
|
102
|
+
* const createTodoEvolu = createEvolu(
|
|
103
|
+
* { todo: { id: id("Todo") } },
|
|
104
|
+
* {
|
|
105
|
+
* appName: AppName.orThrow("AuthenticatedRelayExample"),
|
|
106
|
+
* appOwner,
|
|
107
|
+
* transports: [transport],
|
|
108
|
+
* },
|
|
109
|
+
* );
|
|
110
|
+
* expectTypeOf(createTodoEvolu).toExtend<AnyTask>();
|
|
89
111
|
*
|
|
112
|
+
* // Relay: accept owners allowed by the app's access policy.
|
|
113
|
+
* type IsOwnerAllowed = NonNullable<RelayConfig["isOwnerAllowed"]>;
|
|
114
|
+
* const allowedOwnerIds = new Set([appOwner.id]);
|
|
115
|
+
* const isOwnerAllowed: IsOwnerAllowed = (ownerId, { signal }) =>
|
|
116
|
+
* !signal.aborted && allowedOwnerIds.has(ownerId);
|
|
90
117
|
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
118
|
+
* expect(
|
|
119
|
+
* isOwnerAllowed(appOwner.id, {
|
|
120
|
+
* signal: new AbortController().signal,
|
|
121
|
+
* }),
|
|
122
|
+
* ).toBe(true);
|
|
123
|
+
* expect(transport.url).toContain(`ownerId=${appOwner.id}`);
|
|
94
124
|
* ```
|
|
95
125
|
*/
|
|
96
126
|
readonly isOwnerAllowed?: (
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import * as Kysely from "kysely";
|
|
8
|
-
import {
|
|
8
|
+
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
9
|
+
import { assertNonNullable } from "../Assert.ts";
|
|
10
|
+
import { getOwnProp, mapObject, type ReadonlyRecord } from "../Object.ts";
|
|
9
11
|
import {
|
|
10
12
|
eqSqliteIndex,
|
|
11
13
|
getSqliteSchema,
|
|
@@ -19,29 +21,31 @@ import {
|
|
|
19
21
|
type SqliteQueryOptions,
|
|
20
22
|
type SqliteSchema,
|
|
21
23
|
SqliteValue,
|
|
22
|
-
} from "../Sqlite.
|
|
23
|
-
import type { InferType } from "../Type.js";
|
|
24
|
+
} from "../Sqlite.ts";
|
|
24
25
|
import {
|
|
25
26
|
DateIso,
|
|
26
27
|
type Id,
|
|
27
28
|
IdBytes,
|
|
29
|
+
type InferType,
|
|
30
|
+
Null,
|
|
28
31
|
nullOr,
|
|
29
32
|
object,
|
|
30
|
-
type
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
import type {
|
|
34
|
-
import {
|
|
33
|
+
type ObjectType,
|
|
34
|
+
type UnionType,
|
|
35
|
+
} from "../Type.ts";
|
|
36
|
+
import type { CompileTimeError, Simplify } from "../Types.ts";
|
|
37
|
+
import type { AppOwner } from "./Owner.ts";
|
|
38
|
+
import { OwnerId } from "./Owner.ts";
|
|
35
39
|
import type {
|
|
36
40
|
evoluJsonArrayFrom,
|
|
37
41
|
evoluJsonObjectFrom,
|
|
38
42
|
Query,
|
|
39
43
|
Row,
|
|
40
|
-
} from "./Query.
|
|
41
|
-
import type { CrdtMessage, DbChange } from "./Storage.
|
|
42
|
-
import { TimestampBytes } from "./Timestamp.
|
|
44
|
+
} from "./Query.ts";
|
|
45
|
+
import type { CrdtMessage, DbChange } from "./Storage.ts";
|
|
46
|
+
import { TimestampBytes } from "./Timestamp.ts";
|
|
43
47
|
|
|
44
|
-
/** Any
|
|
48
|
+
/** Any Standard Schema V1 declaration. */
|
|
45
49
|
export type AnyStandardSchemaV1 = StandardSchemaV1<any, any>;
|
|
46
50
|
|
|
47
51
|
/**
|
|
@@ -56,26 +60,36 @@ export type AnyStandardSchemaV1 = StandardSchemaV1<any, any>;
|
|
|
56
60
|
* ### Example
|
|
57
61
|
*
|
|
58
62
|
* ```ts
|
|
59
|
-
*
|
|
63
|
+
* import * as z from "zod";
|
|
64
|
+
* import {
|
|
65
|
+
* id,
|
|
66
|
+
* NonEmptyTrimmedString100,
|
|
67
|
+
* nullOr,
|
|
68
|
+
* SqliteBoolean,
|
|
69
|
+
* } from "@evolu/common";
|
|
70
|
+
*
|
|
71
|
+
* // Evolu Type
|
|
60
72
|
* const TodoId = id("Todo");
|
|
61
|
-
* type TodoId = typeof TodoId.
|
|
73
|
+
* type TodoId = typeof TodoId.Output;
|
|
62
74
|
*
|
|
63
75
|
* const Schema = {
|
|
64
76
|
* todo: {
|
|
65
77
|
* id: TodoId,
|
|
66
|
-
* title:
|
|
78
|
+
* title: NonEmptyTrimmedString100,
|
|
67
79
|
* isCompleted: nullOr(SqliteBoolean),
|
|
68
80
|
* },
|
|
69
81
|
* };
|
|
82
|
+
* expectOk(Schema.todo.title.fromUnknown("Write docs"), "Write docs");
|
|
70
83
|
*
|
|
71
|
-
* //
|
|
72
|
-
* const
|
|
84
|
+
* // Zod, or another Standard Schema library
|
|
85
|
+
* const ZodSchema = {
|
|
73
86
|
* todo: {
|
|
74
|
-
* id: TodoId,
|
|
87
|
+
* id: TodoId,
|
|
75
88
|
* title: z.string().min(1).max(100),
|
|
76
89
|
* isCompleted: z.union([z.literal(0), z.literal(1)]).nullable(),
|
|
77
90
|
* },
|
|
78
91
|
* };
|
|
92
|
+
* expect(ZodSchema.todo.title.safeParse("Write docs").success).toBe(true);
|
|
79
93
|
* ```
|
|
80
94
|
*/
|
|
81
95
|
export type EvoluSchema = ReadonlyRecord<
|
|
@@ -150,7 +164,7 @@ export type CreateQuery<S extends EvoluSchema> = <R extends Row>(
|
|
|
150
164
|
>,
|
|
151
165
|
) => Kysely.SelectQueryBuilder<any, any, R>,
|
|
152
166
|
options?: SqliteQueryOptions,
|
|
153
|
-
) => Query<S, Simplify<R>>;
|
|
167
|
+
) => Query<S, Kysely.Simplify<R>>;
|
|
154
168
|
|
|
155
169
|
/**
|
|
156
170
|
* System columns that are implicitly defined by Evolu.
|
|
@@ -161,7 +175,12 @@ export type CreateQuery<S extends EvoluSchema> = <R extends Row>(
|
|
|
161
175
|
* mark rows as deleted.
|
|
162
176
|
* - `ownerId`: Represents ownership and logically partitions the database.
|
|
163
177
|
*/
|
|
164
|
-
export const SystemColumns
|
|
178
|
+
export const SystemColumns: ObjectType<{
|
|
179
|
+
readonly createdAt: typeof DateIso;
|
|
180
|
+
readonly updatedAt: typeof DateIso;
|
|
181
|
+
readonly isDeleted: UnionType<readonly [typeof SqliteBoolean, typeof Null]>;
|
|
182
|
+
readonly ownerId: typeof OwnerId;
|
|
183
|
+
}> = /*#__PURE__*/ object({
|
|
165
184
|
createdAt: DateIso,
|
|
166
185
|
updatedAt: DateIso,
|
|
167
186
|
isDeleted: /*#__PURE__*/ nullOr(SqliteBoolean),
|
|
@@ -218,24 +237,50 @@ export interface MutationOptions {
|
|
|
218
237
|
* ### Example
|
|
219
238
|
*
|
|
220
239
|
* ```ts
|
|
221
|
-
*
|
|
240
|
+
* import {
|
|
241
|
+
* createAppOwner,
|
|
242
|
+
* createOwnerSecret,
|
|
243
|
+
* createRandomBytes,
|
|
244
|
+
* createSharedOwner,
|
|
245
|
+
* deriveShardOwner,
|
|
246
|
+
* id,
|
|
247
|
+
* NonEmptyTrimmedString100,
|
|
248
|
+
* type Evolu,
|
|
249
|
+
* } from "@evolu/common";
|
|
250
|
+
*
|
|
251
|
+
* const Schema = {
|
|
252
|
+
* task: { id: id("Task"), title: NonEmptyTrimmedString100 },
|
|
253
|
+
* comment: { id: id("Comment"), text: NonEmptyTrimmedString100 },
|
|
254
|
+
* };
|
|
255
|
+
* const randomBytes = createRandomBytes();
|
|
256
|
+
* // Create once, persist the mnemonic securely, and restore it on later runs.
|
|
257
|
+
* const appOwner = createAppOwner(createOwnerSecret({ randomBytes }));
|
|
222
258
|
* const projectOwner = deriveShardOwner(appOwner, [
|
|
223
259
|
* "project",
|
|
224
|
-
*
|
|
260
|
+
* "project-1",
|
|
225
261
|
* ]);
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
* { title: "Task 1" },
|
|
229
|
-
* { ownerId: projectOwner.id },
|
|
262
|
+
* const sharedOwner = createSharedOwner(
|
|
263
|
+
* createOwnerSecret({ randomBytes }),
|
|
230
264
|
* );
|
|
231
265
|
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
266
|
+
* const insertOwnedRows = (evolu: Evolu<typeof Schema>): void => {
|
|
267
|
+
* // Partition app data by project.
|
|
268
|
+
* evolu.insert(
|
|
269
|
+
* "task",
|
|
270
|
+
* { title: NonEmptyTrimmedString100.orThrow("Task 1") },
|
|
271
|
+
* { ownerId: projectOwner.id },
|
|
272
|
+
* );
|
|
273
|
+
*
|
|
274
|
+
* // Put collaborative data under a shared owner.
|
|
275
|
+
* evolu.insert(
|
|
276
|
+
* "comment",
|
|
277
|
+
* { text: NonEmptyTrimmedString100.orThrow("Hello") },
|
|
278
|
+
* { ownerId: sharedOwner.id },
|
|
279
|
+
* );
|
|
280
|
+
* };
|
|
281
|
+
*
|
|
282
|
+
* expect(projectOwner.type).toBe("ShardOwner");
|
|
283
|
+
* expect(sharedOwner.type).toBe("SharedOwner");
|
|
239
284
|
* ```
|
|
240
285
|
*/
|
|
241
286
|
readonly ownerId?: OwnerId;
|
|
@@ -316,10 +361,7 @@ export type ValidateNoSystemColumns<S extends EvoluSchema> =
|
|
|
316
361
|
? keyof S[TableName] extends infer ColumnName
|
|
317
362
|
? ColumnName extends keyof S[TableName]
|
|
318
363
|
? ColumnName extends
|
|
319
|
-
| "
|
|
320
|
-
| "updatedAt"
|
|
321
|
-
| "isDeleted"
|
|
322
|
-
| "ownerId"
|
|
364
|
+
"createdAt" | "updatedAt" | "isDeleted" | "ownerId"
|
|
323
365
|
? SchemaValidationError<`Table "${TableName & string}" uses system column name "${ColumnName & string}". System columns (createdAt, updatedAt, isDeleted, ownerId) are added automatically.`>
|
|
324
366
|
: never
|
|
325
367
|
: never
|
|
@@ -343,8 +385,10 @@ export type ValidateColumnTypes<S extends EvoluSchema> =
|
|
|
343
385
|
: never;
|
|
344
386
|
|
|
345
387
|
/** Schema validation error that shows clear, readable messages */
|
|
346
|
-
export type SchemaValidationError<Message extends string> =
|
|
347
|
-
|
|
388
|
+
export type SchemaValidationError<Message extends string> = CompileTimeError<
|
|
389
|
+
"Schema",
|
|
390
|
+
Message
|
|
391
|
+
>;
|
|
348
392
|
|
|
349
393
|
/** Makes columns whose output type includes `null` optional. */
|
|
350
394
|
export type NullableColumnsToOptional<T extends TableSchema> = {
|
|
@@ -382,12 +426,10 @@ export const evoluSchemaToSqliteSchema = <S extends EvoluSchema>(
|
|
|
382
426
|
);
|
|
383
427
|
|
|
384
428
|
const indexes = indexesConfig
|
|
385
|
-
? indexesConfig(createIndex).map(
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
}),
|
|
390
|
-
)
|
|
429
|
+
? indexesConfig(createIndex).map((index): SqliteIndex => ({
|
|
430
|
+
name: index.toOperationNode().name.name,
|
|
431
|
+
sql: index.compile().sql,
|
|
432
|
+
}))
|
|
391
433
|
: [];
|
|
392
434
|
|
|
393
435
|
return { tables, indexes };
|
|
@@ -405,21 +447,36 @@ export const evoluSchemaToSqliteSchema = <S extends EvoluSchema>(
|
|
|
405
447
|
* ### Example
|
|
406
448
|
*
|
|
407
449
|
* ```ts
|
|
450
|
+
* import {
|
|
451
|
+
* createQueryBuilder,
|
|
452
|
+
* id,
|
|
453
|
+
* NonEmptyTrimmedString100,
|
|
454
|
+
* nullOr,
|
|
455
|
+
* SqliteBoolean,
|
|
456
|
+
* } from "@evolu/common";
|
|
457
|
+
*
|
|
458
|
+
* const TodoId = id("Todo");
|
|
459
|
+
* type TodoId = typeof TodoId.Output;
|
|
408
460
|
* const Schema = {
|
|
409
461
|
* todo: {
|
|
410
|
-
* id:
|
|
411
|
-
* title:
|
|
462
|
+
* id: TodoId,
|
|
463
|
+
* title: NonEmptyTrimmedString100,
|
|
412
464
|
* isCompleted: nullOr(SqliteBoolean),
|
|
413
465
|
* },
|
|
414
466
|
* };
|
|
415
467
|
*
|
|
416
|
-
* // Create
|
|
468
|
+
* // Create one typed builder per schema and reuse it for every query.
|
|
417
469
|
* const createQuery = createQueryBuilder(Schema);
|
|
418
|
-
*
|
|
419
|
-
* // Use it for all queries
|
|
420
470
|
* const todosQuery = createQuery((db) =>
|
|
421
471
|
* db.selectFrom("todo").select(["id", "title", "isCompleted"]),
|
|
422
472
|
* );
|
|
473
|
+
*
|
|
474
|
+
* expectTypeOf<typeof todosQuery.Row>().toEqualTypeOf<{
|
|
475
|
+
* id: TodoId;
|
|
476
|
+
* title: NonEmptyTrimmedString100 | null;
|
|
477
|
+
* isCompleted: SqliteBoolean | null;
|
|
478
|
+
* }>();
|
|
479
|
+
* expect(todosQuery).toBeTypeOf("string");
|
|
423
480
|
* ```
|
|
424
481
|
*/
|
|
425
482
|
export const createQueryBuilder = <S extends EvoluSchema>(
|
|
@@ -449,7 +506,8 @@ export const ensureSqliteSchema =
|
|
|
449
506
|
currentSchema ??= getEvoluSqliteSchema(deps)();
|
|
450
507
|
|
|
451
508
|
for (const [tableName, newColumns] of Object.entries(newSchema.tables)) {
|
|
452
|
-
|
|
509
|
+
assertNonNullable(newColumns);
|
|
510
|
+
const currentColumns = getOwnProp(currentSchema.tables, tableName);
|
|
453
511
|
if (!currentColumns) {
|
|
454
512
|
queries.push(createAppTable(tableName, newColumns));
|
|
455
513
|
} else {
|