@evolu/common 7.0.0 → 7.2.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 (70) hide show
  1. package/README.md +26 -28
  2. package/dist/src/Array.d.ts +120 -43
  3. package/dist/src/Array.d.ts.map +1 -1
  4. package/dist/src/Array.js +71 -51
  5. package/dist/src/Assert.d.ts.map +1 -1
  6. package/dist/src/Brand.d.ts +1 -1
  7. package/dist/src/Cache.d.ts +1 -6
  8. package/dist/src/Cache.d.ts.map +1 -1
  9. package/dist/src/Cache.js +1 -6
  10. package/dist/src/Console.d.ts +1 -1
  11. package/dist/src/Console.js +1 -1
  12. package/dist/src/Crypto.d.ts.map +1 -1
  13. package/dist/src/Crypto.js +5 -1
  14. package/dist/src/Evolu/Internal.d.ts +2 -2
  15. package/dist/src/Evolu/Internal.js +2 -2
  16. package/dist/src/Evolu/Public.d.ts +1 -1
  17. package/dist/src/Evolu/Public.js +1 -1
  18. package/dist/src/Order.d.ts +0 -5
  19. package/dist/src/Order.d.ts.map +1 -1
  20. package/dist/src/Order.js +0 -5
  21. package/dist/src/Platform.d.ts +0 -5
  22. package/dist/src/Platform.d.ts.map +1 -1
  23. package/dist/src/Platform.js +0 -5
  24. package/dist/src/Random.d.ts +0 -5
  25. package/dist/src/Random.d.ts.map +1 -1
  26. package/dist/src/Random.js +0 -5
  27. package/dist/src/Ref.d.ts.map +1 -1
  28. package/dist/src/Result.d.ts +15 -17
  29. package/dist/src/Result.d.ts.map +1 -1
  30. package/dist/src/Store.d.ts +0 -5
  31. package/dist/src/Store.d.ts.map +1 -1
  32. package/dist/src/Store.js +0 -5
  33. package/dist/src/Task.d.ts +4 -10
  34. package/dist/src/Task.d.ts.map +1 -1
  35. package/dist/src/Task.js +0 -5
  36. package/dist/src/Time.d.ts +0 -5
  37. package/dist/src/Time.d.ts.map +1 -1
  38. package/dist/src/Time.js +0 -5
  39. package/dist/src/Type.d.ts +3 -3
  40. package/dist/src/Type.d.ts.map +1 -1
  41. package/dist/src/Type.js +1 -1
  42. package/dist/src/Types.d.ts +37 -0
  43. package/dist/src/Types.d.ts.map +1 -1
  44. package/dist/src/WebSocket.d.ts +0 -5
  45. package/dist/src/WebSocket.d.ts.map +1 -1
  46. package/dist/src/WebSocket.js +0 -5
  47. package/dist/src/Worker.d.ts +0 -5
  48. package/dist/src/Worker.d.ts.map +1 -1
  49. package/dist/src/Worker.js +0 -5
  50. package/package.json +1 -1
  51. package/src/Array.ts +157 -45
  52. package/src/Assert.ts +0 -14
  53. package/src/Brand.ts +1 -1
  54. package/src/Cache.ts +1 -7
  55. package/src/Console.ts +1 -1
  56. package/src/Crypto.ts +5 -1
  57. package/src/Evolu/Internal.ts +2 -2
  58. package/src/Evolu/Public.ts +1 -1
  59. package/src/Order.ts +0 -6
  60. package/src/Platform.ts +0 -6
  61. package/src/Random.ts +0 -6
  62. package/src/Ref.ts +0 -5
  63. package/src/Result.ts +15 -17
  64. package/src/Store.ts +0 -5
  65. package/src/Task.ts +4 -11
  66. package/src/Time.ts +0 -6
  67. package/src/Type.ts +3 -3
  68. package/src/Types.ts +42 -0
  69. package/src/WebSocket.ts +0 -6
  70. package/src/Worker.ts +0 -6
