@evolu/common 5.4.7 → 6.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.
Files changed (242) hide show
  1. package/README.md +30 -34
  2. package/dist/src/Array.d.ts +17 -0
  3. package/dist/src/Array.d.ts.map +1 -0
  4. package/dist/src/Array.js +12 -0
  5. package/dist/src/Assert.d.ts +68 -0
  6. package/dist/src/Assert.d.ts.map +1 -0
  7. package/dist/src/Assert.js +77 -0
  8. package/dist/src/BigInt.d.ts +20 -0
  9. package/dist/src/BigInt.d.ts.map +1 -0
  10. package/dist/src/BigInt.js +18 -0
  11. package/dist/src/Buffer.d.ts +92 -0
  12. package/dist/src/Buffer.d.ts.map +1 -0
  13. package/dist/src/Buffer.js +62 -0
  14. package/dist/src/Callbacks.d.ts +20 -0
  15. package/dist/src/Callbacks.d.ts.map +1 -0
  16. package/dist/src/Callbacks.js +18 -0
  17. package/dist/src/Console.d.ts +78 -0
  18. package/dist/src/Console.d.ts.map +1 -0
  19. package/dist/src/Console.js +103 -0
  20. package/dist/src/Crypto.d.ts +72 -39
  21. package/dist/src/Crypto.d.ts.map +1 -1
  22. package/dist/src/Crypto.js +89 -54
  23. package/dist/src/Eq.d.ts +97 -0
  24. package/dist/src/Eq.d.ts.map +1 -0
  25. package/dist/src/Eq.js +167 -0
  26. package/dist/src/Error.d.ts +14 -10
  27. package/dist/src/Error.d.ts.map +1 -1
  28. package/dist/src/Error.js +43 -11
  29. package/dist/src/Evolu/Config.d.ts +69 -0
  30. package/dist/src/Evolu/Config.d.ts.map +1 -0
  31. package/dist/src/Evolu/Config.js +9 -0
  32. package/dist/src/Evolu/Db.d.ts +126 -0
  33. package/dist/src/Evolu/Db.d.ts.map +1 -0
  34. package/dist/src/Evolu/Db.js +774 -0
  35. package/dist/src/Evolu/Diff.d.ts +43 -0
  36. package/dist/src/Evolu/Diff.d.ts.map +1 -0
  37. package/dist/src/Evolu/Diff.js +95 -0
  38. package/dist/src/Evolu/Evolu.d.ts +334 -0
  39. package/dist/src/Evolu/Evolu.d.ts.map +1 -0
  40. package/dist/src/Evolu/Evolu.js +434 -0
  41. package/dist/src/Evolu/Internal.d.ts +26 -0
  42. package/dist/src/Evolu/Internal.d.ts.map +1 -0
  43. package/dist/src/Evolu/Internal.js +25 -0
  44. package/dist/src/Evolu/Kysely.d.ts +6 -0
  45. package/dist/src/Evolu/Kysely.d.ts.map +1 -0
  46. package/dist/src/Evolu/Kysely.js +21 -0
  47. package/dist/src/Evolu/Owner.d.ts +155 -0
  48. package/dist/src/Evolu/Owner.d.ts.map +1 -0
  49. package/dist/src/Evolu/Owner.js +126 -0
  50. package/dist/src/Evolu/Platform.d.ts +23 -0
  51. package/dist/src/Evolu/Platform.d.ts.map +1 -0
  52. package/dist/src/Evolu/Platform.js +1 -0
  53. package/dist/src/Evolu/Protocol.d.ts +401 -0
  54. package/dist/src/Evolu/Protocol.d.ts.map +1 -0
  55. package/dist/src/Evolu/Protocol.js +1151 -0
  56. package/dist/src/Evolu/Public.d.ts +18 -0
  57. package/dist/src/Evolu/Public.d.ts.map +1 -0
  58. package/dist/src/Evolu/Public.js +11 -0
  59. package/dist/src/Evolu/PublicKysely.d.ts +148 -0
  60. package/dist/src/Evolu/PublicKysely.d.ts.map +1 -0
  61. package/dist/src/Evolu/PublicKysely.js +185 -0
  62. package/dist/src/Evolu/Query.d.ts +63 -0
  63. package/dist/src/Evolu/Query.d.ts.map +1 -0
  64. package/dist/src/Evolu/Query.js +61 -0
  65. package/dist/src/Evolu/Relay.d.ts +13 -0
  66. package/dist/src/Evolu/Relay.d.ts.map +1 -0
  67. package/dist/src/Evolu/Relay.js +109 -0
  68. package/dist/src/Evolu/Schema.d.ts +201 -0
  69. package/dist/src/Evolu/Schema.d.ts.map +1 -0
  70. package/dist/src/Evolu/Schema.js +150 -0
  71. package/dist/src/Evolu/Storage.d.ts +49 -0
  72. package/dist/src/Evolu/Storage.d.ts.map +1 -0
  73. package/dist/src/Evolu/Storage.js +1111 -0
  74. package/dist/src/Evolu/Sync.d.ts +59 -0
  75. package/dist/src/Evolu/Sync.d.ts.map +1 -0
  76. package/dist/src/Evolu/Sync.js +29 -0
  77. package/dist/src/Evolu/Timestamp.d.ts +106 -0
  78. package/dist/src/Evolu/Timestamp.d.ts.map +1 -0
  79. package/dist/src/Evolu/Timestamp.js +179 -0
  80. package/dist/src/Function.d.ts +54 -0
  81. package/dist/src/Function.d.ts.map +1 -0
  82. package/dist/src/Function.js +38 -0
  83. package/dist/src/ManyToManyMap.d.ts +26 -0
  84. package/dist/src/ManyToManyMap.d.ts.map +1 -0
  85. package/dist/src/ManyToManyMap.js +92 -0
  86. package/dist/src/NanoId.d.ts +27 -0
  87. package/dist/src/NanoId.d.ts.map +1 -0
  88. package/dist/src/NanoId.js +6 -0
  89. package/dist/src/Number.d.ts +42 -0
  90. package/dist/src/Number.d.ts.map +1 -0
  91. package/dist/src/Number.js +55 -0
  92. package/dist/src/Object.d.ts +35 -0
  93. package/dist/src/Object.d.ts.map +1 -0
  94. package/dist/src/Object.js +36 -0
  95. package/dist/src/Order.d.ts +90 -0
  96. package/dist/src/Order.d.ts.map +1 -0
  97. package/dist/src/Order.js +85 -0
  98. package/dist/src/Promise.d.ts +180 -0
  99. package/dist/src/Promise.d.ts.map +1 -0
  100. package/dist/src/Promise.js +176 -0
  101. package/dist/src/Random.d.ts +52 -0
  102. package/dist/src/Random.d.ts.map +1 -0
  103. package/dist/src/Random.js +29 -0
  104. package/dist/src/Ref.d.ts +40 -0
  105. package/dist/src/Ref.d.ts.map +1 -0
  106. package/dist/src/Ref.js +13 -0
  107. package/dist/src/Result.d.ts +421 -0
  108. package/dist/src/Result.d.ts.map +1 -0
  109. package/dist/src/Result.js +357 -0
  110. package/dist/src/Skiplist.d.ts +23 -0
  111. package/dist/src/Skiplist.d.ts.map +1 -0
  112. package/dist/src/Skiplist.js +58 -0
  113. package/dist/src/Sqlite.d.ts +116 -52
  114. package/dist/src/Sqlite.d.ts.map +1 -1
  115. package/dist/src/Sqlite.js +183 -67
  116. package/dist/src/Store.d.ts +45 -8
  117. package/dist/src/Store.d.ts.map +1 -1
  118. package/dist/src/Store.js +33 -17
  119. package/dist/src/String.d.ts +2 -0
  120. package/dist/src/String.d.ts.map +1 -0
  121. package/dist/src/String.js +14 -0
  122. package/dist/src/Time.d.ts +20 -0
  123. package/dist/src/Time.d.ts.map +1 -0
  124. package/dist/src/Time.js +25 -0
  125. package/dist/src/Type.d.ts +1937 -0
  126. package/dist/src/Type.d.ts.map +1 -0
  127. package/dist/src/Type.js +2002 -0
  128. package/dist/src/Types.d.ts +188 -0
  129. package/dist/src/Types.d.ts.map +1 -0
  130. package/dist/src/Types.js +6 -0
  131. package/dist/src/WebSocket.d.ts +112 -0
  132. package/dist/src/WebSocket.d.ts.map +1 -0
  133. package/dist/src/WebSocket.js +139 -0
  134. package/dist/src/Worker.d.ts +44 -0
  135. package/dist/src/Worker.d.ts.map +1 -0
  136. package/dist/src/Worker.js +66 -0
  137. package/dist/src/index.d.ts +24 -11
  138. package/dist/src/index.d.ts.map +1 -1
  139. package/dist/src/index.js +24 -11
  140. package/package.json +29 -38
  141. package/src/Array.ts +39 -0
  142. package/src/Assert.ts +116 -0
  143. package/src/BigInt.ts +29 -0
  144. package/src/Buffer.ts +175 -0
  145. package/src/Callbacks.ts +43 -0
  146. package/src/Console.ts +159 -0
  147. package/src/Crypto.ts +169 -115
  148. package/src/Eq.ts +204 -0
  149. package/src/Error.ts +57 -20
  150. package/src/Evolu/Config.ts +83 -0
  151. package/src/Evolu/Db.ts +1275 -0
  152. package/src/Evolu/Diff.ts +142 -0
  153. package/src/Evolu/Evolu.ts +947 -0
  154. package/src/Evolu/Internal.ts +26 -0
  155. package/src/Evolu/Kysely.ts +38 -0
  156. package/src/Evolu/Owner.ts +296 -0
  157. package/src/Evolu/Platform.ts +27 -0
  158. package/src/Evolu/Protocol.ts +1857 -0
  159. package/src/Evolu/Public.ts +43 -0
  160. package/src/Evolu/PublicKysely.ts +240 -0
  161. package/src/Evolu/Query.ts +167 -0
  162. package/src/Evolu/Relay.ts +142 -0
  163. package/src/Evolu/Schema.ts +417 -0
  164. package/src/Evolu/Storage.ts +1281 -0
  165. package/src/Evolu/Sync.ts +105 -0
  166. package/src/Evolu/Timestamp.ts +311 -0
  167. package/src/Function.ts +58 -0
  168. package/src/ManyToManyMap.ts +140 -0
  169. package/src/NanoId.ts +39 -0
  170. package/src/Number.ts +90 -0
  171. package/src/Object.ts +64 -0
  172. package/src/Order.ts +113 -0
  173. package/src/Promise.ts +295 -0
  174. package/src/Random.ts +68 -0
  175. package/src/Ref.ts +63 -0
  176. package/src/Result.ts +453 -0
  177. package/src/Skiplist.ts +102 -0
  178. package/src/Sqlite.ts +366 -153
  179. package/src/Store.ts +79 -36
  180. package/src/String.ts +10 -0
  181. package/src/Time.ts +36 -0
  182. package/src/Type.ts +3978 -0
  183. package/src/Types.ts +209 -0
  184. package/src/WebSocket.ts +273 -0
  185. package/src/Worker.ts +129 -0
  186. package/src/index.ts +24 -11
  187. package/dist/src/Config.d.ts +0 -56
  188. package/dist/src/Config.d.ts.map +0 -1
  189. package/dist/src/Config.js +0 -39
  190. package/dist/src/Crdt.d.ts +0 -89
  191. package/dist/src/Crdt.d.ts.map +0 -1
  192. package/dist/src/Crdt.js +0 -181
  193. package/dist/src/Db.d.ts +0 -107
  194. package/dist/src/Db.d.ts.map +0 -1
  195. package/dist/src/Db.js +0 -443
  196. package/dist/src/Diff.d.ts +0 -27
  197. package/dist/src/Diff.d.ts.map +0 -1
  198. package/dist/src/Diff.js +0 -84
  199. package/dist/src/Evolu.d.ts +0 -426
  200. package/dist/src/Evolu.d.ts.map +0 -1
  201. package/dist/src/Evolu.js +0 -333
  202. package/dist/src/Model.d.ts +0 -141
  203. package/dist/src/Model.d.ts.map +0 -1
  204. package/dist/src/Model.js +0 -125
  205. package/dist/src/Murmurhash.d.ts +0 -2
  206. package/dist/src/Murmurhash.d.ts.map +0 -1
  207. package/dist/src/Murmurhash.js +0 -60
  208. package/dist/src/Owner.d.ts +0 -33
  209. package/dist/src/Owner.d.ts.map +0 -1
  210. package/dist/src/Owner.js +0 -26
  211. package/dist/src/Platform.d.ts +0 -37
  212. package/dist/src/Platform.d.ts.map +0 -1
  213. package/dist/src/Platform.js +0 -11
  214. package/dist/src/Protobuf.d.ts +0 -81
  215. package/dist/src/Protobuf.d.ts.map +0 -1
  216. package/dist/src/Protobuf.js +0 -92
  217. package/dist/src/Public.d.ts +0 -13
  218. package/dist/src/Public.d.ts.map +0 -1
  219. package/dist/src/Public.js +0 -6
  220. package/dist/src/Socket.d.ts +0 -8
  221. package/dist/src/Socket.d.ts.map +0 -1
  222. package/dist/src/Socket.js +0 -51
  223. package/dist/src/Sql.d.ts +0 -12
  224. package/dist/src/Sql.d.ts.map +0 -1
  225. package/dist/src/Sql.js +0 -30
  226. package/dist/src/Sync.d.ts +0 -70
  227. package/dist/src/Sync.d.ts.map +0 -1
  228. package/dist/src/Sync.js +0 -127
  229. package/src/Config.ts +0 -119
  230. package/src/Crdt.ts +0 -361
  231. package/src/Db.ts +0 -955
  232. package/src/Diff.ts +0 -114
  233. package/src/Evolu.ts +0 -1016
  234. package/src/Model.ts +0 -233
  235. package/src/Murmurhash.ts +0 -70
  236. package/src/Owner.ts +0 -69
  237. package/src/Platform.ts +0 -47
  238. package/src/Protobuf.ts +0 -155
  239. package/src/Public.ts +0 -12
  240. package/src/Socket.ts +0 -83
  241. package/src/Sql.ts +0 -41
  242. package/src/Sync.ts +0 -315
