@evolu/common 8.4.0 → 8.6.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 +191 -94
- package/dist/src/Array.d.ts.map +1 -1
- package/dist/src/Array.js +91 -40
- package/dist/src/Assert.d.ts +233 -30
- package/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Assert.js +151 -30
- package/dist/src/BigInt.d.ts +3 -3
- package/dist/src/BigInt.js +3 -3
- package/dist/src/Brand.d.ts +7 -7
- package/dist/src/Buffer.d.ts +12 -4
- package/dist/src/Buffer.d.ts.map +1 -1
- package/dist/src/Cache.d.ts +8 -3
- package/dist/src/Cache.d.ts.map +1 -1
- package/dist/src/Cache.js +8 -3
- package/dist/src/Callbacks.d.ts +8 -4
- package/dist/src/Callbacks.d.ts.map +1 -1
- package/dist/src/Console.d.ts +45 -30
- package/dist/src/Console.d.ts.map +1 -1
- package/dist/src/Console.js +32 -21
- package/dist/src/Crypto.d.ts +13 -8
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +6 -3
- package/dist/src/Eq.d.ts +107 -58
- package/dist/src/Eq.d.ts.map +1 -1
- package/dist/src/Eq.js +308 -112
- package/dist/src/Function.d.ts +54 -24
- package/dist/src/Function.d.ts.map +1 -1
- package/dist/src/Function.js +34 -17
- package/dist/src/Http.d.ts +52 -19
- package/dist/src/Http.d.ts.map +1 -1
- package/dist/src/Identicon.d.ts +9 -4
- package/dist/src/Identicon.d.ts.map +1 -1
- package/dist/src/Identicon.js +9 -4
- package/dist/src/LeakDetector.d.ts.map +1 -1
- package/dist/src/LeakDetector.js +4 -1
- package/dist/src/LockManager.d.ts +12 -10
- package/dist/src/LockManager.d.ts.map +1 -1
- package/dist/src/Lookup.d.ts +4 -2
- package/dist/src/Lookup.d.ts.map +1 -1
- package/dist/src/Lookup.js +5 -2
- package/dist/src/Number.d.ts +28 -24
- package/dist/src/Number.d.ts.map +1 -1
- package/dist/src/Number.js +16 -17
- package/dist/src/Object.d.ts +89 -47
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/Object.js +88 -41
- package/dist/src/Option.d.ts +14 -5
- package/dist/src/Option.d.ts.map +1 -1
- package/dist/src/Option.js +14 -5
- package/dist/src/Order.d.ts +12 -12
- package/dist/src/Order.js +12 -12
- package/dist/src/Platform.d.ts +2 -2
- package/dist/src/Platform.js +1 -0
- package/dist/src/Random.d.ts +7 -4
- package/dist/src/Random.d.ts.map +1 -1
- package/dist/src/Redacted.d.ts +13 -6
- package/dist/src/Redacted.d.ts.map +1 -1
- package/dist/src/Redacted.js +4 -2
- package/dist/src/Ref.d.ts +4 -4
- package/dist/src/Relation.d.ts +5 -7
- package/dist/src/Relation.d.ts.map +1 -1
- package/dist/src/Relation.js +3 -3
- package/dist/src/Resource.d.ts +27 -12
- package/dist/src/Resource.d.ts.map +1 -1
- package/dist/src/Resource.js +9 -3
- package/dist/src/Result.d.ts +258 -114
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +74 -39
- package/dist/src/Schedule.d.ts +233 -116
- package/dist/src/Schedule.d.ts.map +1 -1
- package/dist/src/Schedule.js +204 -110
- package/dist/src/Set.d.ts +43 -24
- package/dist/src/Set.d.ts.map +1 -1
- package/dist/src/Set.js +25 -13
- package/dist/src/Sqlite.d.ts +4 -4
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +18 -15
- package/dist/src/Store.d.ts.map +1 -1
- package/dist/src/Store.js +3 -1
- package/dist/src/String.d.ts.map +1 -1
- package/dist/src/String.js +1 -1
- package/dist/src/Task.d.ts +555 -264
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +278 -168
- package/dist/src/Test.d.ts +10 -4
- package/dist/src/Test.d.ts.map +1 -1
- package/dist/src/Test.js +11 -4
- package/dist/src/Time.d.ts +27 -17
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +25 -8
- package/dist/src/Type.d.ts +1218 -372
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +1056 -379
- package/dist/src/Types.d.ts +95 -40
- package/dist/src/Types.d.ts.map +1 -1
- package/dist/src/Types.js +13 -4
- package/dist/src/WebSocket.d.ts +14 -6
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/WebSocket.js +8 -0
- package/dist/src/Worker.d.ts +10 -6
- package/dist/src/Worker.d.ts.map +1 -1
- package/dist/src/Worker.js +1 -1
- package/dist/src/intl/_en.d.ts +3 -1
- package/dist/src/intl/_en.d.ts.map +1 -1
- package/dist/src/intl/_en.js +17 -3
- package/dist/src/intl/ar.d.ts +3 -1
- package/dist/src/intl/ar.d.ts.map +1 -1
- package/dist/src/intl/ar.js +15 -2
- package/dist/src/intl/bn.d.ts +3 -1
- package/dist/src/intl/bn.d.ts.map +1 -1
- package/dist/src/intl/bn.js +16 -3
- package/dist/src/intl/ca.d.ts +3 -1
- package/dist/src/intl/ca.d.ts.map +1 -1
- package/dist/src/intl/ca.js +16 -3
- package/dist/src/intl/cs.d.ts +3 -1
- package/dist/src/intl/cs.d.ts.map +1 -1
- package/dist/src/intl/cs.js +16 -3
- package/dist/src/intl/da.d.ts +3 -1
- package/dist/src/intl/da.d.ts.map +1 -1
- package/dist/src/intl/da.js +16 -3
- package/dist/src/intl/de.d.ts +3 -1
- package/dist/src/intl/de.d.ts.map +1 -1
- package/dist/src/intl/de.js +16 -3
- package/dist/src/intl/el.d.ts +3 -1
- package/dist/src/intl/el.d.ts.map +1 -1
- package/dist/src/intl/el.js +16 -3
- package/dist/src/intl/es.d.ts +3 -1
- package/dist/src/intl/es.d.ts.map +1 -1
- package/dist/src/intl/es.js +16 -3
- package/dist/src/intl/fa.d.ts +3 -1
- package/dist/src/intl/fa.d.ts.map +1 -1
- package/dist/src/intl/fa.js +16 -3
- package/dist/src/intl/fi.d.ts +3 -1
- package/dist/src/intl/fi.d.ts.map +1 -1
- package/dist/src/intl/fi.js +16 -3
- package/dist/src/intl/fil.d.ts +3 -1
- package/dist/src/intl/fil.d.ts.map +1 -1
- package/dist/src/intl/fil.js +16 -3
- package/dist/src/intl/fr.d.ts +3 -1
- package/dist/src/intl/fr.d.ts.map +1 -1
- package/dist/src/intl/fr.js +16 -3
- package/dist/src/intl/he.d.ts +3 -1
- package/dist/src/intl/he.d.ts.map +1 -1
- package/dist/src/intl/he.js +16 -3
- package/dist/src/intl/hi.d.ts +3 -1
- package/dist/src/intl/hi.d.ts.map +1 -1
- package/dist/src/intl/hi.js +16 -3
- package/dist/src/intl/hr.d.ts +3 -1
- package/dist/src/intl/hr.d.ts.map +1 -1
- package/dist/src/intl/hr.js +16 -3
- package/dist/src/intl/hu.d.ts +2 -1
- package/dist/src/intl/hu.d.ts.map +1 -1
- package/dist/src/intl/hu.js +15 -3
- package/dist/src/intl/id.d.ts +3 -1
- package/dist/src/intl/id.d.ts.map +1 -1
- package/dist/src/intl/id.js +16 -3
- package/dist/src/intl/it.d.ts +3 -1
- package/dist/src/intl/it.d.ts.map +1 -1
- package/dist/src/intl/it.js +16 -3
- package/dist/src/intl/ja.d.ts +3 -1
- package/dist/src/intl/ja.d.ts.map +1 -1
- package/dist/src/intl/ja.js +16 -3
- package/dist/src/intl/ko.d.ts +3 -1
- package/dist/src/intl/ko.d.ts.map +1 -1
- package/dist/src/intl/ko.js +16 -3
- package/dist/src/intl/ml.d.ts +3 -1
- package/dist/src/intl/ml.d.ts.map +1 -1
- package/dist/src/intl/ml.js +16 -3
- package/dist/src/intl/mr.d.ts +3 -1
- package/dist/src/intl/mr.d.ts.map +1 -1
- package/dist/src/intl/mr.js +16 -3
- package/dist/src/intl/ms.d.ts +3 -1
- package/dist/src/intl/ms.d.ts.map +1 -1
- package/dist/src/intl/ms.js +15 -2
- package/dist/src/intl/nb.d.ts +2 -1
- package/dist/src/intl/nb.d.ts.map +1 -1
- package/dist/src/intl/nb.js +14 -2
- package/dist/src/intl/nl.d.ts +3 -1
- package/dist/src/intl/nl.d.ts.map +1 -1
- package/dist/src/intl/nl.js +16 -3
- package/dist/src/intl/pa.d.ts +3 -1
- package/dist/src/intl/pa.d.ts.map +1 -1
- package/dist/src/intl/pa.js +16 -3
- package/dist/src/intl/pl.d.ts +2 -0
- package/dist/src/intl/pl.d.ts.map +1 -1
- package/dist/src/intl/pl.js +15 -2
- package/dist/src/intl/pt-BR.d.ts +3 -1
- package/dist/src/intl/pt-BR.d.ts.map +1 -1
- package/dist/src/intl/pt-BR.js +16 -3
- package/dist/src/intl/pt.d.ts +3 -1
- package/dist/src/intl/pt.d.ts.map +1 -1
- package/dist/src/intl/pt.js +15 -2
- package/dist/src/intl/ro.d.ts +3 -1
- package/dist/src/intl/ro.d.ts.map +1 -1
- package/dist/src/intl/ro.js +16 -3
- package/dist/src/intl/sk.d.ts +3 -1
- package/dist/src/intl/sk.d.ts.map +1 -1
- package/dist/src/intl/sk.js +15 -2
- package/dist/src/intl/sl.d.ts +3 -1
- package/dist/src/intl/sl.d.ts.map +1 -1
- package/dist/src/intl/sl.js +16 -3
- package/dist/src/intl/sv.d.ts +3 -1
- package/dist/src/intl/sv.d.ts.map +1 -1
- package/dist/src/intl/sv.js +16 -3
- package/dist/src/intl/sw.d.ts +1 -0
- package/dist/src/intl/sw.d.ts.map +1 -1
- package/dist/src/intl/sw.js +14 -2
- package/dist/src/intl/ta.d.ts +3 -1
- package/dist/src/intl/ta.d.ts.map +1 -1
- package/dist/src/intl/ta.js +16 -3
- package/dist/src/intl/te.d.ts +3 -1
- package/dist/src/intl/te.d.ts.map +1 -1
- package/dist/src/intl/te.js +16 -3
- package/dist/src/intl/th.d.ts +3 -1
- package/dist/src/intl/th.d.ts.map +1 -1
- package/dist/src/intl/th.js +16 -3
- package/dist/src/intl/tr.d.ts +3 -1
- package/dist/src/intl/tr.d.ts.map +1 -1
- package/dist/src/intl/tr.js +16 -3
- package/dist/src/intl/uk.d.ts +3 -1
- package/dist/src/intl/uk.d.ts.map +1 -1
- package/dist/src/intl/uk.js +16 -3
- package/dist/src/intl/ur.d.ts +3 -1
- package/dist/src/intl/ur.d.ts.map +1 -1
- package/dist/src/intl/ur.js +15 -2
- package/dist/src/intl/vi.d.ts +3 -1
- package/dist/src/intl/vi.d.ts.map +1 -1
- package/dist/src/intl/vi.js +16 -3
- package/dist/src/intl/zh-CN.d.ts +3 -1
- package/dist/src/intl/zh-CN.d.ts.map +1 -1
- package/dist/src/intl/zh-CN.js +16 -3
- package/dist/src/intl/zh-TW.d.ts +3 -1
- package/dist/src/intl/zh-TW.d.ts.map +1 -1
- package/dist/src/intl/zh-TW.js +16 -3
- package/dist/src/local-first/Db.js +3 -2
- package/dist/src/local-first/Evolu.d.ts +47 -24
- package/dist/src/local-first/Evolu.d.ts.map +1 -1
- package/dist/src/local-first/Evolu.js +1 -0
- package/dist/src/local-first/Owner.d.ts +18 -14
- package/dist/src/local-first/Owner.d.ts.map +1 -1
- package/dist/src/local-first/Owner.js +14 -11
- package/dist/src/local-first/Protocol.d.ts +5 -5
- package/dist/src/local-first/Protocol.d.ts.map +1 -1
- package/dist/src/local-first/Protocol.js +35 -29
- package/dist/src/local-first/Query.d.ts +34 -21
- package/dist/src/local-first/Query.d.ts.map +1 -1
- package/dist/src/local-first/Query.js +27 -14
- package/dist/src/local-first/Relay.d.ts +12 -5
- package/dist/src/local-first/Relay.d.ts.map +1 -1
- package/dist/src/local-first/Relay.js +1 -1
- package/dist/src/local-first/Schema.d.ts +19 -11
- package/dist/src/local-first/Schema.d.ts.map +1 -1
- package/dist/src/local-first/Schema.js +11 -6
- package/dist/src/local-first/Shared.d.ts.map +1 -1
- package/dist/src/local-first/Shared.js +4 -2
- package/dist/src/local-first/Storage.d.ts +4 -2
- package/dist/src/local-first/Storage.d.ts.map +1 -1
- package/dist/src/local-first/Timestamp.d.ts.map +1 -1
- package/dist/src/local-first/Timestamp.js +1 -1
- package/package.json +3 -4
- package/src/Array.ts +195 -95
- package/src/Assert.ts +337 -31
- package/src/BigInt.ts +3 -3
- package/src/Brand.ts +7 -7
- package/src/Buffer.ts +12 -4
- package/src/Cache.ts +8 -3
- package/src/Callbacks.ts +8 -4
- package/src/Console.ts +45 -30
- package/src/Crypto.ts +13 -8
- package/src/Eq.ts +450 -122
- package/src/Function.ts +54 -24
- package/src/Http.ts +52 -19
- package/src/Identicon.ts +9 -4
- package/src/LeakDetector.ts +4 -3
- package/src/LockManager.ts +12 -10
- package/src/Lookup.ts +5 -2
- package/src/Number.ts +28 -24
- package/src/Object.ts +115 -49
- package/src/Option.ts +14 -5
- package/src/Order.ts +12 -12
- package/src/Platform.ts +3 -2
- package/src/Random.ts +7 -4
- package/src/Redacted.ts +13 -6
- package/src/Ref.ts +4 -4
- package/src/Relation.ts +8 -10
- package/src/Resource.ts +36 -15
- package/src/Result.ts +263 -119
- package/src/Schedule.ts +233 -116
- package/src/Set.ts +43 -24
- package/src/Sqlite.ts +18 -15
- package/src/Store.ts +3 -1
- package/src/String.ts +1 -1
- package/src/Task.ts +566 -286
- package/src/Test.ts +11 -4
- package/src/Time.ts +36 -19
- package/src/Type.ts +2191 -590
- package/src/Types.ts +108 -40
- package/src/WebSocket.ts +22 -6
- package/src/Worker.ts +11 -7
- package/src/intl/_en.ts +20 -4
- package/src/intl/ar.ts +17 -2
- package/src/intl/bn.ts +19 -4
- package/src/intl/ca.ts +19 -4
- package/src/intl/cs.ts +19 -4
- package/src/intl/da.ts +19 -4
- package/src/intl/de.ts +19 -4
- package/src/intl/el.ts +19 -4
- package/src/intl/es.ts +19 -4
- package/src/intl/fa.ts +19 -4
- package/src/intl/fi.ts +19 -4
- package/src/intl/fil.ts +19 -4
- package/src/intl/fr.ts +19 -4
- package/src/intl/he.ts +19 -4
- package/src/intl/hi.ts +19 -4
- package/src/intl/hr.ts +19 -4
- package/src/intl/hu.ts +18 -4
- package/src/intl/id.ts +19 -4
- package/src/intl/it.ts +19 -4
- package/src/intl/ja.ts +19 -4
- package/src/intl/ko.ts +19 -4
- package/src/intl/ml.ts +19 -4
- package/src/intl/mr.ts +19 -4
- package/src/intl/ms.ts +17 -2
- package/src/intl/nb.ts +16 -2
- package/src/intl/nl.ts +19 -4
- package/src/intl/pa.ts +19 -4
- package/src/intl/pl.ts +18 -2
- package/src/intl/pt-BR.ts +19 -4
- package/src/intl/pt.ts +17 -2
- package/src/intl/ro.ts +19 -4
- package/src/intl/sk.ts +17 -2
- package/src/intl/sl.ts +19 -4
- package/src/intl/sv.ts +19 -4
- package/src/intl/sw.ts +15 -2
- package/src/intl/ta.ts +19 -4
- package/src/intl/te.ts +19 -4
- package/src/intl/th.ts +19 -4
- package/src/intl/tr.ts +19 -4
- package/src/intl/uk.ts +19 -4
- package/src/intl/ur.ts +17 -2
- package/src/intl/vi.ts +19 -3
- package/src/intl/zh-CN.ts +19 -4
- package/src/intl/zh-TW.ts +19 -4
- package/src/local-first/Db.ts +2 -1
- package/src/local-first/Evolu.ts +48 -24
- package/src/local-first/Owner.ts +18 -14
- package/src/local-first/Protocol.ts +45 -35
- package/src/local-first/Query.ts +40 -24
- package/src/local-first/Relay.ts +13 -6
- package/src/local-first/Schema.ts +19 -11
- package/src/local-first/Shared.ts +4 -2
- package/src/local-first/Storage.ts +4 -2
- package/src/local-first/Timestamp.ts +1 -1
package/dist/src/Task.js
CHANGED
|
@@ -51,43 +51,41 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
51
51
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
52
|
});
|
|
53
53
|
/**
|
|
54
|
-
* ## Intro
|
|
55
|
-
*
|
|
56
54
|
* JavaScript-native structured concurrency.
|
|
57
55
|
*
|
|
58
|
-
* Structured concurrency
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* also abort their remaining sibling branches.
|
|
56
|
+
* Structured concurrency organizes running tasks into a tree. Every child
|
|
57
|
+
* belongs to a parent, a parent waits for its children before it completes, and
|
|
58
|
+
* abort propagates from parents to descendants. Races and fail-fast control
|
|
59
|
+
* flow abort siblings that are no longer needed.
|
|
63
60
|
*
|
|
64
61
|
* With plain {@link AbortController} code, these guarantees depend on call-site
|
|
65
|
-
* discipline: someone must remember the `finally` that aborts started
|
|
66
|
-
* the await that waits for cleanup.
|
|
67
|
-
*
|
|
62
|
+
* discipline: someone must remember the `finally` that aborts started tasks and
|
|
63
|
+
* the await that waits for cleanup. Evolu makes both structural: `run(task)`
|
|
64
|
+
* registers every child before it starts, and the parent {@link Run} settles
|
|
68
65
|
* only after child cleanup finishes.
|
|
69
66
|
*
|
|
70
|
-
* Evolu
|
|
67
|
+
* Evolu implements structured concurrency with:
|
|
71
68
|
*
|
|
72
|
-
* - A {@link Task}
|
|
69
|
+
* - A {@link Task} is a function passed to Run that returns an {@link Awaitable}
|
|
70
|
+
* {@link Result} and declares its dependencies.
|
|
73
71
|
* - A {@link Run} starts Tasks and owns their lifetimes.
|
|
74
72
|
* - A {@link Fiber} is the Promise-backed handle returned when a Run starts a
|
|
75
73
|
* Task.
|
|
76
74
|
* - An {@link AbortableFiber} adds explicit abort and async disposal.
|
|
77
75
|
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* propagation, and JavaScript resource management. Together, these primitives
|
|
81
|
-
* provide abort, cleanup, defect handling, dependency injection, monitoring,
|
|
82
|
-
* concurrency, and resource bracketing.
|
|
76
|
+
* Together, these APIs provide abort, cleanup, defect handling, dependency
|
|
77
|
+
* injection, monitoring, and resource management.
|
|
83
78
|
*
|
|
84
|
-
* Tasks return
|
|
85
|
-
* flow represented by {@link AbortError}. If a Task throws or
|
|
86
|
-
* anything else, that is a defect: the root Run reports it and
|
|
87
|
-
* tree so code does not continue in a potentially invalid
|
|
79
|
+
* Tasks return a {@link Result} containing either success or a domain error.
|
|
80
|
+
* Abort is control flow represented by {@link AbortError}. If a Task throws or
|
|
81
|
+
* rejects with anything else, that is a defect: the root Run reports it and
|
|
82
|
+
* shuts down its tree so code does not continue in a potentially invalid
|
|
83
|
+
* state.
|
|
88
84
|
*
|
|
89
85
|
* ```ts
|
|
90
86
|
* import {
|
|
87
|
+
* assertOk,
|
|
88
|
+
* assertType,
|
|
91
89
|
* createRun,
|
|
92
90
|
* err,
|
|
93
91
|
* ok,
|
|
@@ -130,8 +128,8 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
130
128
|
* });
|
|
131
129
|
*
|
|
132
130
|
* const result = await run(getUser(user.id));
|
|
133
|
-
*
|
|
134
|
-
*
|
|
131
|
+
* assertType<Result<User, UserNotFoundError>, typeof result>();
|
|
132
|
+
* assertOk(result, user);
|
|
135
133
|
* ```
|
|
136
134
|
*
|
|
137
135
|
* In composition roots, prefer the lifecycle API from the matching Evolu
|
|
@@ -174,6 +172,8 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
174
172
|
*
|
|
175
173
|
* ```ts
|
|
176
174
|
* import {
|
|
175
|
+
* assertOk,
|
|
176
|
+
* assertType,
|
|
177
177
|
* createRun,
|
|
178
178
|
* err,
|
|
179
179
|
* ok,
|
|
@@ -232,13 +232,14 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
232
232
|
*
|
|
233
233
|
* await using run = createRun();
|
|
234
234
|
* const result = await run(getUserWithProfile("user-1"));
|
|
235
|
-
*
|
|
235
|
+
* assertType<
|
|
236
236
|
* Result<
|
|
237
237
|
* { readonly user: User; readonly profile: Profile },
|
|
238
238
|
* UserNotFoundError | ProfileNotFoundError
|
|
239
|
-
*
|
|
239
|
+
* >,
|
|
240
|
+
* typeof result
|
|
240
241
|
* >();
|
|
241
|
-
*
|
|
242
|
+
* assertOk(result, {
|
|
242
243
|
* user: { id: "user-1", profileId: "profile-1" },
|
|
243
244
|
* profile: { id: "profile-1" },
|
|
244
245
|
* });
|
|
@@ -253,10 +254,11 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
253
254
|
*
|
|
254
255
|
* {@link fetch} with a body mode already returns a plain value, so resilience is
|
|
255
256
|
* ordinary Task composition. Combine {@link timeout} and {@link retry} to bound
|
|
256
|
-
* each attempt and retry recoverable domain
|
|
257
|
+
* each attempt and retry recoverable domain errors:
|
|
257
258
|
*
|
|
258
259
|
* ```ts
|
|
259
260
|
* import {
|
|
261
|
+
* assertType,
|
|
260
262
|
* exponential,
|
|
261
263
|
* fetch,
|
|
262
264
|
* jitter,
|
|
@@ -277,8 +279,9 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
277
279
|
* jitter("100%")(maxDelay("20s")(take(2)(exponential("100ms")))),
|
|
278
280
|
* );
|
|
279
281
|
*
|
|
280
|
-
*
|
|
281
|
-
* Task<string, RetryTaskError<FetchError | TimeoutError
|
|
282
|
+
* assertType<
|
|
283
|
+
* Task<string, RetryTaskError<FetchError | TimeoutError>>,
|
|
284
|
+
* ReturnType<typeof fetchWithRetry>
|
|
282
285
|
* >();
|
|
283
286
|
* ```
|
|
284
287
|
*
|
|
@@ -287,7 +290,15 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
287
290
|
* Run composed Tasks with a `concurrency` option and {@link all}:
|
|
288
291
|
*
|
|
289
292
|
* ```ts
|
|
290
|
-
* import {
|
|
293
|
+
* import {
|
|
294
|
+
* assertEqual,
|
|
295
|
+
* assertOk,
|
|
296
|
+
* all,
|
|
297
|
+
* createRun,
|
|
298
|
+
* ok,
|
|
299
|
+
* sleep,
|
|
300
|
+
* type Task,
|
|
301
|
+
* } from "@evolu/common";
|
|
291
302
|
*
|
|
292
303
|
* await using run = createRun();
|
|
293
304
|
*
|
|
@@ -310,8 +321,8 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
310
321
|
*
|
|
311
322
|
* // At most 2 concurrent requests.
|
|
312
323
|
* const result = await run(all(urls, fetchUrl, { concurrency: 2 }));
|
|
313
|
-
*
|
|
314
|
-
*
|
|
324
|
+
* assertOk(result, urls);
|
|
325
|
+
* assertEqual(maxActiveRequests, 2);
|
|
315
326
|
* ```
|
|
316
327
|
*
|
|
317
328
|
* Task helpers compose Tasks; concurrency primitives are stateful objects that
|
|
@@ -343,7 +354,7 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
343
354
|
* resources, or services shared by all code running inside a Run.
|
|
344
355
|
*
|
|
345
356
|
* ```ts
|
|
346
|
-
* import { createRun, ok, type Task } from "@evolu/common";
|
|
357
|
+
* import { assertOk, createRun, ok, type Task } from "@evolu/common";
|
|
347
358
|
*
|
|
348
359
|
* interface GreetingFormatter {
|
|
349
360
|
* readonly format: (name: string) => string;
|
|
@@ -368,10 +379,10 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
368
379
|
* await using run = createRun({ greetingFormatter: formal });
|
|
369
380
|
*
|
|
370
381
|
* // Root dependencies are inherited.
|
|
371
|
-
*
|
|
382
|
+
* assertOk(await run(greet("Ada")), "Hello, Ada");
|
|
372
383
|
*
|
|
373
384
|
* // Child-specific dependencies replace the root's custom dependencies.
|
|
374
|
-
*
|
|
385
|
+
* assertOk(
|
|
375
386
|
* await run(greet("Ada"), { greetingFormatter: casual }),
|
|
376
387
|
* "Hi, Ada",
|
|
377
388
|
* );
|
|
@@ -422,7 +433,15 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
422
433
|
* `undefined` should represent valid absence, not failure.
|
|
423
434
|
*
|
|
424
435
|
* ```ts
|
|
425
|
-
* import {
|
|
436
|
+
* import {
|
|
437
|
+
* assertEqual,
|
|
438
|
+
* assertFalse,
|
|
439
|
+
* assertTrue,
|
|
440
|
+
* createRun,
|
|
441
|
+
* ok,
|
|
442
|
+
* type Task,
|
|
443
|
+
* type Typed,
|
|
444
|
+
* } from "@evolu/common";
|
|
426
445
|
*
|
|
427
446
|
* interface Socket extends AsyncDisposable {
|
|
428
447
|
* readonly send: (message: string) => string;
|
|
@@ -436,8 +455,9 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
436
455
|
* const openSocket: Task<Socket, ConnectionFailedError> = () =>
|
|
437
456
|
* ok({
|
|
438
457
|
* send: (message) => message,
|
|
439
|
-
* [Symbol.asyncDispose]:
|
|
458
|
+
* [Symbol.asyncDispose]: () => {
|
|
440
459
|
* socketDisposed = true;
|
|
460
|
+
* return Promise.resolve();
|
|
441
461
|
* },
|
|
442
462
|
* });
|
|
443
463
|
*
|
|
@@ -469,16 +489,16 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
469
489
|
*
|
|
470
490
|
* await using run = createRun();
|
|
471
491
|
* const result = await run(createConnection);
|
|
472
|
-
*
|
|
473
|
-
*
|
|
474
|
-
*
|
|
492
|
+
* assertTrue(result.ok);
|
|
493
|
+
* assertFalse(socketDisposed);
|
|
494
|
+
* assertEqual(result.value.send("hello"), "hello");
|
|
475
495
|
* await result.value[Symbol.asyncDispose]();
|
|
476
|
-
*
|
|
496
|
+
* assertTrue(socketDisposed);
|
|
477
497
|
* ```
|
|
478
498
|
*
|
|
479
|
-
* Use {@link Run.ok} with `await using` when
|
|
480
|
-
* disposable value. Use {@link acquireUseRelease} when acquisition and
|
|
481
|
-
* are separate
|
|
499
|
+
* Use {@link Run.ok} with `await using` when a Task whose error type is `never`
|
|
500
|
+
* returns a disposable value. Use {@link acquireUseRelease} when acquisition and
|
|
501
|
+
* release are separate steps rather than a disposable value.
|
|
482
502
|
*
|
|
483
503
|
* ## Awaitable
|
|
484
504
|
*
|
|
@@ -491,7 +511,7 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
491
511
|
*
|
|
492
512
|
* A Task is an async ownership boundary, not a general unit of program
|
|
493
513
|
* decomposition. Calling `run(task)` always creates a child Run by design. Use
|
|
494
|
-
*
|
|
514
|
+
* a plain async function when it does not need its own Run.
|
|
495
515
|
*
|
|
496
516
|
* A unified sync/async effect API is technically possible. It can detect
|
|
497
517
|
* Promise-like values with {@link isPromiseLike}, dispose synchronous resources
|
|
@@ -509,7 +529,7 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
509
529
|
* code performs effects with the result. For example, a pure function can
|
|
510
530
|
* accept a {@link RandomNumber} value instead of depending on {@link Random}.
|
|
511
531
|
*
|
|
512
|
-
* Large CPU-bound
|
|
532
|
+
* Large CPU-bound computations, such as parsing large JSON, sorting millions of
|
|
513
533
|
* items, or complex cryptography, belong in a worker. Model the asynchronous
|
|
514
534
|
* call to that worker as a Task so Run can provide timeout, abort, cleanup, and
|
|
515
535
|
* monitoring.
|
|
@@ -569,10 +589,10 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
569
589
|
* ### What should Task code do with defects?
|
|
570
590
|
*
|
|
571
591
|
* Nothing. Once a defect reaches the {@link Run}, it is too late: the root Run
|
|
572
|
-
* panics, running Tasks are aborted, and the Run tree shuts down.
|
|
573
|
-
*
|
|
574
|
-
*
|
|
575
|
-
*
|
|
592
|
+
* panics, running Tasks are aborted, and the Run tree shuts down. Use
|
|
593
|
+
* {@link trySync} or {@link tryAsync} to turn recoverable exceptions and Promise
|
|
594
|
+
* rejections into typed {@link Result} errors. Let unrecoverable failures
|
|
595
|
+
* propagate as defects.
|
|
576
596
|
*
|
|
577
597
|
* ### Why does a defect panic the whole Run tree?
|
|
578
598
|
*
|
|
@@ -630,7 +650,7 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
630
650
|
* each iteration reuses the same stack frame:
|
|
631
651
|
*
|
|
632
652
|
* ```ts
|
|
633
|
-
* import { createRun, ok, type Task } from "@evolu/common";
|
|
653
|
+
* import { assertOk, createRun, ok, type Task } from "@evolu/common";
|
|
634
654
|
*
|
|
635
655
|
* interface TreeNode {
|
|
636
656
|
* readonly value: string;
|
|
@@ -654,7 +674,7 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
654
674
|
* };
|
|
655
675
|
*
|
|
656
676
|
* await using run = createRun();
|
|
657
|
-
*
|
|
677
|
+
* assertOk(
|
|
658
678
|
* await run(
|
|
659
679
|
* visitTree({
|
|
660
680
|
* value: "root",
|
|
@@ -671,13 +691,6 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
671
691
|
* periodically await {@link yieldNow} for cooperative scheduling, and move
|
|
672
692
|
* CPU-bound work to a worker.
|
|
673
693
|
*
|
|
674
|
-
* ### Should a Task be called directly?
|
|
675
|
-
*
|
|
676
|
-
* Only inside Task internals that explicitly require same-Run execution. A
|
|
677
|
-
* direct call, `task(run)`, uses the current Run instead of creating a child
|
|
678
|
-
* Run, so it bypasses child lifetime tracking, scheduling metadata, and child
|
|
679
|
-
* disposal boundaries. Application code should use `run(task)`.
|
|
680
|
-
*
|
|
681
694
|
* ### Where are fork and join?
|
|
682
695
|
*
|
|
683
696
|
* Calling `run(task)` is fork: it starts a child Task and returns a
|
|
@@ -852,7 +865,7 @@ export const createRunDefaultDeps = () => {
|
|
|
852
865
|
* ### Example
|
|
853
866
|
*
|
|
854
867
|
* ```ts
|
|
855
|
-
* import { createRun, ok, type Task } from "@evolu/common";
|
|
868
|
+
* import { assertOk, createRun, ok, type Task } from "@evolu/common";
|
|
856
869
|
*
|
|
857
870
|
* interface ConfigDep {
|
|
858
871
|
* readonly config: { readonly apiUrl: string };
|
|
@@ -864,7 +877,7 @@ export const createRunDefaultDeps = () => {
|
|
|
864
877
|
* await using run = createRun({
|
|
865
878
|
* config: { apiUrl: "https://api.example.com" },
|
|
866
879
|
* });
|
|
867
|
-
*
|
|
880
|
+
* assertOk(await run(loadApiUrl), "https://api.example.com");
|
|
868
881
|
* ```
|
|
869
882
|
*
|
|
870
883
|
* @group Run
|
|
@@ -1128,7 +1141,6 @@ const createRunInternal = (deps, parent, rootRun, taskMeta) => {
|
|
|
1128
1141
|
if (taskMeta?.priority && scheduler?.postTask) {
|
|
1129
1142
|
result = await scheduler.postTask(() => {
|
|
1130
1143
|
startSignal.throwIfAborted();
|
|
1131
|
-
// eslint-disable-next-line evolu/no-direct-task-call -- The executor invokes the Task with its child Run.
|
|
1132
1144
|
return task(taskRun);
|
|
1133
1145
|
}, {
|
|
1134
1146
|
priority: taskMeta.priority,
|
|
@@ -1137,7 +1149,6 @@ const createRunInternal = (deps, parent, rootRun, taskMeta) => {
|
|
|
1137
1149
|
}
|
|
1138
1150
|
else {
|
|
1139
1151
|
startSignal.throwIfAborted();
|
|
1140
|
-
// eslint-disable-next-line evolu/no-direct-task-call -- The executor invokes the Task with its child Run.
|
|
1141
1152
|
result = await task(taskRun);
|
|
1142
1153
|
}
|
|
1143
1154
|
// Full Result validation is dev-only; production checks only the
|
|
@@ -1286,7 +1297,6 @@ const withTaskMeta = (meta) => (task) => {
|
|
|
1286
1297
|
const taskInternal = task;
|
|
1287
1298
|
assert(meta.abortBehavior === undefined ||
|
|
1288
1299
|
taskInternal[taskMetaSymbol]?.abortBehavior === undefined, "abort behavior helpers cannot wrap the same Task");
|
|
1289
|
-
// eslint-disable-next-line evolu/no-direct-task-call -- Preserve the wrapped Task's child Run.
|
|
1290
1300
|
const wrapped = (run) => task(run);
|
|
1291
1301
|
const taskMeta = taskInternal[taskMetaSymbol];
|
|
1292
1302
|
wrapped[taskMetaSymbol] = taskMeta ? { ...taskMeta, ...meta } : meta;
|
|
@@ -1358,7 +1368,7 @@ const mapInput = (input, fn) => Array.isArray(input)
|
|
|
1358
1368
|
* This helper is a callback bridge. If `reject` forwards an Error created in a
|
|
1359
1369
|
* separate async chain, V8 cannot reconstruct the caller's zero-cost async
|
|
1360
1370
|
* stack through this bridge. Prefer native promise APIs and `await` when the
|
|
1361
|
-
* wrapped
|
|
1371
|
+
* wrapped API already returns a Promise.
|
|
1362
1372
|
*
|
|
1363
1373
|
* One-shot settlement applies only to `resolve` and `reject`. A synchronous
|
|
1364
1374
|
* throw from the setup function is a defect that panics the Run tree even after
|
|
@@ -1383,14 +1393,23 @@ const mapInput = (input, fn) => Array.isArray(input)
|
|
|
1383
1393
|
* ### Example
|
|
1384
1394
|
*
|
|
1385
1395
|
* ```ts
|
|
1386
|
-
* import {
|
|
1396
|
+
* import {
|
|
1397
|
+
* assertEqual,
|
|
1398
|
+
* assertOk,
|
|
1399
|
+
* callback,
|
|
1400
|
+
* createRun,
|
|
1401
|
+
* ok,
|
|
1402
|
+
* type Task,
|
|
1403
|
+
* } from "@evolu/common";
|
|
1387
1404
|
*
|
|
1388
1405
|
* const listeners = new Set<(message: string) => void>();
|
|
1389
1406
|
* const subscribe = (
|
|
1390
1407
|
* listener: (message: string) => void,
|
|
1391
1408
|
* ): (() => void) => {
|
|
1392
1409
|
* listeners.add(listener);
|
|
1393
|
-
* return () =>
|
|
1410
|
+
* return () => {
|
|
1411
|
+
* listeners.delete(listener);
|
|
1412
|
+
* };
|
|
1394
1413
|
* };
|
|
1395
1414
|
* const nextMessage: Task<string> = callback(({ resolve }) =>
|
|
1396
1415
|
* subscribe((message) => resolve(ok(message))),
|
|
@@ -1398,11 +1417,11 @@ const mapInput = (input, fn) => Array.isArray(input)
|
|
|
1398
1417
|
*
|
|
1399
1418
|
* await using run = createRun();
|
|
1400
1419
|
* const fiber = run(nextMessage);
|
|
1401
|
-
*
|
|
1420
|
+
* assertEqual(listeners.size, 1);
|
|
1402
1421
|
* for (const listener of listeners) listener("ready");
|
|
1403
|
-
*
|
|
1422
|
+
* assertOk(await fiber, "ready");
|
|
1404
1423
|
* // The callback cleanup unsubscribes after settlement.
|
|
1405
|
-
*
|
|
1424
|
+
* assertEqual(listeners.size, 0);
|
|
1406
1425
|
* ```
|
|
1407
1426
|
*
|
|
1408
1427
|
* @group Interop
|
|
@@ -1426,10 +1445,10 @@ export const callback = (fn) => (run) => {
|
|
|
1426
1445
|
* ### Example
|
|
1427
1446
|
*
|
|
1428
1447
|
* ```ts
|
|
1429
|
-
* import { createRun, sleep } from "@evolu/common";
|
|
1448
|
+
* import { assertOk, createRun, sleep } from "@evolu/common";
|
|
1430
1449
|
*
|
|
1431
1450
|
* await using run = createRun();
|
|
1432
|
-
*
|
|
1451
|
+
* assertOk(await run(sleep("1ms")), undefined);
|
|
1433
1452
|
* ```
|
|
1434
1453
|
*
|
|
1435
1454
|
* @group Timing
|
|
@@ -1451,6 +1470,8 @@ export const sleep = (duration) => callback(({ run: { deps }, resolve }) => {
|
|
|
1451
1470
|
*
|
|
1452
1471
|
* ```ts
|
|
1453
1472
|
* import {
|
|
1473
|
+
* assertErr,
|
|
1474
|
+
* assertType,
|
|
1454
1475
|
* createRun,
|
|
1455
1476
|
* timeout,
|
|
1456
1477
|
* timeoutError,
|
|
@@ -1462,8 +1483,8 @@ export const sleep = (duration) => callback(({ run: { deps }, resolve }) => {
|
|
|
1462
1483
|
* await using run = createRun();
|
|
1463
1484
|
*
|
|
1464
1485
|
* const result = await run(timeout(waitForAbort, "1ms"));
|
|
1465
|
-
*
|
|
1466
|
-
*
|
|
1486
|
+
* assertType<Result<never, TimeoutError>, typeof result>();
|
|
1487
|
+
* assertErr(result, timeoutError);
|
|
1467
1488
|
* ```
|
|
1468
1489
|
*
|
|
1469
1490
|
* @group Timing
|
|
@@ -1510,6 +1531,8 @@ export const timeoutError = { type: "TimeoutError" };
|
|
|
1510
1531
|
*
|
|
1511
1532
|
* ```ts
|
|
1512
1533
|
* import {
|
|
1534
|
+
* assertErr,
|
|
1535
|
+
* assertType,
|
|
1513
1536
|
* createRun,
|
|
1514
1537
|
* err,
|
|
1515
1538
|
* recurs,
|
|
@@ -1529,10 +1552,11 @@ export const timeoutError = { type: "TimeoutError" };
|
|
|
1529
1552
|
*
|
|
1530
1553
|
* await using run = createRun();
|
|
1531
1554
|
* const result = await run(fetchWithRetry);
|
|
1532
|
-
*
|
|
1533
|
-
* Result<string, RetryTaskError<ServiceUnavailableError
|
|
1555
|
+
* assertType<
|
|
1556
|
+
* Result<string, RetryTaskError<ServiceUnavailableError>>,
|
|
1557
|
+
* typeof result
|
|
1534
1558
|
* >();
|
|
1535
|
-
*
|
|
1559
|
+
* assertErr(result, {
|
|
1536
1560
|
* type: "RetryError",
|
|
1537
1561
|
* attempts: 3,
|
|
1538
1562
|
* lastError: { type: "ServiceUnavailable" },
|
|
@@ -1543,6 +1567,7 @@ export const timeoutError = { type: "TimeoutError" };
|
|
|
1543
1567
|
*
|
|
1544
1568
|
* ```ts
|
|
1545
1569
|
* import {
|
|
1570
|
+
* assertErr,
|
|
1546
1571
|
* createRun,
|
|
1547
1572
|
* err,
|
|
1548
1573
|
* recurs,
|
|
@@ -1565,7 +1590,8 @@ export const timeoutError = { type: "TimeoutError" };
|
|
|
1565
1590
|
* });
|
|
1566
1591
|
*
|
|
1567
1592
|
* await using run = createRun();
|
|
1568
|
-
*
|
|
1593
|
+
* const result = await run(fetchWithRetry);
|
|
1594
|
+
* assertErr(result, {
|
|
1569
1595
|
* type: "RetryError",
|
|
1570
1596
|
* attempts: 1,
|
|
1571
1597
|
* lastError: { type: "PermanentFailure" },
|
|
@@ -1621,7 +1647,15 @@ export const retry = (task, schedule, { shouldRetry = constTrue, onRetry, } = {}
|
|
|
1621
1647
|
* ### Repeating successes
|
|
1622
1648
|
*
|
|
1623
1649
|
* ```ts
|
|
1624
|
-
* import {
|
|
1650
|
+
* import {
|
|
1651
|
+
* assertEqual,
|
|
1652
|
+
* assertOk,
|
|
1653
|
+
* createRun,
|
|
1654
|
+
* ok,
|
|
1655
|
+
* recurs,
|
|
1656
|
+
* repeat,
|
|
1657
|
+
* type Task,
|
|
1658
|
+
* } from "@evolu/common";
|
|
1625
1659
|
*
|
|
1626
1660
|
* let attempts = 0;
|
|
1627
1661
|
* const checkStatus: Task<string> = () => {
|
|
@@ -1632,14 +1666,16 @@ export const retry = (task, schedule, { shouldRetry = constTrue, onRetry, } = {}
|
|
|
1632
1666
|
* const poll = repeat(checkStatus, recurs(3));
|
|
1633
1667
|
*
|
|
1634
1668
|
* await using run = createRun();
|
|
1635
|
-
*
|
|
1636
|
-
*
|
|
1669
|
+
* assertOk(await run(poll), "pending");
|
|
1670
|
+
* assertEqual(attempts, 4);
|
|
1637
1671
|
* ```
|
|
1638
1672
|
*
|
|
1639
1673
|
* ### Stopping with Done
|
|
1640
1674
|
*
|
|
1641
1675
|
* ```ts
|
|
1642
1676
|
* import {
|
|
1677
|
+
* assertErr,
|
|
1678
|
+
* assertEqual,
|
|
1643
1679
|
* createRun,
|
|
1644
1680
|
* done,
|
|
1645
1681
|
* err,
|
|
@@ -1662,8 +1698,8 @@ export const retry = (task, schedule, { shouldRetry = constTrue, onRetry, } = {}
|
|
|
1662
1698
|
*
|
|
1663
1699
|
* await using run = createRun();
|
|
1664
1700
|
* const result = await run(repeat(processQueue, spaced("1ms")));
|
|
1665
|
-
*
|
|
1666
|
-
*
|
|
1701
|
+
* assertErr(result, done());
|
|
1702
|
+
* assertEqual(queue, []);
|
|
1667
1703
|
* ```
|
|
1668
1704
|
*
|
|
1669
1705
|
* @group Repetition
|
|
@@ -1709,6 +1745,9 @@ export const repeat = (task, schedule, { shouldRepeat = constTrue, onRepeat } =
|
|
|
1709
1745
|
*
|
|
1710
1746
|
* ```ts
|
|
1711
1747
|
* import {
|
|
1748
|
+
* assertOk,
|
|
1749
|
+
* assertType,
|
|
1750
|
+
* assertTrue,
|
|
1712
1751
|
* any,
|
|
1713
1752
|
* createRun,
|
|
1714
1753
|
* err,
|
|
@@ -1732,11 +1771,9 @@ export const repeat = (task, schedule, { shouldRepeat = constTrue, onRepeat } =
|
|
|
1732
1771
|
* await using run = createRun();
|
|
1733
1772
|
* const result = await run(any([unavailable, fallback]));
|
|
1734
1773
|
*
|
|
1735
|
-
*
|
|
1736
|
-
*
|
|
1737
|
-
*
|
|
1738
|
-
* expectOk(result, "fallback");
|
|
1739
|
-
* expect(fallbackStarted).toBe(true);
|
|
1774
|
+
* assertType<Result<string, ServiceUnavailableError>, typeof result>();
|
|
1775
|
+
* assertOk(result, "fallback");
|
|
1776
|
+
* assertTrue(fallbackStarted);
|
|
1740
1777
|
* ```
|
|
1741
1778
|
*
|
|
1742
1779
|
* @group Racing
|
|
@@ -1787,6 +1824,7 @@ export const any = (tasks, options) => async (run) => {
|
|
|
1787
1824
|
*
|
|
1788
1825
|
* ```ts
|
|
1789
1826
|
* import {
|
|
1827
|
+
* assertOk,
|
|
1790
1828
|
* createRun,
|
|
1791
1829
|
* isNonEmptyArray,
|
|
1792
1830
|
* ok,
|
|
@@ -1798,7 +1836,7 @@ export const any = (tasks, options) => async (run) => {
|
|
|
1798
1836
|
* await using run = createRun();
|
|
1799
1837
|
* if (isNonEmptyArray(tasks)) {
|
|
1800
1838
|
* const result = await run(race(tasks));
|
|
1801
|
-
*
|
|
1839
|
+
* assertOk(result, "first");
|
|
1802
1840
|
* }
|
|
1803
1841
|
* ```
|
|
1804
1842
|
*
|
|
@@ -1806,6 +1844,9 @@ export const any = (tasks, options) => async (run) => {
|
|
|
1806
1844
|
*
|
|
1807
1845
|
* ```ts
|
|
1808
1846
|
* import {
|
|
1847
|
+
* assertFalse,
|
|
1848
|
+
* assertOk,
|
|
1849
|
+
* assertType,
|
|
1809
1850
|
* createRun,
|
|
1810
1851
|
* ok,
|
|
1811
1852
|
* race,
|
|
@@ -1827,9 +1868,9 @@ export const any = (tasks, options) => async (run) => {
|
|
|
1827
1868
|
* // Input order does not matter: the first settled Result wins, and the
|
|
1828
1869
|
* // still-running loser is aborted.
|
|
1829
1870
|
* const result = await run(race([slow, fast]));
|
|
1830
|
-
*
|
|
1831
|
-
*
|
|
1832
|
-
*
|
|
1871
|
+
* assertType<Result<string>, typeof result>();
|
|
1872
|
+
* assertOk(result, "fast");
|
|
1873
|
+
* assertFalse(slowCompleted);
|
|
1833
1874
|
* ```
|
|
1834
1875
|
*
|
|
1835
1876
|
* @group Racing
|
|
@@ -1860,6 +1901,8 @@ export const race = (tasks) => async (run) => {
|
|
|
1860
1901
|
*
|
|
1861
1902
|
* ```ts
|
|
1862
1903
|
* import {
|
|
1904
|
+
* assertFalse,
|
|
1905
|
+
* assertOk,
|
|
1863
1906
|
* createRun,
|
|
1864
1907
|
* err,
|
|
1865
1908
|
* firstN,
|
|
@@ -1890,8 +1933,8 @@ export const race = (tasks) => async (run) => {
|
|
|
1890
1933
|
*
|
|
1891
1934
|
* // Errs do not count. After two Ok values settle, the slow Task is aborted.
|
|
1892
1935
|
* const result = await run(firstN(tasks, 2, { concurrency: 4 }));
|
|
1893
|
-
*
|
|
1894
|
-
*
|
|
1936
|
+
* assertOk(result, ["fast-1", "fast-2"]);
|
|
1937
|
+
* assertFalse(slowCompleted);
|
|
1895
1938
|
* ```
|
|
1896
1939
|
*
|
|
1897
1940
|
* @group Racing
|
|
@@ -1922,6 +1965,8 @@ export const firstN = (tasks, count, options) => async (run) => {
|
|
|
1922
1965
|
*
|
|
1923
1966
|
* ```ts
|
|
1924
1967
|
* import {
|
|
1968
|
+
* assertFalse,
|
|
1969
|
+
* assertOk,
|
|
1925
1970
|
* createRun,
|
|
1926
1971
|
* err,
|
|
1927
1972
|
* firstNSettled,
|
|
@@ -1947,11 +1992,11 @@ export const firstN = (tasks, count, options) => async (run) => {
|
|
|
1947
1992
|
*
|
|
1948
1993
|
* // Err and Ok both count, and Results use settlement order.
|
|
1949
1994
|
* const result = await run(firstNSettled(tasks, 2, { concurrency: 3 }));
|
|
1950
|
-
*
|
|
1995
|
+
* assertOk(result, [
|
|
1951
1996
|
* { ok: false, error: { type: "ServiceUnavailable" } },
|
|
1952
1997
|
* { ok: true, value: "fast" },
|
|
1953
1998
|
* ]);
|
|
1954
|
-
*
|
|
1999
|
+
* assertFalse(slowCompleted);
|
|
1955
2000
|
* ```
|
|
1956
2001
|
*
|
|
1957
2002
|
* @group Racing
|
|
@@ -1996,6 +2041,9 @@ export const firstNSettled = (tasks, count, options) => async (run) => {
|
|
|
1996
2041
|
*
|
|
1997
2042
|
* ```ts
|
|
1998
2043
|
* import {
|
|
2044
|
+
* assertEqual,
|
|
2045
|
+
* assertFalse,
|
|
2046
|
+
* assertOk,
|
|
1999
2047
|
* createRun,
|
|
2000
2048
|
* each,
|
|
2001
2049
|
* err,
|
|
@@ -2031,9 +2079,9 @@ export const firstNSettled = (tasks, count, options) => async (run) => {
|
|
|
2031
2079
|
* ),
|
|
2032
2080
|
* );
|
|
2033
2081
|
*
|
|
2034
|
-
*
|
|
2035
|
-
*
|
|
2036
|
-
*
|
|
2082
|
+
* assertOk(result, undefined);
|
|
2083
|
+
* assertEqual(first, ["fast", 2]);
|
|
2084
|
+
* assertFalse(slowCompleted);
|
|
2037
2085
|
* ```
|
|
2038
2086
|
*
|
|
2039
2087
|
* `onResult` is a synchronous scheduling decision, not a place to do work. It
|
|
@@ -2078,7 +2126,7 @@ export const each = (tasks, onResult, options = {}) => async (run) => {
|
|
|
2078
2126
|
const index = nextIndex;
|
|
2079
2127
|
nextIndex += 1;
|
|
2080
2128
|
const result = await run(tasks[index]);
|
|
2081
|
-
//
|
|
2129
|
+
// stopped can flip across the await via sibling workers.
|
|
2082
2130
|
if (stopped)
|
|
2083
2131
|
break;
|
|
2084
2132
|
run.signal.throwIfAborted();
|
|
@@ -2097,6 +2145,7 @@ export const each = (tasks, onResult, options = {}) => async (run) => {
|
|
|
2097
2145
|
active -= 1;
|
|
2098
2146
|
if (active === 0)
|
|
2099
2147
|
wake.resolve();
|
|
2148
|
+
// oxlint-disable-next-line typescript/return-await -- StackTrace.test.ts measures this direct await edge in the worker topology.
|
|
2100
2149
|
return await parked;
|
|
2101
2150
|
};
|
|
2102
2151
|
await Promise.race([
|
|
@@ -2129,13 +2178,19 @@ export const each = (tasks, onResult, options = {}) => async (run) => {
|
|
|
2129
2178
|
* ### Example
|
|
2130
2179
|
*
|
|
2131
2180
|
* ```ts
|
|
2132
|
-
* import {
|
|
2181
|
+
* import {
|
|
2182
|
+
* assertOk,
|
|
2183
|
+
* createRun,
|
|
2184
|
+
* ok,
|
|
2185
|
+
* prioritized,
|
|
2186
|
+
* type Task,
|
|
2187
|
+
* } from "@evolu/common";
|
|
2133
2188
|
*
|
|
2134
2189
|
* const rebuildSearchIndex: Task<string> = () => ok("indexed");
|
|
2135
2190
|
* const backgroundIndexing = prioritized("background", rebuildSearchIndex);
|
|
2136
2191
|
*
|
|
2137
2192
|
* await using run = createRun();
|
|
2138
|
-
*
|
|
2193
|
+
* assertOk(await run(backgroundIndexing), "indexed");
|
|
2139
2194
|
* ```
|
|
2140
2195
|
*
|
|
2141
2196
|
* @group Scheduling
|
|
@@ -2155,7 +2210,13 @@ export const prioritized = (priority, task) => withTaskMeta({ priority })(task);
|
|
|
2155
2210
|
* ### Example
|
|
2156
2211
|
*
|
|
2157
2212
|
* ```ts
|
|
2158
|
-
* import {
|
|
2213
|
+
* import {
|
|
2214
|
+
* assertOk,
|
|
2215
|
+
* createRun,
|
|
2216
|
+
* ok,
|
|
2217
|
+
* yieldNow,
|
|
2218
|
+
* type Task,
|
|
2219
|
+
* } from "@evolu/common";
|
|
2159
2220
|
*
|
|
2160
2221
|
* const sumTo =
|
|
2161
2222
|
* (count: number): Task<number> =>
|
|
@@ -2171,7 +2232,7 @@ export const prioritized = (priority, task) => withTaskMeta({ priority })(task);
|
|
|
2171
2232
|
* };
|
|
2172
2233
|
*
|
|
2173
2234
|
* await using run = createRun();
|
|
2174
|
-
*
|
|
2235
|
+
* assertOk(await run(sumTo(1001)), 500500);
|
|
2175
2236
|
* ```
|
|
2176
2237
|
*
|
|
2177
2238
|
* @group Scheduling
|
|
@@ -2197,7 +2258,6 @@ export const yieldNow = async (run) => {
|
|
|
2197
2258
|
run.signal.throwIfAborted();
|
|
2198
2259
|
return ok();
|
|
2199
2260
|
};
|
|
2200
|
-
// Abortability
|
|
2201
2261
|
/**
|
|
2202
2262
|
* Waits until the current {@link Run} aborts, then rejects with its
|
|
2203
2263
|
* {@link AbortError}.
|
|
@@ -2209,6 +2269,10 @@ export const yieldNow = async (run) => {
|
|
|
2209
2269
|
*
|
|
2210
2270
|
* ```ts
|
|
2211
2271
|
* import {
|
|
2272
|
+
* assertEqual,
|
|
2273
|
+
* assertFalse,
|
|
2274
|
+
* assertType,
|
|
2275
|
+
* assertTrue,
|
|
2212
2276
|
* AbortError,
|
|
2213
2277
|
* createRun,
|
|
2214
2278
|
* ok,
|
|
@@ -2225,23 +2289,22 @@ export const yieldNow = async (run) => {
|
|
|
2225
2289
|
* const serverStarted = Promise.withResolvers<void>();
|
|
2226
2290
|
* let serverStopped = false;
|
|
2227
2291
|
* const startServer: Task<Server, never, ServerDep> = (run) => {
|
|
2228
|
-
*
|
|
2292
|
+
* assertEqual(run.deps.port, 3000);
|
|
2229
2293
|
* serverStarted.resolve();
|
|
2230
2294
|
* return ok({
|
|
2231
|
-
* [Symbol.asyncDispose]:
|
|
2295
|
+
* [Symbol.asyncDispose]: () => {
|
|
2232
2296
|
* serverStopped = true;
|
|
2297
|
+
* return Promise.resolve();
|
|
2233
2298
|
* },
|
|
2234
2299
|
* });
|
|
2235
2300
|
* };
|
|
2236
2301
|
*
|
|
2237
2302
|
* const serve = (): Task<never, never, ServerDep> => async (run) => {
|
|
2238
|
-
* await using
|
|
2303
|
+
* await using _ = await run.ok(startServer);
|
|
2239
2304
|
* return await run(waitForAbort);
|
|
2240
2305
|
* };
|
|
2241
2306
|
*
|
|
2242
|
-
*
|
|
2243
|
-
* Task<never, never, ServerDep>
|
|
2244
|
-
* >();
|
|
2307
|
+
* assertType<Task<never, never, ServerDep>, ReturnType<typeof serve>>();
|
|
2245
2308
|
*
|
|
2246
2309
|
* await using run = createRun();
|
|
2247
2310
|
* const fiber = run.abortable(serve(), { port: 3000 });
|
|
@@ -2249,9 +2312,9 @@ export const yieldNow = async (run) => {
|
|
|
2249
2312
|
* fiber.abort();
|
|
2250
2313
|
*
|
|
2251
2314
|
* const result = await fiber;
|
|
2252
|
-
*
|
|
2253
|
-
*
|
|
2254
|
-
*
|
|
2315
|
+
* assertFalse(result.ok);
|
|
2316
|
+
* assertTrue(AbortError.is(result.error));
|
|
2317
|
+
* assertTrue(serverStopped);
|
|
2255
2318
|
* ```
|
|
2256
2319
|
*
|
|
2257
2320
|
* @group Abortability
|
|
@@ -2281,8 +2344,8 @@ export const waitForAbort = async (run) => {
|
|
|
2281
2344
|
* execution. The daemon Task continues under root Run ownership until it
|
|
2282
2345
|
* settles, observes abort, or the root Run is disposed.
|
|
2283
2346
|
*
|
|
2284
|
-
* This is not a replacement for direct {@link AbortSignal} support in
|
|
2285
|
-
*
|
|
2347
|
+
* This is not a replacement for direct {@link AbortSignal} support in APIs that
|
|
2348
|
+
* can observe abort, such as {@link fetch}, timers that accept a signal, or
|
|
2286
2349
|
* callback APIs that accept a signal. Use it as an escape hatch for Tasks that
|
|
2287
2350
|
* ignore abort when an abort request must stop waiting immediately.
|
|
2288
2351
|
*
|
|
@@ -2315,6 +2378,9 @@ export const waitForAbort = async (run) => {
|
|
|
2315
2378
|
*
|
|
2316
2379
|
* ```ts
|
|
2317
2380
|
* import {
|
|
2381
|
+
* assertEqual,
|
|
2382
|
+
* assertFalse,
|
|
2383
|
+
* assertTrue,
|
|
2318
2384
|
* createRun,
|
|
2319
2385
|
* daemon,
|
|
2320
2386
|
* ok,
|
|
@@ -2335,18 +2401,24 @@ export const waitForAbort = async (run) => {
|
|
|
2335
2401
|
* {
|
|
2336
2402
|
* await using run = createRun();
|
|
2337
2403
|
* const result = await run(timeout(daemon(taskNotUsingAbort), "1ms"));
|
|
2338
|
-
*
|
|
2339
|
-
*
|
|
2340
|
-
*
|
|
2404
|
+
* assertFalse(result.ok);
|
|
2405
|
+
* assertEqual(result.error.type, "TimeoutError");
|
|
2406
|
+
* assertFalse(finished);
|
|
2341
2407
|
* finishTask();
|
|
2342
2408
|
* }
|
|
2343
|
-
*
|
|
2409
|
+
* assertTrue(finished);
|
|
2344
2410
|
* ```
|
|
2345
2411
|
*
|
|
2346
|
-
* Promise-
|
|
2412
|
+
* Promise-returning functions should be called inside the Task, not before it.
|
|
2347
2413
|
*
|
|
2348
2414
|
* ```ts
|
|
2349
|
-
* import {
|
|
2415
|
+
* import {
|
|
2416
|
+
* assertOk,
|
|
2417
|
+
* createRun,
|
|
2418
|
+
* ok,
|
|
2419
|
+
* type Result,
|
|
2420
|
+
* type Task,
|
|
2421
|
+
* } from "@evolu/common";
|
|
2350
2422
|
*
|
|
2351
2423
|
* type ResultValue = string;
|
|
2352
2424
|
* const createPromiseReturningResult = (): Promise<Result<ResultValue>> =>
|
|
@@ -2355,14 +2427,20 @@ export const waitForAbort = async (run) => {
|
|
|
2355
2427
|
* const task: Task<ResultValue> = () => createPromiseReturningResult();
|
|
2356
2428
|
*
|
|
2357
2429
|
* await using run = createRun();
|
|
2358
|
-
*
|
|
2430
|
+
* assertOk(await run(task), "value");
|
|
2359
2431
|
* ```
|
|
2360
2432
|
*
|
|
2361
2433
|
* Do not reuse an already-running Promise. It started outside the Task, so the
|
|
2362
2434
|
* Run cannot own its lifetime or request abort before it begins.
|
|
2363
2435
|
*
|
|
2364
2436
|
* ```ts
|
|
2365
|
-
* import {
|
|
2437
|
+
* import {
|
|
2438
|
+
* assertType,
|
|
2439
|
+
* assertTrue,
|
|
2440
|
+
* ok,
|
|
2441
|
+
* type Result,
|
|
2442
|
+
* type Task,
|
|
2443
|
+
* } from "@evolu/common";
|
|
2366
2444
|
*
|
|
2367
2445
|
* type ResultValue = string;
|
|
2368
2446
|
* let promiseStarted = false;
|
|
@@ -2377,8 +2455,8 @@ export const waitForAbort = async (run) => {
|
|
|
2377
2455
|
* const promise = createPromiseReturningResult();
|
|
2378
2456
|
* const task: Task<ResultValue> = () => promise;
|
|
2379
2457
|
*
|
|
2380
|
-
*
|
|
2381
|
-
*
|
|
2458
|
+
* assertTrue(promiseStarted);
|
|
2459
|
+
* assertType<Task<ResultValue>, typeof task>();
|
|
2382
2460
|
* ```
|
|
2383
2461
|
*
|
|
2384
2462
|
* @group Lifetime
|
|
@@ -2425,14 +2503,21 @@ export const daemon = (task) => async (run) => {
|
|
|
2425
2503
|
* ### Example
|
|
2426
2504
|
*
|
|
2427
2505
|
* ```ts
|
|
2428
|
-
* import {
|
|
2506
|
+
* import {
|
|
2507
|
+
* assertFalse,
|
|
2508
|
+
* assertOk,
|
|
2509
|
+
* createRun,
|
|
2510
|
+
* ok,
|
|
2511
|
+
* unabortable,
|
|
2512
|
+
* type Task,
|
|
2513
|
+
* } from "@evolu/common";
|
|
2429
2514
|
*
|
|
2430
2515
|
* const commitStarted = Promise.withResolvers<void>();
|
|
2431
2516
|
* const finishCommit = Promise.withResolvers<void>();
|
|
2432
2517
|
* const commit: Task<string> = unabortable(async (run) => {
|
|
2433
2518
|
* commitStarted.resolve();
|
|
2434
2519
|
* await finishCommit.promise;
|
|
2435
|
-
*
|
|
2520
|
+
* assertFalse(run.signal.aborted);
|
|
2436
2521
|
* return ok("committed");
|
|
2437
2522
|
* });
|
|
2438
2523
|
*
|
|
@@ -2442,7 +2527,7 @@ export const daemon = (task) => async (run) => {
|
|
|
2442
2527
|
* fiber.abort();
|
|
2443
2528
|
* finishCommit.resolve();
|
|
2444
2529
|
*
|
|
2445
|
-
*
|
|
2530
|
+
* assertOk(await fiber, "committed");
|
|
2446
2531
|
* ```
|
|
2447
2532
|
*
|
|
2448
2533
|
* @group Abortability
|
|
@@ -2460,7 +2545,7 @@ export const unabortable = /*#__PURE__*/ withTaskMeta({
|
|
|
2460
2545
|
*
|
|
2461
2546
|
* An abort request before the mask Task starts prevents entering the mask. Once
|
|
2462
2547
|
* the body starts, plain child Tasks inherit the mask, so acquire and release
|
|
2463
|
-
* can run after abort.
|
|
2548
|
+
* can run after abort. Start release Tasks directly in the original mask's
|
|
2464
2549
|
* `finally`; do not wrap release in a nested `unabortableMask`, which is a new
|
|
2465
2550
|
* critical-section entry and may not start after abort.
|
|
2466
2551
|
*
|
|
@@ -2472,6 +2557,9 @@ export const unabortable = /*#__PURE__*/ withTaskMeta({
|
|
|
2472
2557
|
*
|
|
2473
2558
|
* ```ts
|
|
2474
2559
|
* import {
|
|
2560
|
+
* assertEqual,
|
|
2561
|
+
* assertFalse,
|
|
2562
|
+
* assertTrue,
|
|
2475
2563
|
* AbortError,
|
|
2476
2564
|
* createRun,
|
|
2477
2565
|
* ok,
|
|
@@ -2488,17 +2576,17 @@ export const unabortable = /*#__PURE__*/ withTaskMeta({
|
|
|
2488
2576
|
* const operationStarted = Promise.withResolvers<void>();
|
|
2489
2577
|
* const operate =
|
|
2490
2578
|
* (resource: Resource): Task<never> =>
|
|
2491
|
-
*
|
|
2492
|
-
*
|
|
2579
|
+
* (run) => {
|
|
2580
|
+
* assertEqual(resource.id, "resource-1");
|
|
2493
2581
|
* operationStarted.resolve();
|
|
2494
|
-
* return
|
|
2582
|
+
* return run(waitForAbort);
|
|
2495
2583
|
* };
|
|
2496
2584
|
* let released = false;
|
|
2497
2585
|
* const release =
|
|
2498
2586
|
* (_resource: Resource): Task<void> =>
|
|
2499
2587
|
* (run) => {
|
|
2500
2588
|
* // Release inherits the mask even after abort was requested.
|
|
2501
|
-
*
|
|
2589
|
+
* assertFalse(run.signal.aborted);
|
|
2502
2590
|
* released = true;
|
|
2503
2591
|
* return ok();
|
|
2504
2592
|
* };
|
|
@@ -2522,9 +2610,9 @@ export const unabortable = /*#__PURE__*/ withTaskMeta({
|
|
|
2522
2610
|
* await operationStarted.promise;
|
|
2523
2611
|
* fiber.abort();
|
|
2524
2612
|
* const result = await fiber;
|
|
2525
|
-
*
|
|
2526
|
-
*
|
|
2527
|
-
*
|
|
2613
|
+
* assertFalse(result.ok);
|
|
2614
|
+
* assertTrue(AbortError.is(result.error));
|
|
2615
|
+
* assertTrue(released);
|
|
2528
2616
|
* ```
|
|
2529
2617
|
*
|
|
2530
2618
|
* @group Abortability
|
|
@@ -2534,7 +2622,7 @@ export const unabortableMask = (fn) => unabortable((run) => {
|
|
|
2534
2622
|
// Only verifies the Run is masked. A direct call inside an already masked
|
|
2535
2623
|
// Run passes undetected; direct calls bypass Run semantics by design.
|
|
2536
2624
|
assert(runInternal.abortMask > abortableMask, "unabortableMask requires a masked Run; use run(task), not a direct call");
|
|
2537
|
-
const restoreToken = Symbol();
|
|
2625
|
+
const restoreToken = Symbol("restore");
|
|
2538
2626
|
// The token is local to this Task Run; descendant Runs inherit the token
|
|
2539
2627
|
// set so helpers can receive restore while the mask Task is alive.
|
|
2540
2628
|
// Each set is bounded by its Run lifetime and is intentionally not pruned.
|
|
@@ -2560,13 +2648,15 @@ export const unabortableMask = (fn) => unabortable((run) => {
|
|
|
2560
2648
|
* Prefer native `using`, `await using`, or {@link AsyncDisposableStack} for
|
|
2561
2649
|
* owned values that implement {@link Disposable} or {@link AsyncDisposable}. Use
|
|
2562
2650
|
* `acquireUseRelease` when acquisition must be balanced with a separate release
|
|
2563
|
-
*
|
|
2651
|
+
* step, such as unlocking, returning a pooled value, releasing a lease, or
|
|
2564
2652
|
* logging out of a session.
|
|
2565
2653
|
*
|
|
2566
2654
|
* ### Example
|
|
2567
2655
|
*
|
|
2568
2656
|
* ```ts
|
|
2569
2657
|
* import {
|
|
2658
|
+
* assertErr,
|
|
2659
|
+
* assertTrue,
|
|
2570
2660
|
* acquireUseRelease,
|
|
2571
2661
|
* createRun,
|
|
2572
2662
|
* err,
|
|
@@ -2606,9 +2696,9 @@ export const unabortableMask = (fn) => unabortable((run) => {
|
|
|
2606
2696
|
* );
|
|
2607
2697
|
*
|
|
2608
2698
|
* await using run = createRun();
|
|
2609
|
-
*
|
|
2699
|
+
* assertErr(await run(queryUser), { type: "UserUnavailable" });
|
|
2610
2700
|
* // Release still runs when use returns a domain error.
|
|
2611
|
-
*
|
|
2701
|
+
* assertTrue(connectionClosed);
|
|
2612
2702
|
* ```
|
|
2613
2703
|
*
|
|
2614
2704
|
* @group Lifetime
|
|
@@ -2618,7 +2708,7 @@ export const acquireUseRelease = (acquire, use, release) => unabortableMask((res
|
|
|
2618
2708
|
if (!resourceResult.ok)
|
|
2619
2709
|
return resourceResult;
|
|
2620
2710
|
try {
|
|
2621
|
-
//
|
|
2711
|
+
// oxlint-disable-next-line react/rules-of-hooks -- `use` is an acquireUseRelease callback, not a React Hook.
|
|
2622
2712
|
return await run(restore(use(resourceResult.value)));
|
|
2623
2713
|
}
|
|
2624
2714
|
finally {
|
|
@@ -2632,6 +2722,10 @@ export const acquireUseRelease = (acquire, use, release) => unabortableMask((res
|
|
|
2632
2722
|
*
|
|
2633
2723
|
* ```ts
|
|
2634
2724
|
* import {
|
|
2725
|
+
* assertFalse,
|
|
2726
|
+
* assertOk,
|
|
2727
|
+
* assertType,
|
|
2728
|
+
* assertTrue,
|
|
2635
2729
|
* createDeferred,
|
|
2636
2730
|
* createRun,
|
|
2637
2731
|
* ok,
|
|
@@ -2642,22 +2736,28 @@ export const acquireUseRelease = (acquire, use, release) => unabortableMask((res
|
|
|
2642
2736
|
* const deferred = createDeferred<string>();
|
|
2643
2737
|
*
|
|
2644
2738
|
* const fiber = run(deferred.task);
|
|
2645
|
-
*
|
|
2739
|
+
* assertTrue(deferred.resolve(ok("ready")));
|
|
2646
2740
|
*
|
|
2647
2741
|
* const result = await fiber;
|
|
2648
|
-
*
|
|
2649
|
-
*
|
|
2742
|
+
* assertType<Result<string>, typeof result>();
|
|
2743
|
+
* assertOk(result, "ready");
|
|
2650
2744
|
*
|
|
2651
2745
|
* // A Deferred is one-shot: later resolutions are ignored, and future
|
|
2652
2746
|
* // waiters receive the original Result.
|
|
2653
|
-
*
|
|
2654
|
-
*
|
|
2747
|
+
* assertFalse(deferred.resolve(ok("late")));
|
|
2748
|
+
* assertOk(await run(deferred.task), "ready");
|
|
2655
2749
|
* ```
|
|
2656
2750
|
*
|
|
2657
2751
|
* ### Aborting a waiter
|
|
2658
2752
|
*
|
|
2659
2753
|
* ```ts
|
|
2660
|
-
* import {
|
|
2754
|
+
* import {
|
|
2755
|
+
* assertFalse,
|
|
2756
|
+
* assertTrue,
|
|
2757
|
+
* AbortError,
|
|
2758
|
+
* createDeferred,
|
|
2759
|
+
* createRun,
|
|
2760
|
+
* } from "@evolu/common";
|
|
2661
2761
|
*
|
|
2662
2762
|
* await using run = createRun();
|
|
2663
2763
|
* const deferred = createDeferred<string>();
|
|
@@ -2666,8 +2766,8 @@ export const acquireUseRelease = (acquire, use, release) => unabortableMask((res
|
|
|
2666
2766
|
* fiber.abort({ type: "NoLongerNeeded" });
|
|
2667
2767
|
*
|
|
2668
2768
|
* const result = await fiber;
|
|
2669
|
-
*
|
|
2670
|
-
*
|
|
2769
|
+
* assertFalse(result.ok);
|
|
2770
|
+
* assertTrue(AbortError.is(result.error));
|
|
2671
2771
|
* ```
|
|
2672
2772
|
*
|
|
2673
2773
|
* @group Concurrency primitives
|
|
@@ -2703,7 +2803,15 @@ export const createDeferred = () => {
|
|
|
2703
2803
|
* ### Example
|
|
2704
2804
|
*
|
|
2705
2805
|
* ```ts
|
|
2706
|
-
* import {
|
|
2806
|
+
* import {
|
|
2807
|
+
* assertEqual,
|
|
2808
|
+
* assertOk,
|
|
2809
|
+
* assertTrue,
|
|
2810
|
+
* createGate,
|
|
2811
|
+
* createRun,
|
|
2812
|
+
* ok,
|
|
2813
|
+
* type Task,
|
|
2814
|
+
* } from "@evolu/common";
|
|
2707
2815
|
*
|
|
2708
2816
|
* await using run = createRun();
|
|
2709
2817
|
* const networkGate = createGate();
|
|
@@ -2719,13 +2827,13 @@ export const createDeferred = () => {
|
|
|
2719
2827
|
*
|
|
2720
2828
|
* const first = run(syncOnce("first"));
|
|
2721
2829
|
* const second = run(syncOnce("second"));
|
|
2722
|
-
*
|
|
2830
|
+
* assertEqual(uploadedItems, []);
|
|
2723
2831
|
*
|
|
2724
2832
|
* networkGate.open();
|
|
2725
|
-
*
|
|
2726
|
-
*
|
|
2727
|
-
*
|
|
2728
|
-
*
|
|
2833
|
+
* assertOk(await first, undefined);
|
|
2834
|
+
* assertOk(await second, undefined);
|
|
2835
|
+
* assertEqual(uploadedItems, ["first", "second"]);
|
|
2836
|
+
* assertTrue(networkGate.isOpen());
|
|
2729
2837
|
* ```
|
|
2730
2838
|
*
|
|
2731
2839
|
* @group Concurrency primitives
|
|
@@ -2736,7 +2844,6 @@ export const createGate = ({ isOpen = false, } = {}) => {
|
|
|
2736
2844
|
deferred.resolve(ok());
|
|
2737
2845
|
return {
|
|
2738
2846
|
// Direct same-Run delegation is intentional so wait observes the current deferred.
|
|
2739
|
-
// eslint-disable-next-line evolu/no-direct-task-call
|
|
2740
2847
|
wait: (run) => deferred.task(run),
|
|
2741
2848
|
open: () => {
|
|
2742
2849
|
if (isOpen)
|
|
@@ -2769,6 +2876,7 @@ export const createGate = ({ isOpen = false, } = {}) => {
|
|
|
2769
2876
|
*
|
|
2770
2877
|
* ```ts
|
|
2771
2878
|
* import {
|
|
2879
|
+
* assertEqual,
|
|
2772
2880
|
* createRun,
|
|
2773
2881
|
* createSemaphore,
|
|
2774
2882
|
* getOk,
|
|
@@ -2800,8 +2908,8 @@ export const createGate = ({ isOpen = false, } = {}) => {
|
|
|
2800
2908
|
* ]);
|
|
2801
2909
|
*
|
|
2802
2910
|
* const savedUsers = results.map(getOk);
|
|
2803
|
-
*
|
|
2804
|
-
*
|
|
2911
|
+
* assertEqual(savedUsers, ["saved:1", "saved:2", "saved:3"]);
|
|
2912
|
+
* assertEqual(maxActiveSaves, 2);
|
|
2805
2913
|
* ```
|
|
2806
2914
|
*
|
|
2807
2915
|
* @group Concurrency primitives
|
|
@@ -2923,6 +3031,8 @@ export const createSemaphore = (initialPermits, { policy = "fifo", } = {}) => {
|
|
|
2923
3031
|
*
|
|
2924
3032
|
* ```ts
|
|
2925
3033
|
* import {
|
|
3034
|
+
* assertEqual,
|
|
3035
|
+
* assertOk,
|
|
2926
3036
|
* createMutex,
|
|
2927
3037
|
* createRun,
|
|
2928
3038
|
* ok,
|
|
@@ -2945,9 +3055,9 @@ export const createSemaphore = (initialPermits, { policy = "fifo", } = {}) => {
|
|
|
2945
3055
|
* run(deposit(2)),
|
|
2946
3056
|
* run(deposit(3)),
|
|
2947
3057
|
* ]);
|
|
2948
|
-
*
|
|
2949
|
-
*
|
|
2950
|
-
*
|
|
3058
|
+
* assertOk(first, undefined);
|
|
3059
|
+
* assertOk(second, undefined);
|
|
3060
|
+
* assertEqual(balance, 5);
|
|
2951
3061
|
* ```
|
|
2952
3062
|
*
|
|
2953
3063
|
* @group Concurrency primitives
|
|
@@ -3004,14 +3114,14 @@ export function createMutexByKey({ lookup = identity, } = {}) {
|
|
|
3004
3114
|
* ### Example
|
|
3005
3115
|
*
|
|
3006
3116
|
* ```ts
|
|
3007
|
-
* import { createMutexRef, createRun, ok } from "@evolu/common";
|
|
3117
|
+
* import { assertOk, createMutexRef, createRun, ok } from "@evolu/common";
|
|
3008
3118
|
*
|
|
3009
3119
|
* const counter = createMutexRef(0);
|
|
3010
3120
|
* const increment = counter.updateAndGet((value) => () => ok(value + 1));
|
|
3011
3121
|
*
|
|
3012
3122
|
* await using run = createRun();
|
|
3013
|
-
*
|
|
3014
|
-
*
|
|
3123
|
+
* assertOk(await run(increment), 1);
|
|
3124
|
+
* assertOk(await run(counter.get), 1);
|
|
3015
3125
|
* ```
|
|
3016
3126
|
*
|
|
3017
3127
|
* @group Concurrency primitives
|
|
@@ -3065,7 +3175,7 @@ export const createMutexRef = (initialValue) => {
|
|
|
3065
3175
|
// filtering, and pluggable log sinks.
|
|
3066
3176
|
// - Tracing spans with names, timing, parent-child relationships, attributes,
|
|
3067
3177
|
// error status, and helpers for annotating the current or child spans.
|
|
3068
|
-
// - Metrics for counters, gauges, histograms, and
|
|
3178
|
+
// - Metrics for counters, gauges, histograms, and Task execution durations.
|
|
3069
3179
|
// - Resource metadata for service name, service version, deployment
|
|
3070
3180
|
// environment, and user-provided attributes.
|
|
3071
3181
|
// - Exporters for production telemetry backends, including OTLP-compatible
|
|
@@ -3078,5 +3188,5 @@ export const createMutexRef = (initialValue) => {
|
|
|
3078
3188
|
// - Run labels and structured annotations for rendering useful snapshot trees
|
|
3079
3189
|
// instead of anonymous ids.
|
|
3080
3190
|
// - Snapshot and trace views should preserve ownership boundaries, so reusable
|
|
3081
|
-
// resources and long-lived
|
|
3082
|
-
// unrelated child
|
|
3191
|
+
// resources and long-lived Runs appear as labeled subtrees instead of
|
|
3192
|
+
// unrelated child Runs.
|