package/src/Array.ts CHANGED
@@ -1,8 +1,44 @@
1
1
  /**
2
- * 🔒 Type-safe array helpers that do not mutate
2
+ * Array types, type guards, operations, transformations, accessors, and (rare)
3
+ * mutations
3
4
  *
4
- * Array types, guards, operations, transformations, accessors, and (rare)
5
- * mutations.
5
+ * ### Example
6
+ *
7
+ * ```ts
8
+ * // Types - compile-time guarantee of at least one element
9
+ * const _valid: NonEmptyReadonlyArray<number> = [1, 2, 3];
10
+ * // ts-expect-error - empty array is not a valid NonEmptyReadonlyArray
11
+ * const _invalid: NonEmptyReadonlyArray<number> = [];
12
+ *
13
+ * // Type guards
14
+ * const arr: ReadonlyArray<number> = [1, 2, 3];
15
+ * if (isNonEmptyReadonlyArray(arr)) {
16
+ * firstInArray(arr);
17
+ * }
18
+ *
19
+ * // Operations
20
+ * const appended = appendToArray([1, 2, 3], 4); // [1, 2, 3, 4]
21
+ * const prepended = prependToArray([2, 3], 1); // [1, 2, 3]
22
+ *
23
+ * // Transformations
24
+ * const readonly: ReadonlyArray<number> = [1, 2, 3];
25
+ * const mapped = mapArray(readonly, (x) => x * 2); // [2, 4, 6]
26
+ * const filtered = filterArray(readonly, (x) => x > 1); // [2, 3]
27
+ * const deduped = dedupeArray([1, 2, 1, 3, 2]); // [1, 2, 3]
28
+ * const [evens, odds] = partitionArray(
29
+ * [1, 2, 3, 4, 5],
30
+ * (x) => x % 2 === 0,
31
+ * ); // [[2, 4], [1, 3, 5]]
32
+ *
33
+ * // Accessors
34
+ * const first = firstInArray(["a", "b", "c"]); // "a"
35
+ * const last = lastInArray(["a", "b", "c"]); // "c"
36
+ *
37
+ * // Mutations
38
+ * const mutable: NonEmptyArray<number> = [1, 2, 3];
39
+ * shiftArray(mutable); // 1 (guaranteed to exist)
40
+ * mutable; // [2, 3]
41
+ * ```
6
42
  *
7
43
  * Functions are intentionally data-first to be prepared for the upcoming
8
44
  * JavaScript pipe operator.
@@ -43,43 +79,11 @@
43
79
  * **Note**: Feel free to use Array instance methods (mutation) if you think
44
80
  * it's better (performance, local scope, etc.).
45
81
  *
46
- * ### Example
47
- *
48
- * ```ts
49
- * // Types - compile-time guarantee of at least one element
50
- * const _valid: NonEmptyReadonlyArray<number> = [1, 2, 3];
51
- * // ts-expect-error - empty array is not a valid NonEmptyReadonlyArray
52
- * const _invalid: NonEmptyReadonlyArray<number> = [];
53
- *
54
- * // Guards
55
- * const arr: ReadonlyArray<number> = [1, 2, 3];
56
- * if (isNonEmptyReadonlyArray(arr)) {
57
- * firstInArray(arr);
58
- * }
59
- *
60
- * // Operations
61
- * const appended = appendToArray([1, 2, 3], 4); // [1, 2, 3, 4]
62
- * const prepended = prependToArray([2, 3], 1); // [1, 2, 3]
63
- *
64
- * // Transformations
65
- * const readonly: ReadonlyArray<number> = [1, 2, 3];
66
- * const mapped = mapArray(readonly, (x) => x * 2); // [2, 4, 6]
67
- * const filtered = filterArray(readonly, (x) => x > 1); // [2, 3]
68
- * const deduped = dedupeArray([1, 2, 1, 3, 2]); // [1, 2, 3]
69
- *
70
- * // Accessors
71
- * const first = firstInArray(["a", "b", "c"]); // "a"
72
- * const last = lastInArray(["a", "b", "c"]); // "c"
73
- *
74
- * // Mutations
75
- * const mutable: NonEmptyArray<number> = [1, 2, 3];
76
- * shiftArray(mutable); // 1 (guaranteed to exist)
77
- * mutable; // [2, 3]
78
- * ```
79
- *
80
82
  * @module
81
83
  */
82
84
 
