@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
package/src/Assert.ts CHANGED
@@ -4,9 +4,7 @@
4
4
  * @module
5
5
  */
6
6
 
7
- import type { Ok, Result } from "./Result.js";
8
- import type { AbortError } from "./Task.js";
9
- import type { AnyType, InferType, Type } from "./Type.js";
7
+ import type { Type } from "./Type.ts";
10
8
 
11
9
  /**
12
10
  * Ensures a condition is true, throwing an error with the provided message if
@@ -22,8 +20,12 @@ import type { AnyType, InferType, Type } from "./Type.js";
22
20
  * ### Example
23
21
  *
24
22
  * ```ts
25
- * assert(true, "true is not true"); // no-op
26
- * assert(false, "true is not true"); // throws Error
23
+ * import { assert as assertInvariant } from "@evolu/common";
24
+ *
25
+ * expect(() => assertInvariant(true, "Expected true.")).not.toThrow();
26
+ * expect(() => assertInvariant(false, "Expected true.")).toThrow(
27
+ * "Expected true.",
28
+ * );
27
29
  * ```
28
30
  */
29
31
  export const assert: (
@@ -35,6 +37,22 @@ export const assert: (
35
37
  }
36
38
  };
37
39
 
40
+ /**
41
+ * Asserts that a value is non-nullable.
42
+ *
43
+ * Narrows a nullable value to {@link NonNullable} when null or undefined is
44
+ * logically impossible but TypeScript cannot prove it.
45
+ */
46
+ export const assertNonNullable: <T>(
47
+ value: T,
48
+ message?: string,
49
+ ) => asserts value is NonNullable<T> = (
50
+ value,
51
+ message = "Expected value to be non-nullable.",
52
+ ) => {
53
+ assert(value != null, message);
54
+ };
55
+
38
56
  /**
39
57
  * Asserts that an array is non-empty.
40
58
  *
@@ -45,8 +63,13 @@ export const assert: (
45
63
  * ### Example
46
64
  *
47
65
  * ```ts
48
- * assertNonEmptyArray([1, 2, 3]); // no-op
49
- * assertNonEmptyArray([]); // throws Error
66
+ * import { assertNonEmptyArray } from "@evolu/common";
67
+ *
68
+ * const values = [1, 2, 3];
69
+ * assertNonEmptyArray(values);
70
+ * expectTypeOf(values).toEqualTypeOf<[number, ...Array<number>]>();
71
+ * expect(values[0]).toBe(1);
72
+ * expect(() => assertNonEmptyArray([])).toThrow();
50
73
  * ```
51
74
  */
