@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.
Files changed (237) hide show
  1. package/dist/src/Array.d.ts +279 -173
  2. package/dist/src/Array.d.ts.map +1 -1
  3. package/dist/src/Array.js +105 -101
  4. package/dist/src/Assert.d.ts +44 -44
  5. package/dist/src/Assert.d.ts.map +1 -1
  6. package/dist/src/Assert.js +44 -32
  7. package/dist/src/BigInt.d.ts +6 -3
  8. package/dist/src/BigInt.d.ts.map +1 -1
  9. package/dist/src/BigInt.js +5 -2
  10. package/dist/src/Brand.d.ts +27 -40
  11. package/dist/src/Brand.d.ts.map +1 -1
  12. package/dist/src/Buffer.d.ts +27 -11
  13. package/dist/src/Buffer.d.ts.map +1 -1
  14. package/dist/src/Cache.d.ts +9 -4
  15. package/dist/src/Cache.d.ts.map +1 -1
  16. package/dist/src/Cache.js +8 -3
  17. package/dist/src/Callbacks.d.ts +30 -19
  18. package/dist/src/Callbacks.d.ts.map +1 -1
  19. package/dist/src/Console.d.ts +145 -66
  20. package/dist/src/Console.d.ts.map +1 -1
  21. package/dist/src/Console.js +91 -43
  22. package/dist/src/Crypto.d.ts +85 -42
  23. package/dist/src/Crypto.d.ts.map +1 -1
  24. package/dist/src/Crypto.js +44 -20
  25. package/dist/src/Eq.d.ts +87 -21
  26. package/dist/src/Eq.d.ts.map +1 -1
  27. package/dist/src/Eq.js +67 -19
  28. package/dist/src/Error.d.ts +5 -3
  29. package/dist/src/Error.d.ts.map +1 -1
  30. package/dist/src/Error.js +16 -0
  31. package/dist/src/Function.d.ts +119 -58
  32. package/dist/src/Function.d.ts.map +1 -1
  33. package/dist/src/Function.js +86 -43
  34. package/dist/src/Http.d.ts +394 -0
  35. package/dist/src/Http.d.ts.map +1 -0
  36. package/dist/src/Http.js +102 -0
  37. package/dist/src/Identicon.d.ts +16 -7
  38. package/dist/src/Identicon.d.ts.map +1 -1
  39. package/dist/src/Identicon.js +14 -5
  40. package/dist/src/LeakDetector.d.ts +88 -0
  41. package/dist/src/LeakDetector.d.ts.map +1 -0
  42. package/dist/src/LeakDetector.js +86 -0
  43. package/dist/src/LockManager.d.ts +18 -9
  44. package/dist/src/LockManager.d.ts.map +1 -1
  45. package/dist/src/LockManager.js +7 -8
  46. package/dist/src/Lookup.d.ts +43 -13
  47. package/dist/src/Lookup.d.ts.map +1 -1
  48. package/dist/src/Lookup.js +28 -8
  49. package/dist/src/Microtask.d.ts +1 -1
  50. package/dist/src/Microtask.d.ts.map +1 -1
  51. package/dist/src/Microtask.js +3 -7
  52. package/dist/src/Number.d.ts +49 -13
  53. package/dist/src/Number.d.ts.map +1 -1
  54. package/dist/src/Number.js +34 -5
  55. package/dist/src/Object.d.ts +160 -40
  56. package/dist/src/Object.d.ts.map +1 -1
  57. package/dist/src/Object.js +92 -46
  58. package/dist/src/Option.d.ts +10 -7
  59. package/dist/src/Option.d.ts.map +1 -1
  60. package/dist/src/Option.js +9 -6
  61. package/dist/src/Order.d.ts +21 -21
  62. package/dist/src/Order.d.ts.map +1 -1
  63. package/dist/src/Order.js +18 -21
  64. package/dist/src/Platform.d.ts +31 -0
  65. package/dist/src/Platform.d.ts.map +1 -1
  66. package/dist/src/Platform.js +98 -0
  67. package/dist/src/Random.d.ts +32 -17
  68. package/dist/src/Random.d.ts.map +1 -1
  69. package/dist/src/Random.js +12 -8
  70. package/dist/src/Redacted.d.ts +43 -29
  71. package/dist/src/Redacted.d.ts.map +1 -1
  72. package/dist/src/Redacted.js +14 -3
  73. package/dist/src/Ref.d.ts +11 -3
  74. package/dist/src/Ref.d.ts.map +1 -1
  75. package/dist/src/Ref.js +2 -2
  76. package/dist/src/RefCount.d.ts +2 -6
  77. package/dist/src/RefCount.d.ts.map +1 -1
  78. package/dist/src/RefCount.js +33 -90
  79. package/dist/src/Relation.d.ts +70 -5
  80. package/dist/src/Relation.d.ts.map +1 -1
  81. package/dist/src/Relation.js +77 -2
  82. package/dist/src/Resource.d.ts +590 -155
  83. package/dist/src/Resource.d.ts.map +1 -1
  84. package/dist/src/Resource.js +592 -343
  85. package/dist/src/Result.d.ts +838 -191
  86. package/dist/src/Result.d.ts.map +1 -1
  87. package/dist/src/Result.js +163 -102
  88. package/dist/src/Schedule.d.ts +684 -231
  89. package/dist/src/Schedule.d.ts.map +1 -1
  90. package/dist/src/Schedule.js +766 -295
  91. package/dist/src/Set.d.ts +89 -40
  92. package/dist/src/Set.d.ts.map +1 -1
  93. package/dist/src/Set.js +50 -29
  94. package/dist/src/Sqlite.d.ts +29 -72
  95. package/dist/src/Sqlite.d.ts.map +1 -1
  96. package/dist/src/Sqlite.js +41 -46
  97. package/dist/src/StackTrace.d.ts +40 -0
  98. package/dist/src/StackTrace.d.ts.map +1 -0
  99. package/dist/src/StackTrace.js +140 -0
  100. package/dist/src/Store.d.ts +5 -4
  101. package/dist/src/Store.d.ts.map +1 -1
  102. package/dist/src/Store.js +5 -4
  103. package/dist/src/String.d.ts +7 -1
  104. package/dist/src/String.d.ts.map +1 -1
  105. package/dist/src/String.js +20 -7
  106. package/dist/src/Task.d.ts +3572 -1770
  107. package/dist/src/Task.d.ts.map +1 -1
  108. package/dist/src/Task.js +1879 -1274
  109. package/dist/src/Test.d.ts +17 -125
  110. package/dist/src/Test.d.ts.map +1 -1
  111. package/dist/src/Test.js +17 -68
  112. package/dist/src/Time.d.ts +108 -49
  113. package/dist/src/Time.d.ts.map +1 -1
  114. package/dist/src/Time.js +172 -73
  115. package/dist/src/Type.d.ts +3542 -1926
  116. package/dist/src/Type.d.ts.map +1 -1
  117. package/dist/src/Type.js +3070 -1784
  118. package/dist/src/Types.d.ts +200 -108
  119. package/dist/src/Types.d.ts.map +1 -1
  120. package/dist/src/Types.js +39 -8
  121. package/dist/src/WebSocket.d.ts +48 -23
  122. package/dist/src/WebSocket.d.ts.map +1 -1
  123. package/dist/src/WebSocket.js +15 -6
  124. package/dist/src/Worker.d.ts +94 -36
  125. package/dist/src/Worker.d.ts.map +1 -1
  126. package/dist/src/Worker.js +58 -24
  127. package/dist/src/index.d.ts +55 -52
  128. package/dist/src/index.d.ts.map +1 -1
  129. package/dist/src/index.js +3 -1
  130. package/dist/src/intl/cs.d.ts +94 -0
  131. package/dist/src/intl/cs.d.ts.map +1 -0
  132. package/dist/src/intl/cs.js +220 -0
  133. package/dist/src/intl/index.d.ts +7 -0
  134. package/dist/src/intl/index.d.ts.map +1 -0
  135. package/dist/src/intl/index.js +6 -0
  136. package/dist/src/local-first/Db.d.ts +12 -8
  137. package/dist/src/local-first/Db.d.ts.map +1 -1
  138. package/dist/src/local-first/Db.js +109 -132
  139. package/dist/src/local-first/Error.d.ts +4 -4
  140. package/dist/src/local-first/Evolu.d.ts +338 -92
  141. package/dist/src/local-first/Evolu.d.ts.map +1 -1
  142. package/dist/src/local-first/Evolu.js +47 -55
  143. package/dist/src/local-first/LocalAuth.d.ts +4 -4
  144. package/dist/src/local-first/LocalAuth.d.ts.map +1 -1
  145. package/dist/src/local-first/Owner.d.ts +61 -24
  146. package/dist/src/local-first/Owner.d.ts.map +1 -1
  147. package/dist/src/local-first/Owner.js +45 -8
  148. package/dist/src/local-first/Protocol.d.ts +44 -31
  149. package/dist/src/local-first/Protocol.d.ts.map +1 -1
  150. package/dist/src/local-first/Protocol.js +36 -13
  151. package/dist/src/local-first/Query.d.ts +147 -62
  152. package/dist/src/local-first/Query.d.ts.map +1 -1
  153. package/dist/src/local-first/Query.js +112 -58
  154. package/dist/src/local-first/Relay.d.ts +44 -14
  155. package/dist/src/local-first/Relay.d.ts.map +1 -1
  156. package/dist/src/local-first/Schema.d.ts +92 -41
  157. package/dist/src/local-first/Schema.d.ts.map +1 -1
  158. package/dist/src/local-first/Schema.js +25 -8
  159. package/dist/src/local-first/Shared.d.ts +23 -21
  160. package/dist/src/local-first/Shared.d.ts.map +1 -1
  161. package/dist/src/local-first/Shared.js +100 -57
  162. package/dist/src/local-first/Storage.d.ts +53 -32
  163. package/dist/src/local-first/Storage.d.ts.map +1 -1
  164. package/dist/src/local-first/Storage.js +194 -234
  165. package/dist/src/local-first/Timestamp.d.ts +21 -21
  166. package/dist/src/local-first/Timestamp.d.ts.map +1 -1
  167. package/dist/src/local-first/Timestamp.js +2 -2
  168. package/dist/src/local-first/index.d.ts +11 -11
  169. package/package.json +14 -13
  170. package/src/Array.ts +306 -205
  171. package/src/Assert.ts +54 -69
  172. package/src/BigInt.ts +6 -3
  173. package/src/Brand.ts +27 -40
  174. package/src/Buffer.ts +28 -12
  175. package/src/Cache.ts +9 -4
  176. package/src/Callbacks.ts +30 -19
  177. package/src/Console.ts +156 -84
  178. package/src/Crypto.ts +83 -41
  179. package/src/Eq.ts +95 -22
  180. package/src/Error.ts +8 -4
  181. package/src/Function.ts +167 -59
  182. package/src/Http.ts +549 -0
  183. package/src/Identicon.ts +16 -7
  184. package/src/LeakDetector.ts +182 -0
  185. package/src/LockManager.ts +43 -39
  186. package/src/Lookup.ts +62 -28
  187. package/src/Microtask.ts +19 -23
  188. package/src/Number.ts +64 -12
  189. package/src/Object.ts +173 -49
  190. package/src/Option.ts +10 -7
  191. package/src/Order.ts +23 -21
  192. package/src/Platform.ts +136 -0
  193. package/src/Polyfills.ts +6 -12
  194. package/src/Random.ts +32 -19
  195. package/src/Redacted.ts +44 -30
  196. package/src/Ref.ts +14 -6
  197. package/src/RefCount.ts +38 -80
  198. package/src/Relation.ts +202 -10
  199. package/src/Resource.ts +1199 -591
  200. package/src/Result.ts +930 -271
  201. package/src/Schedule.ts +859 -343
  202. package/src/Set.ts +89 -40
  203. package/src/Sqlite.ts +144 -138
  204. package/src/StackTrace.ts +230 -0
  205. package/src/Store.ts +8 -7
  206. package/src/String.ts +22 -5
  207. package/src/Task.ts +5101 -2832
  208. package/src/Test.ts +20 -168
  209. package/src/Time.ts +293 -90
  210. package/src/Type.ts +10034 -4117
  211. package/src/Types.ts +227 -110
  212. package/src/WebSocket.ts +64 -36
  213. package/src/Worker.ts +180 -72
  214. package/src/index.ts +55 -52
  215. package/src/intl/cs.ts +388 -0
  216. package/src/intl/index.ts +7 -0
  217. package/src/local-first/Db.ts +152 -179
  218. package/src/local-first/Error.ts +4 -4
  219. package/src/local-first/Evolu.ts +495 -250
  220. package/src/local-first/LocalAuth.ts +6 -12
  221. package/src/local-first/Owner.ts +58 -21
  222. package/src/local-first/Protocol.ts +49 -31
  223. package/src/local-first/Query.ts +146 -61
  224. package/src/local-first/Relay.ts +51 -21
  225. package/src/local-first/Schema.ts +109 -51
  226. package/src/local-first/Shared.ts +266 -226
  227. package/src/local-first/Storage.ts +266 -264
  228. package/src/local-first/Timestamp.ts +25 -18
  229. package/src/local-first/index.ts +11 -11
  230. package/dist/src/Skiplist.d.ts +0 -28
  231. package/dist/src/Skiplist.d.ts.map +0 -1
  232. package/dist/src/Skiplist.js +0 -64
  233. package/dist/src/Tracer.d.ts +0 -48
  234. package/dist/src/Tracer.d.ts.map +0 -1
  235. package/dist/src/Tracer.js +0 -6
  236. package/src/Skiplist.ts +0 -108
  237. package/src/Tracer.ts +0 -54