85
+ import { PredicateWithIndex, RefinementWithIndex } from "./Types.js";
86
+
83
87
  /**
84
88
  * An array with at least one element.
85
89
  *
@@ -175,8 +179,7 @@ export const prependToArray = <T>(
175
179
  /**
176
180
  * Maps an array using a mapper function.
177
181
  *
178
- * Accepts both mutable and readonly arrays. Does not mutate the original array.
179
- * Preserves non-empty type.
182
+ * Accepts both mutable and readonly arrays. Preserves non-empty type.
180
183
  *
181
184
  * ### Example
182
185
  *
@@ -202,22 +205,49 @@ export function mapArray<T, U>(
202
205
  }
203
206
 
204
207
  /**
205
- * Filters an array using a predicate function, returning a new readonly array.
208
+ * Filters an array using a predicate or refinement function, returning a new
209
+ * readonly array.
206
210
  *
207
- * Accepts both mutable and readonly arrays. Does not mutate the original array.
211
+ * Accepts both mutable and readonly arrays. When used with a refinement
212
+ * function (with `value is Type` syntax), TypeScript will narrow the result
213
+ * type to the narrowed type, making it useful for filtering with Evolu Types
214
+ * like `PositiveInt.is`.
208
215
  *
209
- * ### Example
216
+ * ### Examples
217
+ *
218
+ * #### With predicate
210
219
  *
211
220
  * ```ts
212
221
  * filterArray([1, 2, 3, 4, 5], (x) => x % 2 === 0); // [2, 4]
213
222
  * ```
214
223
  *
224
+ * #### With refinement
225
+ *
226
+ * ```ts
227
+ * const mixed: ReadonlyArray<NonEmptyString | PositiveInt> = [
228
+ * NonEmptyString.orThrow("hello"),
229
+ * PositiveInt.orThrow(42),
230
+ * ];
231
+ * const positiveInts = filterArray(mixed, PositiveInt.is);
232
+ * // positiveInts: ReadonlyArray<PositiveInt> (narrowed type)
233
+ * ```
234
+ *
215
235
  * @category Transformations
216
236
  */
217
- export const filterArray = <T>(
237
+ export function filterArray<T, S extends T>(
238
+ array: ReadonlyArray<T>,
239
+ refinement: RefinementWithIndex<T, S>,
240
+ ): ReadonlyArray<S>;
241
+ export function filterArray<T>(
242
+ array: ReadonlyArray<T>,
243
+ predicate: PredicateWithIndex<T>,
244
+ ): ReadonlyArray<T>;
245
+ export function filterArray<T>(
218
246
  array: ReadonlyArray<T>,
219
- predicate: (item: T, index: number) => boolean,
220
- ): ReadonlyArray<T> => array.filter(predicate) as ReadonlyArray<T>;
247
+ predicate: PredicateWithIndex<T>,
248
+ ): ReadonlyArray<T> {
249
+ return array.filter(predicate) as ReadonlyArray<T>;
250
+ }
221
251
 
222
252
  /**
223
253
  * Returns a new readonly array with duplicate items removed. If `by` is
@@ -272,6 +302,71 @@ export function dedupeArray<T>(
272
302
  }) as ReadonlyArray<T>;
273
303
  }
274
304
 
305
+ /**
306
+ * Partitions an array into two arrays based on a predicate or refinement
307
+ * function.
308
+ *
309
+ * Returns a tuple where the first array contains elements that satisfy the
310
+ * predicate, and the second array contains elements that do not. Accepts both
311
+ * mutable and readonly arrays.
312
+ *
313
+ * When used with a refinement function (with `value is Type` syntax),
314
+ * TypeScript will narrow the first array to the narrowed type, making it useful
315
+ * for filtering with Evolu Types like `PositiveInt.is`.
316
+ *
317
+ * ### Examples
318
+ *
319
+ * #### With predicate
320
+ *
321
+ * ```ts
322
+ * const [evens, odds] = partitionArray(
323
+ * [1, 2, 3, 4, 5],
324
+ * (x) => x % 2 === 0,
325
+ * );
326
+ * evens; // [2, 4]
327
+ * odds; // [1, 3, 5]
328
+ * ```
329
+ *
330
+ * #### With refinement
331
+ *
332
+ * ```ts
333
+ * const mixed: ReadonlyArray<NonEmptyString | PositiveInt> = [
334
+ * NonEmptyString.orThrow("hello"),
335
+ * PositiveInt.orThrow(42),
336
+ * ];
337
+ * const [positiveInts, strings] = partitionArray(mixed, PositiveInt.is);
338
+ * // positiveInts: ReadonlyArray<PositiveInt> (narrowed type)
339
+ * // strings: ReadonlyArray<NonEmptyString> (Exclude<T, PositiveInt>)
340
+ * ```
341
+ *
342
+ * @category Transformations
343
+ */
344
+ export function partitionArray<T, S extends T>(
345
+ array: ReadonlyArray<T>,
346
+ refinement: RefinementWithIndex<T, S>,
347
+ ): readonly [ReadonlyArray<S>, ReadonlyArray<Exclude<T, S>>];
348
+ export function partitionArray<T>(
349
+ array: ReadonlyArray<T>,
350
+ predicate: PredicateWithIndex<T>,
351
+ ): readonly [ReadonlyArray<T>, ReadonlyArray<T>];
352
+ export function partitionArray<T>(
353
+ array: ReadonlyArray<T>,
354
+ predicate: PredicateWithIndex<T>,
355
+ ): readonly [ReadonlyArray<T>, ReadonlyArray<T>] {
356
+ const trueArray: Array<T> = [];
357
+ const falseArray: Array<T> = [];
358
+
359
+ for (let i = 0; i < array.length; i++) {
360
+ if (predicate(array[i], i)) {
361
+ trueArray.push(array[i]);
362
+ } else {
363
+ falseArray.push(array[i]);
364
+ }
365
+ }
366
+
367
+ return [trueArray as ReadonlyArray<T>, falseArray as ReadonlyArray<T>];
368
+ }
369
+
275
370
  /**
276
371
  * Returns the first element of a non-empty array.
277
372
  *
@@ -319,3 +414,20 @@ export const lastInArray = <T>(array: NonEmptyReadonlyArray<T>): T =>
319
414
  * @category Mutations
320
415
  */