52
75
  export const assertNonEmptyArray: <T>(
@@ -69,8 +92,15 @@ export const assertNonEmptyArray: <T>(
69
92
  * ### Example
70
93
  *
71
94
  * ```ts
72
- * assertNonEmptyReadonlyArray([1, 2, 3]); // no-op
73
- * assertNonEmptyReadonlyArray([]); // throws Error
95
+ * import { assertNonEmptyReadonlyArray } from "@evolu/common";
96
+ *
97
+ * const values: ReadonlyArray<number> = [1, 2, 3];
98
+ * assertNonEmptyReadonlyArray(values);
99
+ * expectTypeOf(values).toEqualTypeOf<
100
+ * readonly [number, ...Array<number>]
101
+ * >();
102
+ * expect(values[0]).toBe(1);
103
+ * expect(() => assertNonEmptyReadonlyArray([])).toThrow();
74
104
  * ```
75
105
  */
76
106
  export const assertNonEmptyReadonlyArray: <T>(
@@ -83,61 +113,6 @@ export const assertNonEmptyReadonlyArray: <T>(
83
113
  assert(arr.length > 0, message);
84
114
  };
85
115
 
86
- /**
87
- * Ensures a value conforms to a {@link Type}.
88
- *
89
- * Uses the Type name for the default error message.
90
- *
91
- * ### Example
92
- *
93
- * ```ts
94
- * const length = buffer.getLength();
95
- *
96
- * // We know length is logically non-negative, but TypeScript doesn't.
97
- * assertType(NonNegativeInt, length);
98
- * ```
99
- */
100
- export const assertType: <T extends AnyType>(
101
- type: T,
102
- value: unknown,
103
- message?: string,
104
- ) => asserts value is InferType<T> = (type, value, message) => {
105
- assert(type.is(value), message ?? `Expected ${type.name}.`);
106
- };
107
-
108
- /**
109
- * Asserts that a {@link Result} did not fail with `AbortError`.
110
- *
111
- * Use when abort would indicate a programmer error rather than ordinary control
112
- * flow.
113
- *
114
- * In general, abort is normal control flow. Stopping work and returning
115
- * `AbortError` is the correct behavior when a `Run` or `Fiber` is cancelled.
116
- *
117
- * Use `assertNotAborted` only to protect invariants in code that has already
118
- * decided abort must not happen, such as resource helpers built on
119
- * `unabortable`. In those places it helps fail fast on mistakes, because
120
- * TypeScript cannot fully enforce that lifecycle logic is correct.
121
- */
122
- export function assertNotAborted<T>(
123
- result: Result<T, AbortError>,
124
- message?: string,
125
- ): asserts result is Ok<T>;
126
- export function assertNotAborted<T, E>(
127
- result: Result<T, E | AbortError>,
128
- message?: string,
129
- ): asserts result is Result<T, E>;
130
- export function assertNotAborted<T, E>(
131
- result: Result<T, E | AbortError>,
132
- message = "Expected result to not be aborted.",
133
- ): asserts result is Result<T, E> {
134
- const isAbortError =
135
- !result.ok &&
136
- (result.error as { readonly type?: unknown }).type === "AbortError";
137
-
138
- assert(!isAbortError, message);
139
- }
140
-
141
116
  /**
142
117
  * Guards synchronous methods on objects that may be called after disposal.
143
118
  *
@@ -146,14 +121,24 @@ export function assertNotAborted<T, E>(
146
121
  * ### Example
147
122
  *
148
123
  * ```ts
149
- * using disposer = new globalThis.AsyncDisposableStack();
150
- * assertNotDisposed(disposer); // no-op
124
+ * import { assertNotDisposed } from "@evolu/common";
125
+ *
126
+ * await using disposer = new globalThis.AsyncDisposableStack();
127
+ * expect(() => assertNotDisposed(disposer)).not.toThrow();
151
128
  * await disposer.disposeAsync();
152
- * assertNotDisposed(disposer); // throws Error
129
+ * expect(() => assertNotDisposed(disposer)).toThrow(
130
+ * "Cannot use a disposed object.",
131
+ * );
153
132
  * ```
133
+ *
134
+ * This is the JavaScript equivalent of the .NET `ObjectDisposedException`
135
+ * pattern: once a helper has been disposed, calling its synchronous methods is
136
+ * a programmer error and should throw immediately instead of continuing with
137
+ * invalid state.
154
138
  */
155
139
  export const assertNotDisposed = (
156
- value: DisposableStack | AsyncDisposableStack,
140
+ value:
141
+ DisposableStack | AsyncDisposableStack | { readonly disposed: boolean },
157
142
  ): void => {
158
- assert(!value.disposed, "Expected value to not be disposed.");
143
+ assert(!value.disposed, "Cannot use a disposed object.");
159
144
  };
package/src/BigInt.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * @module
5
5
  */
6
6
 
7
- import type { Predicate } from "./Types.js";
7
+ import type { Predicate } from "./Types.ts";
8
8
 
9
9
  /** Increments a bigint by 1. */
10
10
  export const incrementBigInt = (n: bigint): bigint => n + 1n;
@@ -24,9 +24,12 @@ export const clampBigInt =
24
24
  * ### Example
25
25
  *
26
26
  * ```ts
27
+ * import { isBetweenBigInt } from "@evolu/common";
28
+ *
27
29
  * const isBetween10And20 = isBetweenBigInt(10n, 20n);
28
- * console.log(isBetween10And20(15n)); // true
29
- * console.log(isBetween10And20(25n)); // false
30
+ *
31
+ * expect(isBetween10And20(20n)).toBe(true);
32
+ * expect(isBetween10And20(25n)).toBe(false);
30
33
  * ```
31
34
  */
32
35
  export const isBetweenBigInt =
package/src/Brand.ts CHANGED
@@ -15,57 +15,42 @@
15
15
  * Avoid primitive types in domain code—brand everything. Evolu Type provides
16
16
  * many brand helpers.
17
17
  *
18
- * ### Single Brand
18
+ * ### Single brand
19
19
  *
20
20
  * ```ts
21
- * // A branded type definition
22
- * type UserId = number & Brand<"UserId">;
23
- *
24
- * // A function that creates `UserId` values.
25
- * // Casting with `as UserId` is unsafe, so `createUserId` must be unit-tested.
26
- * const createUserId = (): UserId => {
27
- * return 123 as UserId; // Unsafe casting
28
- * };
21
+ * import type { Brand } from "@evolu/common";
29
22
  *
30
- * const userId = createUserId();
31
- *
32
- * // A function that accepts only `UserId`.
33
- * const getUser = (id: UserId) => {
34
- * // Implementation
35
- * };
23
+ * type UserId = number & Brand<"UserId">;
36
24
  *
37
- * getUser(userId); // Valid
38
- * getUser(123); // TypeScript error
39
- * getUser("123"); // TypeScript error
25
+ * // Branding does not validate at runtime, so isolate the cast in a trusted
26
+ * // factory.
27
+ * const createUserId = (value: number): UserId => value as UserId;
28
+ * const getUser = (id: UserId): number => id;
29
+ * const userId = createUserId(123);
30
+ * expect(getUser(userId)).toBe(123);
31
+ * // @ts-expect-error A plain number is not a UserId.
32
+ * getUser(123);
40
33
  * ```
41
34
  *
42
- * ### Multiple Brands (to act like flags)
35
+ * ### Multiple brands
43
36
  *
44
37
  * ```ts
45
- * // Define branded types
38
+ * import type { Brand } from "@evolu/common";
39
+ *
46
40
  * type Min1 = string & Brand<"Min1">;
47
41
  * type Max100 = string & Brand<"Max100">;
48
42
  * type Min1Max100 = string & Brand<"Min1" | "Max100">;
49
43
  *
50
- * // Functions requiring specific brands
51
- * const requiresMin1 = (value: Min1): void => {};
52
- * const requiresMax100 = (value: Max100): void => {};
53
- *
54
- * // Values with single brands
55
- * const min1Value: Min1 = "hello" as Min1;
56
- * const max100Value: Max100 = "world" as Max100;
44
+ * const requiresMin1 = (value: Min1): string => value;
45
+ * const requiresMax100 = (value: Max100): string => value;
57
46
  *
58
- * // Value with multiple brands
59
47
  * const min1Max100Value: Min1Max100 = "typescript" as Min1Max100;
60
48
  *
61
- * // Valid cases
62
- * requiresMin1(min1Value); // Valid
63
- * requiresMax100(max100Value); // Valid
64
- * requiresMin1(min1Max100Value); // Valid: Min1Max100 satisfies Min1
65
- * requiresMax100(min1Max100Value); // Valid: Min1Max100 satisfies Max100
49
+ * expect(requiresMin1(min1Max100Value)).toBe("typescript");
50
+ * expect(requiresMax100(min1Max100Value)).toBe("typescript");
66
51
  * ```
67
52
  *
68
- * ### Standalone Brand
53
+ * ### Standalone brand
69
54
  *
70
55
  * Brand can be used alone without a base type for purely nominal typing. This
71
56
  * is useful for opaque values where the internal structure is hidden and type
@@ -74,15 +59,17 @@
74
59
  * code platform-agnostic.
75
60
  *
76
61
  * ```ts
77
- * // A nominal type with no underlying structure exposed
62
+ * import type { Brand } from "@evolu/common";
63
+ *
78
64
  * type NativePort = Brand<"NativePort">;
79
65
  *
80
- * // Only values explicitly cast to NativePort are accepted
81
- * const requiresNativePort = (port: NativePort): void => {};
66
+ * const requiresNativePort = (port: NativePort): NativePort => port;
82
67
  *
83
- * const port: NativePort = nativeValue as NativePort;
84
- * requiresNativePort(port); // Valid
85
- * requiresNativePort(nativeValue); // TypeScript error
68
+ * const nativeValue: unknown = { id: 1 };
69
+ * const port = nativeValue as NativePort;
70
+ * expect(requiresNativePort(port)).toBe(nativeValue);
71
+ * // @ts-expect-error An unknown value is not a NativePort.
72
+ * requiresNativePort(nativeValue);
86
73
  * ```
87
74
  */
88
75
  export interface Brand<B extends string> {
package/src/Buffer.ts CHANGED
@@ -4,8 +4,8 @@
4
4
  * @module
5
5
  */
6
6
 
7
- import type { Result } from "./Result.js";
8
- import { NonNegativeInt, zeroNonNegativeInt } from "./Type.js";
7
+ import type { Result } from "./Result.ts";
8
+ import { NonNegativeInt, zeroNonNegativeInt } from "./Type.ts";
9
9
  export {
10
10
  bytesToHex,
11
11
  bytesToUtf8,
@@ -51,18 +51,34 @@ export class BufferError extends Error {
51
51
  * ### Example
52
52
  *
53
53
  * ```ts
54
+ * import {
55
+ * createBuffer,
56
+ * createIdFromString,
57
+ * IdBytes,
58
+ * idBytesToId,
59
+ * idBytesTypeValueLength,
60
+ * idToIdBytes,
61
+ * NonNegativeInt,
62
+ * } from "@evolu/common";
63
+ * import {
64
+ * decodeNonNegativeInt,
65
+ * encodeNonNegativeInt,
66
+ * } from "@evolu/common/local-first";
67
+ *
54
68
  * const buffer = createBuffer();
55
- * encodeNonNegativeInt(buffer, someInt);
56
- * encodeId(buffer, someId);
57
- * const result = buffer.unwrap(); // Final serialized data
69
+ * const id = createIdFromString("buffer-example");
70
+ * encodeNonNegativeInt(buffer, NonNegativeInt.orThrow(300));
71
+ * buffer.extend(idToIdBytes(id));
58
72
  *
59
- * // Decoding example (throws on error)
60
- * try {
61
- * const num = decodeNonNegativeInt(buffer);
62
- * const id = decodeId(buffer);
63
- * } catch (e) {
64
- * console.error(e.stack); // Stack trace for debugging
65
- * }
73
+ * const decoder = createBuffer(buffer.unwrap());
74
+ * expect(decodeNonNegativeInt(decoder)).toBe(300);
75
+ * const decodedId = idBytesToId(
76
+ * IdBytes.orThrow(decoder.shiftN(idBytesTypeValueLength)),
77
+ * );
78
+ * expect(decodedId).toBe(id);
79
+ * expect(() => decodeNonNegativeInt(decoder)).toThrow(
80
+ * "Buffer parse ended prematurely",
81
+ * );
66
82
  * ```
67
83
  *
68
84
  * For more on exponential growth, see:
package/src/Cache.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * @module
5
5
  */
6
6
 
7
- import { PositiveInt } from "./Type.js";
7
+ import { PositiveInt } from "./Type.ts";
8
8
 
9
9
  /**
10
10
  * Generic cache interface providing basic key-value storage operations.
@@ -43,11 +43,16 @@ export interface Cache<K, V> {
43
43
  * ### Example
44
44
  *
45
45
  * ```ts
46
- * const cache = createLruCache<string, number>(2);
46
+ * import { createLruCache, PositiveInt } from "@evolu/common";
47
+ *
48
+ * const cache = createLruCache<string, number>(PositiveInt.orThrow(2));
47
49
  * cache.set("a", 1);
48
50
  * cache.set("b", 2);
49
- * cache.set("c", 3); // Evicts "a"
50
- * cache.has("a"); // false
51
+ * // Reading "a" makes "b" the least recently used entry.
52
+ * expect(cache.get("a")).toBe(1);
53
+ * cache.set("c", 3);
54
+ *
55
+ * expect(cache.has("b")).toBe(false);
51
56
  * ```
52
57
  */
53
58
  export const createLruCache = <K, V>(capacity: PositiveInt): Cache<K, V> => {
package/src/Callbacks.ts CHANGED
@@ -4,10 +4,10 @@
4
4
  * @module
5
5
  */
6
6
 
7
- import type { RandomBytesDep } from "./Crypto.js";
8
- import type { Result } from "./Result.js";
9
- import { createId, Id } from "./Type.js";
10
- import type { Callback } from "./Types.js";
7
+ import type { RandomBytesDep } from "./Crypto.ts";
8
+ import type { Result } from "./Result.ts";
9
+ import { createId, Id } from "./Type.ts";
10
+ import type { Callback } from "./Types.ts";
11
11
 
12
12
  /**
13
13
  * Request-response correlation for callbacks across boundaries.
@@ -22,27 +22,38 @@ import type { Callback } from "./Types.js";
22
22
  * The `execute` method intentionally does not use try-catch or {@link Result}
23
23
  * because it's the callback's responsibility to handle its own errors.
24
24
  *
25
- * ### Example
25
+ * ### Correlating callback responses
26
26
  *
27
27
  * ```ts
28
- * // No-argument callbacks
29
- * const callbacks = createCallbacks(deps);
30
- * const id = callbacks.register(() => console.log("called"));
31
- * callbacks.execute(id);
28
+ * import { createCallbacks, testCreateDeps } from "@evolu/common";
32
29
  *
33
- * // With argument callbacks
34
- * const stringCallbacks = createCallbacks<string>(deps);
35
- * const id = stringCallbacks.register((value) => {
36
- * console.log(value);
30
+ * const deps = testCreateDeps();
31
+ *
32
+ * // No-argument callback
33
+ * using callbacks = createCallbacks(deps);
34
+ * let noArgumentCalls = 0;
35
+ * const noArgumentId = callbacks.register(() => {
36
+ * noArgumentCalls++;
37
+ * });
38
+ * callbacks.execute(noArgumentId);
39
+ * callbacks.execute(noArgumentId);
40
+ * expect(noArgumentCalls).toBe(1);
41
+ *
42
+ * // Typed callback
43
+ * using stringCallbacks = createCallbacks<string>(deps);
44
+ * let received = "";
45
+ * const stringCallbackId = stringCallbacks.register((value) => {
46
+ * received = value;
37
47
  * });
38
- * stringCallbacks.execute(id, "hello");
48
+ * stringCallbacks.execute(stringCallbackId, "hello");
49
+ * expect(received).toBe("hello");
39
50
  *
40
- * // Promise.withResolvers pattern
41
- * const promiseCallbacks = createCallbacks<string>(deps);
51
+ * // Promise.withResolvers
52
+ * using promiseCallbacks = createCallbacks<string>(deps);
42
53
  * const { promise, resolve } = Promise.withResolvers<string>();
43
- * const id = promiseCallbacks.register(resolve);
44
- * promiseCallbacks.execute(id, "resolved value");
45
- * await promise; // "resolved value"
54
+ * const promiseCallbackId = promiseCallbacks.register(resolve);
55
+ * promiseCallbacks.execute(promiseCallbackId, "resolved value");
56
+ * expect(await promise).toBe("resolved value");
46
57
  * ```
47
58
  *
48
59
  * @template T - The type of argument passed to callbacks (defaults to undefined