@@ -3,18 +3,29 @@
3
3
  *
4
4
  * @module
5
5
  */
6
- import * as Kysely from "kysely";
7
- import type { TypeName } from "./Type.js";
8
6
  /**
9
7
  * A function that receives a value and returns nothing.
10
8
  *
11
9
  * Use for event handlers, observers, and async completion handlers.
12
10
  *
13
- * ### Example
11
+ * ### Completion callbacks
14
12
  *
15
13
  * ```ts
16
- * const onComplete: Callback<string> = (value) => console.log(value);
17
- * const queue = new Set<Callback<Result<Data, Error>>>();
14
+ * import { ok, type Callback, type Result } from "@evolu/common";
15
+ *
16
+ * const completedValues: Array<string> = [];
17
+ * const onComplete: Callback<string> = (value) => {
18
+ * completedValues.push(value);
19
+ * };
20
+ * const queue = new Set<Callback<Result<string, Error>>>();
21
+ * queue.add((result) => {
22
+ * if (result.ok) completedValues.push(result.value);
23
+ * });
24
+ *
25
+ * onComplete("direct");
26
+ * for (const callback of queue) callback(ok("queued"));
27
+ *
28
+ * expect(completedValues).toEqual(["direct", "queued"]);
18
29
  * ```
19
30
  */