321
416
  export const shiftArray = <T>(array: NonEmptyArray<T>): T => array.shift() as T;
417
+
418
+ /**
419
+ * Pops an item from a non-empty mutable array, guaranteed to return T.
420
+ *
421
+ * **Mutates** the original array.
422
+ *
423
+ * ### Example
424
+ *
425
+ * ```ts
426
+ * const arr: NonEmptyArray<number> = [1, 2, 3];
427
+ * popArray(arr); // 3
428
+ * arr; // [1, 2]
429
+ * ```
430
+ *
431
+ * @category Mutations
432
+ */
433
+ export const popArray = <T>(array: NonEmptyArray<T>): T => array.pop() as T;
package/src/Assert.ts CHANGED
@@ -1,17 +1,3 @@
1
- /**
2
- * 🚨
3
- *
4
- * This module provides assertion utilities to prevent invalid states from
5
- * propagating through the system by halting execution when a condition fails,
6
- * improving reliability and debuggability.
7
- *
8
- * **Warning**: Do not use this instead of {@link Type}. Assertions are intended
9
- * for conditions that are logically guaranteed but not statically known by
10
- * TypeScript, or for catching and signaling developer mistakes eagerly (e.g.,
11
- * invalid configuration).
12
- *
13
- * @module
14
- */
15
1
  import type { Type } from "./Type.js";
16
2
 
17
3
  /**
package/src/Brand.ts CHANGED
@@ -67,7 +67,7 @@ declare const __brand: unique symbol;
67
67
  *
68
68
  * Works with any base type intersected with a `Brand`.
69
69
  *
70
- * ### Examples
70
+ * ### Example
71
71
  *
72
72
  * - `IsBranded<string>` -> false
73
73
  * - `IsBranded<string & Brand<"X">>` -> true
package/src/Cache.ts CHANGED
@@ -1,9 +1,3 @@
1
- /**
2
- * 🗄️ Generic cache interface and LRU cache implementation.
3
- *
4
- * @module
5
- */
6
-
7
1
  import { PositiveInt } from "./Type.js";
8
2
 
9
3
  /**
@@ -32,7 +26,7 @@ export interface Cache<K, V> {
32
26
  }
33
27
 
34
28
  /**
35
- * Creates a Least Recently Used (LRU) cache with a maximum capacity.
29
+ * Creates an LRU (least recently used) cache with a maximum capacity.
36
30
  *
37
31
  * When the cache reaches capacity, the least recently used entry is evicted.
38
32
  * Both `get` and `set` operations update the access order.
package/src/Console.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * 📝 Cross-platform console
2
+ * Cross-platform console
3
3
  *
4
4
  * Console abstraction for Chrome 123+, Firefox 125+, Safari 18.1+, Node.js
5
5
  * 22.x+, and React Native 0.75+. Includes methods guaranteed to be available in
package/src/Crypto.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  /**
2
- * 🔒
2
+ * Cryptographic utilities
3
+ *
4
+ * Type-safe cryptographic operations including random number generation, SLIP21
5
+ * key derivation, XChaCha20-Poly1305 symmetric encryption, PADMÉ padding, and
6
+ * timing-safe comparisons.
3
7
  *
4
8
  * @module
5
9
  */