package/src/Types.ts ADDED
@@ -0,0 +1,209 @@
1
+ /**
2
+ * TypeScript utility types
3
+ *
4
+ * @module
5
+ */
6
+
7
+ import * as Kysely from "kysely";
8
+
9
+ /**
10
+ * Checks a condition on a value and returns a boolean.
11
+ *
12
+ * A predicate starts with an 'is' prefix, e.g., `isEven`.
13
+ *
14
+ * ### Example
15
+ *
16
+ * ```ts
17
+ * const isEven: Predicate<number> = (n) => n % 2 === 0;
18
+ *
19
+ * const numbers = [1, 2, 3, 4];
20
+ * const evenNumbers = numbers.filter(isEven); // [2, 4]
21
+ * ```
22
+ */
23
+ export type Predicate<T> = (value: T) => boolean;
24
+
25
+ /**
26
+ * A type guard function that refines type `A` to a narrower type `B`.
27
+ *
28
+ * ### Example
29
+ *
30
+ * ```ts
31
+ * type Animal = { name: string };
32
+ * type Dog = Animal & { breed: string };
33
+ *
34
+ * const isDog: Refinement<Animal, Dog> = (animal): animal is Dog =>
35
+ * "breed" in animal;
36
+ *
37
+ * const animal: Animal = { name: "Dog", breed: "Beagle" };
38
+ * if (isDog(animal)) {
39
+ * console.log(animal.breed); // Safe access to `breed`
40
+ * }
41
+ * ```
42
+ */
43
+ export type Refinement<in A, out B extends A> = (a: A) => a is B;
44
+
45
+ /**
46
+ * Makes properties optional if they accept `null` as a value.
47
+ *
48
+ * For each property in `T`, if `null` is a valid value for that property, the
49
+ * property will be made optional in the resulting type.
50
+ *
51
+ * ### Example
52
+ *
53
+ * ```ts
54
+ * type Example = {
55
+ * required: string;
56
+ * optionalWithNull: string | null;
57
+ * };
58
+ *
59
+ * type Result = NullablePartial<Example>;
60
+ * // Result is:
61
+ * // {
62
+ * // required: string;
63
+ * // optionalWithNull?: string | null;
64
+ * // }
65
+ * ```
66
+ */
67
+ export type NullablePartial<
68
+ T,
69
+ NK extends keyof T = {
70
+ [K in keyof T]: null extends T[K] ? K : never;
71
+ }[keyof T],
72
+ NP = Pick<T, Exclude<keyof T, NK>> & Partial<Pick<T, NK>>,
73
+ > = { [K in keyof NP]: NP[K] };
74
+
75
+ /**
76
+ * A type alias for `never` that is used intentionally when casting is not
77
+ * needed and unit tests exist to ensure correctness.
78
+ */
79
+ export type IntentionalNever = never;
80
+
81
+ /**
82
+ * A utility interface for creating branded types.
83
+ *
84
+ * Branded types enhance type safety by differentiating otherwise identical base
85
+ * types, such as `number` or `string`, to enforce stricter type checks.
86
+ *
87
+ * Supports multiple brands, allowing types to act like flags.
88
+ *
89
+ * ### Example 1: Single Brand
90
+ *
91
+ * ```ts
92
+ * // A branded type definition
93
+ * type UserId = number & Brand<"UserId">;
94
+ *
95
+ * // A function that creates `UserId` values.
96
+ * // Casting with `as UserId` is unsafe, so `createUserId` must be unit-tested.
97
+ * const createUserId = (): UserId => {
98
+ * return 123 as UserId; // Unsafe casting
99
+ * };
100
+ *
101
+ * const userId = createUserId();
102
+ *
103
+ * // A function that accepts only `UserId`.
104
+ * const getUser = (id: UserId) => {
105
+ * // Implementation
106
+ * };
107
+ *
108
+ * getUser(userId); // ✅ Valid
109
+ * getUser(123); // ❌ TypeScript error
110
+ * getUser("123"); // ❌ TypeScript error
111
+ * ```
112
+ *
113
+ * ### Example 2: Multiple Brands
114
+ *
115
+ * ```ts
116
+ * // Define branded types
117
+ * type Min1 = string & Brand<"Min1">;
118
+ * type Max100 = string & Brand<"Max100">;
119
+ * type Min1Max100 = string & Brand<"Min1" | "Max100">;
120
+ *
121
+ * // Functions requiring specific brands
122
+ * const requiresMin1 = (value: Min1): void => {};
123
+ * const requiresMax100 = (value: Max100): void => {};
124
+ *
125
+ * // Values with single brands
126
+ * const min1Value: Min1 = "hello" as Min1;
127
+ * const max100Value: Max100 = "world" as Max100;
128
+ *
129
+ * // Value with multiple brands
130
+ * const min1Max100Value: Min1Max100 = "typescript" as Min1Max100;
131
+ *
132
+ * // Valid cases
133
+ * requiresMin1(min1Value); // ✅ Valid
134
+ * requiresMax100(max100Value); // ✅ Valid
135
+ * requiresMin1(min1Max100Value); // ✅ Valid: Min1Max100 satisfies Min1
136
+ * requiresMax100(min1Max100Value); // ✅ Valid: Min1Max100 satisfies Max100
137
+ * ```
138
+ */
139
+ export interface Brand<B extends string> {
140
+ readonly [__brand]: Readonly<Record<B, true>>;
141
+ }
142
+
143
+ declare const __brand: unique symbol;
144
+
145
+ /**
146
+ * Determines whether a type `T` is a branded type.
147
+ *
148
+ * Works with any base type intersected with a `Brand`.
149
+ *
150
+ * ### Examples
151
+ *
152
+ * - `IsBranded<string>` -> false
153
+ * - `IsBranded<string & Brand<"X">>` -> true
154
+ */
155
+ export type IsBranded<T> = T extends Brand<string> ? true : false;
156
+
157
+ /**
158
+ * String | number | bigint | boolean | undefined | null
159
+ *
160
+ * https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types
161
+ */
162
+ export type Literal = string | number | bigint | boolean | undefined | null;
163
+
164
+ /**
165
+ * Infers a broader type from a specific literal value type.
166
+ *
167
+ * Examples:
168
+ *
169
+ * - "foo" -> string
170
+ * - 42 -> number
171
+ * - 42n -> bigint
172
+ * - True -> boolean
173
+ */
174
+ export type WidenLiteral<T extends Literal> = T extends string
175
+ ? string
176
+ : T extends number
177
+ ? number
178
+ : T extends boolean
179
+ ? boolean
180
+ : T extends bigint
181
+ ? bigint
182
+ : T;
183
+
184
+ /**
185
+ * Simplify an intersection type into a single mapped type.
186
+ *
187
+ * This utility forces TypeScript to "flatten" an intersection type into a
188
+ * single object type so that tooltips and error messages are easier to read.
189
+ *
190
+ * ### Example
191
+ *
192
+ * ```ts
193
+ * type A = { a: string } & { b: number };
194
+ * // Without Simplify, TypeScript may display A as:
195
+ * // { a: string } & { b: number }
196
+ *
197
+ * type B = Simplify<A>;
198
+ * // B is equivalent to:
199
+ * // { a: string; b: number }
200
+ * ```
201
+ */
202
+ export type Simplify<T> = Kysely.Simplify<T>;
203
+
204
+ /**
205
+ * Makes a specific property of an object optional while keeping others
206
+ * unchanged.
207
+ */
208
+ export type PartialProp<T, K extends keyof T> = Omit<T, K> &
209
+ Partial<Pick<T, K>>;
@@ -0,0 +1,273 @@
1
+ /**
2
+ * Websocket with auto-reconnect and offline support
3
+ *
4
+ * @module
5
+ */
6
+
7
+ import { assertNoErrorInCatch } from "./Assert.js";
8
+ import { constVoid } from "./Function.js";
9
+ import { retry, RetryError, RetryOptions } from "./Promise.js";
10
+ import { err, ok, Result } from "./Result.js";
11
+
12
+ /** WebSocket with auto-reconnect and offline support. */
13
+ export interface WebSocket extends Disposable {
14
+ /**
15
+ * Send data through the WebSocket connection. Returns {@link Result} with an
16
+ * error if the data couldn't be sent.
17
+ */
18
+ send: (
19
+ data: string | ArrayBufferLike | Blob | ArrayBufferView,
20
+ ) => Result<void, WebSocketSendError>;
21
+
22
+ readonly getReadyState: () => WebSocketReadyState;
23
+ }
24
+
25
+ /**
26
+ * An error that occurs when trying to send data but WebSocket is connecting.
27
+ *
28
+ * https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send
29
+ */
30
+ export interface WebSocketSendError {
31
+ readonly type: "WebSocketSendError";
32
+ }
33
+
34
+ /** WebSocket connection states. */
35
+ export type WebSocketReadyState = "connecting" | "open" | "closing" | "closed";
36
+
37
+ export type CreateWebSocket = (
38
+ url: string,
39
+ options?: WebSocketOptions,
40
+ ) => WebSocket;
41
+
42
+ export interface CreateWebSocketDep {
43
+ readonly createWebSocket: CreateWebSocket;
44
+ }
45
+
46
+ /** Options for creating {@link WebSocket} */
47
+ export interface WebSocketOptions {
48
+ /** Protocol(s) to use with the WebSocket connection. */
49
+ protocols?: string | Array<string>;
50
+
51
+ /** Sets the binary type for the data being received. */
52
+ binaryType?: "blob" | "arraybuffer";
53
+
54
+ /** Callback when the connection is established. */
55
+ onOpen?: () => void;
56
+
57
+ /** Callback when an error occurs. */
58
+ onError?: (error: WebSocketError) => void;
59
+
60
+ /** Callback when the connection is closed. */
61
+ onClose?: (event: CloseEvent) => void;
62
+
63
+ /** Callback when message data is received. */
64
+ onMessage?: (data: string | ArrayBuffer | Blob) => void;
65
+
66
+ /** Options for retry behavior. */
67
+ retryOptions?: Omit<RetryOptions<WebSocketRetryError>, "signal">;
68
+
69
+ /**
70
+ * For custom WebSocket implementations.
71
+ *
72
+ * This suppors blob:
73
+ *
74
+ * https://github.com/callstackincubator/react-native-fast-io
75
+ */
76
+ WebSocketConstructor?: typeof globalThis.WebSocket;
77
+ }
78
+
79
+ export type WebSocketError =
80
+ | WebSocketConnectError
81
+ | WebSocketConnectionError
82
+ | RetryError<WebSocketRetryError>;
83
+
84
+ /**
85
+ * An error that occurs when a connection cannot be established due to a network
86
+ * error.
87
+ */
88
+ export interface WebSocketConnectError {
89
+ readonly type: "WebSocketConnectError";
90
+ readonly event: Event;
91
+ }
92
+
93
+ /**
94
+ * An error that occurs when a connection is closed due to an issue (e.g.,
95
+ * failure to send some data).
96
+ *
97
+ * https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/error_event
98
+ */
99
+ export interface WebSocketConnectionError {
100
+ readonly type: "WebSocketConnectionError";
101
+ readonly event: Event;
102
+ }
103
+
104
+ export type WebSocketRetryError =
105
+ | WebSocketConnectError
106
+ | WebSocketConnectionCloseError;
107
+
108
+ export interface WebSocketConnectionCloseError {
109
+ readonly type: "WebSocketConnectionCloseError";
110
+ readonly event: CloseEvent;
111
+ }
112
+
113
+ /**
114
+ * Create a new {@link WebSocket}.
115
+ *
116
+ * The default behavior is that WebSocket tries to reconnect repeatedly in case
117
+ * the application is offline, because online events (both web and native) are
118
+ * not reliable. Once it connects and the connection is closed, it tries to
119
+ * reconnect again. Retrying the connection can be controlled using the
120
+ * retryOptions retryable predicate.
121
+ *
122
+ * ### How Binary Messages Work in WebSockets
123
+ *
124
+ * The Server Chooses the Message Type:
125
+ *
126
+ * - Text (0x1) → Sent as UTF-8 encoded text (always received as a string in the
127
+ * browser).
128
+ * - Binary (0x2) → Sent as raw binary data (received as a Blob or ArrayBuffer,
129
+ * depending on binaryType).
130
+ *
131
+ * The Client's binaryType Controls How Binary Data is Processed:
132
+ *
133
+ * - If the server sends a text frame (0x1), the browser always delivers
134
+ * event.data as a string, regardless of binaryType.
135
+ * - If the server sends a binary frame (0x2), the browser delivers event.data as:
136
+ *
137
+ * - A Blob (default: "blob")
138
+ * - An ArrayBuffer ("arraybuffer")
139
+ *
140
+ * ### Example
141
+ *
142
+ * TODO:
143
+ */
144
+ export const createWebSocket: CreateWebSocket = (url, options = {}) => {
145
+ const {
146
+ protocols,
147
+ binaryType,
148
+ onOpen,
149
+ onClose,
150
+ onMessage,
151
+ onError,
152
+ retryOptions,
153
+ WebSocketConstructor = globalThis.WebSocket,
154
+ } = options;
155
+ let isDisposed = false;
156
+
157
+ const reconnectController = new AbortController();
158
+
159
+ const defaultRetryOptions: RetryOptions<WebSocketRetryError> = {
160
+ signal: reconnectController.signal,
161
+ maxRetries: Infinity,
162
+ };
163
+
164
+ let socket: globalThis.WebSocket | null = null;
165
+
166
+ const disposeSocket = () => {
167
+ if (!socket) return;
168
+
169
+ // Remove all listeners before closing
170
+ socket.onopen = null;
171
+ socket.onclose = null;
172
+ socket.onmessage = null;
173
+ socket.onerror = null;
174
+
175
+ socket.close();
176
+ socket = null;
177
+ };
178
+
179
+ // To prevent a memory leak from pending connection promise.
180
+ let disposePromise: null | typeof constVoid = null;
181
+
182
+ /**
183
+ * This promise represents continuous connection which:
184
+ *
185
+ * - Is rejected when a connection cannot be established.
186
+ * - Is rejected when a connection is closed.
187
+ * - Is resolved when WebSocket is disposed().
188
+ */
189
+ retry(
190
+ (): Promise<Result<void, WebSocketRetryError>> =>
191
+ new Promise((resolve) => {
192
+ disposePromise = () => {
193
+ resolve(ok());
194
+ };
195
+
196
+ if (isDisposed) disposePromise();
197
+
198
+ disposeSocket();
199
+
200
+ socket = new WebSocketConstructor(url, protocols);
201
+ if (binaryType) socket.binaryType = binaryType;
202
+
203
+ let isOpen = false;
204
+
205
+ socket.onopen = () => {
206
+ isOpen = true;
207
+ onOpen?.();
208
+ };
209
+
210
+ socket.onerror = (event) => {
211
+ const error: WebSocketConnectionError | WebSocketConnectError = isOpen
212
+ ? { type: "WebSocketConnectionError", event }
213
+ : { type: "WebSocketConnectError", event };
214
+ onError?.(error);
215
+ // Trigger reconnect only on WebSocketConnectError.
216
+ if (error.type === "WebSocketConnectError") {
217
+ resolve(err(error));
218
+ }
219
+ };
220
+
221
+ socket.onclose = (event) => {
222
+ onClose?.(event);
223
+ resolve(err({ type: "WebSocketConnectionCloseError", event }));
224
+ };
225
+
226
+ socket.onmessage = (event) => {
227
+ onMessage?.(event.data as string | ArrayBuffer | Blob);
228
+ };
229
+ }),
230
+ {
231
+ ...defaultRetryOptions,
232
+ ...retryOptions,
233
+ },
234
+ )
235
+ .then((result) => {
236
+ if (result.ok || result.error.type === "RetryAbortError") return;
237
+ onError?.(result.error);
238
+ })
239
+ .catch((error: unknown) => {
240
+ assertNoErrorInCatch("WebSocket retry", error);
241
+ });
242
+
243
+ const webSocket: WebSocket = {
244
+ send: (data) => {
245
+ // https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send
246
+ if (!socket || socket.readyState === socket.CONNECTING) {
247
+ return err({ type: "WebSocketSendError" });
248
+ }
249
+ socket.send(data);
250
+ return ok();
251
+ },
252
+
253
+ getReadyState: () =>
254
+ socket ? nativeToStringState[socket.readyState] : "connecting",
255
+
256
+ [Symbol.dispose]() {
257
+ if (isDisposed) return;
258
+ isDisposed = true;
259
+ reconnectController.abort();
260
+ disposeSocket();
261
+ disposePromise?.();
262
+ },
263
+ };
264
+
265
+ return webSocket;
266
+ };
267
+
268
+ const nativeToStringState: Record<number, WebSocketReadyState> = {
269
+ [WebSocket.CONNECTING]: "connecting",
270
+ [WebSocket.OPEN]: "open",
271
+ [WebSocket.CLOSING]: "closing",
272
+ [WebSocket.CLOSED]: "closed",
273
+ };
package/src/Worker.ts ADDED
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Cross-platform worker abstraction
3
+ *
4
+ * @module
5
+ */
6
+
7
+ import { assert } from "./Assert.js";
8
+ import { createTransferableError, TransferableError } from "./Error.js";
9
+
10
+ /** Cross-platform worker abstraction. */
11
+ export interface Worker<Input, Output> {
12
+ /** Sends a message to the worker. */
13
+ readonly postMessage: (message: Input) => void;
14
+
15
+ /** Sets a callback for messages from the worker. */
16
+ readonly onMessage: (callback: (message: Output) => void) => void;
17
+ }
18
+
19
+ export interface WorkerPostMessageDep<Output> {
20
+ readonly postMessage: (message: Output) => void;
21
+ }
22
+
23
+ /**
24
+ * Creates a {@link Worker} that supports initialization with dependencies and
25
+ * safe error handling.
26
+ */
27
+ export const createInitializedWorker = <
28
+ Input extends { readonly type: string } & HasInit<Input>,
29
+ Output extends { readonly type: string } & HasWorkerErrorOutput<Output>,
30
+ Deps,
31
+ >({
32
+ init,
33
+ onMessage,
34
+ }: {
35
+ readonly init: (
36
+ initMessage: Extract<Input, { type: "init" }>,
37
+ postMessage: (msg: Output) => void,
38
+ safeHandler: <A extends Array<any>>(
39
+ handler: (...args: A) => void,
40
+ ) => (...args: A) => void,
41
+ ) => Promise<Deps | null>;
42
+ readonly onMessage: (
43
+ deps: Deps,
44
+ ) => (message: Exclude<Input, { type: "init" }>) => void;
45
+ }): Worker<Input, Output> => {
46
+ type NonInitMessage = Exclude<Input, { type: "init" }>;
47
+
48
+ let onMessageCallback: ((msg: Output) => void) | null = null;
49
+ let deps: Deps | null = null;
50
+ const pendingMessages: Array<Input> = [];
51
+ let initializing = false;
52
+
53
+ const postMessage = (msg: Output) => {
54
+ assert(onMessageCallback != null, "The onMessage wasn't set");
55
+ onMessageCallback(msg);
56
+ };
57
+
58
+ const postMessageTransferableError = (error: unknown) => {
59
+ postMessage({
60
+ type: "onError",
61
+ error: createTransferableError(error),
62
+ } as unknown as Output);
63
+ };
64
+
65
+ const safeHandler =
66
+ <A extends Array<any>>(handler: (...args: A) => void) =>
67
+ (...args: A) => {
68
+ try {
69
+ handler(...args);
70
+ } catch (error) {
71
+ postMessageTransferableError(error);
72
+ }
73
+ };
74
+
75
+ const worker: Worker<Input, Output> = {
76
+ postMessage: (message) => {
77
+ if (message.type !== "init") {
78
+ if (!deps) {
79
+ pendingMessages.push(message);
80
+ } else {
81
+ safeHandler(onMessage(deps))(message as NonInitMessage);
82
+ }
83
+ return;
84
+ }
85
+
86
+ if (initializing) return;
87
+ initializing = true;
88
+
89
+ init(
90
+ message as Extract<Input, { type: "init" }>,
91
+ postMessage,
92
+ safeHandler,
93
+ )
94
+ .then((_deps) => {
95
+ if (_deps == null) return;
96
+ deps = _deps;
97
+ for (const message of pendingMessages) {
98
+ safeHandler(onMessage(deps))(message as NonInitMessage);
99
+ }
100
+ pendingMessages.length = 0;
101
+ })
102
+ .catch(postMessageTransferableError);
103
+ },
104
+
105
+ onMessage: (callback) => {
106
+ onMessageCallback = callback;
107
+ },
108
+ };
109
+
110
+ return worker;
111
+ };
112
+
113
+ type HasInit<Input> =
114
+ Extract<Input, { type: "init" }> extends never
115
+ ? ["Input must contain a variant with { type: 'init' }"]
116
+ : unknown;
117
+
118
+ type HasWorkerErrorOutput<T> =
119
+ Extract<T, { type: "onError" }> extends infer E
120
+ ? [E] extends [never]
121
+ ? [
122
+ "Output must contain { type: 'onError'; error: TransferableError | ... }",
123
+ ]
124
+ : E extends { error: infer Err }
125
+ ? TransferableError extends Err
126
+ ? unknown
127
+ : ["Output.onError.error must include TransferableError"]
128
+ : ["Output.onError must have an error property"]
129
+ : never;
package/src/index.ts CHANGED
@@ -1,15 +1,28 @@
1
- export * from "./Config.js";
2
- export * from "./Crdt.js";
1
+ export * from "./Array.js";
2
+ export * from "./Assert.js";
3
+ export * from "./BigInt.js";
4
+ export * from "./Buffer.js";
5
+ export * from "./Callbacks.js";
6
+ export * from "./Console.js";
3
7
  export * from "./Crypto.js";