20
31
  export type Callback<T> = (value: T) => void;
@@ -23,13 +34,29 @@ export type Callback<T> = (value: T) => void;
23
34
  *
24
35
  * Use for subscriptions or callbacks that need abort-time teardown.
25
36
  *
26
- * ### Example
37
+ * ### Subscription teardown
27
38
  *
28
39
  * ```ts
40
+ * import type { CallbackWithTeardown } from "@evolu/common";
41
+ *
42
+ * interface EventSource {
43
+ * readonly start: () => void;
44
+ * readonly stop: () => void;
45
+ * }
46
+ *
47
+ * const events: Array<string> = [];
48
+ * const source: EventSource = {
49
+ * start: () => events.push("started"),
50
+ * stop: () => events.push("stopped"),
51
+ * };
29
52
  * const subscribe: CallbackWithTeardown<EventSource> = (source) => {
30
53
  * source.start();
31
- * return () => source.stop();
54
+ * return source.stop;
32
55
  * };
56
+ * const teardown = subscribe(source);
57
+ * if (teardown) teardown();
58
+ *
59
+ * expect(events).toEqual(["started", "stopped"]);
33
60
  * ```
34
61
  */
35
62
  export type CallbackWithTeardown<T> = (value: T) => void | (() => void);
@@ -38,13 +65,14 @@ export type CallbackWithTeardown<T> = (value: T) => void | (() => void);
38
65
  *
