@evolu/common 7.4.0 → 8.0.0-next.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.
Files changed (251) hide show
  1. package/README.md +4 -61
  2. package/dist/src/Array.d.ts +343 -102
  3. package/dist/src/Array.d.ts.map +1 -1
  4. package/dist/src/Array.js +181 -85
  5. package/dist/src/Assert.d.ts +57 -11
  6. package/dist/src/Assert.d.ts.map +1 -1
  7. package/dist/src/Assert.js +47 -11
  8. package/dist/src/BigInt.d.ts +6 -1
  9. package/dist/src/BigInt.d.ts.map +1 -1
  10. package/dist/src/BigInt.js +5 -0
  11. package/dist/src/Brand.d.ts +40 -12
  12. package/dist/src/Brand.d.ts.map +1 -1
  13. package/dist/src/Brand.js +5 -0
  14. package/dist/src/Buffer.d.ts +6 -1
  15. package/dist/src/Buffer.d.ts.map +1 -1
  16. package/dist/src/Buffer.js +7 -2
  17. package/dist/src/Cache.d.ts +10 -2
  18. package/dist/src/Cache.d.ts.map +1 -1
  19. package/dist/src/Cache.js +6 -0
  20. package/dist/src/Callbacks.d.ts +10 -7
  21. package/dist/src/Callbacks.d.ts.map +1 -1
  22. package/dist/src/Callbacks.js +23 -13
  23. package/dist/src/Console.d.ts +361 -69
  24. package/dist/src/Console.d.ts.map +1 -1
  25. package/dist/src/Console.js +217 -117
  26. package/dist/src/Crypto.d.ts +70 -21
  27. package/dist/src/Crypto.d.ts.map +1 -1
  28. package/dist/src/Crypto.js +72 -27
  29. package/dist/src/Eq.d.ts +22 -2
  30. package/dist/src/Eq.d.ts.map +1 -1
  31. package/dist/src/Eq.js +21 -1
  32. package/dist/src/Error.d.ts +23 -12
  33. package/dist/src/Error.d.ts.map +1 -1
  34. package/dist/src/Error.js +27 -11
  35. package/dist/src/Function.d.ts +128 -56
  36. package/dist/src/Function.d.ts.map +1 -1
  37. package/dist/src/Function.js +118 -14
  38. package/dist/src/Identicon.d.ts +5 -0
  39. package/dist/src/Identicon.d.ts.map +1 -1
  40. package/dist/src/Identicon.js +6 -1
  41. package/dist/src/Lookup.d.ts +160 -0
  42. package/dist/src/Lookup.d.ts.map +1 -0
  43. package/dist/src/Lookup.js +192 -0
  44. package/dist/src/Microtask.d.ts +21 -0
  45. package/dist/src/Microtask.d.ts.map +1 -0
  46. package/dist/src/Microtask.js +37 -0
  47. package/dist/src/Number.d.ts +18 -4
  48. package/dist/src/Number.d.ts.map +1 -1
  49. package/dist/src/Number.js +23 -1
  50. package/dist/src/Object.d.ts +110 -5
  51. package/dist/src/Object.d.ts.map +1 -1
  52. package/dist/src/Object.js +108 -5
  53. package/dist/src/Option.d.ts +58 -0
  54. package/dist/src/Option.d.ts.map +1 -0
  55. package/dist/src/Option.js +43 -0
  56. package/dist/src/Order.d.ts +5 -0
  57. package/dist/src/Order.d.ts.map +1 -1
  58. package/dist/src/Order.js +8 -3
  59. package/dist/src/Platform.d.ts +36 -2
  60. package/dist/src/Platform.d.ts.map +1 -1
  61. package/dist/src/Platform.js +10 -6
  62. package/dist/src/Polyfills.d.ts +27 -0
  63. package/dist/src/Polyfills.d.ts.map +1 -0
  64. package/dist/src/Polyfills.js +299 -0
  65. package/dist/src/Random.d.ts +18 -7
  66. package/dist/src/Random.d.ts.map +1 -1
  67. package/dist/src/Random.js +9 -7
  68. package/dist/src/Redacted.d.ts +7 -4
  69. package/dist/src/Redacted.d.ts.map +1 -1
  70. package/dist/src/Redacted.js +5 -0
  71. package/dist/src/Ref.d.ts +31 -16
  72. package/dist/src/Ref.d.ts.map +1 -1
  73. package/dist/src/Ref.js +35 -7
  74. package/dist/src/RefCount.d.ts +62 -0
  75. package/dist/src/RefCount.d.ts.map +1 -0
  76. package/dist/src/RefCount.js +83 -0
  77. package/dist/src/Relation.d.ts +84 -29
  78. package/dist/src/Relation.d.ts.map +1 -1
  79. package/dist/src/Relation.js +83 -105
  80. package/dist/src/Resource.d.ts +263 -0
  81. package/dist/src/Resource.d.ts.map +1 -0
  82. package/dist/src/Resource.js +389 -0
  83. package/dist/src/Result.d.ts +390 -374
  84. package/dist/src/Result.d.ts.map +1 -1
  85. package/dist/src/Result.js +142 -70
  86. package/dist/src/Schedule.d.ts +953 -0
  87. package/dist/src/Schedule.d.ts.map +1 -0
  88. package/dist/src/Schedule.js +1199 -0
  89. package/dist/src/Set.d.ts +181 -0
  90. package/dist/src/Set.d.ts.map +1 -0
  91. package/dist/src/Set.js +137 -0
  92. package/dist/src/Skiplist.d.ts +6 -1
  93. package/dist/src/Skiplist.d.ts.map +1 -1
  94. package/dist/src/Skiplist.js +5 -0
  95. package/dist/src/Sqlite.d.ts +160 -60
  96. package/dist/src/Sqlite.d.ts.map +1 -1
  97. package/dist/src/Sqlite.js +290 -190
  98. package/dist/src/Store.d.ts +36 -28
  99. package/dist/src/Store.d.ts.map +1 -1
  100. package/dist/src/Store.js +55 -15
  101. package/dist/src/String.d.ts +5 -0
  102. package/dist/src/String.d.ts.map +1 -1
  103. package/dist/src/String.js +5 -0
  104. package/dist/src/Task.d.ts +2263 -423
  105. package/dist/src/Task.d.ts.map +1 -1
  106. package/dist/src/Task.js +1488 -348
  107. package/dist/src/Test.d.ts +122 -0
  108. package/dist/src/Test.d.ts.map +1 -0
  109. package/dist/src/Test.js +66 -0
  110. package/dist/src/Time.d.ts +201 -48
  111. package/dist/src/Time.d.ts.map +1 -1
  112. package/dist/src/Time.js +190 -86
  113. package/dist/src/Tracer.d.ts +48 -0
  114. package/dist/src/Tracer.d.ts.map +1 -0
  115. package/dist/src/Tracer.js +6 -0
  116. package/dist/src/Type.d.ts +582 -209
  117. package/dist/src/Type.d.ts.map +1 -1
  118. package/dist/src/Type.js +362 -240
  119. package/dist/src/Types.d.ts +160 -6
  120. package/dist/src/Types.d.ts.map +1 -1
  121. package/dist/src/Types.js +22 -2
  122. package/dist/src/WebSocket.d.ts +113 -58
  123. package/dist/src/WebSocket.d.ts.map +1 -1
  124. package/dist/src/WebSocket.js +210 -118
  125. package/dist/src/Worker.d.ts +245 -60
  126. package/dist/src/Worker.d.ts.map +1 -1
  127. package/dist/src/Worker.js +220 -64
  128. package/dist/src/index.d.ts +25 -3
  129. package/dist/src/index.d.ts.map +1 -1
  130. package/dist/src/index.js +19 -3
  131. package/dist/src/local-first/Db.d.ts +24 -213
  132. package/dist/src/local-first/Db.d.ts.map +1 -1
  133. package/dist/src/local-first/Db.js +622 -293
  134. package/dist/src/local-first/Error.d.ts +12 -0
  135. package/dist/src/local-first/Error.d.ts.map +1 -0
  136. package/dist/src/local-first/Error.js +6 -0
  137. package/dist/src/local-first/Evolu.d.ts +330 -285
  138. package/dist/src/local-first/Evolu.d.ts.map +1 -1
  139. package/dist/src/local-first/Evolu.js +472 -402
  140. package/dist/src/local-first/LocalAuth.d.ts +10 -10
  141. package/dist/src/local-first/LocalAuth.d.ts.map +1 -1
  142. package/dist/src/local-first/LocalAuth.js +6 -1
  143. package/dist/src/local-first/Owner.d.ts +70 -27
  144. package/dist/src/local-first/Owner.d.ts.map +1 -1
  145. package/dist/src/local-first/Owner.js +27 -14
  146. package/dist/src/local-first/Protocol.d.ts +58 -50
  147. package/dist/src/local-first/Protocol.d.ts.map +1 -1
  148. package/dist/src/local-first/Protocol.js +253 -155
  149. package/dist/src/local-first/Query.d.ts +133 -43
  150. package/dist/src/local-first/Query.d.ts.map +1 -1
  151. package/dist/src/local-first/Query.js +139 -90
  152. package/dist/src/local-first/Relay.d.ts +18 -38
  153. package/dist/src/local-first/Relay.d.ts.map +1 -1
  154. package/dist/src/local-first/Relay.js +59 -171
  155. package/dist/src/local-first/Schema.d.ts +139 -144
  156. package/dist/src/local-first/Schema.d.ts.map +1 -1
  157. package/dist/src/local-first/Schema.js +78 -163
  158. package/dist/src/local-first/Shared.d.ts +125 -0
  159. package/dist/src/local-first/Shared.d.ts.map +1 -0
  160. package/dist/src/local-first/Shared.js +569 -0
  161. package/dist/src/local-first/Storage.d.ts +50 -53
  162. package/dist/src/local-first/Storage.d.ts.map +1 -1
  163. package/dist/src/local-first/Storage.js +121 -173
  164. package/dist/src/local-first/Timestamp.d.ts +28 -35
  165. package/dist/src/local-first/Timestamp.d.ts.map +1 -1
  166. package/dist/src/local-first/Timestamp.js +24 -25
  167. package/dist/src/local-first/index.d.ts +2 -15
  168. package/dist/src/local-first/index.d.ts.map +1 -1
  169. package/dist/src/local-first/index.js +2 -15
  170. package/package.json +36 -26
  171. package/src/Array.ts +467 -106
  172. package/src/Assert.ts +87 -12
  173. package/src/BigInt.ts +7 -1
  174. package/src/Brand.ts +41 -12
  175. package/src/Buffer.ts +10 -4
  176. package/src/Cache.ts +11 -2
  177. package/src/Callbacks.ts +33 -23
  178. package/src/Console.ts +567 -178
  179. package/src/Crypto.ts +111 -62
  180. package/src/Eq.ts +30 -3
  181. package/src/Error.ts +50 -34
  182. package/src/Function.ts +140 -68
  183. package/src/Identicon.ts +7 -1
  184. package/src/Lookup.ts +415 -0
  185. package/src/Microtask.ts +58 -0
  186. package/src/Number.ts +40 -7
  187. package/src/Object.ts +155 -16
  188. package/src/Option.ts +74 -0
  189. package/src/Order.ts +11 -3
  190. package/src/Platform.ts +43 -7
  191. package/src/Polyfills.ts +465 -0
  192. package/src/Random.ts +25 -11
  193. package/src/Redacted.ts +8 -4
  194. package/src/Ref.ts +72 -21
  195. package/src/RefCount.ts +170 -0
  196. package/src/Relation.ts +188 -136
  197. package/src/Resource.ts +864 -0
  198. package/src/Result.ts +548 -381
  199. package/src/Schedule.ts +1471 -0
  200. package/src/Set.ts +247 -0
  201. package/src/Skiplist.ts +7 -1
  202. package/src/Sqlite.ts +409 -304
  203. package/src/Store.ts +94 -48
  204. package/src/String.ts +6 -0
  205. package/src/Task.ts +3685 -740
  206. package/src/Test.ts +162 -0
  207. package/src/Time.ts +348 -145
  208. package/src/Tracer.ts +54 -0
  209. package/src/Type.ts +1064 -630
  210. package/src/Types.ts +202 -7
  211. package/src/WebSocket.ts +311 -178
  212. package/src/Worker.ts +527 -147
  213. package/src/index.ts +74 -3
  214. package/src/local-first/Db.ts +871 -597
  215. package/src/local-first/Error.ts +17 -0
  216. package/src/local-first/Evolu.ts +884 -823
  217. package/src/local-first/LocalAuth.ts +10 -10
  218. package/src/local-first/Owner.ts +94 -42
  219. package/src/local-first/Protocol.ts +440 -303
  220. package/src/local-first/Query.ts +243 -194
  221. package/src/local-first/Relay.ts +91 -252
  222. package/src/local-first/Schema.ts +284 -394
  223. package/src/local-first/Shared.ts +932 -0
  224. package/src/local-first/Storage.ts +209 -282
  225. package/src/local-first/Timestamp.ts +38 -45
  226. package/src/local-first/index.ts +2 -16
  227. package/LICENSE +0 -21
  228. package/dist/src/Instances.d.ts +0 -34
  229. package/dist/src/Instances.d.ts.map +0 -1
  230. package/dist/src/Instances.js +0 -44
  231. package/dist/src/Resources.d.ts +0 -118
  232. package/dist/src/Resources.d.ts.map +0 -1
  233. package/dist/src/Resources.js +0 -197
  234. package/dist/src/local-first/Platform.d.ts +0 -25
  235. package/dist/src/local-first/Platform.d.ts.map +0 -1
  236. package/dist/src/local-first/Platform.js +0 -1
  237. package/dist/src/local-first/Public.d.ts +0 -22
  238. package/dist/src/local-first/Public.d.ts.map +0 -1
  239. package/dist/src/local-first/Public.js +0 -15
  240. package/dist/src/local-first/PublicKysely.d.ts +0 -148
  241. package/dist/src/local-first/PublicKysely.d.ts.map +0 -1
  242. package/dist/src/local-first/PublicKysely.js +0 -184
  243. package/dist/src/local-first/Sync.d.ts +0 -112
  244. package/dist/src/local-first/Sync.d.ts.map +0 -1
  245. package/dist/src/local-first/Sync.js +0 -529
  246. package/src/Instances.ts +0 -90
  247. package/src/Resources.ts +0 -367
  248. package/src/local-first/Platform.ts +0 -27
  249. package/src/local-first/Public.ts +0 -42
  250. package/src/local-first/PublicKysely.ts +0 -239
  251. package/src/local-first/Sync.ts +0 -960