@@ -1,10 +1,10 @@
1
1
  /**
2
- * 🛠️
2
+ * Internal Evolu
3
3
  *
4
4
  * ### Example
5
5
  *
6
6
  * ```ts
7
- * import { Evolu } from "@evolu/common/evolu";
7
+ * import { createTimestamp } from "@evolu/common/evolu";
8
8
  * ```
9
9
  *
10
10
  * @module
@@ -1,5 +1,5 @@
1
1
  /**
2
- * 💾
2
+ * Public Evolu
3
3
  *
4
4
  * @module
5
5
  */
package/src/Order.ts CHANGED
@@ -1,9 +1,3 @@
1
- /**
2
- * 🔢
3
- *
4
- * @module
5
- */
6
-
7
1
  /**
8
2
  * Compares two values of type `A` and returns their ordering.
9
3
  *
package/src/Platform.ts CHANGED
@@ -1,9 +1,3 @@
1
- /**
2
- * Platform detection utilities for Evolu.
3
- *
4
- * @module
5
- */
6
-
7
1
  /** Detects if the code is running in React Native environment. */
8
2
  export const isReactNative =
9
3
  typeof navigator !== "undefined" &&
package/src/Random.ts CHANGED
@@ -1,9 +1,3 @@
1
- /**
2
- * 🎲
3
- *
4
- * @module
5
- */
6
-
7
1
  import { Random as RandomLib } from "random";
8
2
 
9
3
  /**
package/src/Ref.ts CHANGED
@@ -1,8 +1,3 @@
1
- /**
2
- * A mutable reference for managing state
3
- *
4
- * @module
5
- */
6
1
  import type { Store } from "./Store.js";
7
2
 