39
66
  * A predicate starts with an 'is' prefix, e.g., `isEven`.
40
67
  *
41
- * ### Example
68
+ * ### Filtering values
42
69
  *
43
70
  * ```ts
71
+ * import type { Predicate } from "@evolu/common";
72
+ *
44
73
  * const isEven: Predicate<number> = (n) => n % 2 === 0;
45
74
  *
46
- * const numbers = [1, 2, 3, 4];
47
- * const evenNumbers = numbers.filter(isEven); // [2, 4]
75
+ * expect([1, 2, 3, 4].filter(isEven)).toEqual([2, 4]);
48
76
  * ```
49
77
  */
50
78
  export type Predicate<T> = (value: T) => boolean;
@@ -53,33 +81,40 @@ export type Predicate<T> = (value: T) => boolean;
53
81
  *
54
82
  * Useful for callbacks that need both the element and its position.
55
83
  *
56
- * ### Example
84
+ * ### Filtering by position
57
85
  *
58
86
  * ```ts
87
+ * import type { PredicateWithIndex } from "@evolu/common";
88
+ *
59
89
  * const isEvenIndex: PredicateWithIndex<string> = (value, index) =>
60
90
  * index % 2 === 0;
61
91
  *
62
- * const items = ["a", "b", "c", "d"];
63
- * const evenIndexItems = items.filter(isEvenIndex); // ["a", "c"]
92
+ * expect(["a", "b", "c", "d"].filter(isEvenIndex)).toEqual(["a", "c"]);
64
93
  * ```
65
94
  */
66
95
  export type PredicateWithIndex<T> = (value: T, index: number) => boolean;
67
96
  /**
68
97
  * A type guard function that refines type `A` to a narrower type `B`.
69
98
  *
70
- * ### Example
99
+ * ### Narrowing a value
71
100
  *
72
101
  * ```ts
73
- * type Animal = { name: string };
74
- * type Dog = Animal & { breed: string };
102
+ * import type { Refinement } from "@evolu/common";
103
+ *
104
+ * interface Animal {
105
+ * readonly name: string;
106
+ * }
107
+ * interface Dog extends Animal {
108
+ * readonly breed: string;
109
+ * }
75
110
  *
76
111
  * const isDog: Refinement<Animal, Dog> = (animal): animal is Dog =>
77
112
  * "breed" in animal;
113
+ * const dog: Dog = { name: "Dog", breed: "Beagle" };
114
+ * const animal: Animal = dog;
115
+ * if (!isDog(animal)) throw new Error("Expected a dog");
78
116
  *
79
- * const animal: Animal = { name: "Dog", breed: "Beagle" };
80
- * if (isDog(animal)) {
81
- * console.log(animal.breed); // Safe access to `breed`
82
- * }
117
+ * expect(animal.breed).toBe("Beagle");
83
118
  * ```
84
119
  */
85
120
  export type Refinement<in A, out B extends A> = (a: A) => a is B;
@@ -90,40 +125,112 @@ export type Refinement<in A, out B extends A> = (a: A) => a is B;
90
125
  * Useful for callbacks that need both the element and its position while
91
126
  * maintaining type narrowing.
92
127
  *
93
- * ### Example
128
+ * ### Indexed refinement
94
129
  *
95
130
  * ```ts
96
- * type Item = { type: "number" | "string"; value: unknown };
97
- *
98
- * const isNumberItem: RefinementWithIndex<Item, Item & { type: "number" }> =
99
- * (item, index): item is Item & { type: "number" } =>
100
- * index > 0 && item.type === "number";
131
+ * import { partitionArray, type RefinementWithIndex } from "@evolu/common";
101
132
  *
102
- * const items: ReadonlyArray<Item> = [...];
133
+ * type Item = {
134
+ * readonly type: "number" | "string";
135
+ * readonly value: unknown;
136
+ * };
137
+ * type NumberItem = Item & { readonly type: "number" };
138
+ *
139
+ * const isNumberItem: RefinementWithIndex<Item, NumberItem> = (
140
+ * item,
141
+ * index,
142
+ * ): item is NumberItem => index > 0 && item.type === "number";
143
+ * const items: ReadonlyArray<Item> = [
144
+ * { type: "number", value: 1 },
145
+ * { type: "number", value: 2 },
146
+ * ];
103
147
  * const [numbers, others] = partitionArray(items, isNumberItem);
148
+ *
149
+ * expectTypeOf(numbers).toEqualTypeOf<ReadonlyArray<NumberItem>>();
150
+ * expect(numbers[0]?.value).toBe(2);
151
+ * expect(others[0]?.value).toBe(1);
104
152
  * ```