@@ -1,29 +1,38 @@
1
- import { Brand } from "../Brand.js";
2
- import { Result } from "../Result.js";
3
- import { SqliteDep, SqliteError, SqliteQuery, SqliteRow, SqliteValue } from "../Sqlite.js";
4
- import { Store, StoreSubscribe } from "../Store.js";
5
- import { Id } from "../Type.js";
6
- import { Simplify } from "../Types.js";
1
+ /**
2
+ * Query helpers, execution, and caching.
3
+ *
4
+ * @module
5
+ */
6
+ import type { AliasableExpression, Expression, Simplify as KyselySimplify, RawBuilder, SelectQueryNode } from "kysely";
7
+ import type { Brand } from "../Brand.js";
8
+ import type { SqliteQueryString } from "../Sqlite.js";
9
+ import { SqliteValue } from "../Sqlite.js";
10
+ import type { Simplify } from "../Types.js";
11
+ import type { EvoluSchema } from "./Schema.js";
12
+ export { sql as kyselySql } from "kysely";
13
+ export type { NotNull as KyselyNotNull } from "kysely";
7
14
  /**
8
15
  * A type-safe SQL query.
9
16
  *
10
17
  * ### Example
11
18
  *
12
19
  * ```ts
13
- * const allTodos = evolu.createQuery((db) =>
14
- * db.selectFrom("todo").selectAll(),
15
- * );
20
+ * const createQuery = createQueryBuilder(Schema);
21
+ * const allTodos = createQuery((db) => db.selectFrom("todo").selectAll());
16
22
  * type AllTodosRow = typeof allTodos.Row;
17
23
  * ```
18
24
  */
