@evolu/common 8.5.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 +170 -97
- package/dist/src/Array.d.ts.map +1 -1
- package/dist/src/Array.js +67 -42
- package/dist/src/Assert.d.ts +233 -30
- package/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Assert.js +150 -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/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 +4 -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/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/Resource.d.ts +27 -12
- package/dist/src/Resource.d.ts.map +1 -1
- package/dist/src/Result.d.ts +258 -114
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +71 -34
- 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 +9 -8
- package/dist/src/Task.d.ts +441 -212
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +238 -115
- package/dist/src/Test.d.ts +10 -4
- package/dist/src/Test.d.ts.map +1 -1
- package/dist/src/Test.js +10 -4
- package/dist/src/Time.d.ts +27 -17
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +16 -6
- package/dist/src/Type.d.ts +1096 -387
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +1046 -372
- 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/Worker.d.ts +10 -6
- package/dist/src/Worker.d.ts.map +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/Evolu.d.ts +47 -24
- package/dist/src/local-first/Evolu.d.ts.map +1 -1
- package/dist/src/local-first/Owner.d.ts +10 -7
- package/dist/src/local-first/Owner.d.ts.map +1 -1
- package/dist/src/local-first/Owner.js +10 -7
- package/dist/src/local-first/Protocol.d.ts +5 -5
- package/dist/src/local-first/Protocol.js +5 -5
- 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 +25 -13
- 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/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/Storage.d.ts +4 -2
- package/dist/src/local-first/Storage.d.ts.map +1 -1
- package/package.json +3 -4
- package/src/Array.ts +170 -97
- package/src/Assert.ts +336 -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/LockManager.ts +12 -10
- package/src/Lookup.ts +4 -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 +2 -2
- package/src/Random.ts +7 -4
- package/src/Redacted.ts +13 -6
- package/src/Ref.ts +4 -4
- package/src/Relation.ts +5 -7
- package/src/Resource.ts +27 -12
- package/src/Result.ts +258 -114
- package/src/Schedule.ts +233 -116
- package/src/Set.ts +43 -24
- package/src/Sqlite.ts +9 -8
- package/src/Task.ts +441 -212
- package/src/Test.ts +10 -4
- package/src/Time.ts +27 -17
- package/src/Type.ts +2077 -620
- package/src/Types.ts +108 -40
- package/src/WebSocket.ts +14 -6
- package/src/Worker.ts +10 -6
- 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/Evolu.ts +47 -24
- package/src/local-first/Owner.ts +10 -7
- package/src/local-first/Protocol.ts +5 -5
- package/src/local-first/Query.ts +34 -21
- package/src/local-first/Relay.ts +12 -5
- package/src/local-first/Schema.ts +19 -11
- package/src/local-first/Storage.ts +4 -2
package/src/Task.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ## Intro
|
|
3
|
-
*
|
|
4
2
|
* JavaScript-native structured concurrency.
|
|
5
3
|
*
|
|
6
4
|
* Structured concurrency organizes running tasks into a tree. Every child
|
|
@@ -34,6 +32,8 @@
|
|
|
34
32
|
*
|
|
35
33
|
* ```ts
|
|
36
34
|
* import {
|
|
35
|
+
* assertOk,
|
|
36
|
+
* assertType,
|
|
37
37
|
* createRun,
|
|
38
38
|
* err,
|
|
39
39
|
* ok,
|
|
@@ -76,8 +76,8 @@
|
|
|
76
76
|
* });
|
|
77
77
|
*
|
|
78
78
|
* const result = await run(getUser(user.id));
|
|
79
|
-
*
|
|
80
|
-
*
|
|
79
|
+
* assertType<Result<User, UserNotFoundError>, typeof result>();
|
|
80
|
+
* assertOk(result, user);
|
|
81
81
|
* ```
|
|
82
82
|
*
|
|
83
83
|
* In composition roots, prefer the lifecycle API from the matching Evolu
|
|
@@ -120,6 +120,8 @@
|
|
|
120
120
|
*
|
|
121
121
|
* ```ts
|
|
122
122
|
* import {
|
|
123
|
+
* assertOk,
|
|
124
|
+
* assertType,
|
|
123
125
|
* createRun,
|
|
124
126
|
* err,
|
|
125
127
|
* ok,
|
|
@@ -178,13 +180,14 @@
|
|
|
178
180
|
*
|
|
179
181
|
* await using run = createRun();
|
|
180
182
|
* const result = await run(getUserWithProfile("user-1"));
|
|
181
|
-
*
|
|
183
|
+
* assertType<
|
|
182
184
|
* Result<
|
|
183
185
|
* { readonly user: User; readonly profile: Profile },
|
|
184
186
|
* UserNotFoundError | ProfileNotFoundError
|
|
185
|
-
*
|
|
187
|
+
* >,
|
|
188
|
+
* typeof result
|
|
186
189
|
* >();
|
|
187
|
-
*
|
|
190
|
+
* assertOk(result, {
|
|
188
191
|
* user: { id: "user-1", profileId: "profile-1" },
|
|
189
192
|
* profile: { id: "profile-1" },
|
|
190
193
|
* });
|
|
@@ -203,6 +206,7 @@
|
|
|
203
206
|
*
|
|
204
207
|
* ```ts
|
|
205
208
|
* import {
|
|
209
|
+
* assertType,
|
|
206
210
|
* exponential,
|
|
207
211
|
* fetch,
|
|
208
212
|
* jitter,
|
|
@@ -223,8 +227,9 @@
|
|
|
223
227
|
* jitter("100%")(maxDelay("20s")(take(2)(exponential("100ms")))),
|
|
224
228
|
* );
|
|
225
229
|
*
|
|
226
|
-
*
|
|
227
|
-
* Task<string, RetryTaskError<FetchError | TimeoutError
|
|
230
|
+
* assertType<
|
|
231
|
+
* Task<string, RetryTaskError<FetchError | TimeoutError>>,
|
|
232
|
+
* ReturnType<typeof fetchWithRetry>
|
|
228
233
|
* >();
|
|
229
234
|
* ```
|
|
230
235
|
*
|
|
@@ -233,7 +238,15 @@
|
|
|
233
238
|
* Run composed Tasks with a `concurrency` option and {@link all}:
|
|
234
239
|
*
|
|
235
240
|
* ```ts
|
|
236
|
-
* import {
|
|
241
|
+
* import {
|
|
242
|
+
* assertEqual,
|
|
243
|
+
* assertOk,
|
|
244
|
+
* all,
|
|
245
|
+
* createRun,
|
|
246
|
+
* ok,
|
|
247
|
+
* sleep,
|
|
248
|
+
* type Task,
|
|
249
|
+
* } from "@evolu/common";
|
|
237
250
|
*
|
|
238
251
|
* await using run = createRun();
|
|
239
252
|
*
|
|
@@ -256,8 +269,8 @@
|
|
|
256
269
|
*
|
|
257
270
|
* // At most 2 concurrent requests.
|
|
258
271
|
* const result = await run(all(urls, fetchUrl, { concurrency: 2 }));
|
|
259
|
-
*
|
|
260
|
-
*
|
|
272
|
+
* assertOk(result, urls);
|
|
273
|
+
* assertEqual(maxActiveRequests, 2);
|
|
261
274
|
* ```
|
|
262
275
|
*
|
|
263
276
|
* Task helpers compose Tasks; concurrency primitives are stateful objects that
|
|
@@ -289,7 +302,7 @@
|
|
|
289
302
|
* resources, or services shared by all code running inside a Run.
|
|
290
303
|
*
|
|
291
304
|
* ```ts
|
|
292
|
-
* import { createRun, ok, type Task } from "@evolu/common";
|
|
305
|
+
* import { assertOk, createRun, ok, type Task } from "@evolu/common";
|
|
293
306
|
*
|
|
294
307
|
* interface GreetingFormatter {
|
|
295
308
|
* readonly format: (name: string) => string;
|
|
@@ -314,10 +327,10 @@
|
|
|
314
327
|
* await using run = createRun({ greetingFormatter: formal });
|
|
315
328
|
*
|
|
316
329
|
* // Root dependencies are inherited.
|
|
317
|
-
*
|
|
330
|
+
* assertOk(await run(greet("Ada")), "Hello, Ada");
|
|
318
331
|
*
|
|
319
332
|
* // Child-specific dependencies replace the root's custom dependencies.
|
|
320
|
-
*
|
|
333
|
+
* assertOk(
|
|
321
334
|
* await run(greet("Ada"), { greetingFormatter: casual }),
|
|
322
335
|
* "Hi, Ada",
|
|
323
336
|
* );
|
|
@@ -368,7 +381,15 @@
|
|
|
368
381
|
* `undefined` should represent valid absence, not failure.
|
|
369
382
|
*
|
|
370
383
|
* ```ts
|
|
371
|
-
* import {
|
|
384
|
+
* import {
|
|
385
|
+
* assertEqual,
|
|
386
|
+
* assertFalse,
|
|
387
|
+
* assertTrue,
|
|
388
|
+
* createRun,
|
|
389
|
+
* ok,
|
|
390
|
+
* type Task,
|
|
391
|
+
* type Typed,
|
|
392
|
+
* } from "@evolu/common";
|
|
372
393
|
*
|
|
373
394
|
* interface Socket extends AsyncDisposable {
|
|
374
395
|
* readonly send: (message: string) => string;
|
|
@@ -382,8 +403,9 @@
|
|
|
382
403
|
* const openSocket: Task<Socket, ConnectionFailedError> = () =>
|
|
383
404
|
* ok({
|
|
384
405
|
* send: (message) => message,
|
|
385
|
-
* [Symbol.asyncDispose]:
|
|
406
|
+
* [Symbol.asyncDispose]: () => {
|
|
386
407
|
* socketDisposed = true;
|
|
408
|
+
* return Promise.resolve();
|
|
387
409
|
* },
|
|
388
410
|
* });
|
|
389
411
|
*
|
|
@@ -415,11 +437,11 @@
|
|
|
415
437
|
*
|
|
416
438
|
* await using run = createRun();
|
|
417
439
|
* const result = await run(createConnection);
|
|
418
|
-
*
|
|
419
|
-
*
|
|
420
|
-
*
|
|
440
|
+
* assertTrue(result.ok);
|
|
441
|
+
* assertFalse(socketDisposed);
|
|
442
|
+
* assertEqual(result.value.send("hello"), "hello");
|
|
421
443
|
* await result.value[Symbol.asyncDispose]();
|
|
422
|
-
*
|
|
444
|
+
* assertTrue(socketDisposed);
|
|
423
445
|
* ```
|
|
424
446
|
*
|
|
425
447
|
* Use {@link Run.ok} with `await using` when a Task whose error type is `never`
|
|
@@ -576,7 +598,7 @@
|
|
|
576
598
|
* each iteration reuses the same stack frame:
|
|
577
599
|
*
|
|
578
600
|
* ```ts
|
|
579
|
-
* import { createRun, ok, type Task } from "@evolu/common";
|
|
601
|
+
* import { assertOk, createRun, ok, type Task } from "@evolu/common";
|
|
580
602
|
*
|
|
581
603
|
* interface TreeNode {
|
|
582
604
|
* readonly value: string;
|
|
@@ -600,7 +622,7 @@
|
|
|
600
622
|
* };
|
|
601
623
|
*
|
|
602
624
|
* await using run = createRun();
|
|
603
|
-
*
|
|
625
|
+
* assertOk(
|
|
604
626
|
* await run(
|
|
605
627
|
* visitTree({
|
|
606
628
|
* value: "root",
|
|
@@ -758,22 +780,34 @@ import type {
|
|
|
758
780
|
* A Task that can't fail with a domain error:
|
|
759
781
|
*
|
|
760
782
|
* ```ts
|
|
761
|
-
* import {
|
|
783
|
+
* import {
|
|
784
|
+
* assertEqual,
|
|
785
|
+
* assertOk,
|
|
786
|
+
* createRun,
|
|
787
|
+
* ok,
|
|
788
|
+
* type Task,
|
|
789
|
+
* } from "@evolu/common";
|
|
762
790
|
*
|
|
763
791
|
* const greet: Task<string> = () => ok("Hello!");
|
|
764
|
-
* const main: Task<string> =
|
|
792
|
+
* const main: Task<string> = (run) => run(greet);
|
|
765
793
|
*
|
|
766
794
|
* await using run = createRun();
|
|
767
|
-
*
|
|
795
|
+
* assertOk(await run(main), "Hello!");
|
|
768
796
|
*
|
|
769
797
|
* // Without domain errors, `run.ok` returns the Ok value.
|
|
770
|
-
*
|
|
798
|
+
* assertEqual(await run.ok(main), "Hello!");
|
|
771
799
|
* ```
|
|
772
800
|
*
|
|
773
801
|
* A Task that can fail with a domain error:
|
|
774
802
|
*
|
|
775
803
|
* ```ts
|
|
776
|
-
* import {
|
|
804
|
+
* import {
|
|
805
|
+
* assertErr,
|
|
806
|
+
* createRun,
|
|
807
|
+
* err,
|
|
808
|
+
* type Task,
|
|
809
|
+
* type Typed,
|
|
810
|
+
* } from "@evolu/common";
|
|
777
811
|
*
|
|
778
812
|
* const findUser =
|
|
779
813
|
* (id: string): Task<string, UserNotFoundError> =>
|
|
@@ -785,7 +819,7 @@ import type {
|
|
|
785
819
|
* }
|
|
786
820
|
*
|
|
787
821
|
* await using run = createRun();
|
|
788
|
-
*
|
|
822
|
+
* assertErr(await run(findUser("user-1")), {
|
|
789
823
|
* type: "UserNotFound",
|
|
790
824
|
* id: "user-1",
|
|
791
825
|
* });
|
|
@@ -794,7 +828,7 @@ import type {
|
|
|
794
828
|
* A Task with dependencies:
|
|
795
829
|
*
|
|
796
830
|
* ```ts
|
|
797
|
-
* import { createRun, ok, type Task } from "@evolu/common";
|
|
831
|
+
* import { assertOk, createRun, ok, type Task } from "@evolu/common";
|
|
798
832
|
*
|
|
799
833
|
* interface Config {
|
|
800
834
|
* readonly greeting: string;
|
|
@@ -809,7 +843,7 @@ import type {
|
|
|
809
843
|
*
|
|
810
844
|
* const config: Config = { greeting: "Hello" };
|
|
811
845
|
* await using run = createRun({ config });
|
|
812
|
-
*
|
|
846
|
+
* assertOk(await run(greet), "Hello!");
|
|
813
847
|
* ```
|
|
814
848
|
*
|
|
815
849
|
* Start Tasks with `run(task)`, as shown above.
|
|
@@ -967,7 +1001,13 @@ export interface Run<D = unknown> {
|
|
|
967
1001
|
* ### Example
|
|
968
1002
|
*
|
|
969
1003
|
* ```ts
|
|
970
|
-
* import {
|
|
1004
|
+
* import {
|
|
1005
|
+
* assertSame,
|
|
1006
|
+
* assertOk,
|
|
1007
|
+
* createRun,
|
|
1008
|
+
* ok,
|
|
1009
|
+
* type Task,
|
|
1010
|
+
* } from "@evolu/common";
|
|
971
1011
|
*
|
|
972
1012
|
* interface Db {
|
|
973
1013
|
* readonly name: string;
|
|
@@ -980,15 +1020,15 @@ export interface Run<D = unknown> {
|
|
|
980
1020
|
* const db: Db = { name: "main" };
|
|
981
1021
|
* const loadUser: Task<string> = () => ok("Ada");
|
|
982
1022
|
* const saveUser: Task<void, never, DbDep> = (run) => {
|
|
983
|
-
*
|
|
1023
|
+
* assertSame(run.deps.db, db);
|
|
984
1024
|
* return ok();
|
|
985
1025
|
* };
|
|
986
1026
|
*
|
|
987
1027
|
* await using run = createRun({ db });
|
|
988
1028
|
* const userResult = await run(loadUser);
|
|
989
1029
|
* const savedResult = await run(saveUser);
|
|
990
|
-
*
|
|
991
|
-
*
|
|
1030
|
+
* assertOk(userResult, "Ada");
|
|
1031
|
+
* assertOk(savedResult, undefined);
|
|
992
1032
|
* ```
|
|
993
1033
|
*
|
|
994
1034
|
* Start Tasks with `run(task)`, as shown above.
|
|
@@ -1022,7 +1062,13 @@ export interface Run<D = unknown> {
|
|
|
1022
1062
|
* ### Example
|
|
1023
1063
|
*
|
|
1024
1064
|
* ```ts
|
|
1025
|
-
* import {
|
|
1065
|
+
* import {
|
|
1066
|
+
* assertEqual,
|
|
1067
|
+
* createRun,
|
|
1068
|
+
* ok,
|
|
1069
|
+
* type Task,
|
|
1070
|
+
* type Typed,
|
|
1071
|
+
* } from "@evolu/common";
|
|
1026
1072
|
*
|
|
1027
1073
|
* const loadConfig: Task<string, ConfigInvalidError> = () =>
|
|
1028
1074
|
* ok("config");
|
|
@@ -1030,7 +1076,7 @@ export interface Run<D = unknown> {
|
|
|
1030
1076
|
* interface ConfigInvalidError extends Typed<"ConfigInvalid"> {}
|
|
1031
1077
|
*
|
|
1032
1078
|
* await using run = createRun();
|
|
1033
|
-
*
|
|
1079
|
+
* assertEqual(await run.orThrow(loadConfig), "config");
|
|
1034
1080
|
* ```
|
|
1035
1081
|
*/
|
|
1036
1082
|
readonly orThrow: {
|
|
@@ -1052,7 +1098,13 @@ export interface Run<D = unknown> {
|
|
|
1052
1098
|
* ### Example
|
|
1053
1099
|
*
|
|
1054
1100
|
* ```ts
|
|
1055
|
-
* import {
|
|
1101
|
+
* import {
|
|
1102
|
+
* assertEqual,
|
|
1103
|
+
* assertTrue,
|
|
1104
|
+
* createRun,
|
|
1105
|
+
* ok,
|
|
1106
|
+
* type Task,
|
|
1107
|
+
* } from "@evolu/common";
|
|
1056
1108
|
*
|
|
1057
1109
|
* interface Resource extends AsyncDisposable {
|
|
1058
1110
|
* readonly value: string;
|
|
@@ -1062,17 +1114,18 @@ export interface Run<D = unknown> {
|
|
|
1062
1114
|
* const openResource: Task<Resource> = () =>
|
|
1063
1115
|
* ok({
|
|
1064
1116
|
* value: "resource",
|
|
1065
|
-
* [Symbol.asyncDispose]:
|
|
1117
|
+
* [Symbol.asyncDispose]: () => {
|
|
1066
1118
|
* disposed = true;
|
|
1119
|
+
* return Promise.resolve();
|
|
1067
1120
|
* },
|
|
1068
1121
|
* });
|
|
1069
1122
|
*
|
|
1070
1123
|
* await using run = createRun();
|
|
1071
1124
|
* {
|
|
1072
1125
|
* await using resource = await run.ok(openResource);
|
|
1073
|
-
*
|
|
1126
|
+
* assertEqual(resource.value, "resource");
|
|
1074
1127
|
* }
|
|
1075
|
-
*
|
|
1128
|
+
* assertTrue(disposed);
|
|
1076
1129
|
* ```
|
|
1077
1130
|
*/
|
|
1078
1131
|
readonly ok: {
|
|
@@ -1101,6 +1154,9 @@ export interface Run<D = unknown> {
|
|
|
1101
1154
|
*
|
|
1102
1155
|
* ```ts
|
|
1103
1156
|
* import {
|
|
1157
|
+
* assertFalse,
|
|
1158
|
+
* assertType,
|
|
1159
|
+
* assertTrue,
|
|
1104
1160
|
* AbortError,
|
|
1105
1161
|
* createRun,
|
|
1106
1162
|
* ok,
|
|
@@ -1121,13 +1177,11 @@ export interface Run<D = unknown> {
|
|
|
1121
1177
|
*
|
|
1122
1178
|
* await using run = createRun();
|
|
1123
1179
|
* const fiber = run.abortable(loadUser, { db });
|
|
1124
|
-
*
|
|
1125
|
-
* AbortableFiber<string, never, DbDep>
|
|
1126
|
-
* >();
|
|
1180
|
+
* assertType<AbortableFiber<string, never, DbDep>, typeof fiber>();
|
|
1127
1181
|
* fiber.abort();
|
|
1128
1182
|
* const userResult = await fiber;
|
|
1129
|
-
*
|
|
1130
|
-
*
|
|
1183
|
+
* assertFalse(userResult.ok);
|
|
1184
|
+
* assertTrue(AbortError.is(userResult.error));
|
|
1131
1185
|
* ```
|
|
1132
1186
|
*/
|
|
1133
1187
|
readonly abortable: {
|
|
@@ -1167,35 +1221,45 @@ export interface Run<D = unknown> {
|
|
|
1167
1221
|
* ### Abort masks
|
|
1168
1222
|
*
|
|
1169
1223
|
* ```ts
|
|
1170
|
-
* import {
|
|
1224
|
+
* import {
|
|
1225
|
+
* assertEqual,
|
|
1226
|
+
* assertOk,
|
|
1227
|
+
* assertTrue,
|
|
1228
|
+
* createRun,
|
|
1229
|
+
* ok,
|
|
1230
|
+
* unabortable,
|
|
1231
|
+
* type Task,
|
|
1232
|
+
* } from "@evolu/common";
|
|
1171
1233
|
*
|
|
1172
1234
|
* const syncUsers: Task<string> = () => ok("synced");
|
|
1173
1235
|
* const syncParent = unabortable(async (run) => {
|
|
1174
|
-
*
|
|
1236
|
+
* assertEqual(run.snapshot().abortMask, 1);
|
|
1175
1237
|
*
|
|
1176
1238
|
* // Plain daemon — the caller's mask does not follow it, so abort
|
|
1177
1239
|
* // requests are observed.
|
|
1178
1240
|
* const fiber = run.daemon(syncUsers);
|
|
1179
|
-
*
|
|
1241
|
+
* assertEqual(fiber.run.snapshot().abortMask, 0);
|
|
1180
1242
|
*
|
|
1181
1243
|
* // Explicitly masked daemon — finishes once started.
|
|
1182
1244
|
* const maskedFiber = run.daemon(unabortable(syncUsers));
|
|
1183
|
-
*
|
|
1245
|
+
* assertEqual(maskedFiber.run.snapshot().abortMask, 1);
|
|
1184
1246
|
* const firstResult = await fiber;
|
|
1185
1247
|
* const secondResult = await maskedFiber;
|
|
1186
|
-
*
|
|
1187
|
-
*
|
|
1248
|
+
* assertTrue(firstResult.ok);
|
|
1249
|
+
* assertTrue(secondResult.ok);
|
|
1188
1250
|
* return ok([firstResult.value, secondResult.value] as const);
|
|
1189
1251
|
* });
|
|
1190
1252
|
*
|
|
1191
1253
|
* await using run = createRun();
|
|
1192
|
-
*
|
|
1254
|
+
* assertOk(await run(syncParent), ["synced", "synced"]);
|
|
1193
1255
|
* ```
|
|
1194
1256
|
*
|
|
1195
1257
|
* ### Aborting a daemon
|
|
1196
1258
|
*
|
|
1197
1259
|
* ```ts
|
|
1198
1260
|
* import {
|
|
1261
|
+
* assertFalse,
|
|
1262
|
+
* assertTrue,
|
|
1199
1263
|
* AbortError,
|
|
1200
1264
|
* createRun,
|
|
1201
1265
|
* ok,
|
|
@@ -1217,14 +1281,21 @@ export interface Run<D = unknown> {
|
|
|
1217
1281
|
* const fiber = run.daemon(syncUsers, { db });
|
|
1218
1282
|
* fiber.abort();
|
|
1219
1283
|
* const syncResult = await fiber;
|
|
1220
|
-
*
|
|
1221
|
-
*
|
|
1284
|
+
* assertFalse(syncResult.ok);
|
|
1285
|
+
* assertTrue(AbortError.is(syncResult.error));
|
|
1222
1286
|
* ```
|
|
1223
1287
|
*
|
|
1224
1288
|
* ### Disposing a daemon
|
|
1225
1289
|
*
|
|
1226
1290
|
* ```ts
|
|
1227
|
-
* import {
|
|
1291
|
+
* import {
|
|
1292
|
+
* assertOk,
|
|
1293
|
+
* assertTrue,
|
|
1294
|
+
* createRun,
|
|
1295
|
+
* ok,
|
|
1296
|
+
* waitForAbort,
|
|
1297
|
+
* type Task,
|
|
1298
|
+
* } from "@evolu/common";
|
|
1228
1299
|
*
|
|
1229
1300
|
* let syncStopped = false;
|
|
1230
1301
|
* const syncUsers: Task<never> = async (run) => {
|
|
@@ -1239,9 +1310,9 @@ export interface Run<D = unknown> {
|
|
|
1239
1310
|
* {
|
|
1240
1311
|
* // Async disposal requests abort and waits for the daemon to stop.
|
|
1241
1312
|
* await using _syncFiber = run.daemon(syncUsers);
|
|
1242
|
-
*
|
|
1313
|
+
* assertOk(await run(loadUser), "Ada");
|
|
1243
1314
|
* }
|
|
1244
|
-
*
|
|
1315
|
+
* assertTrue(syncStopped);
|
|
1245
1316
|
* ```
|
|
1246
1317
|
*/
|
|
1247
1318
|
readonly daemon: {
|
|
@@ -1271,7 +1342,13 @@ export interface Run<D = unknown> {
|
|
|
1271
1342
|
* ### Example
|
|
1272
1343
|
*
|
|
1273
1344
|
* ```ts
|
|
1274
|
-
* import {
|
|
1345
|
+
* import {
|
|
1346
|
+
* assertEqual,
|
|
1347
|
+
* assertOk,
|
|
1348
|
+
* createRun,
|
|
1349
|
+
* ok,
|
|
1350
|
+
* type Task,
|
|
1351
|
+
* } from "@evolu/common";
|
|
1275
1352
|
*
|
|
1276
1353
|
* interface DbDep {
|
|
1277
1354
|
* readonly db: { readonly users: Array<string> };
|
|
@@ -1289,9 +1366,9 @@ export interface Run<D = unknown> {
|
|
|
1289
1366
|
* await using createdRun = run.create({ db });
|
|
1290
1367
|
* const userResult = await createdRun(loadUser);
|
|
1291
1368
|
* const savedResult = await createdRun(saveUser);
|
|
1292
|
-
*
|
|
1293
|
-
*
|
|
1294
|
-
*
|
|
1369
|
+
* assertOk(userResult, "Ada");
|
|
1370
|
+
* assertOk(savedResult, undefined);
|
|
1371
|
+
* assertEqual(db.users, ["Ada", "Grace"]);
|
|
1295
1372
|
* ```
|
|
1296
1373
|
*/
|
|
1297
1374
|
readonly create: {
|
|
@@ -1347,20 +1424,27 @@ export interface Run<D = unknown> {
|
|
|
1347
1424
|
* ### Example
|
|
1348
1425
|
*
|
|
1349
1426
|
* ```ts
|
|
1350
|
-
* import {
|
|
1427
|
+
* import {
|
|
1428
|
+
* assertFalse,
|
|
1429
|
+
* assertTrue,
|
|
1430
|
+
* AbortError,
|
|
1431
|
+
* createRun,
|
|
1432
|
+
* ok,
|
|
1433
|
+
* sleep,
|
|
1434
|
+
* } from "@evolu/common";
|
|
1351
1435
|
*
|
|
1352
1436
|
* let socketClosed = false;
|
|
1353
1437
|
* const openSocket = () => ({
|
|
1354
1438
|
* close: () => {
|
|
1355
1439
|
* socketClosed = true;
|
|
1356
1440
|
* },
|
|
1357
|
-
* read:
|
|
1441
|
+
* read: () => Promise.resolve("message"),
|
|
1358
1442
|
* });
|
|
1359
1443
|
*
|
|
1360
1444
|
* await using run = createRun();
|
|
1361
1445
|
* const fiber = run.abortable(async (run) => {
|
|
1362
1446
|
* const socket = openSocket();
|
|
1363
|
-
* using
|
|
1447
|
+
* using _closeOnAbort = run.onAbort(() => {
|
|
1364
1448
|
* socket.close();
|
|
1365
1449
|
* });
|
|
1366
1450
|
*
|
|
@@ -1370,9 +1454,9 @@ export interface Run<D = unknown> {
|
|
|
1370
1454
|
* });
|
|
1371
1455
|
* fiber.abort();
|
|
1372
1456
|
* const result = await fiber;
|
|
1373
|
-
*
|
|
1374
|
-
*
|
|
1375
|
-
*
|
|
1457
|
+
* assertFalse(result.ok);
|
|
1458
|
+
* assertTrue(AbortError.is(result.error));
|
|
1459
|
+
* assertTrue(socketClosed);
|
|
1376
1460
|
* ```
|
|
1377
1461
|
*/
|
|
1378
1462
|
readonly onAbort: (
|
|
@@ -1449,7 +1533,7 @@ export interface DisposableRun<D = unknown>
|
|
|
1449
1533
|
* ### Example
|
|
1450
1534
|
*
|
|
1451
1535
|
* ```ts
|
|
1452
|
-
* import { createRun } from "@evolu/common";
|
|
1536
|
+
* import { assertFalse, assertTrue, createRun } from "@evolu/common";
|
|
1453
1537
|
*
|
|
1454
1538
|
* let connectionClosed = false;
|
|
1455
1539
|
* {
|
|
@@ -1458,9 +1542,9 @@ export interface DisposableRun<D = unknown>
|
|
|
1458
1542
|
* connectionClosed = true;
|
|
1459
1543
|
* });
|
|
1460
1544
|
*
|
|
1461
|
-
*
|
|
1545
|
+
* assertFalse(connectionClosed);
|
|
1462
1546
|
* }
|
|
1463
|
-
*
|
|
1547
|
+
* assertTrue(connectionClosed);
|
|
1464
1548
|
* ```
|
|
1465
1549
|
*/
|
|
1466
1550
|
readonly defer: (finalizer: () => Awaitable<void>) => void;
|
|
@@ -1527,7 +1611,15 @@ export interface DisposableRun<D = unknown>
|
|
|
1527
1611
|
* ### Example
|
|
1528
1612
|
*
|
|
1529
1613
|
* ```ts
|
|
1530
|
-
* import {
|
|
1614
|
+
* import {
|
|
1615
|
+
* assertEqual,
|
|
1616
|
+
* assertOk,
|
|
1617
|
+
* assertType,
|
|
1618
|
+
* createRun,
|
|
1619
|
+
* ok,
|
|
1620
|
+
* type Fiber,
|
|
1621
|
+
* type Task,
|
|
1622
|
+
* } from "@evolu/common";
|
|
1531
1623
|
*
|
|
1532
1624
|
* await using run = createRun();
|
|
1533
1625
|
*
|
|
@@ -1537,9 +1629,9 @@ export interface DisposableRun<D = unknown>
|
|
|
1537
1629
|
* const userResult = await fiber;
|
|
1538
1630
|
* const snapshot = fiber.run.snapshot();
|
|
1539
1631
|
*
|
|
1540
|
-
*
|
|
1541
|
-
*
|
|
1542
|
-
*
|
|
1632
|
+
* assertType<Fiber<string, never>, typeof fiber>();
|
|
1633
|
+
* assertOk(userResult, "Ada");
|
|
1634
|
+
* assertEqual(snapshot.id, fiber.run.id);
|
|
1543
1635
|
* ```
|
|
1544
1636
|
*
|
|
1545
1637
|
* @group Core
|
|
@@ -1599,6 +1691,9 @@ export type InferFiberDeps<TFiber extends AnyFiber> =
|
|
|
1599
1691
|
*
|
|
1600
1692
|
* ```ts
|
|
1601
1693
|
* import {
|
|
1694
|
+
* assertFalse,
|
|
1695
|
+
* assertType,
|
|
1696
|
+
* assertTrue,
|
|
1602
1697
|
* AbortError,
|
|
1603
1698
|
* createRun,
|
|
1604
1699
|
* ok,
|
|
@@ -1615,11 +1710,11 @@ export type InferFiberDeps<TFiber extends AnyFiber> =
|
|
|
1615
1710
|
* };
|
|
1616
1711
|
*
|
|
1617
1712
|
* const fiber = run.abortable<string, never>(fetchData);
|
|
1618
|
-
*
|
|
1713
|
+
* assertType<AbortableFiber<string, never>, typeof fiber>();
|
|
1619
1714
|
* fiber.abort();
|
|
1620
1715
|
* const result = await fiber;
|
|
1621
|
-
*
|
|
1622
|
-
*
|
|
1716
|
+
* assertFalse(result.ok);
|
|
1717
|
+
* assertTrue(AbortError.is(result.error));
|
|
1623
1718
|
* ```
|
|
1624
1719
|
*
|
|
1625
1720
|
* @group Core
|
|
@@ -2067,7 +2162,7 @@ export interface CreateRun {
|
|
|
2067
2162
|
* ### Example
|
|
2068
2163
|
*
|
|
2069
2164
|
* ```ts
|
|
2070
|
-
* import { createRun, ok, type Task } from "@evolu/common";
|
|
2165
|
+
* import { assertOk, createRun, ok, type Task } from "@evolu/common";
|
|
2071
2166
|
*
|
|
2072
2167
|
* interface ConfigDep {
|
|
2073
2168
|
* readonly config: { readonly apiUrl: string };
|
|
@@ -2079,7 +2174,7 @@ export interface CreateRun {
|
|
|
2079
2174
|
* await using run = createRun({
|
|
2080
2175
|
* config: { apiUrl: "https://api.example.com" },
|
|
2081
2176
|
* });
|
|
2082
|
-
*
|
|
2177
|
+
* assertOk(await run(loadApiUrl), "https://api.example.com");
|
|
2083
2178
|
* ```
|
|
2084
2179
|
*
|
|
2085
2180
|
* @group Run
|
|
@@ -2256,12 +2351,12 @@ export const testCreateDeps = (options?: {
|
|
|
2256
2351
|
* ### Example
|
|
2257
2352
|
*
|
|
2258
2353
|
* ```ts
|
|
2259
|
-
* import { ok, testCreateRun, type Task } from "@evolu/common";
|
|
2354
|
+
* import { assertOk, ok, testCreateRun, type Task } from "@evolu/common";
|
|
2260
2355
|
*
|
|
2261
2356
|
* const readTime: Task<number> = (run) => ok(run.deps.time.now());
|
|
2262
2357
|
*
|
|
2263
2358
|
* await using run = testCreateRun();
|
|
2264
|
-
*
|
|
2359
|
+
* assertOk(await run(readTime), 0);
|
|
2265
2360
|
* ```
|
|
2266
2361
|
*
|
|
2267
2362
|
* @group Testing
|
|
@@ -2276,7 +2371,7 @@ export function testCreateRun(
|
|
|
2276
2371
|
* ### Example
|
|
2277
2372
|
*
|
|
2278
2373
|
* ```ts
|
|
2279
|
-
* import { ok, testCreateRun, type Task } from "@evolu/common";
|
|
2374
|
+
* import { assertOk, ok, testCreateRun, type Task } from "@evolu/common";
|
|
2280
2375
|
*
|
|
2281
2376
|
* interface FeatureDep {
|
|
2282
2377
|
* readonly feature: { readonly enabled: boolean };
|
|
@@ -2286,7 +2381,7 @@ export function testCreateRun(
|
|
|
2286
2381
|
* ok(run.deps.feature.enabled);
|
|
2287
2382
|
*
|
|
2288
2383
|
* await using run = testCreateRun({ feature: { enabled: true } });
|
|
2289
|
-
*
|
|
2384
|
+
* assertOk(await run(isFeatureEnabled), true);
|
|
2290
2385
|
* ```
|
|
2291
2386
|
*/
|
|
2292
2387
|
export function testCreateRun<D extends object>(
|
|
@@ -2889,6 +2984,9 @@ export type InferTasksOk<TTasks> = {
|
|
|
2889
2984
|
*
|
|
2890
2985
|
* ```ts
|
|
2891
2986
|
* import {
|
|
2987
|
+
* assertErr,
|
|
2988
|
+
* assertEqual,
|
|
2989
|
+
* assertType,
|
|
2892
2990
|
* all,
|
|
2893
2991
|
* createRun,
|
|
2894
2992
|
* err,
|
|
@@ -2919,14 +3017,12 @@ export type InferTasksOk<TTasks> = {
|
|
|
2919
3017
|
* collect: false,
|
|
2920
3018
|
* }),
|
|
2921
3019
|
* );
|
|
2922
|
-
*
|
|
2923
|
-
*
|
|
2924
|
-
* >();
|
|
2925
|
-
* expectErr(saveResult, {
|
|
3020
|
+
* assertType<Result<void, SaveUserFailedError>, typeof saveResult>();
|
|
3021
|
+
* assertErr(saveResult, {
|
|
2926
3022
|
* type: "SaveUserFailed",
|
|
2927
3023
|
* userId: "missing",
|
|
2928
3024
|
* });
|
|
2929
|
-
*
|
|
3025
|
+
* assertEqual(savedUserIds, ["user-1"]);
|
|
2930
3026
|
* ```
|
|
2931
3027
|
*
|
|
2932
3028
|
* @group Collection
|
|
@@ -2949,6 +3045,8 @@ export function all<const TTasks extends TaskRecord>(
|
|
|
2949
3045
|
*
|
|
2950
3046
|
* ```ts
|
|
2951
3047
|
* import {
|
|
3048
|
+
* assertOk,
|
|
3049
|
+
* assertType,
|
|
2952
3050
|
* all,
|
|
2953
3051
|
* createRun,
|
|
2954
3052
|
* ok,
|
|
@@ -2970,10 +3068,11 @@ export function all<const TTasks extends TaskRecord>(
|
|
|
2970
3068
|
*
|
|
2971
3069
|
* await using run = createRun();
|
|
2972
3070
|
* const dashboard = await run(all([fetchUser, fetchPosts]));
|
|
2973
|
-
*
|
|
2974
|
-
* Result<readonly [User, ReadonlyArray<Post>]
|
|
3071
|
+
* assertType<
|
|
3072
|
+
* Result<readonly [User, ReadonlyArray<Post>]>,
|
|
3073
|
+
* typeof dashboard
|
|
2975
3074
|
* >();
|
|
2976
|
-
*
|
|
3075
|
+
* assertOk(dashboard, [{ id: "user-1" }, [{ id: "post-1" }]]);
|
|
2977
3076
|
* ```
|
|
2978
3077
|
*/
|
|
2979
3078
|
export function all<const TTasks extends ReadonlyArray<AnyTask>>(
|
|
@@ -2992,6 +3091,8 @@ export function all<const TTasks extends ReadonlyArray<AnyTask>>(
|
|
|
2992
3091
|
*
|
|
2993
3092
|
* ```ts
|
|
2994
3093
|
* import {
|
|
3094
|
+
* assertOk,
|
|
3095
|
+
* assertType,
|
|
2995
3096
|
* all,
|
|
2996
3097
|
* createRun,
|
|
2997
3098
|
* ok,
|
|
@@ -3014,10 +3115,11 @@ export function all<const TTasks extends ReadonlyArray<AnyTask>>(
|
|
|
3014
3115
|
* await using run = createRun();
|
|
3015
3116
|
* const result = await run(all({ user: fetchUser, posts: fetchPosts }));
|
|
3016
3117
|
*
|
|
3017
|
-
*
|
|
3018
|
-
* Result<{ readonly user: User; readonly posts: ReadonlyArray<Post> }
|
|
3118
|
+
* assertType<
|
|
3119
|
+
* Result<{ readonly user: User; readonly posts: ReadonlyArray<Post> }>,
|
|
3120
|
+
* typeof result
|
|
3019
3121
|
* >();
|
|
3020
|
-
*
|
|
3122
|
+
* assertOk(result, {
|
|
3021
3123
|
* user: { id: "user-1" },
|
|
3022
3124
|
* posts: [{ id: "post-1" }],
|
|
3023
3125
|
* });
|
|
@@ -3061,6 +3163,9 @@ export function all<
|
|
|
3061
3163
|
*
|
|
3062
3164
|
* ```ts
|
|
3063
3165
|
* import {
|
|
3166
|
+
* assertEqual,
|
|
3167
|
+
* assertOk,
|
|
3168
|
+
* assertType,
|
|
3064
3169
|
* all,
|
|
3065
3170
|
* createRun,
|
|
3066
3171
|
* ok,
|
|
@@ -3085,12 +3190,12 @@ export function all<
|
|
|
3085
3190
|
* });
|
|
3086
3191
|
*
|
|
3087
3192
|
* // Mapping is eager: it happens before the returned Task starts.
|
|
3088
|
-
*
|
|
3193
|
+
* assertEqual(indexes, [0, 1]);
|
|
3089
3194
|
*
|
|
3090
3195
|
* await using run = createRun();
|
|
3091
3196
|
* const result = await run(loadUsers);
|
|
3092
|
-
*
|
|
3093
|
-
*
|
|
3197
|
+
* assertType<Result<readonly [User, User]>, typeof result>();
|
|
3198
|
+
* assertOk(result, [{ id: "user-1" }, { id: "user-2" }]);
|
|
3094
3199
|
* ```
|
|
3095
3200
|
*/
|
|
3096
3201
|
export function all<
|
|
@@ -3113,6 +3218,9 @@ export function all<
|
|
|
3113
3218
|
*
|
|
3114
3219
|
* ```ts
|
|
3115
3220
|
* import {
|
|
3221
|
+
* assertEqual,
|
|
3222
|
+
* assertOk,
|
|
3223
|
+
* assertType,
|
|
3116
3224
|
* all,
|
|
3117
3225
|
* createRun,
|
|
3118
3226
|
* ok,
|
|
@@ -3140,14 +3248,15 @@ export function all<
|
|
|
3140
3248
|
* });
|
|
3141
3249
|
*
|
|
3142
3250
|
* // Mapping is eager: it happens before the returned Task starts.
|
|
3143
|
-
*
|
|
3251
|
+
* assertEqual(roles, ["admin", "reviewer"]);
|
|
3144
3252
|
*
|
|
3145
3253
|
* await using run = createRun();
|
|
3146
3254
|
* const result = await run(loadUsersByRole);
|
|
3147
|
-
*
|
|
3148
|
-
* Result<{ readonly admin: User; readonly reviewer: User }
|
|
3255
|
+
* assertType<
|
|
3256
|
+
* Result<{ readonly admin: User; readonly reviewer: User }>,
|
|
3257
|
+
* typeof result
|
|
3149
3258
|
* >();
|
|
3150
|
-
*
|
|
3259
|
+
* assertOk(result, {
|
|
3151
3260
|
* admin: { id: "user-1" },
|
|
3152
3261
|
* reviewer: { id: "user-2" },
|
|
3153
3262
|
* });
|
|
@@ -3227,6 +3336,9 @@ export type InferTasksSettled<TTasks> = {
|
|
|
3227
3336
|
*
|
|
3228
3337
|
* ```ts
|
|
3229
3338
|
* import {
|
|
3339
|
+
* assertOk,
|
|
3340
|
+
* assertType,
|
|
3341
|
+
* assertTrue,
|
|
3230
3342
|
* allSettled,
|
|
3231
3343
|
* createRun,
|
|
3232
3344
|
* err,
|
|
@@ -3249,20 +3361,21 @@ export type InferTasksSettled<TTasks> = {
|
|
|
3249
3361
|
*
|
|
3250
3362
|
* await using run = createRun();
|
|
3251
3363
|
* const results = await run(allSettled([loadProfile, loadActivity]));
|
|
3252
|
-
*
|
|
3364
|
+
* assertType<
|
|
3253
3365
|
* Result<
|
|
3254
3366
|
* readonly [
|
|
3255
3367
|
* Result<string, ProfileNotFoundError>,
|
|
3256
3368
|
* Result<ReadonlyArray<string>>,
|
|
3257
3369
|
* ]
|
|
3258
|
-
*
|
|
3370
|
+
* >,
|
|
3371
|
+
* typeof results
|
|
3259
3372
|
* >();
|
|
3260
|
-
*
|
|
3373
|
+
* assertOk(results, [
|
|
3261
3374
|
* { ok: false, error: { type: "ProfileNotFound" } },
|
|
3262
3375
|
* { ok: true, value: ["signed-in"] },
|
|
3263
3376
|
* ]);
|
|
3264
3377
|
* // Unlike all, a later Task still runs after an Err.
|
|
3265
|
-
*
|
|
3378
|
+
* assertTrue(activityLoaded);
|
|
3266
3379
|
* ```
|
|
3267
3380
|
*
|
|
3268
3381
|
* @group Collection
|
|
@@ -3279,6 +3392,8 @@ export function allSettled<const TTasks extends ReadonlyArray<AnyTask>>(
|
|
|
3279
3392
|
*
|
|
3280
3393
|
* ```ts
|
|
3281
3394
|
* import {
|
|
3395
|
+
* assertOk,
|
|
3396
|
+
* assertType,
|
|
3282
3397
|
* allSettled,
|
|
3283
3398
|
* createRun,
|
|
3284
3399
|
* err,
|
|
@@ -3303,13 +3418,14 @@ export function allSettled<const TTasks extends ReadonlyArray<AnyTask>>(
|
|
|
3303
3418
|
* allSettled({ user: fetchUser, profile: fetchProfile }),
|
|
3304
3419
|
* );
|
|
3305
3420
|
*
|
|
3306
|
-
*
|
|
3421
|
+
* assertType<
|
|
3307
3422
|
* Result<{
|
|
3308
3423
|
* readonly user: Result<User>;
|
|
3309
3424
|
* readonly profile: Result<string, ProfileNotFoundError>;
|
|
3310
|
-
* }
|
|
3425
|
+
* }>,
|
|
3426
|
+
* typeof results
|
|
3311
3427
|
* >();
|
|
3312
|
-
*
|
|
3428
|
+
* assertOk(results, {
|
|
3313
3429
|
* user: { ok: true, value: { id: "user-1" } },
|
|
3314
3430
|
* profile: { ok: false, error: { type: "ProfileNotFound" } },
|
|
3315
3431
|
* });
|
|
@@ -3327,6 +3443,9 @@ export function allSettled<const TTasks extends TaskRecord>(
|
|
|
3327
3443
|
*
|
|
3328
3444
|
* ```ts
|
|
3329
3445
|
* import {
|
|
3446
|
+
* assertEqual,
|
|
3447
|
+
* assertOk,
|
|
3448
|
+
* assertType,
|
|
3330
3449
|
* allSettled,
|
|
3331
3450
|
* createRun,
|
|
3332
3451
|
* err,
|
|
@@ -3355,19 +3474,20 @@ export function allSettled<const TTasks extends TaskRecord>(
|
|
|
3355
3474
|
* });
|
|
3356
3475
|
*
|
|
3357
3476
|
* // Mapping is eager: it happens before the returned Task starts.
|
|
3358
|
-
*
|
|
3477
|
+
* assertEqual(indexes, [0, 1]);
|
|
3359
3478
|
*
|
|
3360
3479
|
* await using run = createRun();
|
|
3361
3480
|
* const results = await run(loadUsers);
|
|
3362
|
-
*
|
|
3481
|
+
* assertType<
|
|
3363
3482
|
* Result<
|
|
3364
3483
|
* readonly [
|
|
3365
3484
|
* Result<User, UserNotFoundError>,
|
|
3366
3485
|
* Result<User, UserNotFoundError>,
|
|
3367
3486
|
* ]
|
|
3368
|
-
*
|
|
3487
|
+
* >,
|
|
3488
|
+
* typeof results
|
|
3369
3489
|
* >();
|
|
3370
|
-
*
|
|
3490
|
+
* assertOk(results, [
|
|
3371
3491
|
* { ok: true, value: { id: "user-1" } },
|
|
3372
3492
|
* { ok: false, error: { type: "UserNotFound" } },
|
|
3373
3493
|
* ]);
|
|
@@ -3398,6 +3518,9 @@ export function allSettled<
|
|
|
3398
3518
|
*
|
|
3399
3519
|
* ```ts
|
|
3400
3520
|
* import {
|
|
3521
|
+
* assertEqual,
|
|
3522
|
+
* assertOk,
|
|
3523
|
+
* assertType,
|
|
3401
3524
|
* allSettled,
|
|
3402
3525
|
* createRun,
|
|
3403
3526
|
* err,
|
|
@@ -3426,17 +3549,18 @@ export function allSettled<
|
|
|
3426
3549
|
* });
|
|
3427
3550
|
*
|
|
3428
3551
|
* // Mapping is eager: it happens before the returned Task starts.
|
|
3429
|
-
*
|
|
3552
|
+
* assertEqual(roles, ["admin", "reviewer"]);
|
|
3430
3553
|
*
|
|
3431
3554
|
* await using run = createRun();
|
|
3432
3555
|
* const results = await run(loadUsersByRole);
|
|
3433
|
-
*
|
|
3556
|
+
* assertType<
|
|
3434
3557
|
* Result<{
|
|
3435
3558
|
* readonly admin: Result<User, UserNotFoundError>;
|
|
3436
3559
|
* readonly reviewer: Result<User, UserNotFoundError>;
|
|
3437
|
-
* }
|
|
3560
|
+
* }>,
|
|
3561
|
+
* typeof results
|
|
3438
3562
|
* >();
|
|
3439
|
-
*
|
|
3563
|
+
* assertOk(results, {
|
|
3440
3564
|
* admin: { ok: true, value: { id: "user-1" } },
|
|
3441
3565
|
* reviewer: { ok: false, error: { type: "UserNotFound" } },
|
|
3442
3566
|
* });
|
|
@@ -3579,14 +3703,23 @@ const mapInput = (
|
|
|
3579
3703
|
* ### Example
|
|
3580
3704
|
*
|
|
3581
3705
|
* ```ts
|
|
3582
|
-
* import {
|
|
3706
|
+
* import {
|
|
3707
|
+
* assertEqual,
|
|
3708
|
+
* assertOk,
|
|
3709
|
+
* callback,
|
|
3710
|
+
* createRun,
|
|
3711
|
+
* ok,
|
|
3712
|
+
* type Task,
|
|
3713
|
+
* } from "@evolu/common";
|
|
3583
3714
|
*
|
|
3584
3715
|
* const listeners = new Set<(message: string) => void>();
|
|
3585
3716
|
* const subscribe = (
|
|
3586
3717
|
* listener: (message: string) => void,
|
|
3587
3718
|
* ): (() => void) => {
|
|
3588
3719
|
* listeners.add(listener);
|
|
3589
|
-
* return () =>
|
|
3720
|
+
* return () => {
|
|
3721
|
+
* listeners.delete(listener);
|
|
3722
|
+
* };
|
|
3590
3723
|
* };
|
|
3591
3724
|
* const nextMessage: Task<string> = callback(({ resolve }) =>
|
|
3592
3725
|
* subscribe((message) => resolve(ok(message))),
|
|
@@ -3594,11 +3727,11 @@ const mapInput = (
|
|
|
3594
3727
|
*
|
|
3595
3728
|
* await using run = createRun();
|
|
3596
3729
|
* const fiber = run(nextMessage);
|
|
3597
|
-
*
|
|
3730
|
+
* assertEqual(listeners.size, 1);
|
|
3598
3731
|
* for (const listener of listeners) listener("ready");
|
|
3599
|
-
*
|
|
3732
|
+
* assertOk(await fiber, "ready");
|
|
3600
3733
|
* // The callback cleanup unsubscribes after settlement.
|
|
3601
|
-
*
|
|
3734
|
+
* assertEqual(listeners.size, 0);
|
|
3602
3735
|
* ```
|
|
3603
3736
|
*
|
|
3604
3737
|
* @group Interop
|
|
@@ -3633,10 +3766,10 @@ export const callback =
|
|
|
3633
3766
|
* ### Example
|
|
3634
3767
|
*
|
|
3635
3768
|
* ```ts
|
|
3636
|
-
* import { createRun, sleep } from "@evolu/common";
|
|
3769
|
+
* import { assertOk, createRun, sleep } from "@evolu/common";
|
|
3637
3770
|
*
|
|
3638
3771
|
* await using run = createRun();
|
|
3639
|
-
*
|
|
3772
|
+
* assertOk(await run(sleep("1ms")), undefined);
|
|
3640
3773
|
* ```
|
|
3641
3774
|
*
|
|
3642
3775
|
* @group Timing
|
|
@@ -3660,6 +3793,8 @@ export const sleep = (duration: PositiveDuration): Task<void> =>
|
|
|
3660
3793
|
*
|
|
3661
3794
|
* ```ts
|
|
3662
3795
|
* import {
|
|
3796
|
+
* assertErr,
|
|
3797
|
+
* assertType,
|
|
3663
3798
|
* createRun,
|
|
3664
3799
|
* timeout,
|
|
3665
3800
|
* timeoutError,
|
|
@@ -3671,8 +3806,8 @@ export const sleep = (duration: PositiveDuration): Task<void> =>
|
|
|
3671
3806
|
* await using run = createRun();
|
|
3672
3807
|
*
|
|
3673
3808
|
* const result = await run(timeout(waitForAbort, "1ms"));
|
|
3674
|
-
*
|
|
3675
|
-
*
|
|
3809
|
+
* assertType<Result<never, TimeoutError>, typeof result>();
|
|
3810
|
+
* assertErr(result, timeoutError);
|
|
3676
3811
|
* ```
|
|
3677
3812
|
*
|
|
3678
3813
|
* @group Timing
|
|
@@ -3771,6 +3906,8 @@ export interface RetryAttempt<E, Output> extends ScheduleStep<Output> {
|
|
|
3771
3906
|
*
|
|
3772
3907
|
* ```ts
|
|
3773
3908
|
* import {
|
|
3909
|
+
* assertErr,
|
|
3910
|
+
* assertType,
|
|
3774
3911
|
* createRun,
|
|
3775
3912
|
* err,
|
|
3776
3913
|
* recurs,
|
|
@@ -3790,10 +3927,11 @@ export interface RetryAttempt<E, Output> extends ScheduleStep<Output> {
|
|
|
3790
3927
|
*
|
|
3791
3928
|
* await using run = createRun();
|
|
3792
3929
|
* const result = await run(fetchWithRetry);
|
|
3793
|
-
*
|
|
3794
|
-
* Result<string, RetryTaskError<ServiceUnavailableError
|
|
3930
|
+
* assertType<
|
|
3931
|
+
* Result<string, RetryTaskError<ServiceUnavailableError>>,
|
|
3932
|
+
* typeof result
|
|
3795
3933
|
* >();
|
|
3796
|
-
*
|
|
3934
|
+
* assertErr(result, {
|
|
3797
3935
|
* type: "RetryError",
|
|
3798
3936
|
* attempts: 3,
|
|
3799
3937
|
* lastError: { type: "ServiceUnavailable" },
|
|
@@ -3804,6 +3942,7 @@ export interface RetryAttempt<E, Output> extends ScheduleStep<Output> {
|
|
|
3804
3942
|
*
|
|
3805
3943
|
* ```ts
|
|
3806
3944
|
* import {
|
|
3945
|
+
* assertErr,
|
|
3807
3946
|
* createRun,
|
|
3808
3947
|
* err,
|
|
3809
3948
|
* recurs,
|
|
@@ -3826,7 +3965,8 @@ export interface RetryAttempt<E, Output> extends ScheduleStep<Output> {
|
|
|
3826
3965
|
* });
|
|
3827
3966
|
*
|
|
3828
3967
|
* await using run = createRun();
|
|
3829
|
-
*
|
|
3968
|
+
* const result = await run(fetchWithRetry);
|
|
3969
|
+
* assertErr(result, {
|
|
3830
3970
|
* type: "RetryError",
|
|
3831
3971
|
* attempts: 1,
|
|
3832
3972
|
* lastError: { type: "PermanentFailure" },
|
|
@@ -3958,7 +4098,15 @@ export interface RepeatAttempt<T, Output> extends ScheduleStep<Output> {
|
|
|
3958
4098
|
* ### Repeating successes
|
|
3959
4099
|
*
|
|
3960
4100
|
* ```ts
|
|
3961
|
-
* import {
|
|
4101
|
+
* import {
|
|
4102
|
+
* assertEqual,
|
|
4103
|
+
* assertOk,
|
|
4104
|
+
* createRun,
|
|
4105
|
+
* ok,
|
|
4106
|
+
* recurs,
|
|
4107
|
+
* repeat,
|
|
4108
|
+
* type Task,
|
|
4109
|
+
* } from "@evolu/common";
|
|
3962
4110
|
*
|
|
3963
4111
|
* let attempts = 0;
|
|
3964
4112
|
* const checkStatus: Task<string> = () => {
|
|
@@ -3969,14 +4117,16 @@ export interface RepeatAttempt<T, Output> extends ScheduleStep<Output> {
|
|
|
3969
4117
|
* const poll = repeat(checkStatus, recurs(3));
|
|
3970
4118
|
*
|
|
3971
4119
|
* await using run = createRun();
|
|
3972
|
-
*
|
|
3973
|
-
*
|
|
4120
|
+
* assertOk(await run(poll), "pending");
|
|
4121
|
+
* assertEqual(attempts, 4);
|
|
3974
4122
|
* ```
|
|
3975
4123
|
*
|
|
3976
4124
|
* ### Stopping with Done
|
|
3977
4125
|
*
|
|
3978
4126
|
* ```ts
|
|
3979
4127
|
* import {
|
|
4128
|
+
* assertErr,
|
|
4129
|
+
* assertEqual,
|
|
3980
4130
|
* createRun,
|
|
3981
4131
|
* done,
|
|
3982
4132
|
* err,
|
|
@@ -3999,8 +4149,8 @@ export interface RepeatAttempt<T, Output> extends ScheduleStep<Output> {
|
|
|
3999
4149
|
*
|
|
4000
4150
|
* await using run = createRun();
|
|
4001
4151
|
* const result = await run(repeat(processQueue, spaced("1ms")));
|
|
4002
|
-
*
|
|
4003
|
-
*
|
|
4152
|
+
* assertErr(result, done());
|
|
4153
|
+
* assertEqual(queue, []);
|
|
4004
4154
|
* ```
|
|
4005
4155
|
*
|
|
4006
4156
|
* @group Repetition
|
|
@@ -4062,6 +4212,9 @@ export type InferTasksResult<TTasks extends NonEmptyReadonlyArray<AnyTask>> =
|
|
|
4062
4212
|
*
|
|
4063
4213
|
* ```ts
|
|
4064
4214
|
* import {
|
|
4215
|
+
* assertOk,
|
|
4216
|
+
* assertType,
|
|
4217
|
+
* assertTrue,
|
|
4065
4218
|
* any,
|
|
4066
4219
|
* createRun,
|
|
4067
4220
|
* err,
|
|
@@ -4085,11 +4238,9 @@ export type InferTasksResult<TTasks extends NonEmptyReadonlyArray<AnyTask>> =
|
|
|
4085
4238
|
* await using run = createRun();
|
|
4086
4239
|
* const result = await run(any([unavailable, fallback]));
|
|
4087
4240
|
*
|
|
4088
|
-
*
|
|
4089
|
-
*
|
|
4090
|
-
*
|
|
4091
|
-
* expectOk(result, "fallback");
|
|
4092
|
-
* expect(fallbackStarted).toBe(true);
|
|
4241
|
+
* assertType<Result<string, ServiceUnavailableError>, typeof result>();
|
|
4242
|
+
* assertOk(result, "fallback");
|
|
4243
|
+
* assertTrue(fallbackStarted);
|
|
4093
4244
|
* ```
|
|
4094
4245
|
*
|
|
4095
4246
|
* @group Racing
|
|
@@ -4160,6 +4311,7 @@ export const any =
|
|
|
4160
4311
|
*
|
|
4161
4312
|
* ```ts
|
|
4162
4313
|
* import {
|
|
4314
|
+
* assertOk,
|
|
4163
4315
|
* createRun,
|
|
4164
4316
|
* isNonEmptyArray,
|
|
4165
4317
|
* ok,
|
|
@@ -4171,7 +4323,7 @@ export const any =
|
|
|
4171
4323
|
* await using run = createRun();
|
|
4172
4324
|
* if (isNonEmptyArray(tasks)) {
|
|
4173
4325
|
* const result = await run(race(tasks));
|
|
4174
|
-
*
|
|
4326
|
+
* assertOk(result, "first");
|
|
4175
4327
|
* }
|
|
4176
4328
|
* ```
|
|
4177
4329
|
*
|
|
@@ -4179,6 +4331,9 @@ export const any =
|
|
|
4179
4331
|
*
|
|
4180
4332
|
* ```ts
|
|
4181
4333
|
* import {
|
|
4334
|
+
* assertFalse,
|
|
4335
|
+
* assertOk,
|
|
4336
|
+
* assertType,
|
|
4182
4337
|
* createRun,
|
|
4183
4338
|
* ok,
|
|
4184
4339
|
* race,
|
|
@@ -4200,9 +4355,9 @@ export const any =
|
|
|
4200
4355
|
* // Input order does not matter: the first settled Result wins, and the
|
|
4201
4356
|
* // still-running loser is aborted.
|
|
4202
4357
|
* const result = await run(race([slow, fast]));
|
|
4203
|
-
*
|
|
4204
|
-
*
|
|
4205
|
-
*
|
|
4358
|
+
* assertType<Result<string>, typeof result>();
|
|
4359
|
+
* assertOk(result, "fast");
|
|
4360
|
+
* assertFalse(slowCompleted);
|
|
4206
4361
|
* ```
|
|
4207
4362
|
*
|
|
4208
4363
|
* @group Racing
|
|
@@ -4251,6 +4406,8 @@ export const race =
|
|
|
4251
4406
|
*
|
|
4252
4407
|
* ```ts
|
|
4253
4408
|
* import {
|
|
4409
|
+
* assertFalse,
|
|
4410
|
+
* assertOk,
|
|
4254
4411
|
* createRun,
|
|
4255
4412
|
* err,
|
|
4256
4413
|
* firstN,
|
|
@@ -4281,8 +4438,8 @@ export const race =
|
|
|
4281
4438
|
*
|
|
4282
4439
|
* // Errs do not count. After two Ok values settle, the slow Task is aborted.
|
|
4283
4440
|
* const result = await run(firstN(tasks, 2, { concurrency: 4 }));
|
|
4284
|
-
*
|
|
4285
|
-
*
|
|
4441
|
+
* assertOk(result, ["fast-1", "fast-2"]);
|
|
4442
|
+
* assertFalse(slowCompleted);
|
|
4286
4443
|
* ```
|
|
4287
4444
|
*
|
|
4288
4445
|
* @group Racing
|
|
@@ -4330,6 +4487,8 @@ export const firstN =
|
|
|
4330
4487
|
*
|
|
4331
4488
|
* ```ts
|
|
4332
4489
|
* import {
|
|
4490
|
+
* assertFalse,
|
|
4491
|
+
* assertOk,
|
|
4333
4492
|
* createRun,
|
|
4334
4493
|
* err,
|
|
4335
4494
|
* firstNSettled,
|
|
@@ -4355,11 +4514,11 @@ export const firstN =
|
|
|
4355
4514
|
*
|
|
4356
4515
|
* // Err and Ok both count, and Results use settlement order.
|
|
4357
4516
|
* const result = await run(firstNSettled(tasks, 2, { concurrency: 3 }));
|
|
4358
|
-
*
|
|
4517
|
+
* assertOk(result, [
|
|
4359
4518
|
* { ok: false, error: { type: "ServiceUnavailable" } },
|
|
4360
4519
|
* { ok: true, value: "fast" },
|
|
4361
4520
|
* ]);
|
|
4362
|
-
*
|
|
4521
|
+
* assertFalse(slowCompleted);
|
|
4363
4522
|
* ```
|
|
4364
4523
|
*
|
|
4365
4524
|
* @group Racing
|
|
@@ -4446,6 +4605,9 @@ export type EachCallback<TTasks extends NonEmptyReadonlyArray<AnyTask>> = (
|
|
|
4446
4605
|
*
|
|
4447
4606
|
* ```ts
|
|
4448
4607
|
* import {
|
|
4608
|
+
* assertEqual,
|
|
4609
|
+
* assertFalse,
|
|
4610
|
+
* assertOk,
|
|
4449
4611
|
* createRun,
|
|
4450
4612
|
* each,
|
|
4451
4613
|
* err,
|
|
@@ -4481,9 +4643,9 @@ export type EachCallback<TTasks extends NonEmptyReadonlyArray<AnyTask>> = (
|
|
|
4481
4643
|
* ),
|
|
4482
4644
|
* );
|
|
4483
4645
|
*
|
|
4484
|
-
*
|
|
4485
|
-
*
|
|
4486
|
-
*
|
|
4646
|
+
* assertOk(result, undefined);
|
|
4647
|
+
* assertEqual(first, ["fast", 2]);
|
|
4648
|
+
* assertFalse(slowCompleted);
|
|
4487
4649
|
* ```
|
|
4488
4650
|
*
|
|
4489
4651
|
* `onResult` is a synchronous scheduling decision, not a place to do work. It
|
|
@@ -4593,13 +4755,19 @@ export type TaskPriority = "user-blocking" | "user-visible" | "background";
|
|
|
4593
4755
|
* ### Example
|
|
4594
4756
|
*
|
|
4595
4757
|
* ```ts
|
|
4596
|
-
* import {
|
|
4758
|
+
* import {
|
|
4759
|
+
* assertOk,
|
|
4760
|
+
* createRun,
|
|
4761
|
+
* ok,
|
|
4762
|
+
* prioritized,
|
|
4763
|
+
* type Task,
|
|
4764
|
+
* } from "@evolu/common";
|
|
4597
4765
|
*
|
|
4598
4766
|
* const rebuildSearchIndex: Task<string> = () => ok("indexed");
|
|
4599
4767
|
* const backgroundIndexing = prioritized("background", rebuildSearchIndex);
|
|
4600
4768
|
*
|
|
4601
4769
|
* await using run = createRun();
|
|
4602
|
-
*
|
|
4770
|
+
* assertOk(await run(backgroundIndexing), "indexed");
|
|
4603
4771
|
* ```
|
|
4604
4772
|
*
|
|
4605
4773
|
* @group Scheduling
|
|
@@ -4623,7 +4791,13 @@ export const prioritized = <T, E, D = unknown>(
|
|
|
4623
4791
|
* ### Example
|
|
4624
4792
|
*
|
|
4625
4793
|
* ```ts
|
|
4626
|
-
* import {
|
|
4794
|
+
* import {
|
|
4795
|
+
* assertOk,
|
|
4796
|
+
* createRun,
|
|
4797
|
+
* ok,
|
|
4798
|
+
* yieldNow,
|
|
4799
|
+
* type Task,
|
|
4800
|
+
* } from "@evolu/common";
|
|
4627
4801
|
*
|
|
4628
4802
|
* const sumTo =
|
|
4629
4803
|
* (count: number): Task<number> =>
|
|
@@ -4639,7 +4813,7 @@ export const prioritized = <T, E, D = unknown>(
|
|
|
4639
4813
|
* };
|
|
4640
4814
|
*
|
|
4641
4815
|
* await using run = createRun();
|
|
4642
|
-
*
|
|
4816
|
+
* assertOk(await run(sumTo(1001)), 500500);
|
|
4643
4817
|
* ```
|
|
4644
4818
|
*
|
|
4645
4819
|
* @group Scheduling
|
|
@@ -4676,6 +4850,10 @@ export const yieldNow: Task<void> = async (run) => {
|
|
|
4676
4850
|
*
|
|
4677
4851
|
* ```ts
|
|
4678
4852
|
* import {
|
|
4853
|
+
* assertEqual,
|
|
4854
|
+
* assertFalse,
|
|
4855
|
+
* assertType,
|
|
4856
|
+
* assertTrue,
|
|
4679
4857
|
* AbortError,
|
|
4680
4858
|
* createRun,
|
|
4681
4859
|
* ok,
|
|
@@ -4692,23 +4870,22 @@ export const yieldNow: Task<void> = async (run) => {
|
|
|
4692
4870
|
* const serverStarted = Promise.withResolvers<void>();
|
|
4693
4871
|
* let serverStopped = false;
|
|
4694
4872
|
* const startServer: Task<Server, never, ServerDep> = (run) => {
|
|
4695
|
-
*
|
|
4873
|
+
* assertEqual(run.deps.port, 3000);
|
|
4696
4874
|
* serverStarted.resolve();
|
|
4697
4875
|
* return ok({
|
|
4698
|
-
* [Symbol.asyncDispose]:
|
|
4876
|
+
* [Symbol.asyncDispose]: () => {
|
|
4699
4877
|
* serverStopped = true;
|
|
4878
|
+
* return Promise.resolve();
|
|
4700
4879
|
* },
|
|
4701
4880
|
* });
|
|
4702
4881
|
* };
|
|
4703
4882
|
*
|
|
4704
4883
|
* const serve = (): Task<never, never, ServerDep> => async (run) => {
|
|
4705
|
-
* await using
|
|
4884
|
+
* await using _ = await run.ok(startServer);
|
|
4706
4885
|
* return await run(waitForAbort);
|
|
4707
4886
|
* };
|
|
4708
4887
|
*
|
|
4709
|
-
*
|
|
4710
|
-
* Task<never, never, ServerDep>
|
|
4711
|
-
* >();
|
|
4888
|
+
* assertType<Task<never, never, ServerDep>, ReturnType<typeof serve>>();
|
|
4712
4889
|
*
|
|
4713
4890
|
* await using run = createRun();
|
|
4714
4891
|
* const fiber = run.abortable(serve(), { port: 3000 });
|
|
@@ -4716,9 +4893,9 @@ export const yieldNow: Task<void> = async (run) => {
|
|
|
4716
4893
|
* fiber.abort();
|
|
4717
4894
|
*
|
|
4718
4895
|
* const result = await fiber;
|
|
4719
|
-
*
|
|
4720
|
-
*
|
|
4721
|
-
*
|
|
4896
|
+
* assertFalse(result.ok);
|
|
4897
|
+
* assertTrue(AbortError.is(result.error));
|
|
4898
|
+
* assertTrue(serverStopped);
|
|
4722
4899
|
* ```
|
|
4723
4900
|
*
|
|
4724
4901
|
* @group Abortability
|
|
@@ -4773,6 +4950,9 @@ export const waitForAbort: Task<never> = async (run) => {
|
|
|
4773
4950
|
*
|
|
4774
4951
|
* ```ts
|
|
4775
4952
|
* import {
|
|
4953
|
+
* assertEqual,
|
|
4954
|
+
* assertFalse,
|
|
4955
|
+
* assertTrue,
|
|
4776
4956
|
* createRun,
|
|
4777
4957
|
* daemon,
|
|
4778
4958
|
* ok,
|
|
@@ -4793,18 +4973,24 @@ export const waitForAbort: Task<never> = async (run) => {
|
|
|
4793
4973
|
* {
|
|
4794
4974
|
* await using run = createRun();
|
|
4795
4975
|
* const result = await run(timeout(daemon(taskNotUsingAbort), "1ms"));
|
|
4796
|
-
*
|
|
4797
|
-
*
|
|
4798
|
-
*
|
|
4976
|
+
* assertFalse(result.ok);
|
|
4977
|
+
* assertEqual(result.error.type, "TimeoutError");
|
|
4978
|
+
* assertFalse(finished);
|
|
4799
4979
|
* finishTask();
|
|
4800
4980
|
* }
|
|
4801
|
-
*
|
|
4981
|
+
* assertTrue(finished);
|
|
4802
4982
|
* ```
|
|
4803
4983
|
*
|
|
4804
4984
|
* Promise-returning functions should be called inside the Task, not before it.
|
|
4805
4985
|
*
|
|
4806
4986
|
* ```ts
|
|
4807
|
-
* import {
|
|
4987
|
+
* import {
|
|
4988
|
+
* assertOk,
|
|
4989
|
+
* createRun,
|
|
4990
|
+
* ok,
|
|
4991
|
+
* type Result,
|
|
4992
|
+
* type Task,
|
|
4993
|
+
* } from "@evolu/common";
|
|
4808
4994
|
*
|
|
4809
4995
|
* type ResultValue = string;
|
|
4810
4996
|
* const createPromiseReturningResult = (): Promise<Result<ResultValue>> =>
|
|
@@ -4813,14 +4999,20 @@ export const waitForAbort: Task<never> = async (run) => {
|
|
|
4813
4999
|
* const task: Task<ResultValue> = () => createPromiseReturningResult();
|
|
4814
5000
|
*
|
|
4815
5001
|
* await using run = createRun();
|
|
4816
|
-
*
|
|
5002
|
+
* assertOk(await run(task), "value");
|
|
4817
5003
|
* ```
|
|
4818
5004
|
*
|
|
4819
5005
|
* Do not reuse an already-running Promise. It started outside the Task, so the
|
|
4820
5006
|
* Run cannot own its lifetime or request abort before it begins.
|
|
4821
5007
|
*
|
|
4822
5008
|
* ```ts
|
|
4823
|
-
* import {
|
|
5009
|
+
* import {
|
|
5010
|
+
* assertType,
|
|
5011
|
+
* assertTrue,
|
|
5012
|
+
* ok,
|
|
5013
|
+
* type Result,
|
|
5014
|
+
* type Task,
|
|
5015
|
+
* } from "@evolu/common";
|
|
4824
5016
|
*
|
|
4825
5017
|
* type ResultValue = string;
|
|
4826
5018
|
* let promiseStarted = false;
|
|
@@ -4835,8 +5027,8 @@ export const waitForAbort: Task<never> = async (run) => {
|
|
|
4835
5027
|
* const promise = createPromiseReturningResult();
|
|
4836
5028
|
* const task: Task<ResultValue> = () => promise;
|
|
4837
5029
|
*
|
|
4838
|
-
*
|
|
4839
|
-
*
|
|
5030
|
+
* assertTrue(promiseStarted);
|
|
5031
|
+
* assertType<Task<ResultValue>, typeof task>();
|
|
4840
5032
|
* ```
|
|
4841
5033
|
*
|
|
4842
5034
|
* @group Lifetime
|
|
@@ -4874,14 +5066,21 @@ export const daemon =
|
|
|
4874
5066
|
* ### Example
|
|
4875
5067
|
*
|
|
4876
5068
|
* ```ts
|
|
4877
|
-
* import {
|
|
5069
|
+
* import {
|
|
5070
|
+
* assertFalse,
|
|
5071
|
+
* assertOk,
|
|
5072
|
+
* createRun,
|
|
5073
|
+
* ok,
|
|
5074
|
+
* unabortable,
|
|
5075
|
+
* type Task,
|
|
5076
|
+
* } from "@evolu/common";
|
|
4878
5077
|
*
|
|
4879
5078
|
* const commitStarted = Promise.withResolvers<void>();
|
|
4880
5079
|
* const finishCommit = Promise.withResolvers<void>();
|
|
4881
5080
|
* const commit: Task<string> = unabortable(async (run) => {
|
|
4882
5081
|
* commitStarted.resolve();
|
|
4883
5082
|
* await finishCommit.promise;
|
|
4884
|
-
*
|
|
5083
|
+
* assertFalse(run.signal.aborted);
|
|
4885
5084
|
* return ok("committed");
|
|
4886
5085
|
* });
|
|
4887
5086
|
*
|
|
@@ -4891,7 +5090,7 @@ export const daemon =
|
|
|
4891
5090
|
* fiber.abort();
|
|
4892
5091
|
* finishCommit.resolve();
|
|
4893
5092
|
*
|
|
4894
|
-
*
|
|
5093
|
+
* assertOk(await fiber, "committed");
|
|
4895
5094
|
* ```
|
|
4896
5095
|
*
|
|
4897
5096
|
* @group Abortability
|
|
@@ -4922,6 +5121,9 @@ export const unabortable = /*#__PURE__*/ withTaskMeta({
|
|
|
4922
5121
|
*
|
|
4923
5122
|
* ```ts
|
|
4924
5123
|
* import {
|
|
5124
|
+
* assertEqual,
|
|
5125
|
+
* assertFalse,
|
|
5126
|
+
* assertTrue,
|
|
4925
5127
|
* AbortError,
|
|
4926
5128
|
* createRun,
|
|
4927
5129
|
* ok,
|
|
@@ -4938,17 +5140,17 @@ export const unabortable = /*#__PURE__*/ withTaskMeta({
|
|
|
4938
5140
|
* const operationStarted = Promise.withResolvers<void>();
|
|
4939
5141
|
* const operate =
|
|
4940
5142
|
* (resource: Resource): Task<never> =>
|
|
4941
|
-
*
|
|
4942
|
-
*
|
|
5143
|
+
* (run) => {
|
|
5144
|
+
* assertEqual(resource.id, "resource-1");
|
|
4943
5145
|
* operationStarted.resolve();
|
|
4944
|
-
* return
|
|
5146
|
+
* return run(waitForAbort);
|
|
4945
5147
|
* };
|
|
4946
5148
|
* let released = false;
|
|
4947
5149
|
* const release =
|
|
4948
5150
|
* (_resource: Resource): Task<void> =>
|
|
4949
5151
|
* (run) => {
|
|
4950
5152
|
* // Release inherits the mask even after abort was requested.
|
|
4951
|
-
*
|
|
5153
|
+
* assertFalse(run.signal.aborted);
|
|
4952
5154
|
* released = true;
|
|
4953
5155
|
* return ok();
|
|
4954
5156
|
* };
|
|
@@ -4972,9 +5174,9 @@ export const unabortable = /*#__PURE__*/ withTaskMeta({
|
|
|
4972
5174
|
* await operationStarted.promise;
|
|
4973
5175
|
* fiber.abort();
|
|
4974
5176
|
* const result = await fiber;
|
|
4975
|
-
*
|
|
4976
|
-
*
|
|
4977
|
-
*
|
|
5177
|
+
* assertFalse(result.ok);
|
|
5178
|
+
* assertTrue(AbortError.is(result.error));
|
|
5179
|
+
* assertTrue(released);
|
|
4978
5180
|
* ```
|
|
4979
5181
|
*
|
|
4980
5182
|
* @group Abortability
|
|
@@ -5034,6 +5236,8 @@ export const unabortableMask = <T, E, D = unknown>(
|
|
|
5034
5236
|
*
|
|
5035
5237
|
* ```ts
|
|
5036
5238
|
* import {
|
|
5239
|
+
* assertErr,
|
|
5240
|
+
* assertTrue,
|
|
5037
5241
|
* acquireUseRelease,
|
|
5038
5242
|
* createRun,
|
|
5039
5243
|
* err,
|
|
@@ -5073,9 +5277,9 @@ export const unabortableMask = <T, E, D = unknown>(
|
|
|
5073
5277
|
* );
|
|
5074
5278
|
*
|
|
5075
5279
|
* await using run = createRun();
|
|
5076
|
-
*
|
|
5280
|
+
* assertErr(await run(queryUser), { type: "UserUnavailable" });
|
|
5077
5281
|
* // Release still runs when use returns a domain error.
|
|
5078
|
-
*
|
|
5282
|
+
* assertTrue(connectionClosed);
|
|
5079
5283
|
* ```
|
|
5080
5284
|
*
|
|
5081
5285
|
* @group Lifetime
|
|
@@ -5137,6 +5341,10 @@ export interface Deferred<T, E = never> {
|
|
|
5137
5341
|
*
|
|
5138
5342
|
* ```ts
|
|
5139
5343
|
* import {
|
|
5344
|
+
* assertFalse,
|
|
5345
|
+
* assertOk,
|
|
5346
|
+
* assertType,
|
|
5347
|
+
* assertTrue,
|
|
5140
5348
|
* createDeferred,
|
|
5141
5349
|
* createRun,
|
|
5142
5350
|
* ok,
|
|
@@ -5147,22 +5355,28 @@ export interface Deferred<T, E = never> {
|
|
|
5147
5355
|
* const deferred = createDeferred<string>();
|
|
5148
5356
|
*
|
|
5149
5357
|
* const fiber = run(deferred.task);
|
|
5150
|
-
*
|
|
5358
|
+
* assertTrue(deferred.resolve(ok("ready")));
|
|
5151
5359
|
*
|
|
5152
5360
|
* const result = await fiber;
|
|
5153
|
-
*
|
|
5154
|
-
*
|
|
5361
|
+
* assertType<Result<string>, typeof result>();
|
|
5362
|
+
* assertOk(result, "ready");
|
|
5155
5363
|
*
|
|
5156
5364
|
* // A Deferred is one-shot: later resolutions are ignored, and future
|
|
5157
5365
|
* // waiters receive the original Result.
|
|
5158
|
-
*
|
|
5159
|
-
*
|
|
5366
|
+
* assertFalse(deferred.resolve(ok("late")));
|
|
5367
|
+
* assertOk(await run(deferred.task), "ready");
|
|
5160
5368
|
* ```
|
|
5161
5369
|
*
|
|
5162
5370
|
* ### Aborting a waiter
|
|
5163
5371
|
*
|
|
5164
5372
|
* ```ts
|
|
5165
|
-
* import {
|
|
5373
|
+
* import {
|
|
5374
|
+
* assertFalse,
|
|
5375
|
+
* assertTrue,
|
|
5376
|
+
* AbortError,
|
|
5377
|
+
* createDeferred,
|
|
5378
|
+
* createRun,
|
|
5379
|
+
* } from "@evolu/common";
|
|
5166
5380
|
*
|
|
5167
5381
|
* await using run = createRun();
|
|
5168
5382
|
* const deferred = createDeferred<string>();
|
|
@@ -5171,8 +5385,8 @@ export interface Deferred<T, E = never> {
|
|
|
5171
5385
|
* fiber.abort({ type: "NoLongerNeeded" });
|
|
5172
5386
|
*
|
|
5173
5387
|
* const result = await fiber;
|
|
5174
|
-
*
|
|
5175
|
-
*
|
|
5388
|
+
* assertFalse(result.ok);
|
|
5389
|
+
* assertTrue(AbortError.is(result.error));
|
|
5176
5390
|
* ```
|
|
5177
5391
|
*
|
|
5178
5392
|
* @group Concurrency primitives
|
|
@@ -5245,7 +5459,15 @@ export interface Gate {
|
|
|
5245
5459
|
* ### Example
|
|
5246
5460
|
*
|
|
5247
5461
|
* ```ts
|
|
5248
|
-
* import {
|
|
5462
|
+
* import {
|
|
5463
|
+
* assertEqual,
|
|
5464
|
+
* assertOk,
|
|
5465
|
+
* assertTrue,
|
|
5466
|
+
* createGate,
|
|
5467
|
+
* createRun,
|
|
5468
|
+
* ok,
|
|
5469
|
+
* type Task,
|
|
5470
|
+
* } from "@evolu/common";
|
|
5249
5471
|
*
|
|
5250
5472
|
* await using run = createRun();
|
|
5251
5473
|
* const networkGate = createGate();
|
|
@@ -5261,13 +5483,13 @@ export interface Gate {
|
|
|
5261
5483
|
*
|
|
5262
5484
|
* const first = run(syncOnce("first"));
|
|
5263
5485
|
* const second = run(syncOnce("second"));
|
|
5264
|
-
*
|
|
5486
|
+
* assertEqual(uploadedItems, []);
|
|
5265
5487
|
*
|
|
5266
5488
|
* networkGate.open();
|
|
5267
|
-
*
|
|
5268
|
-
*
|
|
5269
|
-
*
|
|
5270
|
-
*
|
|
5489
|
+
* assertOk(await first, undefined);
|
|
5490
|
+
* assertOk(await second, undefined);
|
|
5491
|
+
* assertEqual(uploadedItems, ["first", "second"]);
|
|
5492
|
+
* assertTrue(networkGate.isOpen());
|
|
5271
5493
|
* ```
|
|
5272
5494
|
*
|
|
5273
5495
|
* @group Concurrency primitives
|
|
@@ -5469,6 +5691,7 @@ export interface SemaphoreSnapshot {
|
|
|
5469
5691
|
*
|
|
5470
5692
|
* ```ts
|
|
5471
5693
|
* import {
|
|
5694
|
+
* assertEqual,
|
|
5472
5695
|
* createRun,
|
|
5473
5696
|
* createSemaphore,
|
|
5474
5697
|
* getOk,
|
|
@@ -5500,8 +5723,8 @@ export interface SemaphoreSnapshot {
|
|
|
5500
5723
|
* ]);
|
|
5501
5724
|
*
|
|
5502
5725
|
* const savedUsers = results.map(getOk);
|
|
5503
|
-
*
|
|
5504
|
-
*
|
|
5726
|
+
* assertEqual(savedUsers, ["saved:1", "saved:2", "saved:3"]);
|
|
5727
|
+
* assertEqual(maxActiveSaves, 2);
|
|
5505
5728
|
* ```
|
|
5506
5729
|
*
|
|
5507
5730
|
* @group Concurrency primitives
|
|
@@ -5670,6 +5893,8 @@ export interface Mutex {
|
|
|
5670
5893
|
*
|
|
5671
5894
|
* ```ts
|
|
5672
5895
|
* import {
|
|
5896
|
+
* assertEqual,
|
|
5897
|
+
* assertOk,
|
|
5673
5898
|
* createMutex,
|
|
5674
5899
|
* createRun,
|
|
5675
5900
|
* ok,
|
|
@@ -5692,9 +5917,9 @@ export interface Mutex {
|
|
|
5692
5917
|
* run(deposit(2)),
|
|
5693
5918
|
* run(deposit(3)),
|
|
5694
5919
|
* ]);
|
|
5695
|
-
*
|
|
5696
|
-
*
|
|
5697
|
-
*
|
|
5920
|
+
* assertOk(first, undefined);
|
|
5921
|
+
* assertOk(second, undefined);
|
|
5922
|
+
* assertEqual(balance, 5);
|
|
5698
5923
|
* ```
|
|
5699
5924
|
*
|
|
5700
5925
|
* @group Concurrency primitives
|
|
@@ -5758,6 +5983,8 @@ export interface CreateSemaphoreByKeyOptions<K, L = K> extends LookupOption<
|
|
|
5758
5983
|
*
|
|
5759
5984
|
* ```ts
|
|
5760
5985
|
* import {
|
|
5986
|
+
* assertOk,
|
|
5987
|
+
* assertTrue,
|
|
5761
5988
|
* createRun,
|
|
5762
5989
|
* createSemaphoreByKey,
|
|
5763
5990
|
* ok,
|
|
@@ -5770,11 +5997,11 @@ export interface CreateSemaphoreByKeyOptions<K, L = K> extends LookupOption<
|
|
|
5770
5997
|
* downloadsByHost.withPermit(host, () => ok(`${host}/${file}`));
|
|
5771
5998
|
*
|
|
5772
5999
|
* await using run = createRun();
|
|
5773
|
-
*
|
|
6000
|
+
* assertOk(
|
|
5774
6001
|
* await run(download("a.example", "index.json")),
|
|
5775
6002
|
* "a.example/index.json",
|
|
5776
6003
|
* );
|
|
5777
|
-
*
|
|
6004
|
+
* assertTrue(downloadsByHost.isIdle("a.example"));
|
|
5778
6005
|
* ```
|
|
5779
6006
|
*
|
|
5780
6007
|
* @group Concurrency primitives
|
|
@@ -5852,6 +6079,8 @@ export interface CreateMutexByKeyOptions<K, L = K> extends LookupOption<K, L> {}
|
|
|
5852
6079
|
*
|
|
5853
6080
|
* ```ts
|
|
5854
6081
|
* import {
|
|
6082
|
+
* assertOk,
|
|
6083
|
+
* assertTrue,
|
|
5855
6084
|
* createMutexByKey,
|
|
5856
6085
|
* createRun,
|
|
5857
6086
|
* ok,
|
|
@@ -5868,9 +6097,9 @@ export interface CreateMutexByKeyOptions<K, L = K> extends LookupOption<K, L> {}
|
|
|
5868
6097
|
* });
|
|
5869
6098
|
*
|
|
5870
6099
|
* await using run = createRun();
|
|
5871
|
-
*
|
|
5872
|
-
*
|
|
5873
|
-
*
|
|
6100
|
+
* assertOk(await run(deposit("checking", 2)), 2);
|
|
6101
|
+
* assertOk(await run(deposit("checking", 3)), 5);
|
|
6102
|
+
* assertTrue(accountLocks.isIdle("checking"));
|
|
5874
6103
|
* ```
|
|
5875
6104
|
*
|
|
5876
6105
|
* @group Concurrency primitives
|
|
@@ -5960,14 +6189,14 @@ export interface MutexRef<T> {
|
|
|
5960
6189
|
* ### Example
|
|
5961
6190
|
*
|
|
5962
6191
|
* ```ts
|
|
5963
|
-
* import { createMutexRef, createRun, ok } from "@evolu/common";
|
|
6192
|
+
* import { assertOk, createMutexRef, createRun, ok } from "@evolu/common";
|
|
5964
6193
|
*
|
|
5965
6194
|
* const counter = createMutexRef(0);
|
|
5966
6195
|
* const increment = counter.updateAndGet((value) => () => ok(value + 1));
|
|
5967
6196
|
*
|
|
5968
6197
|
* await using run = createRun();
|
|
5969
|
-
*
|
|
5970
|
-
*
|
|
6198
|
+
* assertOk(await run(increment), 1);
|
|
6199
|
+
* assertOk(await run(counter.get), 1);
|
|
5971
6200
|
* ```
|
|
5972
6201
|
*
|
|
5973
6202
|
* @group Concurrency primitives
|