105
153
  */
106
154
  export type RefinementWithIndex<in A, out B extends A> = (a: A, index: number) => a is B;
155
+ /**
156
+ * Realm-neutral runtime identity for a TypeScript interface.
157
+ *
158
+ * Extend this interface and add its runtime evidence with {@link instance} when
159
+ * constructing a value. Unlike JavaScript `instanceof`, the identity does not
160
+ * depend on a constructor or prototype and therefore survives realms, package
161
+ * duplication, object spreading, and structured cloning.
162
+ *
163
+ * The marker is intentionally forgeable. It identifies values created by
164
+ * trusted constructors; it is not structural validation or a security
165
+ * boundary.
166
+ *
167
+ * ### Adding runtime identity
168
+ *
169
+ * ```ts
170
+ * import { instance, type Instance } from "@evolu/common";
171
+ *
172
+ * interface Foo extends Instance<"Foo"> {
173
+ * readonly value: string;
174
+ * }
175
+ *
176
+ * const foo: Foo = {
177
+ * ...instance("Foo"),
178
+ * value: "value",
179
+ * };
180
+ *
181
+ * expect(foo["~evolu/instance"]).toBe("Foo");
182
+ * ```
183
+ */
184
+ export interface Instance<Name extends string> {
185
+ readonly "~evolu/instance": Name;
186
+ }
187
+ /** Creates the runtime identity property required by {@link Instance}. */
188
+ export declare const instance: <const Name extends string>(name: Name) => Instance<Name>;
189
+ /**
190
+ * Creates a realm-neutral predicate for one {@link Instance} name.
191
+ *
192
+ * The identity must be stored directly on the value; inherited markers are
193
+ * ignored.
194
+ *
195
+ * The explicit value type can include the rest of an interface whose trusted
196
+ * constructors attach the matching identity.
197
+ *
198
+ * ### Checking runtime identity
199
+ *
200
+ * ```ts
201
+ * import { instance, isInstance, type Instance } from "@evolu/common";
202
+ *
203
+ * interface Foo extends Instance<"Foo"> {
204
+ * readonly value: string;
205
+ * }
206
+ *
207
+ * const isFoo = isInstance<Foo>("Foo");
208
+ * const value: unknown = { ...instance("Foo"), value: "value" };
209
+ *
210
+ * expect(isFoo(value)).toBe(true);
211
+ * ```
212
+ */
213
+ export declare const isInstance: <Value extends Instance<string>>(name: Value["~evolu/instance"]) => (value: unknown) => value is Value;
107
214
  /**
108
215
  * Makes properties optional if they accept `null` as a value.
109
216
  *
110
217
  * For each property in `T`, if `null` is a valid value for that property, the
111
218
  * property will be made optional in the resulting type.
112
219
  *
113
- * ### Example
220
+ * ### Optional nullable properties
114
221
  *
115
222
  * ```ts
223
+ * import type { NullablePartial } from "@evolu/common";
224
+ *
116
225
  * type Example = {
117
226
  * required: string;
118
227
  * optionalWithNull: string | null;
119
228
  * };
120
229
  *
121
- * type Result = NullablePartial<Example>;
122
- * // Result is:
123
- * // {
124
- * // required: string;
125
- * // optionalWithNull?: string | null;
126
- * // }
230
+ * expectTypeOf<NullablePartial<Example>>().toEqualTypeOf<{
231
+ * required: string;
232
+ * optionalWithNull?: string | null;
233
+ * }>();
127
234
  * ```
128
235
  */