8
3
  /**
package/src/Result.ts CHANGED
@@ -1,15 +1,13 @@
1
1
  /**
2
- * 🛡️ Type-safe errors
3
- *
4
2
  * The problem with throwing an exception in JavaScript is that the caught error
5
3
  * is always of an unknown type. The unknown type is a problem because we can't
6
4
  * be sure all errors have been handled because the TypeScript compiler can't
7
5
  * tell us.
8
6
  *
9
- * Languages like Rust 🦀 or Haskell 📚 use a type-safe approach to error
10
- * handling, where errors are explicitly represented as part of the return type,
11
- * such as Result or Either, allowing the developer to handle errors safely.
12
- * TypeScript can have this too via the `Result` type.
7
+ * Languages like Rust or Haskell use a type-safe approach to error handling,
8
+ * where errors are explicitly represented as part of the return type, such as
9
+ * Result or Either, allowing the developer to handle errors safely. TypeScript
10
+ * can have this too via the `Result` type.
13
11
  *
14
12
  * The `Result` type can be either {@link Ok} (success) or {@link Err} (error).
15
13
  * Use {@link ok} to create a successful result and {@link err} to create an error
@@ -63,7 +61,7 @@
63
61
  * - For safe code, use `ok` and `err`.
64
62
  * - For unsafe code, use `trySync` or `tryAsync`.
65
63
  *
66
- * Asynchronous safe (because of a Promise using Result) code:
64
+ * Safe asynchronous code (using Result with a Promise):
67
65
  *
68
66
  * ```ts
69
67
  * const fetchUser = async (
@@ -84,7 +82,7 @@
84
82
  * };
85
83
  * ```
86
84
  *
87
- * ### Naming Convention
85
+ * ### Naming convention
88
86
  *
89
87
  * - For values: `const user = getUser()`
90
88
  * - For a single void operation: `const result = foo()`
@@ -117,7 +115,7 @@
117
115
  *
118
116
  * ### Examples
119
117
  *
120
- * #### Sequential Operations with Short-Circuiting
118
+ * #### Sequential operations with short-circuiting
121
119
  *
122
120
  * When performing a sequence of operations where any failure should stop
123
121
  * further processing, use the `Result` type with early returns.
@@ -181,7 +179,7 @@
181
179
  * };
182
180
  * ```
183
181
  *
184
- * ### Handling Unexpected Errors
182
+ * ### Handling unexpected errors
185
183
  *
186
184
  * Even with disciplined use of `trySync` and `tryAsync`, unexpected errors can
187
185
  * still occur due to programming mistakes, third-party library bugs, or edge
@@ -192,7 +190,7 @@
192
190
  * expected errors handled via the `Result` type. Unexpected errors should fail
193
191
  * fast - the operation fails immediately and the error bubbles up.
194
192
  *
195
- * #### In Browser Environments
193
+ * #### In browser environments
196
194
  *
197
195
  * ```ts
198
196
  * // Global error handler for unexpected errors
@@ -209,7 +207,7 @@
209
207
  * });
210
208
  * ```
211
209
  *
212
- * #### In Node.js Environments
210
+ * #### In Node.js environments
213
211
  *
214
212
  * ```ts
215
213
  * // Handle uncaught exceptions - log and fail fast
@@ -347,16 +345,16 @@ export interface Ok<T> {
347
345
  * An error {@link Result}.
348
346
  *
349
347
  * The `error` property can be any type that describes the error. For normal
350
- * business logic, use a plain object. This allows us to structure errors with
348
+ * domain logic, use a plain object. This allows us to structure errors with
351
349
  * custom fields (e.g., `{ type: "MyError", code: 123 }`). Messages for users
352
350
  * belong to translations, not to error objects.
353
351
  *
354
- * If you need a stacktrace for debugging, use an `Error` instance or a custom
352
+ * If you need a stack trace for debugging, use an `Error` instance or a custom
355
353
  * error class to include additional metadata.
356
354
  *
357
355
  * ### Examples
358
356
  *
359
- * #### Business Logic Error (Plain Object, Recommended)
357
+ * #### Domain logic error (plain object, recommended)
360
358
  *
361
359
  * ```ts
362
360
  * const failure = err({
@@ -366,13 +364,13 @@ export interface Ok<T> {
366
364
  * });
367
365
  * ```
368
366
  *
369
- * #### Debugging with Stack Trace (Error Instance)
367
+ * #### Debugging with stack trace (error instance)
370
368
  *
371
369
  * ```ts
372
370
  * const failure = err(new Error("Something went wrong"));
373
371
  * ```
374
372
  *
375
- * #### Custom Error Class
373
+ * #### Custom error class
376
374
  *
377
375
  * ```ts
378
376
  * class MyCustomError extends Error {
package/src/Store.ts CHANGED
@@ -1,8 +1,3 @@
1
- /**
2
- * A mutable reference for managing state with change notifications
3
- *
4
- * @module
5
- */
6
1
  import { Eq, eqStrict } from "./Eq.js";
7
2
  import { Ref } from "./Ref.js";
8
3
 
package/src/Task.ts CHANGED
@@ -1,21 +1,14 @@
1
- /**
2
- * ⚡ Lazy, cancellable Promise that returns Result instead of throwing
3
- *
4
- * @module
5
- */
6
-
7
1
  import { isNonEmptyArray, shiftArray } from "./Array.js";
8
2
  import { Result, err, ok } from "./Result.js";
9
3
  import { Duration, durationToNonNegativeInt } from "./Time.js";
10
4
  import { NonNegativeInt, PositiveInt } from "./Type.js";
11
5
 
12
6
  /**
13
- * `Task` is a lazy, cancellable Promise that returns {@link Result} instead of
14
- * throwing.
7
+ * `Task` is a function that creates and returns an optionally cancellable
8
+ * Promise using {@link Result}.
15
9
  *
16
- * In other words, Task is a function that creates a Promise when it's called.
17
- * This laziness allows safe composition, e.g. retry logic because it prevents
18
- * eager execution.
10
+ * The laziness allows safe composition, e.g. retry logic, because it prevents
11
+ * eager execution until the Task is actually invoked.
19
12
  *
20
13
  * ### Cancellation
21
14
  *
package/src/Time.ts CHANGED
@@ -1,9 +1,3 @@
1
- /**
2
- * ⏳
3
- *
4
- * @module
5
- */
6
-
7
1
  import { assert } from "./Assert.js";
