@evolu/common 8.6.2 → 8.8.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.
- package/dist/src/Array.d.ts +21 -21
- package/dist/src/Array.js +5 -5
- package/dist/src/Assert.d.ts +478 -141
- package/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Assert.js +644 -99
- package/dist/src/Binary.d.ts +254 -0
- package/dist/src/Binary.d.ts.map +1 -0
- package/dist/src/Binary.js +958 -0
- package/dist/src/Console.d.ts +2 -10
- package/dist/src/Console.d.ts.map +1 -1
- package/dist/src/Console.js +6 -12
- package/dist/src/Crypto.d.ts +5 -5
- package/dist/src/Crypto.js +1 -1
- package/dist/src/Eq.d.ts +35 -40
- package/dist/src/Eq.d.ts.map +1 -1
- package/dist/src/Eq.js +51 -87
- package/dist/src/Function.d.ts +9 -14
- package/dist/src/Function.d.ts.map +1 -1
- package/dist/src/Function.js +7 -9
- package/dist/src/Http.d.ts +6 -7
- package/dist/src/Http.d.ts.map +1 -1
- package/dist/src/LeakDetector.d.ts.map +1 -1
- package/dist/src/LeakDetector.js +1 -0
- package/dist/src/LockManager.d.ts +1 -1
- package/dist/src/LockManager.js +1 -1
- package/dist/src/Lookup.d.ts +3 -2
- package/dist/src/Lookup.d.ts.map +1 -1
- package/dist/src/Lookup.js +4 -3
- package/dist/src/Number.d.ts +1 -1
- package/dist/src/Number.d.ts.map +1 -1
- package/dist/src/Number.js +1 -1
- package/dist/src/Object.d.ts +4 -4
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/Object.js +5 -4
- package/dist/src/Option.d.ts +1 -2
- package/dist/src/Option.d.ts.map +1 -1
- package/dist/src/Option.js +1 -2
- package/dist/src/Platform.js +2 -0
- package/dist/src/Polyfills.js +4 -1
- package/dist/src/Random.d.ts +1 -1
- package/dist/src/Result.d.ts +49 -54
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +17 -22
- package/dist/src/Set.d.ts +6 -6
- package/dist/src/Set.js +2 -2
- package/dist/src/Sqlite.js +1 -1
- package/dist/src/String.js +3 -2
- package/dist/src/Task.d.ts +32 -32
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +20 -22
- package/dist/src/Test.d.ts +31 -3
- package/dist/src/Test.d.ts.map +1 -1
- package/dist/src/Test.js +46 -3
- package/dist/src/Time.d.ts +3 -11
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +10 -18
- package/dist/src/Type.d.ts +87 -85
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +70 -63
- package/dist/src/Types.d.ts +12 -12
- package/dist/src/Types.js +1 -1
- package/dist/src/WebSocket.d.ts +4 -7
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/Worker.d.ts +1 -1
- package/dist/src/Worker.js +7 -7
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/intl/_en.d.ts.map +1 -1
- package/dist/src/intl/_en.js +1 -1
- package/dist/src/intl/ar.d.ts.map +1 -1
- package/dist/src/intl/ar.js +1 -1
- package/dist/src/intl/bn.d.ts.map +1 -1
- package/dist/src/intl/bn.js +1 -1
- package/dist/src/intl/ca.d.ts.map +1 -1
- package/dist/src/intl/ca.js +1 -1
- package/dist/src/intl/cs.d.ts.map +1 -1
- package/dist/src/intl/cs.js +1 -1
- package/dist/src/intl/da.d.ts.map +1 -1
- package/dist/src/intl/da.js +1 -1
- package/dist/src/intl/de.d.ts.map +1 -1
- package/dist/src/intl/de.js +1 -1
- package/dist/src/intl/el.d.ts.map +1 -1
- package/dist/src/intl/el.js +1 -1
- package/dist/src/intl/es.d.ts.map +1 -1
- package/dist/src/intl/es.js +1 -1
- package/dist/src/intl/fa.d.ts.map +1 -1
- package/dist/src/intl/fa.js +1 -1
- package/dist/src/intl/fi.d.ts.map +1 -1
- package/dist/src/intl/fi.js +1 -1
- package/dist/src/intl/fil.d.ts.map +1 -1
- package/dist/src/intl/fil.js +1 -1
- package/dist/src/intl/fr.d.ts.map +1 -1
- package/dist/src/intl/fr.js +1 -1
- package/dist/src/intl/he.d.ts.map +1 -1
- package/dist/src/intl/he.js +1 -1
- package/dist/src/intl/hi.d.ts.map +1 -1
- package/dist/src/intl/hi.js +1 -1
- package/dist/src/intl/hr.d.ts.map +1 -1
- package/dist/src/intl/hr.js +1 -1
- package/dist/src/intl/hu.d.ts.map +1 -1
- package/dist/src/intl/hu.js +1 -1
- package/dist/src/intl/id.d.ts.map +1 -1
- package/dist/src/intl/id.js +1 -1
- package/dist/src/intl/it.d.ts.map +1 -1
- package/dist/src/intl/it.js +1 -1
- package/dist/src/intl/ja.d.ts.map +1 -1
- package/dist/src/intl/ja.js +1 -1
- package/dist/src/intl/ko.d.ts.map +1 -1
- package/dist/src/intl/ko.js +1 -1
- package/dist/src/intl/ml.d.ts.map +1 -1
- package/dist/src/intl/ml.js +1 -1
- package/dist/src/intl/mr.d.ts.map +1 -1
- package/dist/src/intl/mr.js +1 -1
- package/dist/src/intl/ms.d.ts.map +1 -1
- package/dist/src/intl/ms.js +1 -1
- package/dist/src/intl/nb.d.ts.map +1 -1
- package/dist/src/intl/nb.js +1 -1
- package/dist/src/intl/nl.d.ts.map +1 -1
- package/dist/src/intl/nl.js +1 -1
- package/dist/src/intl/pa.d.ts.map +1 -1
- package/dist/src/intl/pa.js +1 -1
- package/dist/src/intl/pl.d.ts.map +1 -1
- package/dist/src/intl/pl.js +1 -1
- package/dist/src/intl/pt-BR.d.ts.map +1 -1
- package/dist/src/intl/pt-BR.js +1 -1
- package/dist/src/intl/pt.d.ts.map +1 -1
- package/dist/src/intl/pt.js +1 -1
- package/dist/src/intl/ro.d.ts.map +1 -1
- package/dist/src/intl/ro.js +1 -1
- package/dist/src/intl/sk.d.ts.map +1 -1
- package/dist/src/intl/sk.js +1 -1
- package/dist/src/intl/sl.d.ts.map +1 -1
- package/dist/src/intl/sl.js +1 -1
- package/dist/src/intl/sv.d.ts.map +1 -1
- package/dist/src/intl/sv.js +1 -1
- package/dist/src/intl/sw.d.ts.map +1 -1
- package/dist/src/intl/sw.js +1 -1
- package/dist/src/intl/ta.d.ts.map +1 -1
- package/dist/src/intl/ta.js +1 -1
- package/dist/src/intl/te.d.ts.map +1 -1
- package/dist/src/intl/te.js +1 -1
- package/dist/src/intl/th.d.ts.map +1 -1
- package/dist/src/intl/th.js +1 -1
- package/dist/src/intl/tr.d.ts.map +1 -1
- package/dist/src/intl/tr.js +1 -1
- package/dist/src/intl/uk.d.ts.map +1 -1
- package/dist/src/intl/uk.js +1 -1
- package/dist/src/intl/ur.d.ts.map +1 -1
- package/dist/src/intl/ur.js +1 -1
- package/dist/src/intl/vi.d.ts.map +1 -1
- package/dist/src/intl/vi.js +1 -1
- package/dist/src/intl/zh-CN.d.ts.map +1 -1
- package/dist/src/intl/zh-CN.js +1 -1
- package/dist/src/intl/zh-TW.d.ts.map +1 -1
- package/dist/src/intl/zh-TW.js +1 -1
- package/dist/src/local-first/Evolu.d.ts +12 -12
- package/dist/src/local-first/Evolu.d.ts.map +1 -1
- package/dist/src/local-first/Evolu.js +2 -2
- package/dist/src/local-first/Protocol.d.ts +28 -76
- package/dist/src/local-first/Protocol.d.ts.map +1 -1
- package/dist/src/local-first/Protocol.js +45 -229
- package/dist/src/local-first/Query.d.ts +11 -11
- package/dist/src/local-first/Query.js +6 -6
- package/dist/src/local-first/Relay.d.ts +2 -2
- package/dist/src/local-first/Schema.d.ts +3 -5
- package/dist/src/local-first/Schema.d.ts.map +1 -1
- package/dist/src/local-first/Schema.js +2 -4
- package/dist/src/local-first/Shared.d.ts.map +1 -1
- package/dist/src/local-first/Shared.js +5 -5
- package/dist/src/local-first/Storage.js +4 -4
- package/dist/src/local-first/Timestamp.d.ts +9 -0
- package/dist/src/local-first/Timestamp.d.ts.map +1 -1
- package/dist/src/local-first/Timestamp.js +13 -10
- package/package.json +7 -5
- package/src/Array.test.ts +809 -0
- package/src/Array.ts +21 -21
- package/src/Assert.test.ts +1181 -0
- package/src/Assert.ts +971 -227
- package/src/BigInt.test.ts +28 -0
- package/src/Binary.test.ts +1128 -0
- package/src/Binary.ts +1377 -0
- package/src/Brand.test.ts +90 -0
- package/src/Cache.test.ts +183 -0
- package/src/Callbacks.test.ts +66 -0
- package/src/Console.test.ts +809 -0
- package/src/Console.ts +9 -17
- package/src/Crypto.test.ts +138 -0
- package/src/Crypto.ts +5 -5
- package/src/Eq.test.ts +333 -0
- package/src/Eq.ts +110 -176
- package/src/Error.test.ts +118 -0
- package/src/Function.test.ts +204 -0
- package/src/Function.ts +10 -15
- package/src/Http.test.ts +816 -0
- package/src/Http.ts +6 -7
- package/src/LeakDetector.test.ts +210 -0
- package/src/LeakDetector.ts +1 -0
- package/src/LockManager.ts +2 -2
- package/src/Lookup.test.ts +418 -0
- package/src/Lookup.ts +4 -3
- package/src/Microtask.test.ts +140 -0
- package/src/Number.test.ts +218 -0
- package/src/Number.ts +2 -2
- package/src/Object.test.ts +293 -0
- package/src/Object.ts +5 -4
- package/src/Option.test.ts +104 -0
- package/src/Option.ts +1 -2
- package/src/Order.test.ts +56 -0
- package/src/Platform.ts +2 -0
- package/src/Polyfills.ts +3 -4
- package/src/Random.test.ts +89 -0
- package/src/Random.ts +1 -1
- package/src/Ref.test.ts +139 -0
- package/src/RefCount.test.ts +184 -0
- package/src/Relation.test.ts +505 -0
- package/src/Resource.test.ts +4623 -0
- package/src/Result.test.ts +1829 -0
- package/src/Result.ts +49 -54
- package/src/Schedule.test.ts +1554 -0
- package/src/Set.test.ts +279 -0
- package/src/Set.ts +6 -6
- package/src/Sqlite.ts +1 -1
- package/src/Store.test.ts +288 -0
- package/src/String.test.ts +54 -0
- package/src/String.ts +3 -3
- package/src/Task.test.ts +10820 -0
- package/src/Task.ts +38 -43
- package/src/Test.test.ts +88 -0
- package/src/Test.ts +49 -3
- package/src/Time.test.ts +926 -0
- package/src/Time.ts +13 -21
- package/src/Type.base64.test.ts +88 -0
- package/src/Type.test.ts +20465 -0
- package/src/Type.ts +114 -111
- package/src/Types.test.ts +324 -0
- package/src/Types.ts +13 -13
- package/src/WebSocket.ts +4 -7
- package/src/Worker.test.ts +755 -0
- package/src/Worker.ts +13 -18
- package/src/index.ts +1 -1
- package/src/intl/_en.ts +1 -1
- package/src/intl/ar.ts +1 -1
- package/src/intl/bn.ts +1 -1
- package/src/intl/ca.ts +1 -1
- package/src/intl/cs.ts +1 -1
- package/src/intl/da.ts +1 -1
- package/src/intl/de.ts +1 -1
- package/src/intl/el.ts +1 -1
- package/src/intl/es.ts +1 -1
- package/src/intl/fa.ts +1 -1
- package/src/intl/fi.ts +1 -1
- package/src/intl/fil.ts +1 -1
- package/src/intl/fr.ts +1 -1
- package/src/intl/he.ts +1 -1
- package/src/intl/hi.ts +1 -1
- package/src/intl/hr.ts +1 -1
- package/src/intl/hu.ts +1 -1
- package/src/intl/id.ts +1 -1
- package/src/intl/intl.test.ts +3106 -0
- package/src/intl/it.ts +1 -1
- package/src/intl/ja.ts +1 -1
- package/src/intl/ko.ts +1 -1
- package/src/intl/ml.ts +1 -1
- package/src/intl/mr.ts +1 -1
- package/src/intl/ms.ts +1 -1
- package/src/intl/nb.ts +1 -1
- package/src/intl/nl.ts +1 -1
- package/src/intl/pa.ts +1 -1
- package/src/intl/pl.ts +1 -1
- package/src/intl/pt-BR.ts +1 -1
- package/src/intl/pt.ts +1 -1
- package/src/intl/ro.ts +1 -1
- package/src/intl/sk.ts +1 -1
- package/src/intl/sl.ts +1 -1
- package/src/intl/sv.ts +1 -1
- package/src/intl/sw.ts +1 -1
- package/src/intl/ta.ts +1 -1
- package/src/intl/te.ts +1 -1
- package/src/intl/th.ts +1 -1
- package/src/intl/tr.ts +1 -1
- package/src/intl/uk.ts +1 -1
- package/src/intl/ur.ts +1 -1
- package/src/intl/vi.ts +1 -1
- package/src/intl/zh-CN.ts +1 -1
- package/src/intl/zh-TW.ts +1 -1
- package/src/local-first/Evolu.test.ts +1921 -0
- package/src/local-first/Evolu.ts +18 -14
- package/src/local-first/Owner.test.ts +83 -0
- package/src/local-first/Protocol.test.ts +1037 -0
- package/src/local-first/Protocol.ts +75 -290
- package/src/local-first/Query.test.ts +349 -0
- package/src/local-first/Query.ts +11 -11
- package/src/local-first/Relay.ts +2 -2
- package/src/local-first/Schema.ts +3 -5
- package/src/local-first/Shared.test.ts +1828 -0
- package/src/local-first/Shared.ts +9 -8
- package/src/local-first/Storage.ts +4 -4
- package/src/local-first/Timestamp.test.ts +374 -0
- package/src/local-first/Timestamp.ts +22 -10
- package/dist/src/Buffer.d.ts +0 -122
- package/dist/src/Buffer.d.ts.map +0 -1
- package/dist/src/Buffer.js +0 -69
- package/src/Buffer.ts +0 -206
package/src/Task.ts
CHANGED
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
* });
|
|
77
77
|
*
|
|
78
78
|
* const result = await run(getUser(user.id));
|
|
79
|
-
* assertType<Result<User, UserNotFoundError
|
|
79
|
+
* assertType<typeof result, Result<User, UserNotFoundError>>();
|
|
80
80
|
* assertOk(result, user);
|
|
81
81
|
* ```
|
|
82
82
|
*
|
|
@@ -181,11 +181,11 @@
|
|
|
181
181
|
* await using run = createRun();
|
|
182
182
|
* const result = await run(getUserWithProfile("user-1"));
|
|
183
183
|
* assertType<
|
|
184
|
+
* typeof result,
|
|
184
185
|
* Result<
|
|
185
186
|
* { readonly user: User; readonly profile: Profile },
|
|
186
187
|
* UserNotFoundError | ProfileNotFoundError
|
|
187
|
-
*
|
|
188
|
-
* typeof result
|
|
188
|
+
* >
|
|
189
189
|
* >();
|
|
190
190
|
* assertOk(result, {
|
|
191
191
|
* user: { id: "user-1", profileId: "profile-1" },
|
|
@@ -228,8 +228,8 @@
|
|
|
228
228
|
* );
|
|
229
229
|
*
|
|
230
230
|
* assertType<
|
|
231
|
-
*
|
|
232
|
-
*
|
|
231
|
+
* ReturnType<typeof fetchWithRetry>,
|
|
232
|
+
* Task<string, RetryTaskError<FetchError | TimeoutError>>
|
|
233
233
|
* >();
|
|
234
234
|
* ```
|
|
235
235
|
*
|
|
@@ -685,7 +685,7 @@ import {
|
|
|
685
685
|
type RandomBytes,
|
|
686
686
|
type RandomBytesDep,
|
|
687
687
|
} from "./Crypto.ts";
|
|
688
|
-
import {
|
|
688
|
+
import { eqArraySameValue } from "./Eq.ts";
|
|
689
689
|
import { constTrue, constVoid, identity } from "./Function.ts";
|
|
690
690
|
import type { fetch, NativeFetch, NativeFetchDep } from "./Http.ts";
|
|
691
691
|
import {
|
|
@@ -742,7 +742,6 @@ import {
|
|
|
742
742
|
type TestTimeDep,
|
|
743
743
|
} from "./Time.ts";
|
|
744
744
|
import {
|
|
745
|
-
assertType,
|
|
746
745
|
createId,
|
|
747
746
|
type InferType,
|
|
748
747
|
maxPositiveInt,
|
|
@@ -1177,7 +1176,7 @@ export interface Run<D = unknown> {
|
|
|
1177
1176
|
*
|
|
1178
1177
|
* await using run = createRun();
|
|
1179
1178
|
* const fiber = run.abortable(loadUser, { db });
|
|
1180
|
-
* assertType<AbortableFiber<string, never, DbDep
|
|
1179
|
+
* assertType<typeof fiber, AbortableFiber<string, never, DbDep>>();
|
|
1181
1180
|
* fiber.abort();
|
|
1182
1181
|
* const userResult = await fiber;
|
|
1183
1182
|
* assertFalse(userResult.ok);
|
|
@@ -1629,7 +1628,7 @@ export interface DisposableRun<D = unknown>
|
|
|
1629
1628
|
* const userResult = await fiber;
|
|
1630
1629
|
* const snapshot = fiber.run.snapshot();
|
|
1631
1630
|
*
|
|
1632
|
-
* assertType<Fiber<string, never
|
|
1631
|
+
* assertType<typeof fiber, Fiber<string, never>>();
|
|
1633
1632
|
* assertOk(userResult, "Ada");
|
|
1634
1633
|
* assertEqual(snapshot.id, fiber.run.id);
|
|
1635
1634
|
* ```
|
|
@@ -1710,7 +1709,7 @@ export type InferFiberDeps<TFiber extends AnyFiber> =
|
|
|
1710
1709
|
* };
|
|
1711
1710
|
*
|
|
1712
1711
|
* const fiber = run.abortable<string, never>(fetchData);
|
|
1713
|
-
* assertType<AbortableFiber<string, never
|
|
1712
|
+
* assertType<typeof fiber, AbortableFiber<string, never>>();
|
|
1714
1713
|
* fiber.abort();
|
|
1715
1714
|
* const result = await fiber;
|
|
1716
1715
|
* assertFalse(result.ok);
|
|
@@ -2721,7 +2720,7 @@ const createRunInternal = <D extends object>(
|
|
|
2721
2720
|
// concern. Attach this late so V8 captures the defect stack before any
|
|
2722
2721
|
// catch observes the Fiber.
|
|
2723
2722
|
void fiber.catch(constVoid);
|
|
2724
|
-
//
|
|
2723
|
+
// oxlint-disable-next-line typescript/only-throw-error -- AbortError is Task abort control flow; aborts intentionally carry no stack.
|
|
2725
2724
|
throw taskExit.error;
|
|
2726
2725
|
};
|
|
2727
2726
|
|
|
@@ -2743,13 +2742,13 @@ const createRunInternal = <D extends object>(
|
|
|
2743
2742
|
|
|
2744
2743
|
const root = rootRun ?? run;
|
|
2745
2744
|
|
|
2746
|
-
/*
|
|
2745
|
+
/* oxlint-disable typescript/no-unsafe-return -- Internal overload assignments implement public generics via TaskInternal. */
|
|
2747
2746
|
run.orThrow = (async (task: TaskInternal, taskDeps?: object) =>
|
|
2748
2747
|
getOrThrow(await run(task, taskDeps))) as Run<D>["orThrow"];
|
|
2749
2748
|
|
|
2750
2749
|
run.ok = (async (task: TaskInternal, taskDeps?: object) =>
|
|
2751
2750
|
getOk((await run(task, taskDeps)) as Result<any>)) as Run<D>["ok"];
|
|
2752
|
-
/*
|
|
2751
|
+
/* oxlint-enable typescript/no-unsafe-return */
|
|
2753
2752
|
|
|
2754
2753
|
run.abortable = ((task: TaskInternal, deps?: object) =>
|
|
2755
2754
|
run(task, deps, { abortable: true })) as Run<D>["abortable"];
|
|
@@ -2812,7 +2811,7 @@ const createRunInternal = <D extends object>(
|
|
|
2812
2811
|
|
|
2813
2812
|
if (
|
|
2814
2813
|
snapshot?.state !== state ||
|
|
2815
|
-
!
|
|
2814
|
+
!eqArraySameValue(snapshot.children, childSnapshots)
|
|
2816
2815
|
) {
|
|
2817
2816
|
snapshot = {
|
|
2818
2817
|
id: run.id,
|
|
@@ -2855,7 +2854,7 @@ const createRunInternal = <D extends object>(
|
|
|
2855
2854
|
|
|
2856
2855
|
run[Symbol.asyncDispose] = async (): Promise<void> => {
|
|
2857
2856
|
await dispose();
|
|
2858
|
-
//
|
|
2857
|
+
// oxlint-disable-next-line typescript/only-throw-error -- AbortError is Task abort control flow; rethrowing it avoids reporting the finalizer defect twice in Task code.
|
|
2859
2858
|
if (finalizerAbortError) throw finalizerAbortError;
|
|
2860
2859
|
};
|
|
2861
2860
|
|
|
@@ -3017,7 +3016,7 @@ export type InferTasksOk<TTasks> = {
|
|
|
3017
3016
|
* collect: false,
|
|
3018
3017
|
* }),
|
|
3019
3018
|
* );
|
|
3020
|
-
* assertType<Result<void, SaveUserFailedError
|
|
3019
|
+
* assertType<typeof saveResult, Result<void, SaveUserFailedError>>();
|
|
3021
3020
|
* assertErr(saveResult, {
|
|
3022
3021
|
* type: "SaveUserFailed",
|
|
3023
3022
|
* userId: "missing",
|
|
@@ -3069,8 +3068,8 @@ export function all<const TTasks extends TaskRecord>(
|
|
|
3069
3068
|
* await using run = createRun();
|
|
3070
3069
|
* const dashboard = await run(all([fetchUser, fetchPosts]));
|
|
3071
3070
|
* assertType<
|
|
3072
|
-
*
|
|
3073
|
-
*
|
|
3071
|
+
* typeof dashboard,
|
|
3072
|
+
* Result<readonly [User, ReadonlyArray<Post>]>
|
|
3074
3073
|
* >();
|
|
3075
3074
|
* assertOk(dashboard, [{ id: "user-1" }, [{ id: "post-1" }]]);
|
|
3076
3075
|
* ```
|
|
@@ -3116,8 +3115,8 @@ export function all<const TTasks extends ReadonlyArray<AnyTask>>(
|
|
|
3116
3115
|
* const result = await run(all({ user: fetchUser, posts: fetchPosts }));
|
|
3117
3116
|
*
|
|
3118
3117
|
* assertType<
|
|
3119
|
-
*
|
|
3120
|
-
*
|
|
3118
|
+
* typeof result,
|
|
3119
|
+
* Result<{ readonly user: User; readonly posts: ReadonlyArray<Post> }>
|
|
3121
3120
|
* >();
|
|
3122
3121
|
* assertOk(result, {
|
|
3123
3122
|
* user: { id: "user-1" },
|
|
@@ -3194,7 +3193,7 @@ export function all<
|
|
|
3194
3193
|
*
|
|
3195
3194
|
* await using run = createRun();
|
|
3196
3195
|
* const result = await run(loadUsers);
|
|
3197
|
-
* assertType<Result<readonly [User, User]
|
|
3196
|
+
* assertType<typeof result, Result<readonly [User, User]>>();
|
|
3198
3197
|
* assertOk(result, [{ id: "user-1" }, { id: "user-2" }]);
|
|
3199
3198
|
* ```
|
|
3200
3199
|
*/
|
|
@@ -3253,8 +3252,8 @@ export function all<
|
|
|
3253
3252
|
* await using run = createRun();
|
|
3254
3253
|
* const result = await run(loadUsersByRole);
|
|
3255
3254
|
* assertType<
|
|
3256
|
-
*
|
|
3257
|
-
*
|
|
3255
|
+
* typeof result,
|
|
3256
|
+
* Result<{ readonly admin: User; readonly reviewer: User }>
|
|
3258
3257
|
* >();
|
|
3259
3258
|
* assertOk(result, {
|
|
3260
3259
|
* admin: { id: "user-1" },
|
|
@@ -3362,13 +3361,13 @@ export type InferTasksSettled<TTasks> = {
|
|
|
3362
3361
|
* await using run = createRun();
|
|
3363
3362
|
* const results = await run(allSettled([loadProfile, loadActivity]));
|
|
3364
3363
|
* assertType<
|
|
3364
|
+
* typeof results,
|
|
3365
3365
|
* Result<
|
|
3366
3366
|
* readonly [
|
|
3367
3367
|
* Result<string, ProfileNotFoundError>,
|
|
3368
3368
|
* Result<ReadonlyArray<string>>,
|
|
3369
3369
|
* ]
|
|
3370
|
-
*
|
|
3371
|
-
* typeof results
|
|
3370
|
+
* >
|
|
3372
3371
|
* >();
|
|
3373
3372
|
* assertOk(results, [
|
|
3374
3373
|
* { ok: false, error: { type: "ProfileNotFound" } },
|
|
@@ -3419,11 +3418,11 @@ export function allSettled<const TTasks extends ReadonlyArray<AnyTask>>(
|
|
|
3419
3418
|
* );
|
|
3420
3419
|
*
|
|
3421
3420
|
* assertType<
|
|
3421
|
+
* typeof results,
|
|
3422
3422
|
* Result<{
|
|
3423
3423
|
* readonly user: Result<User>;
|
|
3424
3424
|
* readonly profile: Result<string, ProfileNotFoundError>;
|
|
3425
|
-
* }
|
|
3426
|
-
* typeof results
|
|
3425
|
+
* }>
|
|
3427
3426
|
* >();
|
|
3428
3427
|
* assertOk(results, {
|
|
3429
3428
|
* user: { ok: true, value: { id: "user-1" } },
|
|
@@ -3479,13 +3478,13 @@ export function allSettled<const TTasks extends TaskRecord>(
|
|
|
3479
3478
|
* await using run = createRun();
|
|
3480
3479
|
* const results = await run(loadUsers);
|
|
3481
3480
|
* assertType<
|
|
3481
|
+
* typeof results,
|
|
3482
3482
|
* Result<
|
|
3483
3483
|
* readonly [
|
|
3484
3484
|
* Result<User, UserNotFoundError>,
|
|
3485
3485
|
* Result<User, UserNotFoundError>,
|
|
3486
3486
|
* ]
|
|
3487
|
-
*
|
|
3488
|
-
* typeof results
|
|
3487
|
+
* >
|
|
3489
3488
|
* >();
|
|
3490
3489
|
* assertOk(results, [
|
|
3491
3490
|
* { ok: true, value: { id: "user-1" } },
|
|
@@ -3554,11 +3553,11 @@ export function allSettled<
|
|
|
3554
3553
|
* await using run = createRun();
|
|
3555
3554
|
* const results = await run(loadUsersByRole);
|
|
3556
3555
|
* assertType<
|
|
3556
|
+
* typeof results,
|
|
3557
3557
|
* Result<{
|
|
3558
3558
|
* readonly admin: Result<User, UserNotFoundError>;
|
|
3559
3559
|
* readonly reviewer: Result<User, UserNotFoundError>;
|
|
3560
|
-
* }
|
|
3561
|
-
* typeof results
|
|
3560
|
+
* }>
|
|
3562
3561
|
* >();
|
|
3563
3562
|
* assertOk(results, {
|
|
3564
3563
|
* admin: { ok: true, value: { id: "user-1" } },
|
|
@@ -3806,7 +3805,7 @@ export const sleep = (duration: PositiveDuration): Task<void> =>
|
|
|
3806
3805
|
* await using run = createRun();
|
|
3807
3806
|
*
|
|
3808
3807
|
* const result = await run(timeout(waitForAbort, "1ms"));
|
|
3809
|
-
* assertType<Result<never, TimeoutError
|
|
3808
|
+
* assertType<typeof result, Result<never, TimeoutError>>();
|
|
3810
3809
|
* assertErr(result, timeoutError);
|
|
3811
3810
|
* ```
|
|
3812
3811
|
*
|
|
@@ -3928,8 +3927,8 @@ export interface RetryAttempt<E, Output> extends ScheduleStep<Output> {
|
|
|
3928
3927
|
* await using run = createRun();
|
|
3929
3928
|
* const result = await run(fetchWithRetry);
|
|
3930
3929
|
* assertType<
|
|
3931
|
-
*
|
|
3932
|
-
*
|
|
3930
|
+
* typeof result,
|
|
3931
|
+
* Result<string, RetryTaskError<ServiceUnavailableError>>
|
|
3933
3932
|
* >();
|
|
3934
3933
|
* assertErr(result, {
|
|
3935
3934
|
* type: "RetryError",
|
|
@@ -4238,7 +4237,7 @@ export type InferTasksResult<TTasks extends NonEmptyReadonlyArray<AnyTask>> =
|
|
|
4238
4237
|
* await using run = createRun();
|
|
4239
4238
|
* const result = await run(any([unavailable, fallback]));
|
|
4240
4239
|
*
|
|
4241
|
-
* assertType<Result<string, ServiceUnavailableError
|
|
4240
|
+
* assertType<typeof result, Result<string, ServiceUnavailableError>>();
|
|
4242
4241
|
* assertOk(result, "fallback");
|
|
4243
4242
|
* assertTrue(fallbackStarted);
|
|
4244
4243
|
* ```
|
|
@@ -4355,7 +4354,7 @@ export const any =
|
|
|
4355
4354
|
* // Input order does not matter: the first settled Result wins, and the
|
|
4356
4355
|
* // still-running loser is aborted.
|
|
4357
4356
|
* const result = await run(race([slow, fast]));
|
|
4358
|
-
* assertType<Result<string
|
|
4357
|
+
* assertType<typeof result, Result<string>>();
|
|
4359
4358
|
* assertOk(result, "fast");
|
|
4360
4359
|
* assertFalse(slowCompleted);
|
|
4361
4360
|
* ```
|
|
@@ -4455,8 +4454,6 @@ export const firstN =
|
|
|
4455
4454
|
InferTasksDeps<TTasks>
|
|
4456
4455
|
> =>
|
|
4457
4456
|
async (run) => {
|
|
4458
|
-
assertType(PositiveInt, count);
|
|
4459
|
-
|
|
4460
4457
|
const values: Array<InferTaskOk<TTasks[number]>> = [];
|
|
4461
4458
|
await run(
|
|
4462
4459
|
each(
|
|
@@ -4534,8 +4531,6 @@ export const firstNSettled =
|
|
|
4534
4531
|
InferTasksDeps<TTasks>
|
|
4535
4532
|
> =>
|
|
4536
4533
|
async (run) => {
|
|
4537
|
-
assertType(PositiveInt, count);
|
|
4538
|
-
|
|
4539
4534
|
const results: Array<InferTasksResult<TTasks>> = [];
|
|
4540
4535
|
await run(
|
|
4541
4536
|
each(
|
|
@@ -4885,7 +4880,7 @@ export const yieldNow: Task<void> = async (run) => {
|
|
|
4885
4880
|
* return await run(waitForAbort);
|
|
4886
4881
|
* };
|
|
4887
4882
|
*
|
|
4888
|
-
* assertType<Task<never, never, ServerDep
|
|
4883
|
+
* assertType<ReturnType<typeof serve>, Task<never, never, ServerDep>>();
|
|
4889
4884
|
*
|
|
4890
4885
|
* await using run = createRun();
|
|
4891
4886
|
* const fiber = run.abortable(serve(), { port: 3000 });
|
|
@@ -5028,7 +5023,7 @@ export const waitForAbort: Task<never> = async (run) => {
|
|
|
5028
5023
|
* const task: Task<ResultValue> = () => promise;
|
|
5029
5024
|
*
|
|
5030
5025
|
* assertTrue(promiseStarted);
|
|
5031
|
-
* assertType<Task<ResultValue
|
|
5026
|
+
* assertType<typeof task, Task<ResultValue>>();
|
|
5032
5027
|
* ```
|
|
5033
5028
|
*
|
|
5034
5029
|
* @group Lifetime
|
|
@@ -5358,7 +5353,7 @@ export interface Deferred<T, E = never> {
|
|
|
5358
5353
|
* assertTrue(deferred.resolve(ok("ready")));
|
|
5359
5354
|
*
|
|
5360
5355
|
* const result = await fiber;
|
|
5361
|
-
* assertType<Result<string
|
|
5356
|
+
* assertType<typeof result, Result<string>>();
|
|
5362
5357
|
* assertOk(result, "ready");
|
|
5363
5358
|
*
|
|
5364
5359
|
* // A Deferred is one-shot: later resolutions are ignored, and future
|
package/src/Test.test.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import { assertEqual, assertFalse } from "./Assert.ts";
|
|
3
|
+
|
|
4
|
+
import type { Brand } from "./Brand.ts";
|
|
5
|
+
import { testCreateId, testStubGlobal } from "./Test.ts";
|
|
6
|
+
import { assertType, type Id } from "./Type.ts";
|
|
7
|
+
|
|
8
|
+
describe("testStubGlobal", () => {
|
|
9
|
+
it("deletes a previously absent property on disposal", () => {
|
|
10
|
+
const key = Symbol("absent global");
|
|
11
|
+
const stub = testStubGlobal(key, 42);
|
|
12
|
+
|
|
13
|
+
assertEqual(Reflect.get(globalThis, key), 42);
|
|
14
|
+
|
|
15
|
+
stub[Symbol.dispose]();
|
|
16
|
+
stub[Symbol.dispose]();
|
|
17
|
+
|
|
18
|
+
assertFalse(Reflect.has(globalThis, key));
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("restores the original property descriptor", () => {
|
|
22
|
+
const key = Symbol("existing global");
|
|
23
|
+
const original = {
|
|
24
|
+
configurable: true,
|
|
25
|
+
enumerable: true,
|
|
26
|
+
get: () => 1,
|
|
27
|
+
} satisfies PropertyDescriptor;
|
|
28
|
+
using cleanup = new DisposableStack();
|
|
29
|
+
cleanup.defer(() => {
|
|
30
|
+
Reflect.deleteProperty(globalThis, key);
|
|
31
|
+
});
|
|
32
|
+
Object.defineProperty(globalThis, key, original);
|
|
33
|
+
|
|
34
|
+
{
|
|
35
|
+
using _stub = testStubGlobal(key, 2);
|
|
36
|
+
|
|
37
|
+
assertEqual(Reflect.get(globalThis, key), 2);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const restored = Object.getOwnPropertyDescriptor(globalThis, key);
|
|
41
|
+
assertEqual(restored, {
|
|
42
|
+
configurable: true,
|
|
43
|
+
enumerable: true,
|
|
44
|
+
get: original.get,
|
|
45
|
+
set: undefined,
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("restores nested stubs in disposal order", () => {
|
|
50
|
+
const key = Symbol("nested global");
|
|
51
|
+
|
|
52
|
+
{
|
|
53
|
+
using _outer = testStubGlobal(key, "outer");
|
|
54
|
+
assertEqual(Reflect.get(globalThis, key), "outer");
|
|
55
|
+
|
|
56
|
+
{
|
|
57
|
+
using _inner = testStubGlobal(key, "inner");
|
|
58
|
+
assertEqual(Reflect.get(globalThis, key), "inner");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
assertEqual(Reflect.get(globalThis, key), "outer");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
assertFalse(Reflect.has(globalThis, key));
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe("testCreateId", () => {
|
|
69
|
+
it("creates file-local stable pseudo-random ids", () => {
|
|
70
|
+
const createTestId = testCreateId();
|
|
71
|
+
const first = createTestId();
|
|
72
|
+
const second = createTestId();
|
|
73
|
+
|
|
74
|
+
assertEqual(
|
|
75
|
+
[first, second],
|
|
76
|
+
["ncqMQ1uwd5-zf5YKUbT3VA", "ofZXw_hAfJ8fIcpFxi6nag"],
|
|
77
|
+
);
|
|
78
|
+
assertFalse(Object.is(second, first));
|
|
79
|
+
assertType<typeof first, Id>();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("preserves branded id typing", () => {
|
|
83
|
+
const createTestId = testCreateId();
|
|
84
|
+
const _todoId = createTestId<"Todo">();
|
|
85
|
+
|
|
86
|
+
assertType<typeof _todoId, Id & Brand<"Todo">>();
|
|
87
|
+
});
|
|
88
|
+
});
|
package/src/Test.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Cross-module test utilities for deterministic testing.
|
|
3
3
|
*
|
|
4
|
-
* Test helpers are usually colocated with the code they test.
|
|
5
|
-
*
|
|
4
|
+
* Test helpers are usually colocated with the code they test. General helpers
|
|
5
|
+
* shared across unrelated modules, or helpers whose colocation would create
|
|
6
|
+
* dependency cycles, belong here.
|
|
6
7
|
*
|
|
7
8
|
* @module
|
|
8
9
|
*/
|
|
@@ -12,6 +13,51 @@ import { testCreateRandomBytes } from "./Crypto.ts";
|
|
|
12
13
|
import { testCreateRandomLib } from "./Random.ts";
|
|
13
14
|
import { createId, type Id } from "./Type.ts";
|
|
14
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Temporarily replaces a global property for a test scope.
|
|
18
|
+
*
|
|
19
|
+
* Node.js can mock existing globals with `t.mock.property`, but it rejects a
|
|
20
|
+
* property that does not exist. That catches misspelled mock targets, but it
|
|
21
|
+
* cannot model optional platform globals whose presence varies. Use this helper
|
|
22
|
+
* to provide such a global, for example `scheduler`, or replace a global with
|
|
23
|
+
* `undefined` to exercise a fallback.
|
|
24
|
+
*
|
|
25
|
+
* The original property descriptor is restored on disposal. A property that did
|
|
26
|
+
* not exist is deleted. Prefer dependency injection when available because
|
|
27
|
+
* global properties are shared by concurrently running tests.
|
|
28
|
+
*
|
|
29
|
+
* ### Example
|
|
30
|
+
*
|
|
31
|
+
* ```ts
|
|
32
|
+
* import { assertEqual, assertFalse, testStubGlobal } from "@evolu/common";
|
|
33
|
+
*
|
|
34
|
+
* const key = Symbol("test global");
|
|
35
|
+
* {
|
|
36
|
+
* using _stub = testStubGlobal(key, 42);
|
|
37
|
+
* assertEqual(Reflect.get(globalThis, key), 42);
|
|
38
|
+
* }
|
|
39
|
+
* assertFalse(Reflect.has(globalThis, key));
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export const testStubGlobal = (
|
|
43
|
+
key: PropertyKey,
|
|
44
|
+
value: unknown,
|
|
45
|
+
): Disposable => {
|
|
46
|
+
const descriptor = Object.getOwnPropertyDescriptor(globalThis, key);
|
|
47
|
+
Object.defineProperty(globalThis, key, {
|
|
48
|
+
configurable: true,
|
|
49
|
+
value,
|
|
50
|
+
writable: true,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const disposer = new DisposableStack();
|
|
54
|
+
disposer.defer(() => {
|
|
55
|
+
if (descriptor === undefined) Reflect.deleteProperty(globalThis, key);
|
|
56
|
+
else Object.defineProperty(globalThis, key, descriptor);
|
|
57
|
+
});
|
|
58
|
+
return disposer;
|
|
59
|
+
};
|
|
60
|
+
|
|
15
61
|
export type TestCreateId = <B extends string = never>() => [B] extends [never]
|
|
16
62
|
? Id
|
|
17
63
|
: Id & Brand<B>;
|
|
@@ -48,7 +94,7 @@ export type TestCreateId = <B extends string = never>() => [B] extends [never]
|
|
|
48
94
|
*
|
|
49
95
|
* const replayCreateId = testCreateId();
|
|
50
96
|
* assertEqual(replayCreateId(), callbackId);
|
|
51
|
-
* assertType<Id & Brand<"Todo"
|
|
97
|
+
* assertType<typeof todoId, Id & Brand<"Todo">>();
|
|
52
98
|
* ```
|
|
53
99
|
*/
|
|
54
100
|
export const testCreateId = (): TestCreateId => {
|