129
236
  export type NullablePartial<T, NK extends keyof T = {
@@ -131,6 +238,10 @@ export type NullablePartial<T, NK extends keyof T = {
131
238
  }[keyof T], NP = Pick<T, Exclude<keyof T, NK>> & Partial<Pick<T, NK>>> = {
132
239
  [K in keyof NP]: NP[K];
133
240
  };
241
+ /** A value with a numeric length. */
242
+ export interface ValueWithLength {
243
+ readonly length: number;
244
+ }
134
245
  /**
135
246
  * String, number, bigint, boolean, undefined, null
136
247
  *
@@ -148,13 +259,8 @@ export type Literal = string | number | bigint | boolean | undefined | null;
148
259
  * - True -> boolean
149
260
  */
150
261
  export type WidenLiteral<T extends Literal> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T extends bigint ? bigint : T;
151
- /**
152
- * Removes `readonly` modifier from all properties of a type.
153
- *
154
- * Useful for constructing immutable objects step-by-step (e.g. builder pattern)
155
- * before casting them back to the readonly type.
156
- */
157
- export type Mutable<T> = {
262
+ /** Removes `readonly` modifier from all properties of a type. */
263
+ export type Writable<T> = {
158
264
  -readonly [P in keyof T]: T[P];
159
265
  };
160
266
  /**
@@ -163,19 +269,23 @@ export type Mutable<T> = {
163
269
  * This utility forces TypeScript to "flatten" an intersection type into a
164
270
  * single object type so that tooltips and error messages are easier to read.
165
271
  *
166
- * ### Example
272
+ * ### Flattening an intersection
167
273
  *
168
274
  * ```ts
169
- * type A = { a: string } & { b: number };
170
- * // Without Simplify, TypeScript may display A as:
171
- * // { a: string } & { b: number }
275
+ * import type { Simplify } from "@evolu/common";
172
276
  *
277
+ * type A = { a: string } & { b: number };
173
278
  * type B = Simplify<A>;
174
- * // B is equivalent to:
175
- * // { a: string; b: number }
279
+ *
280
+ * expectTypeOf<B>().toEqualTypeOf<{
281
+ * a: string;
282
+ * b: number;
283
+ * }>();
176
284
  * ```
177
285
  */
178
- export type Simplify<T> = Kysely.Simplify<T>;
286
+ export type Simplify<T> = {
287
+ [K in keyof T]: T[K];
288
+ } & {};
179
289
  /**
180
290
  * Makes a specific property of an object optional while keeping others
181
291
  * unchanged.
@@ -187,21 +297,21 @@ export type PartialProp<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
187
297
  * Use when a function may complete synchronously or asynchronously depending on
188
298
  * runtime conditions (e.g., cache hit vs network fetch).
189
299
  *
190
- * ### Example
300
+ * ### Sync and async completion
191
301
  *
192
302
  * ```ts
193
- * const getData = (id: string): Awaitable<Data> => {
194
- * const cached = cache.get(id);
195
- * if (cached) return cached; // Sync path
196
- * return fetchData(id); // Async path
197
- * };
303
+ * import { isPromiseLike, type Awaitable } from "@evolu/common";
198
304
  *
199
- * // Always works
200
- * const data = await getData(id);
305
+ * const cache = new Map([["cached", "from cache"]]);
306
+ * const getData = (id: string): Awaitable<string> =>
307
+ * cache.get(id) ?? Promise.resolve(`fetched ${id}`);
201
308
  *
202
- * // Or optimize for sync path
203
- * const result = getData(id);
204
- * const data = isPromiseLike(result) ? await result : result;
309
+ * const fetched = await getData("missing");
310
+ * const result = getData("cached");
311
+ * const cached = isPromiseLike(result) ? await result : result;
312
+ *
313
+ * expect(fetched).toBe("fetched missing");
314
+ * expect(cached).toBe("from cache");
205
315
  * ```
206
316
  */
207
317
  export type Awaitable<T> = T | PromiseLike<T>;
@@ -211,33 +321,35 @@ export type Awaitable<T> = T | PromiseLike<T>;
211
321
  * Use with {@link Awaitable} to conditionally `await` only when necessary,
212
322
  * avoiding microtask overhead for synchronous values.
213
323
  *
214
- * ### Example
324
+ * ### Conditional awaiting
215
325
  *
216
326
  * ```ts
217
- * const validate = (id: string): Awaitable<boolean> => {
218
- * const cached = cache.get(id);
219
- * if (cached !== undefined) return cached; // Sync path
220
- * return fetchValidation(id); // Async path
221
- * };
327
+ * import { isPromiseLike, type Awaitable } from "@evolu/common";
222
328
  *
223
- * const result = validate(id);
329
+ * const cache = new Map([["cached", true]]);
330
+ * const validate = (id: string): Awaitable<boolean> =>
331
+ * cache.get(id) ?? Promise.resolve(false);
332
+ *
333
+ * const result = validate("cached");
224
334
  * const isValid = isPromiseLike(result) ? await result : result;
335
+ *
336
+ * expect(isValid).toBe(true);
225
337
  * ```
226
338
  */
227
339
  export declare const isPromiseLike: <T>(value: Awaitable<T>) => value is PromiseLike<T>;
228
- /** Single digit 0-9. Useful for template literal type validation. */
340
+ /** Decimal digit from `"0"` to `"9"`. */
229
341
  export type Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
230
- /** Digit 1-9. Useful for template literal type validation. */
342
+ /** Decimal digit from `"1"` to `"9"`. */
231
343
  export type Digit1To9 = Exclude<Digit, "0">;
232
- /** Numeric string 1-6. Useful for days validation. */
344
+ /** Decimal string from `"1"` to `"6"`. */
233
345
  export type Digit1To6 = "1" | "2" | "3" | "4" | "5" | "6";
234
- /** Numeric string 1-23. Useful for hours validation. */
346
+ /** Decimal string from `"1"` to `"23"`. */
235
347
  export type Digit1To23 = Digit1To9 | `1${Digit}` | `2${"0" | "1" | "2" | "3"}`;
236
- /** Numeric string 1-51. Useful for weeks validation. */
348
+ /** Decimal string from `"1"` to `"51"`. */
237
349
  export type Digit1To51 = Digit1To9 | `${"1" | "2" | "3" | "4"}${Digit}` | `5${"0" | "1"}`;
238
- /** Numeric string 1-99. Useful for years validation. */
350
+ /** Decimal string from `"1"` to `"99"`. */
239
351
  export type Digit1To99 = Digit1To9 | `${Digit1To9}${Digit}`;
240
- /** Numeric string 1-59. Useful for minutes, seconds validation. */
352
+ /** Decimal string from `"1"` to `"59"`. */
241
353
  export type Digit1To59 = Digit1To9 | `1${Digit}` | `2${Digit}` | `3${Digit}` | `4${Digit}` | `5${Digit}`;
242
354
  /** Numeric literal 1-99. */
243
355
  export type Int1To99 = NumberFromString<Digit1To99>;
@@ -249,57 +361,37 @@ export type Int1To100 = Int1To99 | 100;
249
361
  * Used by {@link Int1To99}.
250
362
  */
251
363
  export type NumberFromString<T extends string> = T extends `${infer N extends number}` ? N : never;
364
+ /** Creates a readable compiler-facing error message. */
365
+ export type CompileTimeError<Context extends string, Message extends string> = `⛔ ${Context} error: ${Message}`;
366
+ /** Returns whether a type is a union. */
367
+ export type IsUnion<T, Whole = T> = [T] extends [never] ? false : T extends Whole ? [Whole] extends [T] ? false : true : never;
368
+ /** Returns every property key present in any member of a union. */
369
+ export type KeysOfUnion<T> = T extends T ? keyof T : never;
252
370
  /** Converts a union to an intersection. */
253
371
  export type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
372
+ /** Intersects the parameter types of a union of unary functions. */
373
+ export type ParameterIntersection<T> = [T] extends [(value: infer I) => void] ? I : unknown;
254
374
  /**
255
375
  * Removes keys from each member of a union.
256
376
  *
257
377
  * Use when {@link Omit} would collapse a discriminated union into a single
258
378
  * shared shape.
259
379
  *
260
- * ### Example
380
+ * ### Preserving discriminated unions
261
381
  *
262
382
  * ```ts
383
+ * import type { DistributiveOmit } from "@evolu/common";
384
+ *
263
385
  * type Event =
264
386
  * | { type: "a"; a: string; shared: number }
265
387
  * | { type: "b"; b: number; shared: number };
266
388
  *
267
389
  * type Payload = DistributiveOmit<Event, "shared">;
268
- * // { type: "a"; a: string } | { type: "b"; b: number }
269
- * ```
270
- */
271
- export type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
272
- /**
273
- * Extracts members of a discriminated union by their `type` literal.
274
- *
275
- * Constrains `TType` to valid `type` values, so typos fail at the type argument
276
- * instead of silently producing `never`.
277
- *
278
- * ### Example
279
390
  *
280
- * ```ts
281
- * type Message =
282
- * | { readonly type: "Create"; readonly id: string }
283
- * | { readonly type: "Delete"; readonly id: string };
284
- *
285
- * type CreateMessage = ExtractType<Message, "Create">;
286
- * // { readonly type: "Create"; readonly id: string }
287
- *
288
- * // Type error: "Cretae" is not a valid Message type
289
- * type _Typo = ExtractType<Message, "Cretae">;
391
+ * expectTypeOf<Payload>().toEqualTypeOf<
392
+ * { type: "a"; a: string } | { type: "b"; b: number }
393
+ * >();
290
394
  * ```
291
395
  */
292
- export type ExtractType<TUnion extends {
293
- readonly type: TypeName;
294
- }, TType extends TUnion["type"]> = Extract<TUnion, {
295
- readonly type: TType;
296
- }>;
297
- /**
298
- * Constrains `T` to only contain keys not present in `Existing`.
299
- *
300
- * Use as a generic constraint to prevent overriding existing properties.
301
- */
302
- export type NewKeys<T, Existing> = {
303
- [K in keyof T]: K extends keyof Existing ? never : T[K];
304
- };
396
+ export type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
305
397
  //# sourceMappingURL=Types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Types.d.ts","sourceRoot":"","sources":["../../src/Types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Types.d.ts","sourceRoot":"","sources":["../../src/Types.ts"],"names":[],"mappings":"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"}
package/dist/src/Types.js CHANGED
@@ -3,24 +3,55 @@
3
3
  *
4
4
  * @module
5
5
  */
6
- import * as Kysely from "kysely";
6
+ /** Creates the runtime identity property required by {@link Instance}. */
7
+ export const instance = (name) => ({ "~evolu/instance": name });
8
+ /**
9
+ * Creates a realm-neutral predicate for one {@link Instance} name.
10
+ *
11
+ * The identity must be stored directly on the value; inherited markers are
12
+ * ignored.
13
+ *
14
+ * The explicit value type can include the rest of an interface whose trusted
15
+ * constructors attach the matching identity.
16
+ *
17
+ * ### Checking runtime identity
18
+ *
19
+ * ```ts
20
+ * import { instance, isInstance, type Instance } from "@evolu/common";
21
+ *
22
+ * interface Foo extends Instance<"Foo"> {
23
+ * readonly value: string;
24
+ * }
25
+ *
26
+ * const isFoo = isInstance<Foo>("Foo");
27
+ * const value: unknown = { ...instance("Foo"), value: "value" };
28
+ *
29
+ * expect(isFoo(value)).toBe(true);
30
+ * ```
31
+ */
32
+ export const isInstance = (name) => (value) => value !== null &&
33
+ typeof value === "object" &&
34
+ globalThis.Object.hasOwn(value, "~evolu/instance") &&
35
+ value["~evolu/instance"] === name;
7
36
  /**
8
37
  * Type guard to check if a value is a {@link PromiseLike}.
9
38
  *
10
39
  * Use with {@link Awaitable} to conditionally `await` only when necessary,
11
40
  * avoiding microtask overhead for synchronous values.
12
41
  *
13
- * ### Example
42
+ * ### Conditional awaiting
14
43
  *
15
44
  * ```ts
16
- * const validate = (id: string): Awaitable<boolean> => {
17
- * const cached = cache.get(id);
18
- * if (cached !== undefined) return cached; // Sync path
19
- * return fetchValidation(id); // Async path
20
- * };
45
+ * import { isPromiseLike, type Awaitable } from "@evolu/common";
46
+ *
47
+ * const cache = new Map([["cached", true]]);
48
+ * const validate = (id: string): Awaitable<boolean> =>
49
+ * cache.get(id) ?? Promise.resolve(false);
21
50
  *
22
- * const result = validate(id);
51
+ * const result = validate("cached");
23
52
  * const isValid = isPromiseLike(result) ? await result : result;
53
+ *
54
+ * expect(isValid).toBe(true);
24
55
  * ```
25
56
  */
26
57
  export const isPromiseLike = (value) => typeof value?.then === "function";
@@ -3,11 +3,11 @@
3
3
  *
4
4
  * @module
5
5
  */
6
- import type { Result } from "./Result.js";
7
- import type { Schedule } from "./Schedule.js";
8
- import type { RetryError, Task } from "./Task.js";
9
- import type { Millis } from "./Time.js";
10
- import { type Typed } from "./Type.js";
6
+ import type { Result } from "./Result.ts";
7
+ import type { Schedule } from "./Schedule.ts";
8
+ import type { RetryError, Task } from "./Task.ts";
9
+ import type { Millis } from "./Time.ts";
10
+ import { type Typed } from "./Type.ts";
11
11
  /**
12
12
  * WebSocket with auto-reconnect.
13
13
  *
@@ -42,20 +42,42 @@ import { type Typed } from "./Type.js";
42
42
  * - A Blob (default: "blob")
43
43
  * - An ArrayBuffer ("arraybuffer")
44
44
  *
45
- * ### Example
45
+ * ### Connecting and sending
46
46
  *
47
47
  * ```ts
48
- * const ws = await run(
49
- * createWebSocket("wss://example.com", {
50
- * onMessage: (data) => console.log("Received:", data),
51
- * onOpen: () => console.log("Connected"),
52
- * onClose: () => console.log("Disconnected"),
53
- * }),
54
- * );
55
- * if (ws.ok) {
56
- * ws.value.send("Hello");
57
- * // Later: await ws.value[Symbol.asyncDispose]();
58
- * }
48
+ * import {
49
+ * createRun,
50
+ * createWebSocket,
51
+ * testCreateWebSocket,
52
+ * type CreateWebSocket,
53
+ * type Task,
54
+ * type WebSocketSendError,
55
+ * } from "@evolu/common";
56
+ *
57
+ * const connectAndSend =
58
+ * (
59
+ * createSocket: CreateWebSocket = createWebSocket,
60
+ * ): Task<void, WebSocketSendError> =>
61
+ * async (run) => {
62
+ * await using socket = await run.ok(
63
+ * createSocket("wss://example.com", {
64
+ * protocols: ["evolu"],
65
+ * binaryType: "arraybuffer",
66
+ * onOpen: () => console.log("Connected"),
67
+ * onMessage: (data) => console.log("Received:", data),
68
+ * onClose: () => console.log("Disconnected"),
69
+ * }),
70
+ * );
71
+ * return socket.send("Hello");
72
+ * };
73
+ *
74
+ * const socketFactory = testCreateWebSocket();
75
+ * await using run = createRun();
76
+ *
77
+ * expectOk(await run(connectAndSend(socketFactory)), undefined);
78
+ * expect(socketFactory.sentMessages).toEqual([
79
+ * { url: "wss://example.com", data: "Hello" },
80
+ * ]);
59
81
  * ```
60
82
  */
61
83
  export interface WebSocket extends AsyncDisposable {
@@ -104,12 +126,8 @@ export interface WebSocketOptions {
104
126
  /** Callback when message data is received. */
105
127
  readonly onMessage?: (data: string | ArrayBuffer | Blob) => void;
106
128
  /**
107
- * Retry schedule for reconnection. Defaults to:
108
- *
109
- * ```ts
110
- * // A jittered, capped, unlimited exponential backoff.
111
- * jitter(1)(maxDelay("30s")(exponential("100ms")));
112
- * ```
129
+ * Retry schedule for reconnection. Defaults to
130
+ * {@link webSocketReconnectSchedule}.
113
131
  */
114
132
  readonly schedule?: Schedule<Millis, WebSocketRetryError>;
115
133
  /**
@@ -146,6 +164,13 @@ export type WebSocketRetryError = WebSocketConnectError | WebSocketConnectionClo
146
164
  export interface WebSocketConnectionCloseError extends Typed<"WebSocketConnectionCloseError"> {
147
165
  readonly event: CloseEvent;
148
166
  }
167
+ /**
168
+ * Default WebSocket reconnect schedule.
169
+ *
170
+ * Uses unlimited exponential backoff with a 100ms base, 30s cap, and full
171
+ * jitter.
172
+ */
173
+ export declare const webSocketReconnectSchedule: Schedule<Millis, WebSocketRetryError>;
149
174
  /** Create a new {@link WebSocket}. */
150
175
  export declare const createWebSocket: CreateWebSocket;
151
176
  /**