8
2
  import { DateIso, NonNegativeInt } from "./Type.js";
9
3
 
package/src/Type.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * 🧩 Type-safe runtime types
2
+ * Runtime types
3
3
  *
4
4
  * Evolu {@link Type} is like a type guard that returns typed errors (via
5
5
  * {@link Result}) instead of throwing. We either get a safely typed value or a
@@ -213,7 +213,7 @@ import { hasNodeBuffer } from "./Platform.js";
213
213
  import { err, getOrNull, getOrThrow, ok, Result, trySync } from "./Result.js";
214
214
  import { safelyStringifyUnknownValue } from "./String.js";
215
215
  import type { TimeDep } from "./Time.js";
216
- import type { Literal, Simplify, WidenLiteral } from "./Types.js";
216
+ import type { Literal, Refinement, Simplify, WidenLiteral } from "./Types.js";
217
217
  import { IntentionalNever } from "./Types.js";
218
218
 
219
219
  export interface Type<
@@ -353,7 +353,7 @@ export interface Type<
353
353
  * console.log(filteredStrings); // ["hello", "world"]
354
354
  * ```
355
355
  */
356
- readonly is: (value: unknown) => value is T;
356
+ readonly is: Refinement<unknown, T>;
357
357
 
358
358
  readonly [EvoluTypeSymbol]: true;
359
359
 
package/src/Types.ts CHANGED
@@ -22,6 +22,23 @@ import * as Kysely from "kysely";
22
22
  */
23
23
  export type Predicate<T> = (value: T) => boolean;
24
24
 
25
+ /**
26
+ * Checks a condition on a value at a given index and returns a boolean.
27
+ *
28
+ * Useful for callbacks that need both the element and its position.
29
+ *
30
+ * ### Example
31
+ *
32
+ * ```ts
33
+ * const isEvenIndex: PredicateWithIndex<string> = (value, index) =>
34
+ * index % 2 === 0;
35
+ *
36
+ * const items = ["a", "b", "c", "d"];
37
+ * const evenIndexItems = items.filter(isEvenIndex); // ["a", "c"]
38
+ * ```
39
+ */
40
+ export type PredicateWithIndex<T> = (value: T, index: number) => boolean;
41
+
25
42
  /**
26
43
  * A type guard function that refines type `A` to a narrower type `B`.
27
44
  *
@@ -42,6 +59,31 @@ export type Predicate<T> = (value: T) => boolean;
42
59
  */
43
60
  export type Refinement<in A, out B extends A> = (a: A) => a is B;
44
61
 
62
+ /**
63
+ * A type guard function that refines type `A` to a narrower type `B` at a given
64
+ * index.
65
+ *
66
+ * Useful for callbacks that need both the element and its position while
67
+ * maintaining type narrowing.
68
+ *
69
+ * ### Example
70
+ *
71
+ * ```ts
72
+ * type Item = { type: "number" | "string"; value: unknown };
73
+ *
74
+ * const isNumberItem: RefinementWithIndex<Item, Item & { type: "number" }> =
75
+ * (item, index): item is Item & { type: "number" } =>
76
+ * index > 0 && item.type === "number";
77
+ *
78
+ * const items: ReadonlyArray<Item> = [...];
79
+ * const [numbers, others] = partitionArray(items, isNumberItem);
80
+ * ```
81
+ */
82
+ export type RefinementWithIndex<in A, out B extends A> = (
83
+ a: A,
84
+ index: number,
85
+ ) => a is B;
86
+
45
87
  /**
46
88
  * Makes properties optional if they accept `null` as a value.
47
89
  *
package/src/WebSocket.ts CHANGED
@@ -1,9 +1,3 @@
1
- /**
2
- * Websocket with auto-reconnect and offline support
3
- *
4
- * @module
5
- */
6
-
7
1
  import { constVoid } from "./Function.js";
8
2
  import { err, ok, Result } from "./Result.js";
9
3
  import { retry, RetryError, RetryOptions } from "./Task.js";
package/src/Worker.ts CHANGED
@@ -1,9 +1,3 @@
1
- /**
2
- * Cross-platform worker abstraction
3
- *
4
- * @module
5
- */
6
-
7
1
  import { assert } from "./Assert.js";
8
2
  import { createTransferableError, TransferableError } from "./Error.js";
9
3