19
- export type Query<R extends Row = Row> = string & Brand<"Query"> & {
25
+ export type Query<S extends EvoluSchema = EvoluSchema, R extends Row = Row> = SqliteQueryString & Brand<"Query"> & {
26
+ /** A shorthand for the query schema. */
27
+ Schema: S;
20
28
  /**
21
29
  * A shorthand for {@link InferRow}.
22
30
  *
23
31
  * ### Example
24
32
  *
25
33
  * ```ts
26
- * const allTodos = evolu.createQuery((db) =>
34
+ * const createQuery = createQueryBuilder(Schema);
35
+ * const allTodos = createQuery((db) =>
27
36
  * db.selectFrom("todo").selectAll(),
28
37
  * );
29
38
  * type AllTodosRow = typeof allTodos.Row;
@@ -31,47 +40,124 @@ export type Query<R extends Row = Row> = string & Brand<"Query"> & {
31
40
  */
32
41
  Row: R;
33
42
  };
34
- /**
35
- * Evolu serializes {@link SqliteQuery} into a string to be easily used as a key
36
- * and for comparison.
37
- */
38
- export declare const serializeQuery: <R extends Row>(query: SqliteQuery) => Query<R>;
39
- export declare const deserializeQuery: <R extends Row>(query: Query<R>) => SqliteQuery;
40
- export type InferRow<T extends Query> = T extends Query<infer R> ? R : never;
43
+ export type InferRow<T extends Query> = T extends Query<any, infer R> ? R : never;
41
44
  export interface Row {
42
45
  readonly [key: string]: SqliteValue | Row | ReadonlyArray<Row>;
43
46
  }
44
- export declare const emptyRows: ReadonlyArray<Row>;
47
+ /**
48
+ * An improved Evolu version of Kysely's SQLite `jsonArrayFrom` helper.
49
+ *
50
+ * Kysely's `ParseJSONResultsPlugin` heuristically parses any result string that
51
+ * looks like JSON. Evolu instead prefixes JSON produced by these helpers with a
52
+ * per-runtime identifier and only parses values carrying that prefix, avoiding
53
+ * accidental parsing of ordinary string columns that merely happen to start
54
+ * with `{` or `[`.
55
+ *
56
+ * ### Example
57
+ *
58
+ * ```ts
59
+ * import { evoluJsonArrayFrom } from "@evolu/common";
60
+ *
61
+ * const result = await db
62
+ * .selectFrom("person")
63
+ * .select((eb) => [
64
+ * "id",
65
+ * evoluJsonArrayFrom(
66
+ * eb
67
+ * .selectFrom("pet")
68
+ * .select(["pet.id as pet_id", "pet.name"])
69
+ * .whereRef("pet.owner_id", "=", "person.id")
70
+ * .orderBy("pet.name"),
71
+ * ).as("pets"),
72
+ * ])
73
+ * .execute();
74
+ *
75
+ * result[0]?.id;
76
+ * result[0]?.pets[0].pet_id;
77
+ * result[0]?.pets[0].name;
78
+ * ```
79
+ */
80
+ export declare const evoluJsonArrayFrom: <O>(expr: SelectQueryBuilderExpression<O>) => RawBuilder<Array<KyselySimplify<O>>>;
81
+ /**
82
+ * An improved Evolu version of Kysely's SQLite `jsonObjectFrom` helper.
83
+ *
84
+ * Kysely's `ParseJSONResultsPlugin` heuristically parses any result string that
85
+ * looks like JSON. Evolu instead prefixes JSON produced by these helpers with a
86
+ * per-runtime identifier and only parses values carrying that prefix, avoiding
87
+ * accidental parsing of ordinary string columns that merely happen to start
88
+ * with `{` or `[`.
89
+ *
90
+ * The subquery must only return one row.
91
+ *
92
+ * ### Example
93
+ *
94
+ * ```ts
95
+ * import { evoluJsonObjectFrom } from "@evolu/common";
96
+ *
97
+ * const result = await db
98
+ * .selectFrom("person")
99
+ * .select((eb) => [
100
+ * "id",
101
+ * evoluJsonObjectFrom(
102
+ * eb
103
+ * .selectFrom("pet")
104
+ * .select(["pet.id as pet_id", "pet.name"])
105
+ * .whereRef("pet.owner_id", "=", "person.id")
106
+ * .where("pet.is_favorite", "=", true),
107
+ * ).as("favorite_pet"),
108
+ * ])
109
+ * .execute();
110
+ *
111
+ * result[0]?.id;
112
+ * result[0]?.favorite_pet?.pet_id;
113
+ * result[0]?.favorite_pet?.name;
114
+ * ```
115
+ */
116
+ export declare const evoluJsonObjectFrom: <O>(expr: SelectQueryBuilderExpression<O>) => RawBuilder<KyselySimplify<O> | null>;
117
+ /**
118
+ * An improved Evolu version of Kysely's SQLite `jsonBuildObject` helper.
119
+ *
120
+ * Kysely's `ParseJSONResultsPlugin` heuristically parses any result string that
121
+ * looks like JSON. Evolu instead prefixes JSON produced by these helpers with a
122
+ * per-runtime identifier and only parses values carrying that prefix, avoiding
123
+ * accidental parsing of ordinary string columns that merely happen to start
124
+ * with `{` or `[`.
125
+ *
126
+ * ### Example
127
+ *
128
+ * ```ts
129
+ * import { evoluJsonBuildObject, kyselySql } from "@evolu/common";
130
+ *
131
+ * const result = await db
132
+ * .selectFrom("person")
133
+ * .select((eb) => [
134
+ * "id",
135
+ * evoluJsonBuildObject({
136
+ * first: eb.ref("first_name"),
137
+ * last: eb.ref("last_name"),
138
+ * full: kyselySql<string>`first_name || ' ' || last_name`,
139
+ * }).as("name"),
140
+ * ])
141
+ * .execute();
142
+ *
143
+ * result[0]?.id;
144
+ * result[0]?.name.first;
145
+ * result[0]?.name.last;
146
+ * result[0]?.name.full;
147
+ * ```
148
+ */
149
+ export declare const evoluJsonBuildObject: <O extends Record<string, Expression<unknown>>>(obj: O) => RawBuilder<KyselySimplify<{ [K in keyof O]: O[K] extends Expression<infer V> ? V : never; }>>;
150
+ export declare const getJsonObjectArgs: (node: SelectQueryNode, table: string) => Array<Expression<unknown> | string>;
45
151
  /** Rows returned by a query. */
46
152
  export type QueryRows<R extends Row = Row> = ReadonlyArray<Readonly<Simplify<R>>>;
47
- export type Queries<R extends Row = Row> = ReadonlyArray<Query<R>>;
153
+ export type Queries<S extends EvoluSchema = EvoluSchema, R extends Row = Row> = ReadonlyArray<Query<S, R>>;
48
154
  export type QueriesToQueryRows<Q extends Queries> = {
49
- [P in keyof Q]: Q[P] extends Query<infer R> ? QueryRows<R> : never;
155
+ [P in keyof Q]: Q[P] extends Query<any, infer R> ? QueryRows<R> : never;
50
156
  };
51
157
  export type QueriesToQueryRowsPromises<Q extends Queries> = {
52
- [P in keyof Q]: Q[P] extends Query<infer R> ? Promise<QueryRows<R>> : never;
158
+ [P in keyof Q]: Q[P] extends Query<any, infer R> ? Promise<QueryRows<R>> : never;
53
159
  };
54
- export type QueryRowsMap = ReadonlyMap<Query, ReadonlyArray<Row>>;
55
- export interface SubscribedQueries {
56
- subscribe: (query: Query) => StoreSubscribe;
57
- has: (query: Query) => boolean;
58
- get: () => ReadonlyArray<Query>;
59
- }
60
- export declare const createSubscribedQueries: (rowsStore: Store<QueryRowsMap>) => SubscribedQueries;
61
- export interface GetQueryRowsCacheDep {
62
- readonly getQueryRowsCache: GetQueryRowsCache;
63
- }
64
- export type GetQueryRowsCache = (tabId: Id) => QueryRowsCache;
65
- export interface QueryRowsCache {
66
- readonly set: (queriesRows: ReadonlyArray<readonly [Query, ReadonlyArray<SqliteRow>]>) => void;
67
- readonly get: () => QueryRowsMap;
68
- }
69
- export declare const createGetQueryRowsCache: () => GetQueryRowsCache;
70
- export declare const loadQueries: (deps: GetQueryRowsCacheDep & SqliteDep) => (tabId: Id, queries: ReadonlyArray<Query>) => Result<ReadonlyArray<QueryPatches>, SqliteError>;
71
- export interface QueryPatches {
72
- readonly query: Query;
73
- readonly patches: ReadonlyArray<Patch>;
74
- }
160
+ export type RowsByQueryMap<S extends EvoluSchema = EvoluSchema> = ReadonlyMap<Query<S>, ReadonlyArray<Row>>;
75
161
  export type Patch = ReplaceAllPatch | ReplaceAtPatch;
76
162
  export interface ReplaceAllPatch {
77
163
  readonly op: "replaceAll";
@@ -108,5 +194,9 @@ export declare const applyPatches: (patches: ReadonlyArray<Patch>, current: Read
108
194
  * See: https://github.com/kysely-org/kysely/issues/1372#issuecomment-2702773948
109
195
  */
110
196
  export declare const kyselyJsonIdentifier: string & Brand<"Id">;
197
+ interface SelectQueryBuilderExpression<O> extends AliasableExpression<O> {
198
+ get isSelectQueryBuilder(): true;
199
+ toOperationNode(): SelectQueryNode;
200
+ }
111
201
  export declare const parseSqliteJsonArray: <T>(arr: ReadonlyArray<T>) => ReadonlyArray<T>;
112
202
  //# sourceMappingURL=Query.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Query.d.ts","sourceRoot":"","sources":["../../../src/local-first/Query.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Query.d.ts","sourceRoot":"","sources":["../../../src/local-first/Query.ts"],"names":[],"mappings":"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"}
@@ -1,96 +1,134 @@
1
- import { bytesToHex, hexToBytes } from "../Buffer.js";
1
+ /**
2
+ * Query helpers, execution, and caching.
3
+ *
4
+ * @module
5
+ */
6
+ import { AliasNode, ColumnNode, ExpressionWrapper, IdentifierNode, sql as kyselySqlBuilder, ReferenceNode, TableNode, ValueNode, } from "kysely";
2
7
  import { createRandomBytes } from "../Crypto.js";
3
- import { createRecord, isPlainObject, objectToEntries, } from "../Object.js";
4
- import { ok } from "../Result.js";
5
- import { eqSqliteValue, explainSqliteQueryPlan, } from "../Sqlite.js";
8
+ import { createRecord, isPlainObject } from "../Object.js";
9
+ import { eqSqliteValue, SqliteValue } from "../Sqlite.js";
6
10
  import { createId, String } from "../Type.js";
11
+ export { sql as kyselySql } from "kysely";
7
12
  /**
8
- * Evolu serializes {@link SqliteQuery} into a string to be easily used as a key
9
- * and for comparison.
13
+ * An improved Evolu version of Kysely's SQLite `jsonArrayFrom` helper.
14
+ *
15
+ * Kysely's `ParseJSONResultsPlugin` heuristically parses any result string that
16
+ * looks like JSON. Evolu instead prefixes JSON produced by these helpers with a
17
+ * per-runtime identifier and only parses values carrying that prefix, avoiding
18
+ * accidental parsing of ordinary string columns that merely happen to start
19
+ * with `{` or `[`.
20
+ *
21
+ * ### Example
22
+ *
23
+ * ```ts
24
+ * import { evoluJsonArrayFrom } from "@evolu/common";
25
+ *
26
+ * const result = await db
27
+ * .selectFrom("person")
28
+ * .select((eb) => [
29
+ * "id",
30
+ * evoluJsonArrayFrom(
31
+ * eb
32
+ * .selectFrom("pet")
33
+ * .select(["pet.id as pet_id", "pet.name"])
34
+ * .whereRef("pet.owner_id", "=", "person.id")
35
+ * .orderBy("pet.name"),
36
+ * ).as("pets"),
37
+ * ])
38
+ * .execute();
39
+ *
40
+ * result[0]?.id;
41
+ * result[0]?.pets[0].pet_id;
42
+ * result[0]?.pets[0].name;
43
+ * ```
10
44
  */
11
- export const serializeQuery = (query) => {
12
- const params = query.parameters.map((v) => v instanceof Uint8Array
13
- ? ["b", bytesToHex(v)]
14
- : ["j", v]);
15
- const options = query.options
16
- ? objectToEntries(query.options).toSorted(([a], [b]) => a.localeCompare(b))
17
- : [];
18
- return JSON.stringify([query.sql, params, options]);
19
- };
20
- export const deserializeQuery = (query) => {
21
- const [sql, paramsArr, optionsArr] = JSON.parse(query);
22
- const parameters = paramsArr.map(([type, value]) => type === "b" ? hexToBytes(value) : value);
23
- const options = optionsArr.length
24
- ? Object.fromEntries(optionsArr)
25
- : undefined;
26
- return {
27
- sql,
28
- parameters,
29
- ...(options !== undefined && { options }),
30
- };
31
- };
32
- // To preserve identity.
33
- export const emptyRows = [];
34
- export const createSubscribedQueries = (rowsStore) => {
35
- const subscribedQueryMap = new Map();
36
- const subscribedQueries = {
37
- subscribe: (query) => (listener) => {
38
- subscribedQueryMap.set(query, (subscribedQueryMap.get(query) ?? 0) + 1);
39
- const unsubscribe = rowsStore.subscribe(listener);
40
- return () => {
41
- const count = subscribedQueryMap.get(query);
42
- if (count != null && count > 1) {
43
- subscribedQueryMap.set(query, count - 1);
44
- }
45
- else {
46
- subscribedQueryMap.delete(query);
47
- }
48
- unsubscribe();
49
- };
50
- },
51
- get: () => [...subscribedQueryMap.keys()],
52
- has: (query) => subscribedQueryMap.has(query),
53
- };
54
- return subscribedQueries;
55
- };
56
- export const createGetQueryRowsCache = () => {
57
- const tabQueryRowsCacheMap = new Map();
58
- return (tabId) => {
59
- let cache = tabQueryRowsCacheMap.get(tabId);
60
- if (!cache) {
61
- let queryRowsCache = new Map();
62
- cache = {
63
- set: (queriesRows) => {
64
- queryRowsCache = new Map([...queryRowsCache, ...queriesRows]);
65
- },
66
- get: () => queryRowsCache,
67
- };
68
- tabQueryRowsCacheMap.set(tabId, cache);
45
+ export const evoluJsonArrayFrom = (expr) => kyselySqlBuilder `(select ${kyselySqlBuilder.lit(kyselyJsonIdentifier)} || coalesce(json_group_array(json_object(${kyselySqlBuilder.join(getSqliteJsonObjectArgs(expr.toOperationNode(), "agg"))})), '[]') from ${expr} as agg)`;
46
+ /**
47
+ * An improved Evolu version of Kysely's SQLite `jsonObjectFrom` helper.
48
+ *
49
+ * Kysely's `ParseJSONResultsPlugin` heuristically parses any result string that
50
+ * looks like JSON. Evolu instead prefixes JSON produced by these helpers with a
51
+ * per-runtime identifier and only parses values carrying that prefix, avoiding
52
+ * accidental parsing of ordinary string columns that merely happen to start
53
+ * with `{` or `[`.
54
+ *
55
+ * The subquery must only return one row.
56
+ *
57
+ * ### Example
58
+ *
59
+ * ```ts
60
+ * import { evoluJsonObjectFrom } from "@evolu/common";
61
+ *
62
+ * const result = await db
63
+ * .selectFrom("person")
64
+ * .select((eb) => [
65
+ * "id",
66
+ * evoluJsonObjectFrom(
67
+ * eb
68
+ * .selectFrom("pet")
69
+ * .select(["pet.id as pet_id", "pet.name"])
70
+ * .whereRef("pet.owner_id", "=", "person.id")
71
+ * .where("pet.is_favorite", "=", true),
72
+ * ).as("favorite_pet"),
73
+ * ])
74
+ * .execute();
75
+ *
76
+ * result[0]?.id;
77
+ * result[0]?.favorite_pet?.pet_id;
78
+ * result[0]?.favorite_pet?.name;
79
+ * ```
80
+ */
81
+ export const evoluJsonObjectFrom = (expr) => kyselySqlBuilder `(select ${kyselySqlBuilder.lit(kyselyJsonIdentifier)} || json_object(${kyselySqlBuilder.join(getSqliteJsonObjectArgs(expr.toOperationNode(), "obj"))}) from ${expr} as obj)`;
82
+ /**
83
+ * An improved Evolu version of Kysely's SQLite `jsonBuildObject` helper.
84
+ *
85
+ * Kysely's `ParseJSONResultsPlugin` heuristically parses any result string that
86
+ * looks like JSON. Evolu instead prefixes JSON produced by these helpers with a
87
+ * per-runtime identifier and only parses values carrying that prefix, avoiding
88
+ * accidental parsing of ordinary string columns that merely happen to start
89
+ * with `{` or `[`.
90
+ *
91
+ * ### Example
92
+ *
93
+ * ```ts
94
+ * import { evoluJsonBuildObject, kyselySql } from "@evolu/common";
95
+ *
96
+ * const result = await db
97
+ * .selectFrom("person")
98
+ * .select((eb) => [
99
+ * "id",
100
+ * evoluJsonBuildObject({
101
+ * first: eb.ref("first_name"),
102
+ * last: eb.ref("last_name"),
103
+ * full: kyselySql<string>`first_name || ' ' || last_name`,
104
+ * }).as("name"),
105
+ * ])
106
+ * .execute();
107
+ *
108
+ * result[0]?.id;
109
+ * result[0]?.name.first;
110
+ * result[0]?.name.last;
111
+ * result[0]?.name.full;
112
+ * ```
113
+ */
114
+ export const evoluJsonBuildObject = (obj) => kyselySqlBuilder `${kyselySqlBuilder.lit(kyselyJsonIdentifier)} || json_object(${kyselySqlBuilder.join(Object.keys(obj).flatMap((k) => [kyselySqlBuilder.lit(k), obj[k]]))})`;
115
+ export const getJsonObjectArgs = (node, table) => {
116
+ const args = [];
117
+ for (const { selection: s } of node.selections ?? []) {
118
+ if (ReferenceNode.is(s) && ColumnNode.is(s.column)) {
119
+ args.push(colName(s.column.column.name), colRef(table, s.column.column.name));
69
120
  }
70
- return cache;
71
- };
72
- };
73
- export const loadQueries = (deps) => (tabId, queries) => {
74
- const queriesRows = [];
75
- for (const query of queries) {
76
- const sqlQuery = deserializeQuery(query);
77
- const result = deps.sqlite.exec(sqlQuery);
78
- if (!result.ok)
79
- return result;
80
- queriesRows.push([query, result.value.rows]);
81
- if (sqlQuery.options?.logExplainQueryPlan) {
82
- explainSqliteQueryPlan(deps)(sqlQuery);
121
+ else if (ColumnNode.is(s)) {
122
+ args.push(colName(s.column.name), colRef(table, s.column.name));
123
+ }
124
+ else if (AliasNode.is(s) && IdentifierNode.is(s.alias)) {
125
+ args.push(colName(s.alias.name), colRef(table, s.alias.name));
126
+ }
127
+ else {
128
+ throw new Error(`can't extract column names from the select query node`);
83
129
  }
84
130
  }
85
- const queryRowsCache = deps.getQueryRowsCache(tabId);
86
- const previousState = queryRowsCache.get();
87
- queryRowsCache.set(queriesRows);
88
- const currentState = queryRowsCache.get();
89
- const queryPatchesArray = queries.map((query) => ({
90
- query,
91
- patches: makePatches(previousState.get(query), currentState.get(query) ?? emptyRows),
92
- }));
93
- return ok(queryPatchesArray);
131
+ return args;
94
132
  };
95
133
  /**
96
134
  * We detect only changes in the whole result and in-place edits. In the future,
@@ -100,8 +138,9 @@ export const loadQueries = (deps) => (tabId, queries) => {
100
138
  * if necessary.
101
139
  */
102
140
  export const makePatches = (previousRows, nextRows) => {
103
- if (previousRows === undefined)
141
+ if (previousRows === undefined) {
104
142
  return [{ op: "replaceAll", value: nextRows }];
143
+ }
105
144
  // TODO: Detect prepend and append, it's cheap.
106
145
  if (previousRows.length !== nextRows.length) {
107
146
  return [{ op: "replaceAll", value: nextRows }];
@@ -149,9 +188,17 @@ export const applyPatches = (patches, current) => patches.reduce((next, patch) =
149
188
  *
150
189
  * See: https://github.com/kysely-org/kysely/issues/1372#issuecomment-2702773948
151
190
  */
152
- export const kyselyJsonIdentifier = createId({
153
- randomBytes: createRandomBytes(),
191
+ export const kyselyJsonIdentifier = /*#__PURE__*/ createId({
192
+ randomBytes: /*#__PURE__*/ createRandomBytes(),
154
193
  });
194
+ const getSqliteJsonObjectArgs = (node, table) => {
195
+ try {
196
+ return getJsonObjectArgs(node, table);
197
+ }
198
+ catch {
199
+ throw new Error("SQLite evoluJsonArrayFrom and evoluJsonObjectFrom can only handle explicit selections due to limitations of the json_object function. selectAll() is not allowed in the subquery.");
200
+ }
201
+ };
155
202
  export const parseSqliteJsonArray = (arr) => {
156
203
  const result = new Array(arr.length);
157
204
  for (let i = 0; i < arr.length; ++i) {
@@ -161,7 +208,7 @@ export const parseSqliteJsonArray = (arr) => {
161
208
  };
162
209
  const parse = (obj) => {
163
210
  if (String.is(obj) && obj.startsWith(kyselyJsonIdentifier)) {
164
- return JSON.parse(obj.slice(kyselyJsonIdentifier.length));
211
+ return parse(JSON.parse(obj.slice(kyselyJsonIdentifier.length)));
165
212
  }
166
213
  if (Array.isArray(obj)) {
167
214
  return parseSqliteJsonArray(obj);
@@ -178,3 +225,5 @@ const parseObject = (obj) => {
178
225
  }
179
226
  return result;
180
227
  };
228
+ const colName = (col) => new ExpressionWrapper(ValueNode.createImmediate(col));
229
+ const colRef = (table, col) => new ExpressionWrapper(ReferenceNode.create(ColumnNode.create(col), TableNode.create(table)));
@@ -1,26 +1,27 @@
1
- import { ConsoleConfig, ConsoleDep } from "../Console.js";
2
- import { TimingSafeEqualDep } from "../Crypto.js";
3
- import { LazyValue } from "../Function.js";
4
- import { Result } from "../Result.js";
5
- import { SqliteDep, SqliteError } from "../Sqlite.js";
6
- import { MaybeAsync } from "../Task.js";
7
- import { SimpleName } from "../Type.js";
1
+ /**
2
+ * Relay server for data synchronization.
3
+ *
4
+ * @module
5
+ */
6
+ import type { TimingSafeEqualDep } from "../Crypto.js";
7
+ import type { SqliteDep } from "../Sqlite.js";
8
+ import { Name } from "../Type.js";
9
+ import { type Awaitable } from "../Types.js";
8
10
  import { OwnerId } from "./Owner.js";
9
- import { ProtocolInvalidDataError } from "./Protocol.js";
10
- import { CreateBaseSqliteStorageConfig, SqliteStorageDeps, Storage, StorageConfig } from "./Storage.js";
11
- export interface RelayConfig extends ConsoleConfig, StorageConfig {
11
+ import type { SqliteStorageDeps, Storage, StorageConfig } from "./Storage.js";
12
+ export interface RelayConfig extends StorageConfig {
12
13
  /**
13
14
  * The relay name.
14
15
  *
15
16
  * Implementations can use this for identification purposes (e.g., database
16
17
  * file name, logging).
17
18
  */
18
- readonly name?: SimpleName;
19
+ readonly name?: Name;
19
20
  /**
20
21
  * Optional callback to check if an {@link OwnerId} is allowed to access the
21
22
  * relay. If this callback is not provided, all owners are allowed.
22
23
  *
23
- * The callback receives the {@link OwnerId} and returns a {@link MaybeAsync}
24
+ * The callback receives the {@link OwnerId} and returns a {@link Awaitable}
24
25
  * boolean: `true` to allow access, or `false` to deny.
25
26
  *
26
27
  * The callback can be synchronous (for SQLite or in-memory checks) or
@@ -34,7 +35,7 @@ export interface RelayConfig extends ConsoleConfig, StorageConfig {
34
35
  * relay access, not write permissions. Since all data is encrypted on the
35
36
  * relay, OwnerId exposure is safe.
36
37
  *
37
- * Owners specify which relays to connect to via {@link OwnerTransport}. In
38
+ * Owners specify which relays to connect to via `OwnerTransport`. In
38
39
  * WebSocket-based implementations, this check occurs before accepting the
39
40
  * connection, with the OwnerId typically extracted from the URL Path (e.g.,
40
41
  * `ws://localhost:4000/<ownerId>`). The relay requires the URL to be in the
@@ -59,7 +60,7 @@ export interface RelayConfig extends ConsoleConfig, StorageConfig {
59
60
  * Promise.resolve(ownerId === "6jy_2F4RT5qqeLgJ14_dnQ"),
60
61
  * ```
61
62
  */
62
- readonly isOwnerAllowed?: (ownerId: OwnerId) => MaybeAsync<boolean>;
63
+ readonly isOwnerAllowed?: (ownerId: OwnerId) => Awaitable<boolean>;
63
64
  }
64
65
  /**
65
66
  * A completely interchangeable server for syncing and backing up encrypted data
@@ -70,29 +71,8 @@ export interface RelayConfig extends ConsoleConfig, StorageConfig {
70
71
  * decentralization and infinite horizontal scalability with minimal
71
72
  * infrastructure.
72
73
  */
73
- export interface Relay extends Disposable {
74
- }
75
- export declare const createRelaySqliteStorage: (deps: SqliteStorageDeps & TimingSafeEqualDep) => (config: CreateBaseSqliteStorageConfig) => Storage;
76
- export declare const createRelayStorageTables: (deps: SqliteDep) => Result<void, SqliteError>;
77
- export interface RelayLogger {
78
- readonly started: (enableLogging: boolean, port: number) => void;
79
- readonly storageError: (error: unknown) => void;
80
- readonly upgradeSocketError: (error: Error) => void;
81
- readonly invalidOrMissingOwnerIdInUrl: (url: string | undefined) => void;
82
- readonly unauthorizedOwner: (ownerId: OwnerId) => void;
83
- readonly connectionEstablished: (totalConnectionCount: number) => void;
84
- readonly connectionWebSocketError: (error: Error) => void;
85
- readonly relayOptionSubscribe: (ownerId: OwnerId, getSubscriberCount: LazyValue<number>) => void;
86
- readonly relayOptionUnsubscribe: (ownerId: OwnerId, getSubscriberCount: LazyValue<number>) => void;
87
- readonly relayOptionBroadcast: (ownerId: OwnerId, broadcastCount: number, subscriberCount: number) => void;
88
- readonly messageLength: (messageLength: number) => void;
89
- readonly applyProtocolMessageAsRelayError: (error: ProtocolInvalidDataError) => void;
90
- readonly responseLength: (responseLength: number) => void;
91
- readonly applyProtocolMessageAsRelayUnknownError: (error: unknown) => void;
92
- readonly connectionClosed: (totalConnectionCount: number) => void;
93
- readonly shuttingDown: () => void;
94
- readonly webSocketServerDisposed: () => void;
95
- readonly httpServerDisposed: () => void;
74
+ export interface Relay extends AsyncDisposable {
96
75
  }
97
- export declare const createRelayLogger: (deps: ConsoleDep) => RelayLogger;
76
+ export declare const createRelaySqliteStorage: (deps: SqliteStorageDeps & TimingSafeEqualDep) => (config: StorageConfig) => Storage;
77
+ export declare const createRelayStorageTables: (deps: SqliteDep) => void;
98
78
  //# sourceMappingURL=Relay.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Relay.d.ts","sourceRoot":"","sources":["../../../src/local-first/Relay.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Relay.d.ts","sourceRoot":"","sources":["../../../src/local-first/Relay.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAG9C,OAAO,EAAE,IAAI,EAAe,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,OAAO,EAIR,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAEV,iBAAiB,EACjB,OAAO,EACP,aAAa,EAEd,MAAM,cAAc,CAAC;AAStB,MAAM,WAAW,WAAY,SAAQ,aAAa;IAChD;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC;IAErB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA0CG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,SAAS,CAAC,OAAO,CAAC,CAAC;CACpE;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,KAAM,SAAQ,eAAe;CAAG;AAEjD,eAAO,MAAM,wBAAwB,GAClC,MAAM,iBAAiB,GAAG,kBAAkB,MAC5C,QAAQ,aAAa,KAAG,OA0LxB,CAAC;AAEJ,eAAO,MAAM,wBAAwB,GAAI,MAAM,SAAS,KAAG,IAuB1D,CAAC"}