4
- export * from "./Db.js";
5
- export * from "./Diff.js";
8
+ export * from "./Eq.js";
6
9
  export * from "./Error.js";
7
- export * from "./Evolu.js";
8
- export * from "./Model.js";
9
- export * from "./Murmurhash.js";
10
- export * from "./Owner.js";
11
- export * from "./Platform.js";
12
- export * from "./Protobuf.js";
10
+ export * from "./Evolu/Public.js";
11
+ export * from "./Function.js";
12
+ export * from "./ManyToManyMap.js";
13
+ export * from "./NanoId.js";
14
+ export * from "./Number.js";
15
+ export * from "./Object.js";
16
+ export * from "./Order.js";
17
+ export * from "./Promise.js";
18
+ export * from "./Random.js";
19
+ export * from "./Ref.js";
20
+ export * from "./Result.js";
13
21
  export * from "./Sqlite.js";
14
22
  export * from "./Store.js";
15
- export * from "./Sync.js";
23
+ export * from "./String.js";
24
+ export * from "./Time.js";
25
+ export * from "./Type.js";
26
+ export * from "./Types.js";
27
+ export * from "./WebSocket.js";
28
+ export * from "./Worker.js";
@@ -1,56 +0,0 @@
1
- import * as Context from "effect/Context";
2
- import * as ManagedRuntime from "effect/ManagedRuntime";
3
- export interface Config {
4
- /**
5
- * URL to reload browser tabs after {@link Owner} reset or restore.
6
- *
7
- * The default value is `/`.
8
- */
9
- reloadUrl: string;
10
- /**
11
- * URL for Evolu sync and backup server.
12
- *
13
- * The default value is `https://evolu.world`.
14
- */
15
- syncUrl: string;
16
- /**
17
- * Evolu is multitenant - it can run more instances concurrently. Every Evolu
18
- * instance has to have its own unique name. Database files are separated and
19
- * invisible to each other.
20
- *
21
- * The default value is: `Evolu`.
22
- */
23
- name: string;
24
- /**
25
- * Maximum physical clock drift allowed in ms.
26
- *
27
- * The default value is 5 * 60 * 1000 (5 minutes).
28
- */
29
- maxDrift: number;
30
- /**
31
- * Setting the minimum log level. The default value is `none`.
32
- *
33
- * For development, use `trace` to log all events and `debug` to log only
34
- * events with values. For production, use `warning`.
35
- */
36
- minimumLogLevel: "none" | "trace" | "debug" | "warning";
37
- /**
38
- * Enables websocket connection
39
- *
40
- * If set to true runs a websocket connection on the sync url
41
- */
42
- enableWebsocketConnection?: true;
43
- /**
44
- * Allows to reuse websocket connections for multiple database setup
45
- *
46
- * Works INSTEAD of enableWebsocket and if set overrides enableWebsocket this
47
- * attaches the database to a connection produced by a call back from another
48
- * database that has enableWebsocketConnection
49
- */
50
- externalWebsocketConnection?: WebSocket;
51
- }
52
- export declare const Config: Context.Tag<Config, Config>;
53
- export declare const defaultConfig: Config;
54
- /** https://effect.website/docs/guides/runtime */
55
- export declare const createRuntime: (partialConfig?: Partial<Config>) => ManagedRuntime.ManagedRuntime<Config, never>;
56
- //# sourceMappingURL=Config.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Config.d.ts","sourceRoot":"","sources":["../../src/Config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAI1C,OAAO,KAAK,cAAc,MAAM,uBAAuB,CAAC;AAGxD,MAAM,WAAW,MAAM;IACrB;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;;;;OAMG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;;OAKG;IACH,eAAe,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;IAExD;;;;OAIG;IACH,yBAAyB,CAAC,EAAE,IAAI,CAAC;IAEjC;;;;;;OAMG;IACH,2BAA2B,CAAC,EAAE,SAAS,CAAC;CACzC;AAED,eAAO,MAAM,MAAM,6BAAuC,CAAC;AAE3D,eAAO,MAAM,aAAa,EAAE,MAM3B,CAAC;AAEF,iDAAiD;AACjD,eAAO,MAAM,aAAa,mBACR,OAAO,CAAC,MAAM,CAAC,KAC9B,cAAc,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,CAsB7C,CAAC"}