effect 3.3.5 → 3.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/Micro/package.json +6 -0
  2. package/dist/cjs/Array.js +18 -3
  3. package/dist/cjs/Array.js.map +1 -1
  4. package/dist/cjs/Chunk.js +13 -2
  5. package/dist/cjs/Chunk.js.map +1 -1
  6. package/dist/cjs/Effect.js +236 -15
  7. package/dist/cjs/Effect.js.map +1 -1
  8. package/dist/cjs/Either.js +31 -1
  9. package/dist/cjs/Either.js.map +1 -1
  10. package/dist/cjs/ManagedRuntime.js.map +1 -1
  11. package/dist/cjs/Micro.js +2383 -0
  12. package/dist/cjs/Micro.js.map +1 -0
  13. package/dist/cjs/Option.js +1 -2
  14. package/dist/cjs/Option.js.map +1 -1
  15. package/dist/cjs/Schedule.js +2 -2
  16. package/dist/cjs/Stream.js.map +1 -1
  17. package/dist/cjs/Tuple.js +16 -9
  18. package/dist/cjs/Tuple.js.map +1 -1
  19. package/dist/cjs/index.js +4 -2
  20. package/dist/cjs/index.js.map +1 -1
  21. package/dist/cjs/internal/core-effect.js +4 -2
  22. package/dist/cjs/internal/core-effect.js.map +1 -1
  23. package/dist/cjs/internal/core.js +12 -2
  24. package/dist/cjs/internal/core.js.map +1 -1
  25. package/dist/cjs/internal/fiberRuntime.js +32 -0
  26. package/dist/cjs/internal/fiberRuntime.js.map +1 -1
  27. package/dist/cjs/internal/stream.js.map +1 -1
  28. package/dist/cjs/internal/version.js +1 -1
  29. package/dist/dts/Array.d.ts +14 -0
  30. package/dist/dts/Array.d.ts.map +1 -1
  31. package/dist/dts/Cause.d.ts +1 -1
  32. package/dist/dts/Chunk.d.ts +11 -0
  33. package/dist/dts/Chunk.d.ts.map +1 -1
  34. package/dist/dts/Effect.d.ts +235 -12
  35. package/dist/dts/Effect.d.ts.map +1 -1
  36. package/dist/dts/Either.d.ts +35 -0
  37. package/dist/dts/Either.d.ts.map +1 -1
  38. package/dist/dts/ManagedRuntime.d.ts +15 -0
  39. package/dist/dts/ManagedRuntime.d.ts.map +1 -1
  40. package/dist/dts/Micro.d.ts +2010 -0
  41. package/dist/dts/Micro.d.ts.map +1 -0
  42. package/dist/dts/Option.d.ts +2 -0
  43. package/dist/dts/Option.d.ts.map +1 -1
  44. package/dist/dts/Schedule.d.ts +2 -2
  45. package/dist/dts/Stream.d.ts +45 -6
  46. package/dist/dts/Stream.d.ts.map +1 -1
  47. package/dist/dts/Tuple.d.ts +18 -0
  48. package/dist/dts/Tuple.d.ts.map +1 -1
  49. package/dist/dts/index.d.ts +7 -0
  50. package/dist/dts/index.d.ts.map +1 -1
  51. package/dist/dts/internal/core-effect.d.ts.map +1 -1
  52. package/dist/dts/internal/core.d.ts.map +1 -1
  53. package/dist/dts/internal/fiberRuntime.d.ts.map +1 -1
  54. package/dist/esm/Array.js +14 -0
  55. package/dist/esm/Array.js.map +1 -1
  56. package/dist/esm/Chunk.js +11 -0
  57. package/dist/esm/Chunk.js.map +1 -1
  58. package/dist/esm/Effect.js +233 -12
  59. package/dist/esm/Effect.js.map +1 -1
  60. package/dist/esm/Either.js +30 -0
  61. package/dist/esm/Either.js.map +1 -1
  62. package/dist/esm/ManagedRuntime.js.map +1 -1
  63. package/dist/esm/Micro.js +2307 -0
  64. package/dist/esm/Micro.js.map +1 -0
  65. package/dist/esm/Option.js +1 -1
  66. package/dist/esm/Option.js.map +1 -1
  67. package/dist/esm/Schedule.js +2 -2
  68. package/dist/esm/Stream.js.map +1 -1
  69. package/dist/esm/Tuple.js +15 -8
  70. package/dist/esm/Tuple.js.map +1 -1
  71. package/dist/esm/index.js +7 -0
  72. package/dist/esm/index.js.map +1 -1
  73. package/dist/esm/internal/core-effect.js +2 -0
  74. package/dist/esm/internal/core-effect.js.map +1 -1
  75. package/dist/esm/internal/core.js +10 -1
  76. package/dist/esm/internal/core.js.map +1 -1
  77. package/dist/esm/internal/fiberRuntime.js +32 -0
  78. package/dist/esm/internal/fiberRuntime.js.map +1 -1
  79. package/dist/esm/internal/stream.js.map +1 -1
  80. package/dist/esm/internal/version.js +1 -1
  81. package/package.json +9 -1
  82. package/src/Array.ts +15 -0
  83. package/src/Cause.ts +1 -1
  84. package/src/Chunk.ts +12 -0
  85. package/src/Effect.ts +243 -12
  86. package/src/Either.ts +51 -0
  87. package/src/ManagedRuntime.ts +16 -0
  88. package/src/Micro.ts +3835 -0
  89. package/src/Option.ts +12 -1
  90. package/src/Schedule.ts +2 -2
  91. package/src/Stream.ts +60 -8
  92. package/src/Tuple.ts +18 -8
  93. package/src/index.ts +8 -0
  94. package/src/internal/core-effect.ts +33 -0
  95. package/src/internal/core.ts +18 -1
  96. package/src/internal/fiberRuntime.ts +32 -0
  97. package/src/internal/stream.ts +8 -4
  98. package/src/internal/version.ts +1 -1
package/src/Micro.ts ADDED
@@ -0,0 +1,3835 @@
1
+ /**
2
+ * A lightweight alternative to the `Effect` data type, with a subset of the functionality.
3
+ *
4
+ * @since 3.4.0
5
+ * @experimental
6
+ */
7
+ import type { Channel, ChannelTypeId } from "./Channel.js"
8
+ import * as Context from "./Context.js"
9
+ import type { Effect, EffectTypeId } from "./Effect.js"
10
+ import * as Effectable from "./Effectable.js"
11
+ import * as Either from "./Either.js"
12
+ import { constTrue, constVoid, dual, identity, type LazyArg } from "./Function.js"
13
+ import { globalValue } from "./GlobalValue.js"
14
+ import type { TypeLambda } from "./HKT.js"
15
+ import type { Inspectable } from "./Inspectable.js"
16
+ import { NodeInspectSymbol, toStringUnknown } from "./Inspectable.js"
17
+ import { StructuralPrototype } from "./internal/effectable.js"
18
+ import { SingleShotGen } from "./internal/singleShotGen.js"
19
+ import * as Option from "./Option.js"
20
+ import { type Pipeable, pipeArguments } from "./Pipeable.js"
21
+ import { isIterable, isTagged, type Predicate, type Refinement } from "./Predicate.js"
22
+ import type { ReadonlyRecord } from "./Record.js"
23
+ import type { Sink, SinkTypeId } from "./Sink.js"
24
+ import type { Stream, StreamTypeId } from "./Stream.js"
25
+ import type { Concurrency, Covariant, Equals, NoInfer, NotFunction, Simplify } from "./Types.js"
26
+ import { YieldWrap, yieldWrapGet } from "./Utils.js"
27
+
28
+ /**
29
+ * @since 3.4.0
30
+ * @experimental
31
+ * @category type ids
32
+ */
33
+ export const TypeId: unique symbol = Symbol.for("effect/Micro")
34
+
35
+ /**
36
+ * @since 3.4.0
37
+ * @experimental
38
+ * @category type ids
39
+ */
40
+ export type TypeId = typeof TypeId
41
+
42
+ /**
43
+ * @since 3.4.0
44
+ * @experimental
45
+ * @category symbols
46
+ */
47
+ export const runSymbol: unique symbol = Symbol.for("effect/Micro/runSymbol")
48
+
49
+ /**
50
+ * @since 3.4.0
51
+ * @experimental
52
+ * @category symbols
53
+ */
54
+ export type runSymbol = typeof runSymbol
55
+
56
+ /**
57
+ * A lightweight alternative to the `Effect` data type, with a subset of the functionality.
58
+ *
59
+ * @since 3.4.0
60
+ * @experimental
61
+ * @category models
62
+ */
63
+ export interface Micro<out A, out E = never, out R = never> extends Effect<A, E, R> {
64
+ readonly [TypeId]: Micro.Variance<A, E, R>
65
+ readonly [runSymbol]: (env: Env<any>, onResult: (result: Result<A, E>) => void) => void
66
+ [Symbol.iterator](): MicroIterator<Micro<A, E, R>>
67
+ }
68
+
69
+ /**
70
+ * @category type lambdas
71
+ * @since 3.4.1
72
+ */
73
+ export interface MicroTypeLambda extends TypeLambda {
74
+ readonly type: Micro<this["Target"], this["Out1"], this["Out2"]>
75
+ }
76
+
77
+ /**
78
+ * @since 3.4.0
79
+ * @experimental
80
+ */
81
+ export declare namespace Micro {
82
+ /**
83
+ * @since 3.4.0
84
+ * @experimental
85
+ */
86
+ export interface Variance<A, E, R> {
87
+ _A: Covariant<A>
88
+ _E: Covariant<E>
89
+ _R: Covariant<R>
90
+ }
91
+
92
+ /**
93
+ * @since 3.4.0
94
+ * @experimental
95
+ */
96
+ export type Success<T> = T extends Micro<infer _A, infer _E, infer _R> ? _A : never
97
+
98
+ /**
99
+ * @since 3.4.0
100
+ * @experimental
101
+ */
102
+ export type Error<T> = T extends Micro<infer _A, infer _E, infer _R> ? _E : never
103
+
104
+ /**
105
+ * @since 3.4.0
106
+ * @experimental
107
+ */
108
+ export type Context<T> = T extends Micro<infer _A, infer _E, infer _R> ? _R : never
109
+ }
110
+
111
+ /**
112
+ * @since 3.4.0
113
+ * @experimental
114
+ * @category guards
115
+ */
116
+ export const isMicro = (u: unknown): u is Micro<any, any, any> => typeof u === "object" && u !== null && TypeId in u
117
+
118
+ /**
119
+ * @since 3.4.0
120
+ * @experimental
121
+ * @category models
122
+ */
123
+ export interface MicroIterator<T extends Micro<any, any, any>> {
124
+ next(...args: ReadonlyArray<any>): IteratorResult<YieldWrap<T>, Micro.Success<T>>
125
+ }
126
+
127
+ // ----------------------------------------------------------------------------
128
+ // Failures
129
+ // ----------------------------------------------------------------------------
130
+
131
+ /**
132
+ * @since 3.4.0
133
+ * @experimental
134
+ * @category failure
135
+ */
136
+ export const FailureTypeId = Symbol.for("effect/Micro/Failure")
137
+
138
+ /**
139
+ * @since 3.4.0
140
+ * @experimental
141
+ * @category failure
142
+ */
143
+ export type FailureTypeId = typeof FailureTypeId
144
+
145
+ /**
146
+ * A Micro Failure is a data type that represents the different ways a Micro can fail.
147
+ *
148
+ * @since 3.4.0
149
+ * @experimental
150
+ * @category failure
151
+ */
152
+ export type Failure<E> = Failure.Unexpected | Failure.Expected<E> | Failure.Aborted
153
+
154
+ /**
155
+ * @since 3.4.0
156
+ * @experimental
157
+ * @category failure
158
+ */
159
+ export declare namespace Failure {
160
+ /**
161
+ * @since 3.4.0
162
+ * @experimental
163
+ */
164
+ export interface Proto<Tag extends string, E> extends Pipeable, globalThis.Error {
165
+ readonly [FailureTypeId]: {
166
+ _E: Covariant<E>
167
+ }
168
+ readonly _tag: Tag
169
+ readonly traces: ReadonlyArray<string>
170
+ }
171
+
172
+ /**
173
+ * @since 3.4.0
174
+ * @experimental
175
+ * @category failure
176
+ */
177
+ export interface Unexpected extends Proto<"Unexpected", never> {
178
+ readonly defect: unknown
179
+ }
180
+
181
+ /**
182
+ * @since 3.4.0
183
+ * @experimental
184
+ * @category failure
185
+ */
186
+ export interface Expected<E> extends Proto<"Expected", E> {
187
+ readonly error: E
188
+ }
189
+
190
+ /**
191
+ * @since 3.4.0
192
+ * @experimental
193
+ * @category failure
194
+ */
195
+ export interface Aborted extends Proto<"Aborted", never> {}
196
+ }
197
+
198
+ const failureVariance = {
199
+ _E: identity
200
+ }
201
+
202
+ abstract class FailureImpl<Tag extends string, E> extends globalThis.Error implements Failure.Proto<Tag, E> {
203
+ readonly [FailureTypeId]: {
204
+ _E: Covariant<E>
205
+ }
206
+ constructor(
207
+ readonly _tag: Tag,
208
+ originalError: unknown,
209
+ readonly traces: ReadonlyArray<string>
210
+ ) {
211
+ const failureName = `Failure${_tag}`
212
+ let name: string
213
+ let message: string
214
+ let stack: string
215
+ if (originalError instanceof globalThis.Error) {
216
+ name = `(${failureName}) ${originalError.name}`
217
+ message = originalError.message as string
218
+ const messageLines = message.split("\n").length
219
+ stack = originalError.stack
220
+ ? `(${failureName}) ${originalError.stack.split("\n").slice(0, messageLines + 3).join("\n")}`
221
+ : `${name}: ${message}`
222
+ } else {
223
+ name = failureName
224
+ message = toStringUnknown(originalError, 0)
225
+ stack = `${name}: ${message}`
226
+ }
227
+ if (traces.length > 0) {
228
+ stack += `\n ${traces.join("\n ")}`
229
+ }
230
+ super(message)
231
+ this[FailureTypeId] = failureVariance
232
+ this.name = name
233
+ this.stack = stack
234
+ }
235
+ pipe() {
236
+ return pipeArguments(this, arguments)
237
+ }
238
+ toString() {
239
+ return this.stack
240
+ }
241
+ [NodeInspectSymbol]() {
242
+ return this.stack
243
+ }
244
+ }
245
+
246
+ class FailureExpectedImpl<E> extends FailureImpl<"Expected", E> implements Failure.Expected<E> {
247
+ constructor(readonly error: E, traces: ReadonlyArray<string> = []) {
248
+ super("Expected", error, traces)
249
+ }
250
+ }
251
+
252
+ /**
253
+ * @since 3.4.0
254
+ * @experimental
255
+ * @category failure
256
+ */
257
+ export const FailureExpected = <E>(error: E, traces: ReadonlyArray<string> = []): Failure<E> =>
258
+ new FailureExpectedImpl(error, traces)
259
+
260
+ class FailureUnexpectedImpl extends FailureImpl<"Unexpected", never> implements Failure.Unexpected {
261
+ constructor(readonly defect: unknown, traces: ReadonlyArray<string> = []) {
262
+ super("Unexpected", defect, traces)
263
+ }
264
+ }
265
+
266
+ /**
267
+ * @since 3.4.0
268
+ * @experimental
269
+ * @category failure
270
+ */
271
+ export const FailureUnexpected = (defect: unknown, traces: ReadonlyArray<string> = []): Failure<never> =>
272
+ new FailureUnexpectedImpl(defect, traces)
273
+
274
+ class FailureAbortedImpl extends FailureImpl<"Aborted", never> implements Failure.Aborted {
275
+ constructor(traces: ReadonlyArray<string> = []) {
276
+ super("Aborted", "aborted", traces)
277
+ }
278
+ }
279
+
280
+ /**
281
+ * @since 3.4.0
282
+ * @experimental
283
+ * @category failure
284
+ */
285
+ export const FailureAborted = (traces: ReadonlyArray<string> = []): Failure<never> => new FailureAbortedImpl(traces)
286
+
287
+ /**
288
+ * @since 3.4.0
289
+ * @experimental
290
+ * @category failure
291
+ */
292
+ export const failureIsExpected = <E>(self: Failure<E>): self is Failure.Expected<E> => self._tag === "Expected"
293
+
294
+ /**
295
+ * @since 3.4.0
296
+ * @experimental
297
+ * @category failure
298
+ */
299
+ export const failureIsUnexpected = <E>(self: Failure<E>): self is Failure.Unexpected => self._tag === "Unexpected"
300
+
301
+ /**
302
+ * @since 3.4.0
303
+ * @experimental
304
+ * @category failure
305
+ */
306
+ export const failureIsAborted = <E>(self: Failure<E>): self is Failure.Aborted => self._tag === "Aborted"
307
+
308
+ /**
309
+ * @since 3.4.0
310
+ * @experimental
311
+ * @category failure
312
+ */
313
+ export const failureSquash = <E>(self: Failure<E>): unknown =>
314
+ self._tag === "Expected" ? self.error : self._tag === "Unexpected" ? self.defect : self
315
+
316
+ /**
317
+ * @since 3.4.0
318
+ * @experimental
319
+ * @category failure
320
+ */
321
+ export const failureWithTrace: {
322
+ (trace: string): <E>(self: Failure<E>) => Failure<E>
323
+ <E>(self: Failure<E>, trace: string): Failure<E>
324
+ } = dual(2, <E>(self: Failure<E>, trace: string): Failure<E> => {
325
+ if (self._tag === "Expected") {
326
+ return FailureExpected(self.error, [...self.traces, trace])
327
+ } else if (self._tag === "Unexpected") {
328
+ return FailureUnexpected(self.defect, [...self.traces, trace])
329
+ }
330
+ return FailureAborted([...self.traces, trace])
331
+ })
332
+
333
+ // ----------------------------------------------------------------------------
334
+ // Result
335
+ // ----------------------------------------------------------------------------
336
+
337
+ /**
338
+ * The Micro Result type is a data type that represents the result of a Micro
339
+ * computation.
340
+ *
341
+ * It uses the `Either` data type to represent the success and failure cases.
342
+ *
343
+ * @since 3.4.0
344
+ * @experimental
345
+ * @category result
346
+ */
347
+ export type Result<A, E = never> = Either.Either<A, Failure<E>>
348
+
349
+ /**
350
+ * @since 3.4.0
351
+ * @experimental
352
+ * @category result
353
+ */
354
+ export const ResultAborted: Result<never> = Either.left(FailureAborted())
355
+
356
+ /**
357
+ * @since 3.4.0
358
+ * @experimental
359
+ * @category result
360
+ */
361
+ export const ResultSuccess: <A>(a: A) => Result<A, never> = Either.right
362
+
363
+ /**
364
+ * @since 3.4.0
365
+ * @experimental
366
+ * @category result
367
+ */
368
+ export const ResultFail = <E>(e: E): Result<never, E> => Either.left(FailureExpected(e))
369
+
370
+ /**
371
+ * @since 3.4.0
372
+ * @experimental
373
+ * @category result
374
+ */
375
+ export const ResultFailUnexpected = (defect: unknown): Result<never> => Either.left(FailureUnexpected(defect))
376
+
377
+ /**
378
+ * @since 3.4.0
379
+ * @experimental
380
+ * @category result
381
+ */
382
+ export const ResultFailWith: <E>(failure: Failure<E>) => Result<never, E> = Either.left
383
+
384
+ /**
385
+ * @since 3.4.0
386
+ * @experimental
387
+ * @category result
388
+ */
389
+ export const resultIsSuccess: <A, E>(self: Result<A, E>) => self is Either.Right<Failure<E>, A> = Either.isRight
390
+
391
+ /**
392
+ * @since 3.4.0
393
+ * @experimental
394
+ * @category result
395
+ */
396
+ export const resultIsFailure: <A, E>(self: Result<A, E>) => self is Either.Left<Failure<E>, A> = Either.isLeft
397
+
398
+ /**
399
+ * @since 3.4.0
400
+ * @experimental
401
+ * @category result
402
+ */
403
+ export const resultIsAborted = <A, E>(self: Result<A, E>): self is Either.Left<Failure.Aborted, A> =>
404
+ resultIsFailure(self) && self.left._tag === "Aborted"
405
+
406
+ /**
407
+ * @since 3.4.0
408
+ * @experimental
409
+ * @category result
410
+ */
411
+ export const resultIsFailureExpected = <A, E>(self: Result<A, E>): self is Either.Left<Failure.Expected<E>, A> =>
412
+ resultIsFailure(self) && self.left._tag === "Expected"
413
+
414
+ /**
415
+ * @since 3.4.0
416
+ * @experimental
417
+ * @category result
418
+ */
419
+ export const resultIsFailureUnexpected = <A, E>(self: Result<A, E>): self is Either.Left<Failure.Unexpected, A> =>
420
+ resultIsFailure(self) && self.left._tag === "Unexpected"
421
+
422
+ /**
423
+ * @since 3.4.0
424
+ * @experimental
425
+ * @category result
426
+ */
427
+ export const resultVoid: Result<void> = ResultSuccess(void 0)
428
+
429
+ // ----------------------------------------------------------------------------
430
+ // env
431
+ // ----------------------------------------------------------------------------
432
+
433
+ /**
434
+ * @since 3.4.0
435
+ * @experimental
436
+ * @category environment
437
+ */
438
+ export const EnvTypeId = Symbol.for("effect/Micro/Env")
439
+
440
+ /**
441
+ * @since 3.4.0
442
+ * @experimental
443
+ * @category environment
444
+ */
445
+ export type EnvTypeId = typeof EnvTypeId
446
+
447
+ /**
448
+ * @since 3.4.0
449
+ * @experimental
450
+ * @category environment
451
+ */
452
+ export interface Env<R> extends Pipeable {
453
+ readonly [EnvTypeId]: {
454
+ _R: Covariant<R>
455
+ }
456
+ readonly refs: ReadonlyRecord<string, unknown>
457
+ }
458
+
459
+ /**
460
+ * @since 3.4.0
461
+ * @experimental
462
+ * @category environment
463
+ */
464
+ export const EnvRefTypeId: unique symbol = Symbol.for("effect/Micro/EnvRef")
465
+
466
+ /**
467
+ * @since 3.4.0
468
+ * @experimental
469
+ * @category environment
470
+ */
471
+ export type EnvRefTypeId = typeof EnvRefTypeId
472
+
473
+ /**
474
+ * @since 3.4.0
475
+ * @experimental
476
+ * @category environment
477
+ */
478
+ export interface EnvRef<A> {
479
+ readonly [EnvRefTypeId]: EnvRefTypeId
480
+ readonly key: string
481
+ readonly initial: A
482
+ }
483
+
484
+ const EnvProto = {
485
+ [EnvTypeId]: {
486
+ _R: identity
487
+ },
488
+ pipe() {
489
+ return pipeArguments(this, arguments)
490
+ }
491
+ }
492
+
493
+ /**
494
+ * @since 3.4.0
495
+ * @experimental
496
+ * @category environment
497
+ */
498
+ export const envMake = <R = never>(
499
+ refs: Record<string, unknown>
500
+ ): Env<R> => {
501
+ const self = Object.create(EnvProto)
502
+ self.refs = refs
503
+ return self
504
+ }
505
+
506
+ /**
507
+ * @since 3.4.0
508
+ * @experimental
509
+ * @category environment
510
+ */
511
+ export const envUnsafeMakeEmpty = (): Env<never> => {
512
+ const controller = new AbortController()
513
+ const refs = Object.create(null)
514
+ refs[currentAbortController.key] = controller
515
+ refs[currentAbortSignal.key] = controller.signal
516
+ return envMake(refs)
517
+ }
518
+
519
+ /**
520
+ * @since 3.4.0
521
+ * @experimental
522
+ * @category environment
523
+ */
524
+ export const envGet: {
525
+ <A>(ref: EnvRef<A>): <R>(self: Env<R>) => A
526
+ <A, R>(self: Env<R>, ref: EnvRef<A>): A
527
+ } = dual(2, <R, A>(self: Env<R>, ref: EnvRef<A>): A => ref.key in self.refs ? (self.refs[ref.key] as A) : ref.initial)
528
+
529
+ /**
530
+ * @since 3.4.0
531
+ * @experimental
532
+ * @category environment
533
+ */
534
+ export const envSet: {
535
+ <A>(ref: EnvRef<A>, value: A): <R>(self: Env<R>) => Env<R>
536
+ <A, R>(self: Env<R>, ref: EnvRef<A>, value: A): Env<R>
537
+ } = dual(3, <R, A>(self: Env<R>, ref: EnvRef<A>, value: A): Env<R> => {
538
+ const refs = Object.assign(Object.create(null), self.refs)
539
+ refs[ref.key] = value
540
+ return envMake(refs)
541
+ })
542
+
543
+ /**
544
+ * @since 3.4.0
545
+ * @experimental
546
+ * @category environment
547
+ */
548
+ export const envMutate: {
549
+ (f: (map: Record<string, unknown>) => void): <R>(self: Env<R>) => Env<R>
550
+ <R>(self: Env<R>, f: (map: Record<string, unknown>) => void): Env<R>
551
+ } = dual(
552
+ 2,
553
+ <R>(self: Env<R>, f: (map: Record<string, unknown>) => ReadonlyRecord<string, unknown>): Env<R> =>
554
+ envMake(f(Object.assign(Object.create(null), self.refs)))
555
+ )
556
+
557
+ /**
558
+ * Access the given `Context.Tag` from the environment.
559
+ *
560
+ * @since 3.4.0
561
+ * @experimental
562
+ * @category environment
563
+ */
564
+ export const service = <I, S>(tag: Context.Tag<I, S>): Micro<S, never, I> =>
565
+ make(function(env, onResult) {
566
+ onResult(ResultSuccess(Context.get(envGet(env, currentContext) as Context.Context<I>, tag as any) as S))
567
+ })
568
+
569
+ /**
570
+ * Access the given `Context.Tag` from the environment, without tracking the
571
+ * dependency at the type level.
572
+ *
573
+ * It will return an `Option` of the service, depending on whether it is
574
+ * available in the environment or not.
575
+ *
576
+ * @since 3.4.0
577
+ * @experimental
578
+ * @category environment
579
+ */
580
+ export const serviceOption = <I, S>(tag: Context.Tag<I, S>): Micro<Option.Option<S>> =>
581
+ make(function(env, onResult) {
582
+ onResult(ResultSuccess(Context.getOption(envGet(env, currentContext) as Context.Context<I>, tag)))
583
+ })
584
+
585
+ /**
586
+ * Retrieve the current value of the given `EnvRef`.
587
+ *
588
+ * @since 3.4.0
589
+ * @experimental
590
+ * @category environment
591
+ */
592
+ export const getEnvRef = <A>(envRef: EnvRef<A>): Micro<A> =>
593
+ make((env, onResult) => onResult(Either.right(envGet(env, envRef))))
594
+
595
+ /**
596
+ * Set the value of the given `EnvRef` for the duration of the effect.
597
+ *
598
+ * @since 3.4.0
599
+ * @experimental
600
+ * @category environment
601
+ */
602
+ export const locally: {
603
+ <A>(fiberRef: EnvRef<A>, value: A): <XA, E, R>(self: Micro<XA, E, R>) => Micro<XA, E, R>
604
+ <XA, E, R, A>(self: Micro<XA, E, R>, fiberRef: EnvRef<A>, value: A): Micro<XA, E, R>
605
+ } = dual(
606
+ 3,
607
+ <XA, E, R, A>(self: Micro<XA, E, R>, fiberRef: EnvRef<A>, value: A): Micro<XA, E, R> =>
608
+ make((env, onResult) => self[runSymbol](envSet(env, fiberRef, value), onResult))
609
+ )
610
+
611
+ /**
612
+ * Access the current `Context` from the environment.
613
+ *
614
+ * @since 3.4.0
615
+ * @experimental
616
+ * @category environment
617
+ */
618
+ export const context = <R>(): Micro<Context.Context<R>> => getEnvRef(currentContext) as any
619
+
620
+ /**
621
+ * Merge the given `Context` with the current context.
622
+ *
623
+ * @since 3.4.0
624
+ * @experimental
625
+ * @category environment
626
+ */
627
+ export const provideContext: {
628
+ <XR>(context: Context.Context<XR>): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, Exclude<R, XR>>
629
+ <A, E, R, XR>(self: Micro<A, E, R>, context: Context.Context<XR>): Micro<A, E, Exclude<R, XR>>
630
+ } = dual(
631
+ 2,
632
+ <A, E, R, XR>(self: Micro<A, E, R>, provided: Context.Context<XR>): Micro<A, E, Exclude<R, XR>> =>
633
+ make(function(env, onResult) {
634
+ const context = envGet(env, currentContext)
635
+ const nextEnv = envSet(env, currentContext, Context.merge(context, provided))
636
+ self[runSymbol](nextEnv, onResult)
637
+ })
638
+ )
639
+
640
+ /**
641
+ * Add the provided service to the current context.
642
+ *
643
+ * @since 3.4.0
644
+ * @experimental
645
+ * @category environment
646
+ */
647
+ export const provideService: {
648
+ <I, S>(tag: Context.Tag<I, S>, service: S): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, Exclude<R, I>>
649
+ <A, E, R, I, S>(self: Micro<A, E, R>, tag: Context.Tag<I, S>, service: S): Micro<A, E, Exclude<R, I>>
650
+ } = dual(
651
+ 3,
652
+ <A, E, R, I, S>(self: Micro<A, E, R>, tag: Context.Tag<I, S>, service: S): Micro<A, E, Exclude<R, I>> =>
653
+ make(function(env, onResult) {
654
+ const context = envGet(env, currentContext)
655
+ const nextEnv = envSet(env, currentContext, Context.add(context, tag, service))
656
+ self[runSymbol](nextEnv, onResult)
657
+ })
658
+ )
659
+
660
+ /**
661
+ * Create a service using the provided `Micro` effect, and add it to the
662
+ * current context.
663
+ *
664
+ * @since 3.4.0
665
+ * @experimental
666
+ * @category environment
667
+ */
668
+ export const provideServiceMicro: {
669
+ <I, S, E2, R2>(
670
+ tag: Context.Tag<I, S>,
671
+ acquire: Micro<S, E2, R2>
672
+ ): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E | E2, Exclude<R, I> | R2>
673
+ <A, E, R, I, S, E2, R2>(
674
+ self: Micro<A, E, R>,
675
+ tag: Context.Tag<I, S>,
676
+ acquire: Micro<S, E2, R2>
677
+ ): Micro<A, E | E2, Exclude<R, I> | R2>
678
+ } = dual(
679
+ 3,
680
+ <A, E, R, I, S, E2, R2>(
681
+ self: Micro<A, E, R>,
682
+ tag: Context.Tag<I, S>,
683
+ acquire: Micro<S, E2, R2>
684
+ ): Micro<A, E | E2, Exclude<R, I> | R2> => flatMap(acquire, (service) => provideService(self, tag, service))
685
+ )
686
+
687
+ // ========================================================================
688
+ // Env refs
689
+ // ========================================================================
690
+
691
+ const EnvRefProto = {
692
+ [EnvRefTypeId]: EnvRefTypeId
693
+ }
694
+
695
+ /**
696
+ * @since 3.4.0
697
+ * @experimental
698
+ * @category environment refs
699
+ */
700
+ export const envRefMake = <A>(key: string, initial: LazyArg<A>): EnvRef<A> =>
701
+ globalValue(key, () => {
702
+ const self = Object.create(EnvRefProto)
703
+ self.key = key
704
+ self.initial = initial()
705
+ return self
706
+ })
707
+
708
+ /**
709
+ * @since 3.4.0
710
+ * @experimental
711
+ * @category environment refs
712
+ */
713
+ export const currentAbortController: EnvRef<AbortController> = envRefMake(
714
+ "effect/Micro/currentAbortController",
715
+ () => new AbortController()
716
+ )
717
+
718
+ /**
719
+ * @since 3.4.0
720
+ * @experimental
721
+ * @category environment refs
722
+ */
723
+ export const currentAbortSignal: EnvRef<AbortSignal> = envRefMake(
724
+ "effect/Micro/currentAbortSignal",
725
+ () => currentAbortController.initial.signal
726
+ )
727
+
728
+ /**
729
+ * @since 3.4.0
730
+ * @experimental
731
+ * @category environment refs
732
+ */
733
+ export const currentContext: EnvRef<Context.Context<never>> = envRefMake(
734
+ "effect/Micro/currentContext",
735
+ () => Context.empty()
736
+ )
737
+
738
+ /**
739
+ * @since 3.4.0
740
+ * @experimental
741
+ * @category environment refs
742
+ */
743
+ export const currentConcurrency: EnvRef<"unbounded" | number> = envRefMake(
744
+ "effect/Micro/currentConcurrency",
745
+ () => "unbounded"
746
+ )
747
+
748
+ /**
749
+ * @since 3.4.0
750
+ * @experimental
751
+ * @category environment refs
752
+ */
753
+ export const currentMaxDepthBeforeYield: EnvRef<number> = envRefMake(
754
+ "effect/Micro/currentMaxDepthBeforeYield",
755
+ () => 2048
756
+ )
757
+
758
+ const currentInterruptible: EnvRef<boolean> = envRefMake(
759
+ "effect/Micro/currentInterruptible",
760
+ () => true
761
+ )
762
+
763
+ /**
764
+ * If you have a `Micro` that uses `concurrency: "inherit"`, you can use this
765
+ * api to control the concurrency of that `Micro` when it is run.
766
+ *
767
+ * @since 3.4.0
768
+ * @experimental
769
+ * @category environment refs
770
+ * @example
771
+ * import * as Micro from "effect/Micro"
772
+ *
773
+ * Micro.forEach([1, 2, 3], (n) => Micro.succeed(n), {
774
+ * concurrency: "inherit"
775
+ * }).pipe(
776
+ * Micro.withConcurrency(2) // use a concurrency of 2
777
+ * )
778
+ */
779
+ export const withConcurrency: {
780
+ (concurrency: "unbounded" | number): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, R>
781
+ <A, E, R>(self: Micro<A, E, R>, concurrency: "unbounded" | number): Micro<A, E, R>
782
+ } = dual(
783
+ 2,
784
+ <A, E, R>(self: Micro<A, E, R>, concurrency: "unbounded" | number): Micro<A, E, R> =>
785
+ locally(self, currentConcurrency, concurrency)
786
+ )
787
+
788
+ // ----------------------------------------------------------------------------
789
+ // constructors
790
+ // ----------------------------------------------------------------------------
791
+
792
+ const MicroProto = {
793
+ ...Effectable.EffectPrototype,
794
+ _op: "Micro",
795
+ [TypeId]: {
796
+ _A: identity,
797
+ _E: identity,
798
+ _R: identity
799
+ },
800
+ [Symbol.iterator]() {
801
+ return new SingleShotGen(new YieldWrap(this)) as any
802
+ }
803
+ }
804
+
805
+ const microDepthState = globalValue("effect/Micro/microDepthState", () => ({
806
+ depth: 0,
807
+ maxDepthBeforeYield: currentMaxDepthBeforeYield.initial
808
+ }))
809
+
810
+ const unsafeMake = <A, E, R>(
811
+ run: (env: Env<R>, onResult: (result: Result<A, E>) => void) => void
812
+ ): Micro<A, E, R> => {
813
+ const self = Object.create(MicroProto)
814
+ self[runSymbol] = run
815
+ return self
816
+ }
817
+
818
+ const unsafeMakeOptions = <A, E, R>(
819
+ run: (env: Env<R>, onResult: (result: Result<A, E>) => void) => void,
820
+ checkAbort: boolean
821
+ ): Micro<A, E, R> =>
822
+ unsafeMake(function execute(env, onResult) {
823
+ if (
824
+ checkAbort && env.refs[currentInterruptible.key] !== false &&
825
+ (env.refs[currentAbortSignal.key] as AbortSignal).aborted
826
+ ) {
827
+ return onResult(ResultAborted)
828
+ }
829
+ microDepthState.depth++
830
+ if (microDepthState.depth === 1) {
831
+ microDepthState.maxDepthBeforeYield = envGet(env, currentMaxDepthBeforeYield)
832
+ }
833
+ if (microDepthState.depth >= microDepthState.maxDepthBeforeYield) {
834
+ yieldAdd(() => execute(env, onResult))
835
+ } else {
836
+ try {
837
+ run(env, onResult)
838
+ } catch (err) {
839
+ onResult(ResultFailUnexpected(err))
840
+ }
841
+ }
842
+ microDepthState.depth--
843
+ })
844
+
845
+ /**
846
+ * A low-level constructor for creating a `Micro` effect. It takes a function
847
+ * that receives an environment and a callback which should be called with the
848
+ * result of the effect.
849
+ *
850
+ * @since 3.4.0
851
+ * @experimental
852
+ * @category constructors
853
+ */
854
+ export const make = <A, E, R>(
855
+ run: (env: Env<R>, onResult: (result: Result<A, E>) => void) => void
856
+ ): Micro<A, E, R> => unsafeMakeOptions(run, true)
857
+
858
+ /**
859
+ * Converts a `Result` into a `Micro` effect.
860
+ *
861
+ * @since 3.4.0
862
+ * @experimental
863
+ * @category constructors
864
+ */
865
+ export const fromResult = <A, E>(self: Result<A, E>): Micro<A, E> =>
866
+ make(function(_env, onResult) {
867
+ onResult(self)
868
+ })
869
+
870
+ /**
871
+ * Converts a lazy `Result` into a `Micro` effect.
872
+ *
873
+ * @since 3.4.0
874
+ * @experimental
875
+ * @category constructors
876
+ */
877
+ export const fromResultSync = <A, E>(self: LazyArg<Result<A, E>>): Micro<A, E> =>
878
+ make(function(_env, onResult) {
879
+ onResult(self())
880
+ })
881
+
882
+ /**
883
+ * Creates a `Micro` effect that will succeed with the specified constant value.
884
+ *
885
+ * @since 3.4.0
886
+ * @experimental
887
+ * @category constructors
888
+ */
889
+ export const succeed = <A>(a: A): Micro<A> => fromResult(ResultSuccess(a))
890
+
891
+ /**
892
+ * Creates a `Micro` effect that will succeed with `Option.Some` of the value.
893
+ *
894
+ * @since 3.4.0
895
+ * @experimental
896
+ * @category constructors
897
+ */
898
+ export const succeedSome = <A>(a: A): Micro<Option.Option<A>> => succeed(Option.some(a))
899
+
900
+ /**
901
+ * Creates a `Micro` effect that will succeed with `Option.None`.
902
+ *
903
+ * @since 3.4.0
904
+ * @experimental
905
+ * @category constructors
906
+ */
907
+ export const succeedNone: Micro<Option.Option<never>> = succeed(Option.none())
908
+
909
+ /**
910
+ * Creates a `Micro` effect that will fail with the specified error.
911
+ *
912
+ * This will result in a `FailureExpected`, where the error is tracked at the
913
+ * type level.
914
+ *
915
+ * @since 3.4.0
916
+ * @experimental
917
+ * @category constructors
918
+ */
919
+ export const fail = <E>(e: E): Micro<never, E> => fromResult(ResultFail(e))
920
+
921
+ /**
922
+ * Creates a `Micro` effect that will fail with the lazily evaluated error.
923
+ *
924
+ * This will result in a `FailureExpected`, where the error is tracked at the
925
+ * type level.
926
+ *
927
+ * @since 3.4.0
928
+ * @experimental
929
+ * @category constructors
930
+ */
931
+ export const failSync = <E>(e: LazyArg<E>): Micro<never, E> =>
932
+ make(function(_env, onResult) {
933
+ onResult(ResultFail(e()))
934
+ })
935
+
936
+ /**
937
+ * Creates a `Micro` effect that will die with the specified error.
938
+ *
939
+ * This will result in a `FailureUnexpected`, where the error is not tracked at
940
+ * the type level.
941
+ *
942
+ * @since 3.4.0
943
+ * @experimental
944
+ * @category constructors
945
+ */
946
+ export const die = (defect: unknown): Micro<never> => fromResult(ResultFailUnexpected(defect))
947
+
948
+ /**
949
+ * Creates a `Micro` effect that will fail with the specified `Failure`.
950
+ *
951
+ * @since 3.4.0
952
+ * @experimental
953
+ * @category constructors
954
+ */
955
+ export const failWith = <E>(failure: Failure<E>): Micro<never, E> => fromResult(ResultFailWith(failure))
956
+
957
+ /**
958
+ * Creates a `Micro` effect that will fail with the lazily evaluated `Failure`.
959
+ *
960
+ * @since 3.4.0
961
+ * @experimental
962
+ * @category constructors
963
+ */
964
+ export const failWithSync = <E>(failure: LazyArg<Failure<E>>): Micro<never, E> =>
965
+ fromResultSync(() => ResultFailWith(failure()))
966
+
967
+ /**
968
+ * Creates a `Micro` effect that will succeed with the lazily evaluated value.
969
+ *
970
+ * If the evaluation of the value throws an error, the effect will fail with
971
+ * `FailureUnexpected`.
972
+ *
973
+ * @since 3.4.0
974
+ * @experimental
975
+ * @category constructors
976
+ */
977
+ export const sync = <A>(evaluate: LazyArg<A>): Micro<A> =>
978
+ make(function(_env, onResult) {
979
+ onResult(ResultSuccess(evaluate()))
980
+ })
981
+
982
+ /**
983
+ * Converts an `Option` into a `Micro` effect, that will fail with a
984
+ * `Option.None` if the option is `None`. Otherwise, it will succeed with the
985
+ * value of the option.
986
+ *
987
+ * @since 3.4.0
988
+ * @experimental
989
+ * @category constructors
990
+ */
991
+ export const fromOption = <A>(option: Option.Option<A>): Micro<A, Option.None<never>> =>
992
+ make(function(_env, onResult) {
993
+ onResult(option._tag === "Some" ? ResultSuccess(option.value) : ResultFail(Option.none()) as any)
994
+ })
995
+
996
+ /**
997
+ * Converts an `Either` into a `Micro` effect, that will fail with the left side
998
+ * of the either if it is a `Left`. Otherwise, it will succeed with the right
999
+ * side of the either.
1000
+ *
1001
+ * @since 3.4.0
1002
+ * @experimental
1003
+ * @category constructors
1004
+ */
1005
+ export const fromEither = <R, L>(either: Either.Either<R, L>): Micro<R, L> =>
1006
+ make(function(_env, onResult) {
1007
+ onResult(either._tag === "Right" ? either : ResultFail(either.left) as any)
1008
+ })
1009
+
1010
+ /**
1011
+ * Lazily creates a `Micro` effect from the given side-effect.
1012
+ *
1013
+ * @since 3.4.0
1014
+ * @experimental
1015
+ * @category constructors
1016
+ */
1017
+ export const suspend = <A, E, R>(evaluate: LazyArg<Micro<A, E, R>>): Micro<A, E, R> =>
1018
+ make(function(env, onResult) {
1019
+ evaluate()[runSymbol](env, onResult)
1020
+ })
1021
+
1022
+ const void_: Micro<void> = succeed(void 0)
1023
+ export {
1024
+ /**
1025
+ * A `Micro` effect that will succeed with `void` (`undefined`).
1026
+ *
1027
+ * @since 3.4.0
1028
+ * @experimental
1029
+ * @category constructors
1030
+ */
1031
+ void_ as void
1032
+ }
1033
+
1034
+ /**
1035
+ * Create a `Micro` effect from an asynchronous computation.
1036
+ *
1037
+ * You can return a cleanup effect that will be run when the effect is aborted.
1038
+ * It is also passed an `AbortSignal` that is triggered when the effect is
1039
+ * aborted.
1040
+ *
1041
+ * @since 3.4.0
1042
+ * @experimental
1043
+ * @category constructors
1044
+ */
1045
+ export const async = <A, E = never, R = never>(
1046
+ register: (resume: (effect: Micro<A, E, R>) => void, signal: AbortSignal) => void | Micro<void, never, R>
1047
+ ): Micro<A, E, R> =>
1048
+ make(function(env, onResult) {
1049
+ let resumed = false
1050
+ const controller = register.length > 1 ? new AbortController() : undefined
1051
+ const signal = envGet(env, currentAbortSignal)
1052
+ let cleanup: Micro<void, never, R> | void = undefined
1053
+ function onAbort() {
1054
+ if (cleanup) {
1055
+ resume(uninterruptible(andThen(cleanup, fromResult(ResultAborted))))
1056
+ } else {
1057
+ resume(fromResult(ResultAborted))
1058
+ }
1059
+ if (controller !== undefined) {
1060
+ controller.abort()
1061
+ }
1062
+ }
1063
+ function resume(effect: Micro<A, E, R>) {
1064
+ if (resumed) {
1065
+ return
1066
+ }
1067
+ resumed = true
1068
+ signal.removeEventListener("abort", onAbort)
1069
+ effect[runSymbol](env, onResult)
1070
+ }
1071
+ cleanup = controller === undefined
1072
+ ? (register as any)(resume)
1073
+ : register(resume, controller.signal)
1074
+ if (resumed) return
1075
+ signal.addEventListener("abort", onAbort)
1076
+ })
1077
+
1078
+ const try_ = <A, E>(options: {
1079
+ try: LazyArg<A>
1080
+ catch: (error: unknown) => E
1081
+ }): Micro<A, E> =>
1082
+ make(function(_env, onResult) {
1083
+ try {
1084
+ onResult(ResultSuccess(options.try()))
1085
+ } catch (err) {
1086
+ onResult(ResultFail(options.catch(err)))
1087
+ }
1088
+ })
1089
+ export {
1090
+ /**
1091
+ * The `Micro` equivalent of a try / catch block, which allows you to map
1092
+ * thrown errors to a specific error type.
1093
+ *
1094
+ * @since 3.4.0
1095
+ * @experimental
1096
+ * @category constructors
1097
+ * @example
1098
+ * import { Micro } from "effect"
1099
+ *
1100
+ * Micro.try({
1101
+ * try: () => throw new Error("boom"),
1102
+ * catch: (cause) => new Error("caught", { cause })
1103
+ * })
1104
+ */
1105
+ try_ as try
1106
+ }
1107
+
1108
+ /**
1109
+ * Wrap a `Promise` into a `Micro` effect. Any errors will result in a
1110
+ * `FailureUnexpected`.
1111
+ *
1112
+ * @since 3.4.0
1113
+ * @experimental
1114
+ * @category constructors
1115
+ */
1116
+ export const promise = <A>(evaluate: (signal: AbortSignal) => PromiseLike<A>): Micro<A> =>
1117
+ async<A>(function(resume, signal) {
1118
+ evaluate(signal).then(
1119
+ (a) => resume(succeed(a)),
1120
+ (e) => resume(die(e))
1121
+ )
1122
+ })
1123
+
1124
+ /**
1125
+ * Wrap a `Promise` into a `Micro` effect. Any errors will be caught and
1126
+ * converted into a specific error type.
1127
+ *
1128
+ * @since 3.4.0
1129
+ * @experimental
1130
+ * @category constructors
1131
+ * @example
1132
+ * import { Micro } from "effect"
1133
+ *
1134
+ * Micro.tryPromise({
1135
+ * try: () => Promise.resolve("success"),
1136
+ * catch: (cause) => new Error("caught", { cause })
1137
+ * })
1138
+ */
1139
+ export const tryPromise = <A, E>(options: {
1140
+ readonly try: (signal: AbortSignal) => PromiseLike<A>
1141
+ readonly catch: (error: unknown) => E
1142
+ }): Micro<A, E> =>
1143
+ async<A, E>(function(resume, signal) {
1144
+ try {
1145
+ options.try(signal).then(
1146
+ (a) => resume(succeed(a)),
1147
+ (e) => resume(fail(options.catch(e)))
1148
+ )
1149
+ } catch (err) {
1150
+ resume(fail(options.catch(err)))
1151
+ }
1152
+ })
1153
+
1154
+ const yieldState: {
1155
+ tasks: Array<() => void>
1156
+ working: boolean
1157
+ } = globalValue("effect/Micro/yieldState", () => ({
1158
+ tasks: [],
1159
+ working: false
1160
+ }))
1161
+
1162
+ const yieldRunTasks = () => {
1163
+ const tasks = yieldState.tasks
1164
+ yieldState.tasks = []
1165
+ for (let i = 0, len = tasks.length; i < len; i++) {
1166
+ tasks[i]()
1167
+ }
1168
+ }
1169
+
1170
+ const setImmediate = "setImmediate" in globalThis ? globalThis.setImmediate : (f: () => void) => setTimeout(f, 0)
1171
+
1172
+ const yieldAdd = (task: () => void) => {
1173
+ yieldState.tasks.push(task)
1174
+ if (!yieldState.working) {
1175
+ yieldState.working = true
1176
+ setImmediate(() => {
1177
+ yieldState.working = false
1178
+ yieldRunTasks()
1179
+ })
1180
+ }
1181
+ }
1182
+
1183
+ /**
1184
+ * Pause the execution of the current `Micro` effect, and resume it on the next
1185
+ * iteration of the event loop.
1186
+ *
1187
+ * @since 3.4.0
1188
+ * @experimental
1189
+ * @category constructors
1190
+ */
1191
+ export const yieldNow: Micro<void> = make(function(_env, onResult) {
1192
+ yieldAdd(() => onResult(resultVoid))
1193
+ })
1194
+
1195
+ /**
1196
+ * Flush any yielded effects that are waiting to be executed.
1197
+ *
1198
+ * @since 3.4.0
1199
+ * @experimental
1200
+ * @category constructors
1201
+ */
1202
+ export const yieldFlush: Micro<void> = sync(function() {
1203
+ while (yieldState.tasks.length > 0) {
1204
+ yieldRunTasks()
1205
+ }
1206
+ })
1207
+
1208
+ /**
1209
+ * A `Micro` that will never succeed or fail. It wraps `setInterval` to prevent
1210
+ * the Javascript runtime from exiting.
1211
+ *
1212
+ * @since 3.4.0
1213
+ * @experimental
1214
+ * @category constructors
1215
+ */
1216
+ export const never: Micro<never> = async<never>(function() {
1217
+ const interval = setInterval(constVoid, 2147483646)
1218
+ return sync(() => clearInterval(interval))
1219
+ })
1220
+
1221
+ /**
1222
+ * @since 3.4.0
1223
+ * @experimental
1224
+ * @category constructors
1225
+ */
1226
+ export const gen = <Eff extends YieldWrap<Micro<any, any, any>>, AEff>(
1227
+ f: () => Generator<Eff, AEff, never>
1228
+ ): Micro<
1229
+ AEff,
1230
+ [Eff] extends [never] ? never : [Eff] extends [YieldWrap<Micro<infer _A, infer E, infer _R>>] ? E : never,
1231
+ [Eff] extends [never] ? never : [Eff] extends [YieldWrap<Micro<infer _A, infer _E, infer R>>] ? R : never
1232
+ > =>
1233
+ make(function(env, onResult) {
1234
+ const iterator = f() as Iterator<YieldWrap<Micro<any, any, any>>, AEff, any>
1235
+ let running = false
1236
+ let value: any = undefined
1237
+ function run() {
1238
+ running = true
1239
+ try {
1240
+ let shouldContinue = true
1241
+ while (shouldContinue) {
1242
+ const result = iterator.next(value)
1243
+ if (result.done) {
1244
+ return onResult(ResultSuccess(result.value))
1245
+ }
1246
+ shouldContinue = false
1247
+ yieldWrapGet(result.value)[runSymbol](env, function(result) {
1248
+ if (result._tag === "Left") {
1249
+ onResult(result)
1250
+ } else {
1251
+ shouldContinue = true
1252
+ value = result.right
1253
+ if (!running) run()
1254
+ }
1255
+ })
1256
+ }
1257
+ } catch (err) {
1258
+ onResult(ResultFailUnexpected(err))
1259
+ }
1260
+ running = false
1261
+ }
1262
+ run()
1263
+ })
1264
+
1265
+ // ----------------------------------------------------------------------------
1266
+ // mapping & sequencing
1267
+ // ----------------------------------------------------------------------------
1268
+
1269
+ /**
1270
+ * Flattens any nested `Micro` effects, merging the error and requirement types.
1271
+ *
1272
+ * @since 3.4.0
1273
+ * @experimental
1274
+ * @category mapping & sequencing
1275
+ */
1276
+ export const flatten = <A, E, R, E2, R2>(self: Micro<Micro<A, E, R>, E2, R2>): Micro<A, E | E2, R | R2> =>
1277
+ make(function(env, onResult) {
1278
+ self[runSymbol](
1279
+ env,
1280
+ (result) => result._tag === "Left" ? onResult(result as any) : result.right[runSymbol](env, onResult)
1281
+ )
1282
+ })
1283
+
1284
+ /**
1285
+ * Transforms the success value of the `Micro` effect with the specified
1286
+ * function.
1287
+ *
1288
+ * @since 3.4.0
1289
+ * @experimental
1290
+ * @category mapping & sequencing
1291
+ */
1292
+ export const map: {
1293
+ <A, B>(f: (a: A) => B): <E, R>(self: Micro<A, E, R>) => Micro<B, E, R>
1294
+ <A, E, R, B>(self: Micro<A, E, R>, f: (a: A) => B): Micro<B, E, R>
1295
+ } = dual(2, <A, E, R, B>(self: Micro<A, E, R>, f: (a: A) => B): Micro<B, E, R> =>
1296
+ make(function(env, onResult) {
1297
+ self[runSymbol](env, function(result) {
1298
+ onResult(result._tag === "Left" ? result as any : ResultSuccess(f(result.right)))
1299
+ })
1300
+ }))
1301
+
1302
+ /**
1303
+ * Create a `Micro` effect that will replace the success value of the given
1304
+ * effect.
1305
+ *
1306
+ * @since 3.4.0
1307
+ * @experimental
1308
+ * @category mapping & sequencing
1309
+ */
1310
+ export const as: {
1311
+ <A, B>(value: B): <E, R>(self: Micro<A, E, R>) => Micro<B, E, R>
1312
+ <A, E, R, B>(self: Micro<A, E, R>, value: B): Micro<B, E, R>
1313
+ } = dual(2, <A, E, R, B>(self: Micro<A, E, R>, value: B): Micro<B, E, R> => map(self, (_) => value))
1314
+
1315
+ /**
1316
+ * Wrap the success value of this `Micro` effect in an `Option.Some`.
1317
+ *
1318
+ * @since 3.4.0
1319
+ * @experimental
1320
+ * @category mapping & sequencing
1321
+ */
1322
+ export const asSome = <A, E, R>(self: Micro<A, E, R>): Micro<Option.Option<A>, E, R> => map(self, Option.some) as any
1323
+
1324
+ /**
1325
+ * Map the success value of this `Micro` effect to another `Micro` effect, then
1326
+ * flatten the result.
1327
+ *
1328
+ * @since 3.4.0
1329
+ * @experimental
1330
+ * @category mapping & sequencing
1331
+ */
1332
+ export const flatMap: {
1333
+ <A, B, E2, R2>(f: (a: A) => Micro<B, E2, R2>): <E, R>(self: Micro<A, E, R>) => Micro<B, E | E2, R | R2>
1334
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: A) => Micro<B, E2, R2>): Micro<B, E | E2, R | R2>
1335
+ } = dual(
1336
+ 2,
1337
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: A) => Micro<B, E2, R2>): Micro<B, E | E2, R | R2> =>
1338
+ make(function(env, onResult) {
1339
+ self[runSymbol](env, function(result) {
1340
+ if (result._tag === "Left") {
1341
+ return onResult(result as any)
1342
+ }
1343
+ f(result.right)[runSymbol](env, onResult)
1344
+ })
1345
+ })
1346
+ )
1347
+
1348
+ /**
1349
+ * Swap the error and success types of the `Micro` effect.
1350
+ *
1351
+ * @since 3.4.0
1352
+ * @experimental
1353
+ * @category mapping & sequencing
1354
+ */
1355
+ export const flip = <A, E, R>(self: Micro<A, E, R>): Micro<E, A, R> =>
1356
+ matchMicro(self, {
1357
+ onFailure: succeed,
1358
+ onSuccess: fail
1359
+ })
1360
+
1361
+ /**
1362
+ * A more flexible version of `flatMap`, that combines `map` and `flatMap` into
1363
+ * a single api.
1364
+ *
1365
+ * It also allows you to pass in a `Micro` effect directly, which will be
1366
+ * executed after the current effect.
1367
+ *
1368
+ * @since 3.4.0
1369
+ * @experimental
1370
+ * @category mapping & sequencing
1371
+ */
1372
+ export const andThen: {
1373
+ <A, X>(
1374
+ f: (a: A) => X
1375
+ ): <E, R>(
1376
+ self: Micro<A, E, R>
1377
+ ) => [X] extends [Micro<infer A1, infer E1, infer R1>] ? Micro<A1, E | E1, R | R1>
1378
+ : Micro<X, E, R>
1379
+ <X>(
1380
+ f: NotFunction<X>
1381
+ ): <A, E, R>(
1382
+ self: Micro<A, E, R>
1383
+ ) => [X] extends [Micro<infer A1, infer E1, infer R1>] ? Micro<A1, E | E1, R | R1>
1384
+ : Micro<X, E, R>
1385
+ <A, E, R, X>(
1386
+ self: Micro<A, E, R>,
1387
+ f: (a: A) => X
1388
+ ): [X] extends [Micro<infer A1, infer E1, infer R1>] ? Micro<A1, E | E1, R | R1>
1389
+ : Micro<X, E, R>
1390
+ <A, E, R, X>(
1391
+ self: Micro<A, E, R>,
1392
+ f: NotFunction<X>
1393
+ ): [X] extends [Micro<infer A1, infer E1, infer R1>] ? Micro<A1, E | E1, R | R1>
1394
+ : Micro<X, E, R>
1395
+ } = dual(
1396
+ 2,
1397
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: any): Micro<B, E | E2, R | R2> =>
1398
+ make(function(env, onResult) {
1399
+ self[runSymbol](env, function(result) {
1400
+ if (result._tag === "Left") {
1401
+ return onResult(result as any)
1402
+ } else if (envGet(env, currentAbortSignal).aborted) {
1403
+ return onResult(ResultAborted)
1404
+ }
1405
+ const value = isMicro(f) ? f : typeof f === "function" ? f(result.right) : f
1406
+ if (isMicro(value)) {
1407
+ value[runSymbol](env, onResult)
1408
+ } else {
1409
+ onResult(ResultSuccess(value))
1410
+ }
1411
+ })
1412
+ })
1413
+ )
1414
+
1415
+ /**
1416
+ * Execute a side effect from the success value of the `Micro` effect.
1417
+ *
1418
+ * It is similar to the `andThen` api, but the success value is ignored.
1419
+ *
1420
+ * @since 3.4.0
1421
+ * @experimental
1422
+ * @category mapping & sequencing
1423
+ */
1424
+ export const tap: {
1425
+ <A, X>(
1426
+ f: (a: NoInfer<A>) => X
1427
+ ): <E, R>(
1428
+ self: Micro<A, E, R>
1429
+ ) => [X] extends [Micro<infer _A1, infer E1, infer R1>] ? Micro<A, E | E1, R | R1>
1430
+ : Micro<A, E, R>
1431
+ <X>(
1432
+ f: NotFunction<X>
1433
+ ): <A, E, R>(
1434
+ self: Micro<A, E, R>
1435
+ ) => [X] extends [Micro<infer _A1, infer E1, infer R1>] ? Micro<A, E | E1, R | R1>
1436
+ : Micro<A, E, R>
1437
+ <A, E, R, X>(
1438
+ self: Micro<A, E, R>,
1439
+ f: (a: NoInfer<A>) => X
1440
+ ): [X] extends [Micro<infer _A1, infer E1, infer R1>] ? Micro<A, E | E1, R | R1>
1441
+ : Micro<A, E, R>
1442
+ <A, E, R, X>(
1443
+ self: Micro<A, E, R>,
1444
+ f: NotFunction<X>
1445
+ ): [X] extends [Micro<infer _A1, infer E1, infer R1>] ? Micro<A, E | E1, R | R1>
1446
+ : Micro<A, E, R>
1447
+ } = dual(
1448
+ 2,
1449
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: A) => Micro<B, E2, R2>): Micro<A, E | E2, R | R2> =>
1450
+ make(function(env, onResult) {
1451
+ self[runSymbol](env, function(selfResult) {
1452
+ if (selfResult._tag === "Left") {
1453
+ return onResult(selfResult as any)
1454
+ } else if (envGet(env, currentAbortSignal).aborted) {
1455
+ return onResult(ResultAborted)
1456
+ }
1457
+ const value = isMicro(f) ? f : typeof f === "function" ? f(selfResult.right) : f
1458
+ if (isMicro(value)) {
1459
+ value[runSymbol](env, function(tapResult) {
1460
+ if (tapResult._tag === "Left") {
1461
+ return onResult(tapResult)
1462
+ }
1463
+ onResult(selfResult)
1464
+ })
1465
+ } else {
1466
+ onResult(selfResult)
1467
+ }
1468
+ })
1469
+ })
1470
+ )
1471
+
1472
+ /**
1473
+ * Replace the success value of the `Micro` effect with `void`.
1474
+ *
1475
+ * @since 3.4.0
1476
+ * @experimental
1477
+ * @category mapping & sequencing
1478
+ */
1479
+ export const asVoid = <A, E, R>(self: Micro<A, E, R>): Micro<void, E, R> => map(self, (_) => void 0)
1480
+
1481
+ /**
1482
+ * Access the `Result` of the given `Micro` effect.
1483
+ *
1484
+ * @since 3.4.0
1485
+ * @experimental
1486
+ * @category mapping & sequencing
1487
+ */
1488
+ export const asResult = <A, E, R>(self: Micro<A, E, R>): Micro<Result<A, E>, never, R> =>
1489
+ make(function(env, onResult) {
1490
+ self[runSymbol](env, function(result) {
1491
+ onResult(ResultSuccess(result))
1492
+ })
1493
+ })
1494
+
1495
+ /**
1496
+ * Replace the error type of the given `Micro` with the full `Failure` object.
1497
+ *
1498
+ * @since 3.4.0
1499
+ * @experimental
1500
+ * @category mapping & sequencing
1501
+ */
1502
+ export const sandbox = <A, E, R>(self: Micro<A, E, R>): Micro<A, Failure<E>, R> =>
1503
+ catchFailure(self, (failure) => fail(failure))
1504
+
1505
+ function forkSignal(env: Env<any>) {
1506
+ const controller = new AbortController()
1507
+ const parentSignal = envGet(env, currentAbortSignal)
1508
+ function onAbort() {
1509
+ controller.abort()
1510
+ parentSignal.removeEventListener("abort", onAbort)
1511
+ }
1512
+ parentSignal.addEventListener("abort", onAbort)
1513
+ const envWithSignal = envMutate(env, function(refs) {
1514
+ refs[currentAbortController.key] = controller
1515
+ refs[currentAbortSignal.key] = controller.signal
1516
+ return refs
1517
+ })
1518
+ return [envWithSignal, onAbort] as const
1519
+ }
1520
+
1521
+ /**
1522
+ * Returns an effect that races all the specified effects,
1523
+ * yielding the value of the first effect to succeed with a value. Losers of
1524
+ * the race will be interrupted immediately
1525
+ *
1526
+ * @since 3.4.0
1527
+ * @experimental
1528
+ * @category sequencing
1529
+ */
1530
+ export const raceAll = <Eff extends Micro<any, any, any>>(
1531
+ all: Iterable<Eff>
1532
+ ): Micro<Micro.Success<Eff>, Micro.Error<Eff>, Micro.Context<Eff>> =>
1533
+ make(function(env, onResult) {
1534
+ const [envWithSignal, onAbort] = forkSignal(env)
1535
+
1536
+ const effects = Array.from(all)
1537
+ let len = effects.length
1538
+ let index = 0
1539
+ let done = 0
1540
+ let result: Result<any, any> | undefined = undefined
1541
+ const failures: Array<Failure<any>> = []
1542
+ function onDone(result_: Result<any, any>) {
1543
+ done++
1544
+ if (result_._tag === "Right" && result === undefined) {
1545
+ len = index
1546
+ result = result_
1547
+ onAbort()
1548
+ } else if (result_._tag === "Left") {
1549
+ failures.push(result_.left)
1550
+ }
1551
+ if (done >= len) {
1552
+ onResult(result ?? Either.left(failures[0]))
1553
+ }
1554
+ }
1555
+
1556
+ for (; index < len; index++) {
1557
+ effects[index][runSymbol](envWithSignal, onDone)
1558
+ }
1559
+ })
1560
+
1561
+ /**
1562
+ * Returns an effect that races all the specified effects,
1563
+ * yielding the value of the first effect to succeed or fail. Losers of
1564
+ * the race will be interrupted immediately
1565
+ *
1566
+ * @since 3.4.0
1567
+ * @experimental
1568
+ * @category sequencing
1569
+ */
1570
+ export const raceAllFirst = <Eff extends Micro<any, any, any>>(
1571
+ all: Iterable<Eff>
1572
+ ): Micro<Micro.Success<Eff>, Micro.Error<Eff>, Micro.Context<Eff>> =>
1573
+ make(function(env, onResult) {
1574
+ const [envWithSignal, onAbort] = forkSignal(env)
1575
+
1576
+ const effects = Array.from(all)
1577
+ let len = effects.length
1578
+ let index = 0
1579
+ let done = 0
1580
+ let result: Result<any, any> | undefined = undefined
1581
+ const failures: Array<Failure<any>> = []
1582
+ function onDone(result_: Result<any, any>) {
1583
+ done++
1584
+ if (result === undefined) {
1585
+ len = index
1586
+ result = result_
1587
+ onAbort()
1588
+ }
1589
+ if (done >= len) {
1590
+ onResult(result ?? Either.left(failures[0]))
1591
+ }
1592
+ }
1593
+
1594
+ for (; index < len; index++) {
1595
+ effects[index][runSymbol](envWithSignal, onDone)
1596
+ }
1597
+ })
1598
+
1599
+ /**
1600
+ * Returns an effect that races two effects, yielding the value of the first
1601
+ * effect to succeed. Losers of the race will be interrupted immediately
1602
+ *
1603
+ * @since 3.4.0
1604
+ * @experimental
1605
+ * @category sequencing
1606
+ */
1607
+ export const race: {
1608
+ <A2, E2, R2>(that: Micro<A2, E2, R2>): <A, E, R>(self: Micro<A, E, R>) => Micro<A | A2, E | E2, R | R2>
1609
+ <A, E, R, A2, E2, R2>(self: Micro<A, E, R>, that: Micro<A2, E2, R2>): Micro<A | A2, E | E2, R | R2>
1610
+ } = dual(
1611
+ 2,
1612
+ <A, E, R, A2, E2, R2>(self: Micro<A, E, R>, that: Micro<A2, E2, R2>): Micro<A | A2, E | E2, R | R2> =>
1613
+ raceAll([self, that])
1614
+ )
1615
+
1616
+ /**
1617
+ * Returns an effect that races two effects, yielding the value of the first
1618
+ * effect to succeed *or* fail. Losers of the race will be interrupted immediately
1619
+ *
1620
+ * @since 3.4.0
1621
+ * @experimental
1622
+ * @category sequencing
1623
+ */
1624
+ export const raceFirst: {
1625
+ <A2, E2, R2>(that: Micro<A2, E2, R2>): <A, E, R>(self: Micro<A, E, R>) => Micro<A | A2, E | E2, R | R2>
1626
+ <A, E, R, A2, E2, R2>(self: Micro<A, E, R>, that: Micro<A2, E2, R2>): Micro<A | A2, E | E2, R | R2>
1627
+ } = dual(
1628
+ 2,
1629
+ <A, E, R, A2, E2, R2>(self: Micro<A, E, R>, that: Micro<A2, E2, R2>): Micro<A | A2, E | E2, R | R2> =>
1630
+ raceAllFirst([self, that])
1631
+ )
1632
+
1633
+ // ----------------------------------------------------------------------------
1634
+ // zipping
1635
+ // ----------------------------------------------------------------------------
1636
+
1637
+ /**
1638
+ * Combine two `Micro` effects into a single effect that produces a tuple of
1639
+ * their results.
1640
+ *
1641
+ * @since 3.4.0
1642
+ * @experimental
1643
+ * @category zipping
1644
+ */
1645
+ export const zip: {
1646
+ <A2, E2, R2>(
1647
+ that: Micro<A2, E2, R2>,
1648
+ options?:
1649
+ | { readonly concurrent?: boolean | undefined }
1650
+ | undefined
1651
+ ): <A, E, R>(self: Micro<A, E, R>) => Micro<[A, A2], E2 | E, R2 | R>
1652
+ <A, E, R, A2, E2, R2>(
1653
+ self: Micro<A, E, R>,
1654
+ that: Micro<A2, E2, R2>,
1655
+ options?:
1656
+ | { readonly concurrent?: boolean | undefined }
1657
+ | undefined
1658
+ ): Micro<[A, A2], E | E2, R | R2>
1659
+ } = dual((args) => isMicro(args[1]), <A, E, R, A2, E2, R2>(
1660
+ self: Micro<A, E, R>,
1661
+ that: Micro<A2, E2, R2>,
1662
+ options?:
1663
+ | { readonly concurrent?: boolean | undefined }
1664
+ | undefined
1665
+ ): Micro<[A, A2], E | E2, R | R2> => {
1666
+ if (options?.concurrent) {
1667
+ return all([self, that], { concurrency: "unbounded" })
1668
+ }
1669
+ return flatMap(self, (a) => map(that, (a2) => [a, a2]))
1670
+ })
1671
+
1672
+ // ----------------------------------------------------------------------------
1673
+ // filtering & conditionals
1674
+ // ----------------------------------------------------------------------------
1675
+
1676
+ /**
1677
+ * Filter the specified effect with the provided function, failing with specified
1678
+ * `Failure` if the predicate fails.
1679
+ *
1680
+ * In addition to the filtering capabilities discussed earlier, you have the option to further
1681
+ * refine and narrow down the type of the success channel by providing a
1682
+ *
1683
+ * @since 3.4.0
1684
+ * @experimental
1685
+ * @category filtering & conditionals
1686
+ */
1687
+ export const filterOrFailWith: {
1688
+ <A, B extends A, E2>(
1689
+ refinement: Refinement<A, B>,
1690
+ orFailWith: (a: NoInfer<A>) => Failure<E2>
1691
+ ): <E, R>(self: Micro<A, E, R>) => Micro<B, E2 | E, R>
1692
+ <A, E2>(
1693
+ predicate: Predicate<NoInfer<A>>,
1694
+ orFailWith: (a: NoInfer<A>) => Failure<E2>
1695
+ ): <E, R>(self: Micro<A, E, R>) => Micro<A, E2 | E, R>
1696
+ <A, E, R, B extends A, E2>(
1697
+ self: Micro<A, E, R>,
1698
+ refinement: Refinement<A, B>,
1699
+ orFailWith: (a: A) => Failure<E2>
1700
+ ): Micro<B, E | E2, R>
1701
+ <A, E, R, E2>(self: Micro<A, E, R>, predicate: Predicate<A>, orFailWith: (a: A) => Failure<E2>): Micro<A, E | E2, R>
1702
+ } = dual((args) => isMicro(args[0]), <A, E, R, B extends A, E2>(
1703
+ self: Micro<A, E, R>,
1704
+ refinement: Refinement<A, B>,
1705
+ orFailWith: (a: A) => Failure<E2>
1706
+ ): Micro<B, E | E2, R> => flatMap(self, (a) => refinement(a) ? succeed(a as any) : failWith(orFailWith(a))))
1707
+
1708
+ /**
1709
+ * Filter the specified effect with the provided function, failing with specified
1710
+ * error if the predicate fails.
1711
+ *
1712
+ * In addition to the filtering capabilities discussed earlier, you have the option to further
1713
+ * refine and narrow down the type of the success channel by providing a
1714
+ *
1715
+ * @since 3.4.0
1716
+ * @experimental
1717
+ * @category filtering & conditionals
1718
+ */
1719
+ export const filterOrFail: {
1720
+ <A, B extends A, E2>(
1721
+ refinement: Refinement<A, B>,
1722
+ orFailWith: (a: NoInfer<A>) => E2
1723
+ ): <E, R>(self: Micro<A, E, R>) => Micro<B, E2 | E, R>
1724
+ <A, E2>(
1725
+ predicate: Predicate<NoInfer<A>>,
1726
+ orFailWith: (a: NoInfer<A>) => E2
1727
+ ): <E, R>(self: Micro<A, E, R>) => Micro<A, E2 | E, R>
1728
+ <A, E, R, B extends A, E2>(
1729
+ self: Micro<A, E, R>,
1730
+ refinement: Refinement<A, B>,
1731
+ orFailWith: (a: A) => E2
1732
+ ): Micro<B, E | E2, R>
1733
+ <A, E, R, E2>(self: Micro<A, E, R>, predicate: Predicate<A>, orFailWith: (a: A) => E2): Micro<A, E | E2, R>
1734
+ } = dual((args) => isMicro(args[0]), <A, E, R, B extends A, E2>(
1735
+ self: Micro<A, E, R>,
1736
+ refinement: Refinement<A, B>,
1737
+ orFailWith: (a: A) => E2
1738
+ ): Micro<B, E | E2, R> => flatMap(self, (a) => refinement(a) ? succeed(a as any) : fail(orFailWith(a))))
1739
+
1740
+ /**
1741
+ * The moral equivalent of `if (p) exp`.
1742
+ *
1743
+ * @since 3.4.0
1744
+ * @experimental
1745
+ * @category filtering & conditionals
1746
+ */
1747
+ export const when: {
1748
+ <E2 = never, R2 = never>(
1749
+ condition: LazyArg<boolean> | Micro<boolean, E2, R2>
1750
+ ): <A, E, R>(self: Micro<A, E, R>) => Micro<Option.Option<A>, E | E2, R | R2>
1751
+ <A, E, R, E2 = never, R2 = never>(
1752
+ self: Micro<A, E, R>,
1753
+ condition: LazyArg<boolean> | Micro<boolean, E2, R2>
1754
+ ): Micro<Option.Option<A>, E | E2, R | R2>
1755
+ } = dual(
1756
+ 2,
1757
+ <A, E, R, E2 = never, R2 = never>(
1758
+ self: Micro<A, E, R>,
1759
+ condition: LazyArg<boolean> | Micro<boolean, E2, R2>
1760
+ ): Micro<Option.Option<A>, E | E2, R | R2> =>
1761
+ flatMap(isMicro(condition) ? condition : sync(condition), (pass) => pass ? asSome(self) : succeed(Option.none()))
1762
+ )
1763
+
1764
+ // ----------------------------------------------------------------------------
1765
+ // repetition
1766
+ // ----------------------------------------------------------------------------
1767
+
1768
+ /**
1769
+ * Repeat the given `Micro` using the provided options.
1770
+ *
1771
+ * The `while` predicate will be checked after each iteration, and can use the
1772
+ * fall `Result` of the effect to determine if the repetition should continue.
1773
+ *
1774
+ * @since 3.4.0
1775
+ * @experimental
1776
+ * @category repetition
1777
+ */
1778
+ export const repeatResult: {
1779
+ <A, E>(options: {
1780
+ while: Predicate<Result<A, E>>
1781
+ times?: number | undefined
1782
+ delay?: DelayFn | undefined
1783
+ }): <R>(self: Micro<A, E, R>) => Micro<A, E, R>
1784
+ <A, E, R>(self: Micro<A, E, R>, options: {
1785
+ while: Predicate<Result<A, E>>
1786
+ times?: number | undefined
1787
+ delay?: DelayFn | undefined
1788
+ }): Micro<A, E, R>
1789
+ } = dual(2, <A, E, R>(self: Micro<A, E, R>, options: {
1790
+ while: Predicate<Result<A, E>>
1791
+ times?: number | undefined
1792
+ delay?: DelayFn | undefined
1793
+ }): Micro<A, E, R> =>
1794
+ make(function(env, onResult) {
1795
+ const startedAt = options.delay ? Date.now() : 0
1796
+ let attempt = 0
1797
+ self[runSymbol](env, function loop(result) {
1798
+ if (options.while !== undefined && !options.while(result)) {
1799
+ return onResult(result)
1800
+ } else if (options.times !== undefined && attempt >= options.times) {
1801
+ return onResult(result)
1802
+ }
1803
+ attempt++
1804
+ let delayEffect = yieldNow
1805
+ if (options.delay !== undefined) {
1806
+ const elapsed = Date.now() - startedAt
1807
+ const duration = options.delay(attempt, elapsed)
1808
+ if (Option.isNone(duration)) {
1809
+ return onResult(result)
1810
+ }
1811
+ delayEffect = sleep(duration.value)
1812
+ }
1813
+ delayEffect[runSymbol](env, function(result) {
1814
+ if (result._tag === "Left") {
1815
+ return onResult(result as any)
1816
+ }
1817
+ self[runSymbol](env, loop)
1818
+ })
1819
+ })
1820
+ }))
1821
+
1822
+ /**
1823
+ * Repeat the given `Micro` effect using the provided options. Only successful
1824
+ * results will be repeated.
1825
+ *
1826
+ * @since 3.4.0
1827
+ * @experimental
1828
+ * @category repetition
1829
+ */
1830
+ export const repeat: {
1831
+ <A, E>(
1832
+ options?: {
1833
+ while?: Predicate<A> | undefined
1834
+ times?: number | undefined
1835
+ delay?: DelayFn | undefined
1836
+ } | undefined
1837
+ ): <R>(self: Micro<A, E, R>) => Micro<A, E, R>
1838
+ <A, E, R>(
1839
+ self: Micro<A, E, R>,
1840
+ options?: {
1841
+ while?: Predicate<A> | undefined
1842
+ times?: number | undefined
1843
+ delay?: DelayFn | undefined
1844
+ } | undefined
1845
+ ): Micro<A, E, R>
1846
+ } = dual((args) => isMicro(args[0]), <A, E, R>(
1847
+ self: Micro<A, E, R>,
1848
+ options?: {
1849
+ while?: Predicate<A> | undefined
1850
+ times?: number | undefined
1851
+ delay?: DelayFn | undefined
1852
+ } | undefined
1853
+ ): Micro<A, E, R> =>
1854
+ repeatResult(self, {
1855
+ ...options,
1856
+ while: (result) => result._tag === "Right" && (options?.while === undefined || options.while(result.right))
1857
+ }))
1858
+
1859
+ /**
1860
+ * Repeat the given `Micro` effect forever, only stopping if the effect fails.
1861
+ *
1862
+ * @since 3.4.0
1863
+ * @experimental
1864
+ * @category repetition
1865
+ */
1866
+ export const forever = <A, E, R>(self: Micro<A, E, R>): Micro<never, E, R> => repeat(self) as any
1867
+
1868
+ // ----------------------------------------------------------------------------
1869
+ // delay fn
1870
+ // ----------------------------------------------------------------------------
1871
+
1872
+ /**
1873
+ * Represents a function that can be used to calculate the delay between
1874
+ * repeats.
1875
+ *
1876
+ * The function takes the current attempt number and the elapsed time since
1877
+ * the first attempt, and returns the delay for the next attempt. If the
1878
+ * function returns `None`, the repetition will stop.
1879
+ *
1880
+ * @since 3.4.0
1881
+ * @experimental
1882
+ * @category delay fn
1883
+ */
1884
+ export type DelayFn = (attempt: number, elapsed: number) => Option.Option<number>
1885
+
1886
+ /**
1887
+ * Create a `DelayFn` that will generate a duration with an exponential backoff.
1888
+ *
1889
+ * @since 3.4.0
1890
+ * @experimental
1891
+ * @category delay fn
1892
+ */
1893
+ export const delayExponential = (baseMillis: number, factor = 2): DelayFn => (attempt) =>
1894
+ Option.some(attempt ** factor * baseMillis)
1895
+
1896
+ /**
1897
+ * Create a `DelayFn` that will generate a duration with fixed intervals.
1898
+ *
1899
+ * @since 3.4.0
1900
+ * @experimental
1901
+ * @category delay fn
1902
+ */
1903
+ export const delaySpaced = (millis: number): DelayFn => (_) => Option.some(millis)
1904
+
1905
+ /**
1906
+ * Transform a `DelayFn` to one that will have a duration that will never exceed
1907
+ * the specified maximum.
1908
+ *
1909
+ * @since 3.4.0
1910
+ * @experimental
1911
+ * @category delay fn
1912
+ */
1913
+ export const delayWithMax: {
1914
+ (max: number): (self: DelayFn) => DelayFn
1915
+ (self: DelayFn, max: number): DelayFn
1916
+ } = dual(
1917
+ 2,
1918
+ (self: DelayFn, max: number): DelayFn => (attempt, elapsed) =>
1919
+ Option.map(self(attempt, elapsed), (duration) => Math.min(duration, max))
1920
+ )
1921
+
1922
+ /**
1923
+ * Transform a `DelayFn` to one that will stop repeating after the specified
1924
+ * amount of time.
1925
+ *
1926
+ * @since 3.4.0
1927
+ * @experimental
1928
+ * @category delay fn
1929
+ */
1930
+ export const delayWithMaxElapsed: {
1931
+ (max: number): (self: DelayFn) => DelayFn
1932
+ (self: DelayFn, max: number): DelayFn
1933
+ } = dual(
1934
+ 2,
1935
+ (self: DelayFn, max: number): DelayFn => (attempt, elapsed) => elapsed < max ? self(attempt, elapsed) : Option.none()
1936
+ )
1937
+
1938
+ /**
1939
+ * Transform a `DelayFn` to one that will stop repeating after the specified
1940
+ * number of attempts.
1941
+ *
1942
+ * @since 3.4.0
1943
+ * @experimental
1944
+ * @category delay fn
1945
+ */
1946
+ export const delayWithRecurs: {
1947
+ (n: number): (self: DelayFn) => DelayFn
1948
+ (self: DelayFn, n: number): DelayFn
1949
+ } = dual(
1950
+ 2,
1951
+ (self: DelayFn, n: number): DelayFn => (attempt, elapsed) => Option.filter(self(attempt, elapsed), () => attempt <= n)
1952
+ )
1953
+
1954
+ // ----------------------------------------------------------------------------
1955
+ // error handling
1956
+ // ----------------------------------------------------------------------------
1957
+
1958
+ /**
1959
+ * Catch the full `Failure` object of the given `Micro` effect, allowing you to
1960
+ * recover from any kind of failure.
1961
+ *
1962
+ * @since 3.4.0
1963
+ * @experimental
1964
+ * @category error handling
1965
+ */
1966
+ export const catchFailure: {
1967
+ <E, B, E2, R2>(
1968
+ f: (failure: NoInfer<Failure<E>>) => Micro<B, E2, R2>
1969
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E2, R | R2>
1970
+ <A, E, R, B, E2, R2>(
1971
+ self: Micro<A, E, R>,
1972
+ f: (failure: NoInfer<Failure<E>>) => Micro<B, E2, R2>
1973
+ ): Micro<A | B, E2, R | R2>
1974
+ } = dual(
1975
+ 2,
1976
+ <A, E, R, B, E2, R2>(
1977
+ self: Micro<A, E, R>,
1978
+ f: (failure: NoInfer<Failure<E>>) => Micro<B, E2, R2>
1979
+ ): Micro<A | B, E2, R | R2> => catchFailureIf(self, constTrue, f)
1980
+ )
1981
+
1982
+ /**
1983
+ * Selectively catch a `Failure` object of the given `Micro` effect,
1984
+ * using the provided predicate to determine if the failure should be caught.
1985
+ *
1986
+ * @since 3.4.0
1987
+ * @experimental
1988
+ * @category error handling
1989
+ */
1990
+ export const catchFailureIf: {
1991
+ <E, B, E2, R2, EB extends Failure<E>>(
1992
+ refinement: Refinement<Failure<E>, EB>,
1993
+ f: (failure: EB) => Micro<B, E2, R2>
1994
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E2, R | R2>
1995
+ <E, B, E2, R2>(
1996
+ predicate: Predicate<Failure<NoInfer<E>>>,
1997
+ f: (failure: NoInfer<Failure<E>>) => Micro<B, E2, R2>
1998
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E2, R | R2>
1999
+ <A, E, R, B, E2, R2, EB extends Failure<E>>(
2000
+ self: Micro<A, E, R>,
2001
+ refinement: Refinement<Failure<E>, EB>,
2002
+ f: (failure: EB) => Micro<B, E2, R2>
2003
+ ): Micro<A | B, E2, R | R2>
2004
+ <A, E, R, B, E2, R2>(
2005
+ self: Micro<A, E, R>,
2006
+ predicate: Predicate<Failure<NoInfer<E>>>,
2007
+ f: (failure: NoInfer<Failure<E>>) => Micro<B, E2, R2>
2008
+ ): Micro<A | B, E2, R | R2>
2009
+ } = dual(3, <A, E, R, B, E2, R2, EB extends Failure<E>>(
2010
+ self: Micro<A, E, R>,
2011
+ refinement: Refinement<Failure<E>, EB>,
2012
+ f: (failure: EB) => Micro<B, E2, R2>
2013
+ ): Micro<A | B, E2, R | R2> =>
2014
+ make(function(env, onResult) {
2015
+ self[runSymbol](env, function(result) {
2016
+ if (result._tag === "Right" || !refinement(result.left)) {
2017
+ return onResult(result as any)
2018
+ }
2019
+ f(result.left)[runSymbol](env, onResult)
2020
+ })
2021
+ }))
2022
+
2023
+ /**
2024
+ * Catch the error of the given `Micro` effect, allowing you to recover from it.
2025
+ *
2026
+ * It only catches expected (`FailureExpected`) errors.
2027
+ *
2028
+ * @since 3.4.0
2029
+ * @experimental
2030
+ * @category error handling
2031
+ */
2032
+ export const catchExpected: {
2033
+ <E, B, E2, R2>(
2034
+ f: (e: NoInfer<E>) => Micro<B, E2, R2>
2035
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E2, R | R2>
2036
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (e: NoInfer<E>) => Micro<B, E2, R2>): Micro<A | B, E2, R | R2>
2037
+ } = dual(
2038
+ 2,
2039
+ <A, E, R, B, E2, R2>(
2040
+ self: Micro<A, E, R>,
2041
+ f: (a: NoInfer<E>) => Micro<B, E2, R2>
2042
+ ): Micro<A | B, E2, R | R2> => catchFailureIf(self, failureIsExpected, (failure) => f(failure.error))
2043
+ )
2044
+
2045
+ /**
2046
+ * Catch any unexpected errors of the given `Micro` effect, allowing you to recover from them.
2047
+ *
2048
+ * @since 3.4.0
2049
+ * @experimental
2050
+ * @category error handling
2051
+ */
2052
+ export const catchUnexpected: {
2053
+ <E, B, E2, R2>(
2054
+ f: (defect: unknown) => Micro<B, E2, R2>
2055
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E | E2, R | R2>
2056
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (defect: unknown) => Micro<B, E2, R2>): Micro<A | B, E | E2, R | R2>
2057
+ } = dual(
2058
+ 2,
2059
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (defect: unknown) => Micro<B, E2, R2>): Micro<A | B, E | E2, R | R2> =>
2060
+ catchFailureIf(self, failureIsUnexpected, (failure) => f(failure.defect))
2061
+ )
2062
+
2063
+ /**
2064
+ * Perform a side effect using the full `Failure` object of the given `Micro`.
2065
+ *
2066
+ * @since 3.4.0
2067
+ * @experimental
2068
+ * @category error handling
2069
+ */
2070
+ export const tapFailure: {
2071
+ <E, B, E2, R2>(
2072
+ f: (a: NoInfer<Failure<E>>) => Micro<B, E2, R2>
2073
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A, E | E2, R | R2>
2074
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: NoInfer<Failure<E>>) => Micro<B, E2, R2>): Micro<A, E | E2, R | R2>
2075
+ } = dual(
2076
+ 2,
2077
+ <A, E, R, B, E2, R2>(
2078
+ self: Micro<A, E, R>,
2079
+ f: (a: NoInfer<Failure<E>>) => Micro<B, E2, R2>
2080
+ ): Micro<A, E | E2, R | R2> => tapFailureIf(self, constTrue, f)
2081
+ )
2082
+
2083
+ /**
2084
+ * Perform a side effect using if a `Failure` object matches the specified
2085
+ * predicate.
2086
+ *
2087
+ * @since 3.4.0
2088
+ * @experimental
2089
+ * @category error handling
2090
+ */
2091
+ export const tapFailureIf: {
2092
+ <E, B, E2, R2, EB extends Failure<E>>(
2093
+ refinement: Refinement<Failure<E>, EB>,
2094
+ f: (a: EB) => Micro<B, E2, R2>
2095
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A, E | E2, R | R2>
2096
+ <E, B, E2, R2>(
2097
+ predicate: (failure: NoInfer<Failure<E>>) => boolean,
2098
+ f: (a: NoInfer<Failure<E>>) => Micro<B, E2, R2>
2099
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A, E | E2, R | R2>
2100
+ <A, E, R, B, E2, R2, EB extends Failure<E>>(
2101
+ self: Micro<A, E, R>,
2102
+ refinement: Refinement<Failure<E>, EB>,
2103
+ f: (a: EB) => Micro<B, E2, R2>
2104
+ ): Micro<A, E | E2, R | R2>
2105
+ <A, E, R, B, E2, R2>(
2106
+ self: Micro<A, E, R>,
2107
+ predicate: (failure: NoInfer<Failure<E>>) => boolean,
2108
+ f: (a: NoInfer<Failure<E>>) => Micro<B, E2, R2>
2109
+ ): Micro<A, E | E2, R | R2>
2110
+ } = dual(
2111
+ 3,
2112
+ <A, E, R, B, E2, R2, EB extends Failure<E>>(
2113
+ self: Micro<A, E, R>,
2114
+ refinement: Refinement<Failure<E>, EB>,
2115
+ f: (a: EB) => Micro<B, E2, R2>
2116
+ ): Micro<A, E | E2, R | R2> =>
2117
+ catchFailureIf(self, refinement, (failure) => andThen(f(failure as any), failWith(failure)))
2118
+ )
2119
+
2120
+ /**
2121
+ * Perform a side effect from expected errors of the given `Micro`.
2122
+ *
2123
+ * @since 3.4.0
2124
+ * @experimental
2125
+ * @category error handling
2126
+ */
2127
+ export const tapExpected: {
2128
+ <E, B, E2, R2>(
2129
+ f: (a: NoInfer<E>) => Micro<B, E2, R2>
2130
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A, E | E2, R | R2>
2131
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: NoInfer<E>) => Micro<B, E2, R2>): Micro<A, E | E2, R | R2>
2132
+ } = dual(
2133
+ 2,
2134
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: NoInfer<E>) => Micro<B, E2, R2>): Micro<A, E | E2, R | R2> =>
2135
+ tapFailureIf(self, failureIsExpected, (failure) => f(failure.error))
2136
+ )
2137
+
2138
+ /**
2139
+ * Perform a side effect from unexpected errors of the given `Micro`.
2140
+ *
2141
+ * @since 3.4.0
2142
+ * @experimental
2143
+ * @category error handling
2144
+ */
2145
+ export const tapUnexpected: {
2146
+ <E, B, E2, R2>(
2147
+ f: (defect: unknown) => Micro<B, E2, R2>
2148
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A, E | E2, R | R2>
2149
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (defect: unknown) => Micro<B, E2, R2>): Micro<A, E | E2, R | R2>
2150
+ } = dual(
2151
+ 2,
2152
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (defect: unknown) => Micro<B, E2, R2>): Micro<A, E | E2, R | R2> =>
2153
+ tapFailureIf(self, failureIsUnexpected, (failure) => f(failure.defect))
2154
+ )
2155
+
2156
+ /**
2157
+ * Catch any expected errors that match the specified predicate.
2158
+ *
2159
+ * @since 3.4.0
2160
+ * @experimental
2161
+ * @category error handling
2162
+ */
2163
+ export const catchIf: {
2164
+ <E, EB extends E, B, E2, R2>(
2165
+ pred: Refinement<E, EB>,
2166
+ f: (a: NoInfer<EB>) => Micro<B, E2, R2>
2167
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E2, R | R2>
2168
+ <E, B, E2, R2>(
2169
+ pred: Predicate<NoInfer<E>>,
2170
+ f: (a: NoInfer<E>) => Micro<B, E2, R2>
2171
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E2, R | R2>
2172
+ <A, E, R, EB extends E, B, E2, R2>(
2173
+ self: Micro<A, E, R>,
2174
+ pred: Refinement<E, EB>,
2175
+ f: (a: NoInfer<EB>) => Micro<B, E2, R2>
2176
+ ): Micro<A | B, E2, R | R2>
2177
+ <A, E, R, B, E2, R2>(
2178
+ self: Micro<A, E, R>,
2179
+ pred: Predicate<NoInfer<E>>,
2180
+ f: (a: NoInfer<E>) => Micro<B, E2, R2>
2181
+ ): Micro<A | B, E2, R | R2>
2182
+ } = dual(
2183
+ 3,
2184
+ <A, E, R, EB extends E, B, E2, R2>(
2185
+ self: Micro<A, E, R>,
2186
+ pred: Refinement<E, EB>,
2187
+ f: (a: NoInfer<EB>) => Micro<B, E2, R2>
2188
+ ): Micro<A | B, E2, R | R2> =>
2189
+ catchFailureIf(
2190
+ self,
2191
+ (f): f is Failure.Expected<EB> => failureIsExpected(f) && pred(f.error),
2192
+ (failure) => f(failure.error)
2193
+ )
2194
+ )
2195
+
2196
+ /**
2197
+ * Recovers from the specified tagged error.
2198
+ *
2199
+ * @since 3.4.0
2200
+ * @experimental
2201
+ * @category error handling
2202
+ */
2203
+ export const catchTag: {
2204
+ <K extends E extends { _tag: string } ? E["_tag"] : never, E, A1, E1, R1>(
2205
+ k: K,
2206
+ f: (e: Extract<E, { _tag: K }>) => Micro<A1, E1, R1>
2207
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A1 | A, E1 | Exclude<E, { _tag: K }>, R1 | R>
2208
+ <A, E, R, K extends E extends { _tag: string } ? E["_tag"] : never, R1, E1, A1>(
2209
+ self: Micro<A, E, R>,
2210
+ k: K,
2211
+ f: (e: Extract<E, { _tag: K }>) => Micro<A1, E1, R1>
2212
+ ): Micro<A | A1, E1 | Exclude<E, { _tag: K }>, R | R1>
2213
+ } = dual(3, <A, E, R, K extends E extends { _tag: string } ? E["_tag"] : never, R1, E1, A1>(
2214
+ self: Micro<A, E, R>,
2215
+ k: K,
2216
+ f: (e: Extract<E, { _tag: K }>) => Micro<A1, E1, R1>
2217
+ ): Micro<A | A1, E1 | Exclude<E, { _tag: K }>, R | R1> => catchIf(self, (error) => isTagged(error, k), f as any))
2218
+
2219
+ /**
2220
+ * Transform the full `Failure` object of the given `Micro` effect.
2221
+ *
2222
+ * @since 3.4.0
2223
+ * @experimental
2224
+ * @category error handling
2225
+ */
2226
+ export const mapFailure: {
2227
+ <E, E2>(f: (a: Failure<E>) => Failure<E2>): <A, R>(self: Micro<A, E, R>) => Micro<A, E2, R>
2228
+ <A, E, R, E2>(self: Micro<A, E, R>, f: (a: Failure<E>) => Failure<E2>): Micro<A, E2, R>
2229
+ } = dual(
2230
+ 2,
2231
+ <A, E, R, E2>(self: Micro<A, E, R>, f: (a: Failure<E>) => Failure<E2>): Micro<A, E2, R> =>
2232
+ catchFailure(self, (failure) => failWith(f(failure)))
2233
+ )
2234
+
2235
+ /**
2236
+ * Transform any expected errors of the given `Micro` effect.
2237
+ *
2238
+ * @since 3.4.0
2239
+ * @experimental
2240
+ * @category error handling
2241
+ */
2242
+ export const mapError: {
2243
+ <E, E2>(f: (a: E) => E2): <A, R>(self: Micro<A, E, R>) => Micro<A, E2, R>
2244
+ <A, E, R, E2>(self: Micro<A, E, R>, f: (a: E) => E2): Micro<A, E2, R>
2245
+ } = dual(
2246
+ 2,
2247
+ <A, E, R, E2>(self: Micro<A, E, R>, f: (a: E) => E2): Micro<A, E2, R> =>
2248
+ catchExpected(self, (error) => fail(f(error)))
2249
+ )
2250
+
2251
+ /**
2252
+ * Elevate any expected errors of the given `Micro` effect to unexpected errors,
2253
+ * resulting in an error type of `never`.
2254
+ *
2255
+ * @since 3.4.0
2256
+ * @experimental
2257
+ * @category error handling
2258
+ */
2259
+ export const orDie = <A, E, R>(self: Micro<A, E, R>): Micro<A, never, R> => catchExpected(self, die)
2260
+
2261
+ /**
2262
+ * Recover from all errors by succeeding with the given value.
2263
+ *
2264
+ * @since 3.4.0
2265
+ * @experimental
2266
+ * @category error handling
2267
+ */
2268
+ export const orElseSucceed: {
2269
+ <B>(f: LazyArg<B>): <A, E, R>(self: Micro<A, E, R>) => Micro<A | B, never, R>
2270
+ <A, E, R, B>(self: Micro<A, E, R>, f: LazyArg<B>): Micro<A | B, never, R>
2271
+ } = dual(
2272
+ 2,
2273
+ <A, E, R, B>(self: Micro<A, E, R>, f: LazyArg<B>): Micro<A | B, never, R> => catchExpected(self, (_) => sync(f))
2274
+ )
2275
+
2276
+ /**
2277
+ * Ignore any expected errors of the given `Micro` effect, returning `void`.
2278
+ *
2279
+ * @since 3.4.0
2280
+ * @experimental
2281
+ * @category error handling
2282
+ */
2283
+ export const ignore = <A, E, R>(self: Micro<A, E, R>): Micro<void, never, R> =>
2284
+ matchMicro(self, { onFailure: (_) => void_, onSuccess: (_) => void_ })
2285
+
2286
+ /**
2287
+ * Ignore any expected errors of the given `Micro` effect, returning `void`.
2288
+ *
2289
+ * @since 3.4.0
2290
+ * @experimental
2291
+ * @category error handling
2292
+ */
2293
+ export const ignoreLogged = <A, E, R>(self: Micro<A, E, R>): Micro<void, never, R> =>
2294
+ matchMicro(self, {
2295
+ onFailure: (failure) => sync(() => console.error(failure)),
2296
+ onSuccess: (_) => void_
2297
+ })
2298
+
2299
+ /**
2300
+ * Replace the success value of the given `Micro` effect with an `Option`,
2301
+ * wrapping the success value in `Some` and returning `None` if the effect fails
2302
+ * with an expected error.
2303
+ *
2304
+ * @since 3.4.0
2305
+ * @experimental
2306
+ * @category error handling
2307
+ */
2308
+ export const option = <A, E, R>(self: Micro<A, E, R>): Micro<Option.Option<A>, never, R> =>
2309
+ match(self, { onFailure: (_) => Option.none(), onSuccess: Option.some })
2310
+
2311
+ /**
2312
+ * Replace the success value of the given `Micro` effect with an `Either`,
2313
+ * wrapping the success value in `Right` and wrapping any expected errors with
2314
+ * a `Left`.
2315
+ *
2316
+ * @since 3.4.0
2317
+ * @experimental
2318
+ * @category error handling
2319
+ */
2320
+ export const either = <A, E, R>(self: Micro<A, E, R>): Micro<Either.Either<A, E>, never, R> =>
2321
+ match(self, { onFailure: Either.left, onSuccess: Either.right })
2322
+
2323
+ /**
2324
+ * Retry the given `Micro` effect using the provided options.
2325
+ *
2326
+ * @since 3.4.0
2327
+ * @experimental
2328
+ * @category error handling
2329
+ */
2330
+ export const retry: {
2331
+ <A, E>(
2332
+ options?: {
2333
+ while?: Predicate<E> | undefined
2334
+ times?: number | undefined
2335
+ delay?: DelayFn | undefined
2336
+ } | undefined
2337
+ ): <R>(self: Micro<A, E, R>) => Micro<A, E, R>
2338
+ <A, E, R>(
2339
+ self: Micro<A, E, R>,
2340
+ options?: {
2341
+ while?: Predicate<E> | undefined
2342
+ times?: number | undefined
2343
+ delay?: DelayFn | undefined
2344
+ } | undefined
2345
+ ): Micro<A, E, R>
2346
+ } = dual((args) => isMicro(args[0]), <A, E, R>(
2347
+ self: Micro<A, E, R>,
2348
+ options?: {
2349
+ while?: Predicate<E> | undefined
2350
+ times?: number | undefined
2351
+ delay?: DelayFn | undefined
2352
+ } | undefined
2353
+ ): Micro<A, E, R> =>
2354
+ repeatResult(self, {
2355
+ ...options,
2356
+ while: (result) =>
2357
+ result._tag === "Left" && result.left._tag === "Expected" &&
2358
+ (options?.while === undefined || options.while(result.left.error))
2359
+ }))
2360
+
2361
+ /**
2362
+ * Add a stack trace to any failures that occur in the effect. The trace will be
2363
+ * added to the `traces` field of the `Failure` object.
2364
+ *
2365
+ * @since 3.4.0
2366
+ * @experimental
2367
+ * @category error handling
2368
+ */
2369
+ export const withTrace: {
2370
+ (name: string): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, R>
2371
+ <A, E, R>(self: Micro<A, E, R>, name: string): Micro<A, E, R>
2372
+ } = function() {
2373
+ const prevLimit = globalThis.Error.stackTraceLimit
2374
+ globalThis.Error.stackTraceLimit = 2
2375
+ const error = new globalThis.Error()
2376
+ globalThis.Error.stackTraceLimit = prevLimit
2377
+ function generate(name: string, failure: Failure<any>) {
2378
+ const stack = error.stack
2379
+ if (!stack) {
2380
+ return failure
2381
+ }
2382
+ const line = stack.split("\n")[2]?.trim().replace(/^at /, "")
2383
+ if (!line) {
2384
+ return failure
2385
+ }
2386
+ const lineMatch = line.match(/\((.*)\)$/)
2387
+ return failureWithTrace(failure, `at ${name} (${lineMatch ? lineMatch[1] : line})`)
2388
+ }
2389
+ const f = (name: string) => (self: Micro<any, any, any>) =>
2390
+ unsafeMakeOptions(function(env, onResult) {
2391
+ self[runSymbol](env, function(result) {
2392
+ onResult(result._tag === "Left" ? Either.left(generate(name, result.left)) : result)
2393
+ })
2394
+ }, false)
2395
+ if (arguments.length === 2) {
2396
+ return f(arguments[1])(arguments[0])
2397
+ }
2398
+ return f(arguments[0])
2399
+ } as any
2400
+
2401
+ // ----------------------------------------------------------------------------
2402
+ // pattern matching
2403
+ // ----------------------------------------------------------------------------
2404
+
2405
+ /**
2406
+ * @since 3.4.0
2407
+ * @experimental
2408
+ * @category pattern matching
2409
+ */
2410
+ export const matchFailureMicro: {
2411
+ <E, A2, E2, R2, A, A3, E3, R3>(
2412
+ options: {
2413
+ readonly onFailure: (failure: Failure<E>) => Micro<A2, E2, R2>
2414
+ readonly onSuccess: (a: A) => Micro<A3, E3, R3>
2415
+ }
2416
+ ): <R>(self: Micro<A, E, R>) => Micro<A2 | A3, E2 | E3, R2 | R3 | R>
2417
+ <A, E, R, A2, E2, R2, A3, E3, R3>(
2418
+ self: Micro<A, E, R>,
2419
+ options: {
2420
+ readonly onFailure: (failure: Failure<E>) => Micro<A2, E2, R2>
2421
+ readonly onSuccess: (a: A) => Micro<A3, E3, R3>
2422
+ }
2423
+ ): Micro<A2 | A3, E2 | E3, R2 | R3 | R>
2424
+ } = dual(
2425
+ 2,
2426
+ <A, E, R, A2, E2, R2, A3, E3, R3>(
2427
+ self: Micro<A, E, R>,
2428
+ options: {
2429
+ readonly onFailure: (failure: Failure<E>) => Micro<A2, E2, R2>
2430
+ readonly onSuccess: (a: A) => Micro<A3, E3, R3>
2431
+ }
2432
+ ): Micro<A2 | A3, E2 | E3, R2 | R3 | R> =>
2433
+ make(function(env, onResult) {
2434
+ self[runSymbol](env, function(result) {
2435
+ try {
2436
+ const next = result._tag === "Left" ? options.onFailure(result.left) : options.onSuccess(result.right)
2437
+ next[runSymbol](env, onResult)
2438
+ } catch (err) {
2439
+ onResult(ResultFailUnexpected(err))
2440
+ }
2441
+ })
2442
+ })
2443
+ )
2444
+
2445
+ /**
2446
+ * @since 3.4.0
2447
+ * @experimental
2448
+ * @category pattern matching
2449
+ */
2450
+ export const matchFailure: {
2451
+ <E, A2, A, A3>(
2452
+ options: {
2453
+ readonly onFailure: (failure: Failure<E>) => A2
2454
+ readonly onSuccess: (a: A) => A3
2455
+ }
2456
+ ): <R>(self: Micro<A, E, R>) => Micro<A2 | A3, never, R>
2457
+ <A, E, R, A2, A3>(
2458
+ self: Micro<A, E, R>,
2459
+ options: {
2460
+ readonly onFailure: (failure: Failure<E>) => A2
2461
+ readonly onSuccess: (a: A) => A3
2462
+ }
2463
+ ): Micro<A2 | A3, never, R>
2464
+ } = dual(
2465
+ 2,
2466
+ <A, E, R, A2, A3>(
2467
+ self: Micro<A, E, R>,
2468
+ options: {
2469
+ readonly onFailure: (failure: Failure<E>) => A2
2470
+ readonly onSuccess: (a: A) => A3
2471
+ }
2472
+ ): Micro<A2 | A3, never, R> =>
2473
+ matchFailureMicro(self, {
2474
+ onFailure: (failure) => sync(() => options.onFailure(failure)),
2475
+ onSuccess: (value) => sync(() => options.onSuccess(value))
2476
+ })
2477
+ )
2478
+
2479
+ /**
2480
+ * @since 3.4.0
2481
+ * @experimental
2482
+ * @category pattern matching
2483
+ */
2484
+ export const matchMicro: {
2485
+ <E, A2, E2, R2, A, A3, E3, R3>(
2486
+ options: {
2487
+ readonly onFailure: (e: E) => Micro<A2, E2, R2>
2488
+ readonly onSuccess: (a: A) => Micro<A3, E3, R3>
2489
+ }
2490
+ ): <R>(self: Micro<A, E, R>) => Micro<A2 | A3, E2 | E3, R2 | R3 | R>
2491
+ <A, E, R, A2, E2, R2, A3, E3, R3>(
2492
+ self: Micro<A, E, R>,
2493
+ options: {
2494
+ readonly onFailure: (e: E) => Micro<A2, E2, R2>
2495
+ readonly onSuccess: (a: A) => Micro<A3, E3, R3>
2496
+ }
2497
+ ): Micro<A2 | A3, E2 | E3, R2 | R3 | R>
2498
+ } = dual(
2499
+ 2,
2500
+ <A, E, R, A2, E2, R2, A3, E3, R3>(
2501
+ self: Micro<A, E, R>,
2502
+ options: {
2503
+ readonly onFailure: (e: E) => Micro<A2, E2, R2>
2504
+ readonly onSuccess: (a: A) => Micro<A3, E3, R3>
2505
+ }
2506
+ ): Micro<A2 | A3, E2 | E3, R2 | R3 | R> =>
2507
+ matchFailureMicro(self, {
2508
+ onFailure: (failure) => failure._tag === "Expected" ? options.onFailure(failure.error) : failWith(failure),
2509
+ onSuccess: options.onSuccess
2510
+ })
2511
+ )
2512
+
2513
+ /**
2514
+ * @since 3.4.0
2515
+ * @experimental
2516
+ * @category pattern matching
2517
+ */
2518
+ export const match: {
2519
+ <E, A2, A, A3>(
2520
+ options: {
2521
+ readonly onFailure: (error: E) => A2
2522
+ readonly onSuccess: (value: A) => A3
2523
+ }
2524
+ ): <R>(self: Micro<A, E, R>) => Micro<A2 | A3, never, R>
2525
+ <A, E, R, A2, A3>(
2526
+ self: Micro<A, E, R>,
2527
+ options: {
2528
+ readonly onFailure: (error: E) => A2
2529
+ readonly onSuccess: (value: A) => A3
2530
+ }
2531
+ ): Micro<A2 | A3, never, R>
2532
+ } = dual(
2533
+ 2,
2534
+ <A, E, R, A2, A3>(
2535
+ self: Micro<A, E, R>,
2536
+ options: {
2537
+ readonly onFailure: (error: E) => A2
2538
+ readonly onSuccess: (value: A) => A3
2539
+ }
2540
+ ): Micro<A2 | A3, never, R> =>
2541
+ matchMicro(self, {
2542
+ onFailure: (error) => sync(() => options.onFailure(error)),
2543
+ onSuccess: (value) => sync(() => options.onSuccess(value))
2544
+ })
2545
+ )
2546
+
2547
+ // ----------------------------------------------------------------------------
2548
+ // delays & timeouts
2549
+ // ----------------------------------------------------------------------------
2550
+
2551
+ /**
2552
+ * Create a `Micro` effect that will sleep for the specified duration.
2553
+ *
2554
+ * @since 3.4.0
2555
+ * @experimental
2556
+ * @category delays & timeouts
2557
+ */
2558
+ export const sleep = (millis: number): Micro<void> =>
2559
+ async(function(resume) {
2560
+ const timeout = setTimeout(function() {
2561
+ resume(void_)
2562
+ }, millis)
2563
+ return sync(() => {
2564
+ return clearTimeout(timeout)
2565
+ })
2566
+ })
2567
+
2568
+ /**
2569
+ * Returns an effect that will delay the execution of this effect by the
2570
+ * specified duration.
2571
+ *
2572
+ * @since 3.4.0
2573
+ * @experimental
2574
+ * @category delays & timeouts
2575
+ */
2576
+ export const delay: {
2577
+ (millis: number): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, R>
2578
+ <A, E, R>(self: Micro<A, E, R>, millis: number): Micro<A, E, R>
2579
+ } = dual(
2580
+ 2,
2581
+ <A, E, R>(self: Micro<A, E, R>, millis: number): Micro<A, E, R> => andThen(sleep(millis), self)
2582
+ )
2583
+
2584
+ /**
2585
+ * Returns an effect that will timeout this effect, that will execute the
2586
+ * fallback effect if the timeout elapses before the effect has produced a value.
2587
+ *
2588
+ * If the timeout elapses, the running effect will be safely interrupted.
2589
+ *
2590
+ * @since 3.4.0
2591
+ * @experimental
2592
+ * @category delays & timeouts
2593
+ */
2594
+ export const timeoutOrElse: {
2595
+ <A2, E2, R2>(options: {
2596
+ readonly duration: number
2597
+ readonly onTimeout: LazyArg<Micro<A2, E2, R2>>
2598
+ }): <A, E, R>(self: Micro<A, E, R>) => Micro<A | A2, E | E2, R | R2>
2599
+ <A, E, R, A2, E2, R2>(self: Micro<A, E, R>, options: {
2600
+ readonly duration: number
2601
+ readonly onTimeout: LazyArg<Micro<A2, E2, R2>>
2602
+ }): Micro<A | A2, E | E2, R | R2>
2603
+ } = dual(
2604
+ 2,
2605
+ <A, E, R, A2, E2, R2>(self: Micro<A, E, R>, options: {
2606
+ readonly duration: number
2607
+ readonly onTimeout: LazyArg<Micro<A2, E2, R2>>
2608
+ }): Micro<A | A2, E | E2, R | R2> =>
2609
+ raceFirst(self, andThen(interruptible(sleep(options.duration)), options.onTimeout))
2610
+ )
2611
+
2612
+ /**
2613
+ * Returns an effect that will timeout this effect, succeeding with a `None`
2614
+ * if the timeout elapses before the effect has produced a value; and `Some` of
2615
+ * the produced value otherwise.
2616
+ *
2617
+ * If the timeout elapses, the running effect will be safely interrupted.
2618
+ *
2619
+ * @since 3.4.0
2620
+ * @experimental
2621
+ * @category delays & timeouts
2622
+ */
2623
+ export const timeout: {
2624
+ (millis: number): <A, E, R>(self: Micro<A, E, R>) => Micro<Option.Option<A>, E, R>
2625
+ <A, E, R>(self: Micro<A, E, R>, millis: number): Micro<Option.Option<A>, E, R>
2626
+ } = dual(
2627
+ 2,
2628
+ <A, E, R>(self: Micro<A, E, R>, millis: number): Micro<Option.Option<A>, E, R> =>
2629
+ raceFirst(
2630
+ asSome(self),
2631
+ as(interruptible(sleep(millis)), Option.none())
2632
+ )
2633
+ )
2634
+
2635
+ // ----------------------------------------------------------------------------
2636
+ // resources & finalization
2637
+ // ----------------------------------------------------------------------------
2638
+
2639
+ /**
2640
+ * @since 3.4.0
2641
+ * @experimental
2642
+ * @category resources & finalization
2643
+ */
2644
+ export const MicroScopeTypeId: unique symbol = Symbol.for("effect/Micro/MicroScope")
2645
+
2646
+ /**
2647
+ * @since 3.4.0
2648
+ * @experimental
2649
+ * @category resources & finalization
2650
+ */
2651
+ export type MicroScopeTypeId = typeof MicroScopeTypeId
2652
+
2653
+ /**
2654
+ * @since 3.4.0
2655
+ * @experimental
2656
+ * @category resources & finalization
2657
+ */
2658
+ export interface MicroScope {
2659
+ readonly [MicroScopeTypeId]: MicroScopeTypeId
2660
+ readonly addFinalizer: (finalizer: (result: Result<unknown, unknown>) => Micro<void>) => Micro<void>
2661
+ readonly fork: Micro<MicroScope.Closeable>
2662
+ }
2663
+
2664
+ /**
2665
+ * @since 3.4.0
2666
+ * @experimental
2667
+ * @category resources & finalization
2668
+ */
2669
+ export declare namespace MicroScope {
2670
+ /**
2671
+ * @since 3.4.0
2672
+ * @experimental
2673
+ * @category resources & finalization
2674
+ */
2675
+ export interface Closeable extends MicroScope {
2676
+ readonly close: (result: Result<any, any>) => Micro<void>
2677
+ }
2678
+ }
2679
+
2680
+ /**
2681
+ * @since 3.4.0
2682
+ * @experimental
2683
+ * @category resources & finalization
2684
+ */
2685
+ export const MicroScope: Context.Tag<MicroScope, MicroScope> = Context.GenericTag<MicroScope>("effect/Micro/MicroScope")
2686
+
2687
+ class ScopeImpl implements MicroScope.Closeable {
2688
+ readonly [MicroScopeTypeId]: MicroScopeTypeId
2689
+ state: {
2690
+ readonly _tag: "Open"
2691
+ readonly finalizers: Set<(result: Result<any, any>) => Micro<void>>
2692
+ } | {
2693
+ readonly _tag: "Closed"
2694
+ readonly result: Result<any, any>
2695
+ } = { _tag: "Open", finalizers: new Set() }
2696
+
2697
+ constructor() {
2698
+ this[MicroScopeTypeId] = MicroScopeTypeId
2699
+ }
2700
+
2701
+ unsafeAddFinalizer(finalizer: (result: Result<any, any>) => Micro<void>): void {
2702
+ if (this.state._tag === "Open") {
2703
+ this.state.finalizers.add(finalizer)
2704
+ }
2705
+ }
2706
+ addFinalizer(finalizer: (result: Result<any, any>) => Micro<void>): Micro<void> {
2707
+ return suspend(() => {
2708
+ if (this.state._tag === "Open") {
2709
+ this.state.finalizers.add(finalizer)
2710
+ return void_
2711
+ }
2712
+ return finalizer(this.state.result)
2713
+ })
2714
+ }
2715
+ unsafeRemoveFinalizer(finalizer: (result: Result<any, any>) => Micro<void>): void {
2716
+ if (this.state._tag === "Open") {
2717
+ this.state.finalizers.delete(finalizer)
2718
+ }
2719
+ }
2720
+ close(result: Result<any, any>): Micro<void> {
2721
+ return suspend(() => {
2722
+ if (this.state._tag === "Open") {
2723
+ const finalizers = Array.from(this.state.finalizers).reverse()
2724
+ this.state = { _tag: "Closed", result }
2725
+ return flatMap(
2726
+ forEach(finalizers, (finalizer) => asResult(finalizer(result))),
2727
+ (results) => asVoid(fromResult(Either.all(results)))
2728
+ )
2729
+ }
2730
+ return void_
2731
+ })
2732
+ }
2733
+ get fork() {
2734
+ return sync(() => {
2735
+ const newScope = new ScopeImpl()
2736
+ if (this.state._tag === "Closed") {
2737
+ newScope.state = this.state
2738
+ return newScope
2739
+ }
2740
+ function fin(result: Result<any, any>) {
2741
+ return newScope.close(result)
2742
+ }
2743
+ this.state.finalizers.add(fin)
2744
+ newScope.unsafeAddFinalizer((_) => sync(() => this.unsafeRemoveFinalizer(fin)))
2745
+ return newScope
2746
+ })
2747
+ }
2748
+ }
2749
+
2750
+ /**
2751
+ * @since 3.4.0
2752
+ * @experimental
2753
+ * @category resources & finalization
2754
+ */
2755
+ export const scopeMake: Micro<MicroScope.Closeable> = sync(() => new ScopeImpl())
2756
+
2757
+ /**
2758
+ * @since 3.4.0
2759
+ * @experimental
2760
+ * @category resources & finalization
2761
+ */
2762
+ export const scopeUnsafeMake = (): MicroScope.Closeable => new ScopeImpl()
2763
+
2764
+ /**
2765
+ * Access the current `MicroScope`.
2766
+ *
2767
+ * @since 3.4.0
2768
+ * @experimental
2769
+ * @category resources & finalization
2770
+ */
2771
+ export const scope: Micro<MicroScope, never, MicroScope> = service(MicroScope)
2772
+
2773
+ /**
2774
+ * Provide a `MicroScope` to an effect.
2775
+ *
2776
+ * @since 3.4.0
2777
+ * @experimental
2778
+ * @category resources & finalization
2779
+ */
2780
+ export const provideScope: {
2781
+ (scope: MicroScope): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, Exclude<R, MicroScope>>
2782
+ <A, E, R>(self: Micro<A, E, R>, scope: MicroScope): Micro<A, E, Exclude<R, MicroScope>>
2783
+ } = dual(
2784
+ 2,
2785
+ <A, E, R>(self: Micro<A, E, R>, scope: MicroScope): Micro<A, E, Exclude<R, MicroScope>> =>
2786
+ provideService(self, MicroScope, scope)
2787
+ )
2788
+
2789
+ /**
2790
+ * Provide a `MicroScope` to the given effect, closing it after the effect has
2791
+ * finished executing.
2792
+ *
2793
+ * @since 3.4.0
2794
+ * @experimental
2795
+ * @category resources & finalization
2796
+ */
2797
+ export const scoped = <A, E, R>(self: Micro<A, E, R>): Micro<A, E, Exclude<R, MicroScope>> =>
2798
+ suspend(function() {
2799
+ const scope = new ScopeImpl()
2800
+ return onResult(provideService(self, MicroScope, scope), (result) => scope.close(result))
2801
+ })
2802
+
2803
+ /**
2804
+ * Create a resource with a cleanup `Micro` effect, ensuring the cleanup is
2805
+ * executed when the `MicroScope` is closed.
2806
+ *
2807
+ * @since 3.4.0
2808
+ * @experimental
2809
+ * @category resources & finalization
2810
+ */
2811
+ export const acquireRelease = <A, E, R>(
2812
+ acquire: Micro<A, E, R>,
2813
+ release: (a: A, result: Result<unknown, unknown>) => Micro<void>
2814
+ ): Micro<A, E, R | MicroScope> =>
2815
+ uninterruptible(flatMap(
2816
+ scope,
2817
+ (scope) => tap(acquire, (a) => scope.addFinalizer((result) => release(a, result)))
2818
+ ))
2819
+
2820
+ /**
2821
+ * Add a finalizer to the current `MicroScope`.
2822
+ *
2823
+ * @since 3.4.0
2824
+ * @experimental
2825
+ * @category resources & finalization
2826
+ */
2827
+ export const addFinalizer = (
2828
+ finalizer: (result: Result<unknown, unknown>) => Micro<void>
2829
+ ): Micro<void, never, MicroScope> => flatMap(scope, (scope) => scope.addFinalizer(finalizer))
2830
+
2831
+ /**
2832
+ * When the `Micro` effect is completed, run the given finalizer effect with the
2833
+ * `Result` of the executed effect.
2834
+ *
2835
+ * @since 3.4.0
2836
+ * @experimental
2837
+ * @category resources & finalization
2838
+ */
2839
+ export const onResult: {
2840
+ <A, E, XE, XR>(
2841
+ f: (result: Result<A, E>) => Micro<void, XE, XR>
2842
+ ): <R>(self: Micro<A, E, R>) => Micro<A, E | XE, R | XR>
2843
+ <A, E, R, XE, XR>(self: Micro<A, E, R>, f: (result: Result<A, E>) => Micro<void, XE, XR>): Micro<A, E | XE, R | XR>
2844
+ } = dual(
2845
+ 2,
2846
+ <A, E, R, XE, XR>(self: Micro<A, E, R>, f: (result: Result<A, E>) => Micro<void, XE, XR>): Micro<A, E | XE, R | XR> =>
2847
+ onResultIf(self, constTrue, f)
2848
+ )
2849
+
2850
+ /**
2851
+ * When the `Micro` effect is completed, run the given finalizer effect if it
2852
+ * matches the specified predicate.
2853
+ *
2854
+ * @since 3.4.0
2855
+ * @experimental
2856
+ * @category resources & finalization
2857
+ */
2858
+ export const onResultIf: {
2859
+ <A, E, XE, XR, B extends Result<A, E>>(
2860
+ refinement: Refinement<Result<A, E>, B>,
2861
+ f: (result: B) => Micro<void, XE, XR>
2862
+ ): <R>(self: Micro<A, E, R>) => Micro<A, E | XE, R | XR>
2863
+ <A, E, XE, XR>(
2864
+ predicate: Predicate<Result<NoInfer<A>, NoInfer<E>>>,
2865
+ f: (result: Result<NoInfer<A>, NoInfer<E>>) => Micro<void, XE, XR>
2866
+ ): <R>(self: Micro<A, E, R>) => Micro<A, E | XE, R | XR>
2867
+ <A, E, R, XE, XR, B extends Result<A, E>>(
2868
+ self: Micro<A, E, R>,
2869
+ refinement: Refinement<Result<A, E>, B>,
2870
+ f: (result: B) => Micro<void, XE, XR>
2871
+ ): Micro<A, E | XE, R | XR>
2872
+ <A, E, R, XE, XR>(
2873
+ self: Micro<A, E, R>,
2874
+ predicate: Predicate<Result<NoInfer<A>, NoInfer<E>>>,
2875
+ f: (result: Result<NoInfer<A>, NoInfer<E>>) => Micro<void, XE, XR>
2876
+ ): Micro<A, E | XE, R | XR>
2877
+ } = dual(
2878
+ 3,
2879
+ <A, E, R, XE, XR, B extends Result<A, E>>(
2880
+ self: Micro<A, E, R>,
2881
+ refinement: Refinement<Result<A, E>, B>,
2882
+ f: (result: B) => Micro<void, XE, XR>
2883
+ ): Micro<A, E | XE, R | XR> =>
2884
+ uninterruptibleMask((restore) =>
2885
+ make(function(env, onResult) {
2886
+ restore(self)[runSymbol](env, function(result) {
2887
+ if (!refinement(result)) {
2888
+ return onResult(result)
2889
+ }
2890
+ f(result)[runSymbol](env, function(finalizerResult) {
2891
+ if (finalizerResult._tag === "Left") {
2892
+ return onResult(finalizerResult as any)
2893
+ }
2894
+ onResult(result)
2895
+ })
2896
+ })
2897
+ })
2898
+ )
2899
+ )
2900
+
2901
+ /**
2902
+ * Regardless of the result of the this `Micro` effect, run the finalizer effect.
2903
+ *
2904
+ * @since 3.4.0
2905
+ * @experimental
2906
+ * @category resources & finalization
2907
+ */
2908
+ export const ensuring: {
2909
+ <XE, XR>(
2910
+ finalizer: Micro<void, XE, XR>
2911
+ ): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E | XE, R | XR>
2912
+ <A, E, R, XE, XR>(self: Micro<A, E, R>, finalizer: Micro<void, XE, XR>): Micro<A, E | XE, R | XR>
2913
+ } = dual(
2914
+ 2,
2915
+ <A, E, R, XE, XR>(self: Micro<A, E, R>, finalizer: Micro<void, XE, XR>): Micro<A, E | XE, R | XR> =>
2916
+ onResult(self, (_) => finalizer)
2917
+ )
2918
+
2919
+ /**
2920
+ * When the `Micro` effect fails, run the given finalizer effect with the
2921
+ * `Failure` of the executed effect.
2922
+ *
2923
+ * @since 3.4.0
2924
+ * @experimental
2925
+ * @category resources & finalization
2926
+ */
2927
+ export const onFailure: {
2928
+ <A, E, XE, XR>(
2929
+ f: (failure: Failure<NoInfer<E>>) => Micro<void, XE, XR>
2930
+ ): <R>(self: Micro<A, E, R>) => Micro<A, E | XE, R | XR>
2931
+ <A, E, R, XE, XR>(
2932
+ self: Micro<A, E, R>,
2933
+ f: (failure: Failure<NoInfer<E>>) => Micro<void, XE, XR>
2934
+ ): Micro<A, E | XE, R | XR>
2935
+ } = dual(
2936
+ 2,
2937
+ <A, E, R, XE, XR>(
2938
+ self: Micro<A, E, R>,
2939
+ f: (failure: Failure<NoInfer<E>>) => Micro<void, XE, XR>
2940
+ ): Micro<A, E | XE, R | XR> => onResultIf(self, resultIsFailure, (result) => f(result.left))
2941
+ )
2942
+
2943
+ /**
2944
+ * If this `Micro` effect is aborted, run the finalizer effect.
2945
+ *
2946
+ * @since 3.4.0
2947
+ * @experimental
2948
+ * @category resources & finalization
2949
+ */
2950
+ export const onAbort: {
2951
+ <XE, XR>(
2952
+ finalizer: Micro<void, XE, XR>
2953
+ ): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E | XE, R | XR>
2954
+ <A, E, R, XE, XR>(self: Micro<A, E, R>, finalizer: Micro<void, XE, XR>): Micro<A, E | XE, R | XR>
2955
+ } = dual(
2956
+ 2,
2957
+ <A, E, R, XE, XR>(self: Micro<A, E, R>, finalizer: Micro<void, XE, XR>): Micro<A, E | XE, R | XR> =>
2958
+ onResultIf(self, resultIsAborted, (_) => finalizer)
2959
+ )
2960
+
2961
+ /**
2962
+ * Acquire a resource, use it, and then release the resource when the `use`
2963
+ * effect has completed.
2964
+ *
2965
+ * @since 3.4.0
2966
+ * @experimental
2967
+ * @category resources & finalization
2968
+ */
2969
+ export const acquireUseRelease = <Resource, E, R, A, E2, R2, E3, R3>(
2970
+ acquire: Micro<Resource, E, R>,
2971
+ use: (a: Resource) => Micro<A, E2, R2>,
2972
+ release: (a: Resource, result: Result<A, E2>) => Micro<void, E3, R3>
2973
+ ): Micro<A, E | E2 | E3, R | R2 | R3> =>
2974
+ uninterruptibleMask((restore) =>
2975
+ flatMap(
2976
+ acquire,
2977
+ (a) =>
2978
+ flatMap(
2979
+ asResult(restore(use(a))),
2980
+ (result) => andThen(release(a, result), fromResult(result))
2981
+ )
2982
+ )
2983
+ )
2984
+
2985
+ // ----------------------------------------------------------------------------
2986
+ // interruption
2987
+ // ----------------------------------------------------------------------------
2988
+
2989
+ /**
2990
+ * Abort the current `Micro` effect.
2991
+ *
2992
+ * @since 3.4.0
2993
+ * @experimental
2994
+ * @category interruption
2995
+ */
2996
+ export const abort: Micro<never> = make(function(env, onResult) {
2997
+ const controller = envGet(env, currentAbortController)
2998
+ controller.abort()
2999
+ onResult(ResultAborted)
3000
+ })
3001
+
3002
+ /**
3003
+ * Wrap the given `Micro` effect in an uninterruptible region, preventing the
3004
+ * effect from being aborted.
3005
+ *
3006
+ * @since 3.4.0
3007
+ * @experimental
3008
+ * @category interruption
3009
+ */
3010
+ export const uninterruptible = <A, E, R>(self: Micro<A, E, R>): Micro<A, E, R> =>
3011
+ unsafeMakeOptions(function(env, onResult) {
3012
+ const nextEnv = envMutate(env, function(env) {
3013
+ env[currentInterruptible.key] = false
3014
+ env[currentAbortSignal.key] = new AbortController().signal
3015
+ return env
3016
+ })
3017
+ self[runSymbol](nextEnv, onResult)
3018
+ }, false)
3019
+
3020
+ /**
3021
+ * Wrap the given `Micro` effect in an uninterruptible region, preventing the
3022
+ * effect from being aborted.
3023
+ *
3024
+ * You can use the `restore` function to restore a `Micro` effect to the
3025
+ * interruptibility state before the `uninterruptibleMask` was applied.
3026
+ *
3027
+ * @since 3.4.0
3028
+ * @experimental
3029
+ * @category interruption
3030
+ * @example
3031
+ * import * as Micro from "effect/Micro"
3032
+ *
3033
+ * Micro.uninterruptibleMask((restore) =>
3034
+ * Micro.sleep(1000).pipe( // uninterruptible
3035
+ * Micro.andThen(restore(Micro.sleep(1000))) // interruptible
3036
+ * )
3037
+ * )
3038
+ */
3039
+ export const uninterruptibleMask = <A, E, R>(
3040
+ f: (restore: <A, E, R>(effect: Micro<A, E, R>) => Micro<A, E, R>) => Micro<A, E, R>
3041
+ ): Micro<A, E, R> =>
3042
+ unsafeMakeOptions((env, onResult) => {
3043
+ const isInterruptible = envGet(env, currentInterruptible)
3044
+ const effect = isInterruptible ? f(interruptible) : f(identity)
3045
+ const nextEnv = isInterruptible ?
3046
+ envMutate(env, function(env) {
3047
+ env[currentInterruptible.key] = false
3048
+ env[currentAbortSignal.key] = new AbortController().signal
3049
+ return env
3050
+ }) :
3051
+ env
3052
+ effect[runSymbol](nextEnv, onResult)
3053
+ }, false)
3054
+
3055
+ /**
3056
+ * Wrap the given `Micro` effect in an interruptible region, allowing the effect
3057
+ * to be aborted.
3058
+ *
3059
+ * @since 3.4.0
3060
+ * @experimental
3061
+ * @category interruption
3062
+ */
3063
+ export const interruptible = <A, E, R>(self: Micro<A, E, R>): Micro<A, E, R> =>
3064
+ make((env, onResult) => {
3065
+ const isInterruptible = envGet(env, currentInterruptible)
3066
+ let newEnv = env
3067
+ if (!isInterruptible) {
3068
+ const controller = envGet(env, currentAbortController)
3069
+ newEnv = envMutate(env, function(env) {
3070
+ env[currentInterruptible.key] = true
3071
+ env[currentAbortSignal.key] = controller.signal
3072
+ return env
3073
+ })
3074
+ }
3075
+ self[runSymbol](newEnv, onResult)
3076
+ })
3077
+
3078
+ // ========================================================================
3079
+ // collecting & elements
3080
+ // ========================================================================
3081
+
3082
+ /**
3083
+ * @since 3.4.0
3084
+ * @experimental
3085
+ */
3086
+ export declare namespace All {
3087
+ /**
3088
+ * @since 3.4.0
3089
+ * @experimental
3090
+ */
3091
+ export type MicroAny = Micro<any, any, any>
3092
+
3093
+ /**
3094
+ * @since 3.4.0
3095
+ * @experimental
3096
+ */
3097
+ export type ReturnIterable<T extends Iterable<MicroAny>, Discard extends boolean> = [T] extends
3098
+ [Iterable<Micro<infer A, infer E, infer R>>] ? Micro<
3099
+ Discard extends true ? void : Array<A>,
3100
+ E,
3101
+ R
3102
+ >
3103
+ : never
3104
+
3105
+ /**
3106
+ * @since 3.4.0
3107
+ * @experimental
3108
+ */
3109
+ export type ReturnTuple<T extends ReadonlyArray<unknown>, Discard extends boolean> = Micro<
3110
+ Discard extends true ? void
3111
+ : T[number] extends never ? []
3112
+ : { -readonly [K in keyof T]: T[K] extends Micro<infer _A, infer _E, infer _R> ? _A : never },
3113
+ T[number] extends never ? never
3114
+ : T[number] extends Micro<infer _A, infer _E, infer _R> ? _E
3115
+ : never,
3116
+ T[number] extends never ? never
3117
+ : T[number] extends Micro<infer _A, infer _E, infer _R> ? _R
3118
+ : never
3119
+ > extends infer X ? X : never
3120
+
3121
+ /**
3122
+ * @since 3.4.0
3123
+ * @experimental
3124
+ */
3125
+ export type ReturnObject<T, Discard extends boolean> = [T] extends [{ [K: string]: MicroAny }] ? Micro<
3126
+ Discard extends true ? void :
3127
+ { -readonly [K in keyof T]: [T[K]] extends [Micro<infer _A, infer _E, infer _R>] ? _A : never },
3128
+ keyof T extends never ? never
3129
+ : T[keyof T] extends Micro<infer _A, infer _E, infer _R> ? _E
3130
+ : never,
3131
+ keyof T extends never ? never
3132
+ : T[keyof T] extends Micro<infer _A, infer _E, infer _R> ? _R
3133
+ : never
3134
+ >
3135
+ : never
3136
+
3137
+ /**
3138
+ * @since 3.4.0
3139
+ * @experimental
3140
+ */
3141
+ export type IsDiscard<A> = [Extract<A, { readonly discard: true }>] extends [never] ? false : true
3142
+
3143
+ /**
3144
+ * @since 3.4.0
3145
+ * @experimental
3146
+ */
3147
+ export type Return<
3148
+ Arg extends Iterable<MicroAny> | Record<string, MicroAny>,
3149
+ O extends {
3150
+ readonly concurrency?: Concurrency | undefined
3151
+ readonly discard?: boolean | undefined
3152
+ }
3153
+ > = [Arg] extends [ReadonlyArray<MicroAny>] ? ReturnTuple<Arg, IsDiscard<O>>
3154
+ : [Arg] extends [Iterable<MicroAny>] ? ReturnIterable<Arg, IsDiscard<O>>
3155
+ : [Arg] extends [Record<string, MicroAny>] ? ReturnObject<Arg, IsDiscard<O>>
3156
+ : never
3157
+ }
3158
+
3159
+ /**
3160
+ * Runs all the provided effects in sequence respecting the structure provided in input.
3161
+ *
3162
+ * Supports multiple arguments, a single argument tuple / array or record / struct.
3163
+ *
3164
+ * @since 3.4.0
3165
+ * @experimental
3166
+ * @category collecting & elements
3167
+ */
3168
+ export const all = <
3169
+ const Arg extends Iterable<Micro<any, any, any>> | Record<string, Micro<any, any, any>>,
3170
+ O extends {
3171
+ readonly concurrency?: Concurrency | undefined
3172
+ readonly discard?: boolean | undefined
3173
+ }
3174
+ >(arg: Arg, options?: O): All.Return<Arg, O> => {
3175
+ if (Array.isArray(arg) || isIterable(arg)) {
3176
+ return (forEach as any)(arg, identity, options)
3177
+ } else if (options?.discard) {
3178
+ return (forEach as any)(Object.values(arg), identity, options)
3179
+ }
3180
+ return suspend(() => {
3181
+ const out: Record<string, unknown> = {}
3182
+ return as(
3183
+ forEach(Object.entries(arg), ([key, effect]) =>
3184
+ map(effect, (value) => {
3185
+ out[key] = value
3186
+ }), {
3187
+ discard: true,
3188
+ concurrency: options?.concurrency
3189
+ }),
3190
+ out
3191
+ )
3192
+ }) as any
3193
+ }
3194
+
3195
+ /**
3196
+ * For each element of the provided iterable, run the effect and collect the results.
3197
+ *
3198
+ * If the `discard` option is set to `true`, the results will be discarded and
3199
+ * the effect will return `void`.
3200
+ *
3201
+ * The `concurrency` option can be set to control how many effects are run in
3202
+ * parallel. By default, the effects are run sequentially.
3203
+ *
3204
+ * @since 3.4.0
3205
+ * @experimental
3206
+ * @category collecting & elements
3207
+ */
3208
+ export const forEach: {
3209
+ <A, B, E, R>(iterable: Iterable<A>, f: (a: A, index: number) => Micro<B, E, R>, options?: {
3210
+ readonly concurrency?: Concurrency | undefined
3211
+ readonly discard?: false | undefined
3212
+ }): Micro<Array<B>, E, R>
3213
+ <A, B, E, R>(iterable: Iterable<A>, f: (a: A, index: number) => Micro<B, E, R>, options: {
3214
+ readonly concurrency?: Concurrency | undefined
3215
+ readonly discard: true
3216
+ }): Micro<void, E, R>
3217
+ } = <
3218
+ A,
3219
+ B,
3220
+ E,
3221
+ R
3222
+ >(iterable: Iterable<A>, f: (a: A, index: number) => Micro<B, E, R>, options?: {
3223
+ readonly concurrency?: Concurrency | undefined
3224
+ readonly discard?: boolean | undefined
3225
+ }): Micro<any, E, R> =>
3226
+ make(function(env, onResult) {
3227
+ const concurrencyOption = options?.concurrency === "inherit"
3228
+ ? envGet(env, currentConcurrency)
3229
+ : options?.concurrency ?? 1
3230
+ const concurrency = concurrencyOption === "unbounded"
3231
+ ? Number.POSITIVE_INFINITY
3232
+ : Math.max(1, concurrencyOption)
3233
+
3234
+ // abort
3235
+ const [envWithSignal, onAbort] = forkSignal(env)
3236
+
3237
+ // iterate
3238
+ let failure: Result<any, any> | undefined = undefined
3239
+ const items = Array.from(iterable)
3240
+ let length = items.length
3241
+ const out: Array<B> | undefined = options?.discard ? undefined : new Array(length)
3242
+ let index = 0
3243
+ let inProgress = 0
3244
+ let doneCount = 0
3245
+ let pumping = false
3246
+ function pump() {
3247
+ pumping = true
3248
+ while (inProgress < concurrency && index < length) {
3249
+ const currentIndex = index
3250
+ const item = items[currentIndex]
3251
+ index++
3252
+ inProgress++
3253
+ try {
3254
+ f(item, currentIndex)[runSymbol](envWithSignal, function(result) {
3255
+ if (result._tag === "Left") {
3256
+ if (failure === undefined) {
3257
+ failure = result
3258
+ length = index
3259
+ onAbort()
3260
+ }
3261
+ } else if (out !== undefined) {
3262
+ out[currentIndex] = result.right
3263
+ }
3264
+ doneCount++
3265
+ inProgress--
3266
+ if (doneCount === length) {
3267
+ onResult(failure ?? Either.right(out))
3268
+ } else if (!pumping && inProgress < concurrency) {
3269
+ pump()
3270
+ }
3271
+ })
3272
+ } catch (err) {
3273
+ failure = ResultFailUnexpected(err)
3274
+ length = index
3275
+ onAbort()
3276
+ }
3277
+ }
3278
+ pumping = false
3279
+ }
3280
+ pump()
3281
+ })
3282
+
3283
+ /**
3284
+ * Effectfully filter the elements of the provided iterable.
3285
+ *
3286
+ * Use the `concurrency` option to control how many elements are processed in parallel.
3287
+ *
3288
+ * @since 3.4.0
3289
+ * @experimental
3290
+ * @category collecting & elements
3291
+ */
3292
+ export const filter = <A, E, R>(iterable: Iterable<A>, f: (a: NoInfer<A>) => Micro<boolean, E, R>, options?: {
3293
+ readonly concurrency?: Concurrency | undefined
3294
+ readonly negate?: boolean | undefined
3295
+ }): Micro<Array<A>, E, R> =>
3296
+ filterMap(iterable, (a) =>
3297
+ map(f(a), (pass) => {
3298
+ pass = options?.negate ? !pass : pass
3299
+ return pass ? Option.some(a) : Option.none()
3300
+ }))
3301
+
3302
+ /**
3303
+ * Effectfully filter the elements of the provided iterable.
3304
+ *
3305
+ * Use the `concurrency` option to control how many elements are processed in parallel.
3306
+ *
3307
+ * @since 3.4.0
3308
+ * @experimental
3309
+ * @category collecting & elements
3310
+ */
3311
+ export const filterMap = <A, B, E, R>(
3312
+ iterable: Iterable<A>,
3313
+ f: (a: NoInfer<A>) => Micro<Option.Option<B>, E, R>,
3314
+ options?: {
3315
+ readonly concurrency?: Concurrency | undefined
3316
+ }
3317
+ ): Micro<Array<B>, E, R> =>
3318
+ suspend(() => {
3319
+ const out: Array<B> = []
3320
+ return as(
3321
+ forEach(iterable, (a) =>
3322
+ map(f(a), (o) => {
3323
+ if (o._tag === "Some") {
3324
+ out.push(o.value)
3325
+ }
3326
+ }), {
3327
+ discard: true,
3328
+ concurrency: options?.concurrency
3329
+ }),
3330
+ out
3331
+ )
3332
+ })
3333
+
3334
+ // ----------------------------------------------------------------------------
3335
+ // do notation
3336
+ // ----------------------------------------------------------------------------
3337
+
3338
+ /**
3339
+ * Start a do notation block.
3340
+ *
3341
+ * @since 3.4.0
3342
+ * @experimental
3343
+ * @category do notation
3344
+ */
3345
+ export const Do: Micro<{}> = succeed({})
3346
+
3347
+ /**
3348
+ * Bind the success value of this `Micro` effect to the provided name.
3349
+ *
3350
+ * @since 3.4.0
3351
+ * @experimental
3352
+ * @category do notation
3353
+ */
3354
+ export const bindTo: {
3355
+ <N extends string>(name: N): <A, E, R>(self: Micro<A, E, R>) => Micro<{ [K in N]: A }, E, R>
3356
+ <A, E, R, N extends string>(self: Micro<A, E, R>, name: N): Micro<{ [K in N]: A }, E, R>
3357
+ } = dual(2, <A, E, R, N extends string>(self: Micro<A, E, R>, name: N): Micro<{ [K in N]: A }, E, R> =>
3358
+ map(
3359
+ self,
3360
+ (f) => ({ [name]: f } as any)
3361
+ ))
3362
+
3363
+ /**
3364
+ * Bind the success value of this `Micro` effect to the provided name.
3365
+ *
3366
+ * @since 3.4.0
3367
+ * @experimental
3368
+ * @category do notation
3369
+ */
3370
+ export const bind: {
3371
+ <N extends string, A extends Record<string, any>, B, E2, R2>(
3372
+ name: N,
3373
+ f: (a: A) => Micro<B, E2, R2>
3374
+ ): <E, R>(self: Micro<A, E, R>) => Micro<Simplify<Omit<A, N> & { [K in N]: B }>, E | E2, R | R2>
3375
+ <A extends Record<string, any>, E, R, B, E2, R2, N extends string>(
3376
+ self: Micro<A, E, R>,
3377
+ name: N,
3378
+ f: (a: A) => Micro<B, E2, R2>
3379
+ ): Micro<Simplify<Omit<A, N> & { [K in N]: B }>, E | E2, R | R2>
3380
+ } = dual(3, <A extends Record<string, any>, E, R, B, E2, R2, N extends string>(
3381
+ self: Micro<A, E, R>,
3382
+ name: N,
3383
+ f: (a: A) => Micro<B, E2, R2>
3384
+ ): Micro<Simplify<Omit<A, N> & { [K in N]: B }>, E | E2, R | R2> =>
3385
+ flatMap(
3386
+ self,
3387
+ (a) => map(f(a), (b) => ({ ...a, [name]: b } as any))
3388
+ ))
3389
+
3390
+ const let_: {
3391
+ <N extends string, A extends Record<string, any>, B>(
3392
+ name: N,
3393
+ f: (a: A) => B
3394
+ ): <E, R>(self: Micro<A, E, R>) => Micro<Simplify<Omit<A, N> & { [K in N]: B }>, E, R>
3395
+ <A extends Record<string, any>, E, R, B, N extends string>(
3396
+ self: Micro<A, E, R>,
3397
+ name: N,
3398
+ f: (a: A) => B
3399
+ ): Micro<Simplify<Omit<A, N> & { [K in N]: B }>, E, R>
3400
+ } = dual(3, <A extends Record<string, any>, E, R, B, N extends string>(
3401
+ self: Micro<A, E, R>,
3402
+ name: N,
3403
+ f: (a: A) => B
3404
+ ): Micro<Simplify<Omit<A, N> & { [K in N]: B }>, E, R> =>
3405
+ map(
3406
+ self,
3407
+ (a) => ({ ...a, [name]: f(a) } as any)
3408
+ ))
3409
+ export {
3410
+ /**
3411
+ * Bind the result of a synchronous computation to the given name.
3412
+ *
3413
+ * @since 3.4.0
3414
+ * @experimental
3415
+ * @category do notation
3416
+ */
3417
+ let_ as let
3418
+ }
3419
+
3420
+ // ----------------------------------------------------------------------------
3421
+ // handle & forking
3422
+ // ----------------------------------------------------------------------------
3423
+
3424
+ /**
3425
+ * @since 3.4.0
3426
+ * @experimental
3427
+ * @category handle & forking
3428
+ */
3429
+ export const HandleTypeId: unique symbol = Symbol.for("effect/Micro/Handle")
3430
+
3431
+ /**
3432
+ * @since 3.4.0
3433
+ * @experimental
3434
+ * @category handle & forking
3435
+ */
3436
+ export type HandleTypeId = typeof HandleTypeId
3437
+
3438
+ /**
3439
+ * @since 3.4.0
3440
+ * @experimental
3441
+ * @category handle & forking
3442
+ */
3443
+ export interface Handle<A, E = never> {
3444
+ readonly [HandleTypeId]: HandleTypeId
3445
+ readonly await: Micro<Result<A, E>>
3446
+ readonly join: Micro<A, E>
3447
+ readonly abort: Micro<Result<A, E>>
3448
+ readonly unsafeAbort: () => void
3449
+ readonly addObserver: (observer: (result: Result<A, E>) => void) => void
3450
+ readonly removeObserver: (observer: (result: Result<A, E>) => void) => void
3451
+ readonly unsafePoll: () => Result<A, E> | null
3452
+ }
3453
+
3454
+ /**
3455
+ * @since 3.4.0
3456
+ * @experimental
3457
+ * @category handle & forking
3458
+ */
3459
+ export const isHandle = (u: unknown): u is Handle<unknown, unknown> =>
3460
+ typeof u === "object" && u !== null && HandleTypeId in u
3461
+
3462
+ class HandleImpl<A, E> implements Handle<A, E> {
3463
+ readonly [HandleTypeId]: HandleTypeId
3464
+
3465
+ readonly observers: Set<(result: Result<A, E>) => void> = new Set()
3466
+ private _result: Result<A, E> | undefined = undefined
3467
+ _controller: AbortController
3468
+ readonly isRoot: boolean
3469
+
3470
+ constructor(readonly parentSignal: AbortSignal, controller?: AbortController) {
3471
+ this[HandleTypeId] = HandleTypeId
3472
+ this.isRoot = controller !== undefined
3473
+ this._controller = controller ?? new AbortController()
3474
+ if (!this.isRoot) {
3475
+ parentSignal.addEventListener("abort", this.unsafeAbort)
3476
+ }
3477
+ }
3478
+
3479
+ unsafePoll(): Result<A, E> | null {
3480
+ return this._result ?? null
3481
+ }
3482
+
3483
+ unsafeAbort = () => {
3484
+ this._controller.abort()
3485
+ }
3486
+
3487
+ emit(result: Result<A, E>): void {
3488
+ if (this._result) {
3489
+ return
3490
+ }
3491
+ this._result = result
3492
+ if (!this.isRoot) {
3493
+ this.parentSignal.removeEventListener("abort", this.unsafeAbort)
3494
+ }
3495
+ this.observers.forEach((observer) => observer(result))
3496
+ this.observers.clear()
3497
+ }
3498
+
3499
+ addObserver(observer: (result: Result<A, E>) => void): void {
3500
+ if (this._result) {
3501
+ return observer(this._result)
3502
+ }
3503
+ this.observers.add(observer)
3504
+ }
3505
+
3506
+ removeObserver(observer: (result: Result<A, E>) => void): void {
3507
+ this.observers.delete(observer)
3508
+ }
3509
+
3510
+ get await(): Micro<Result<A, E>> {
3511
+ return suspend(() => {
3512
+ if (this._result) {
3513
+ return succeed(this._result)
3514
+ }
3515
+ return async((resume) => {
3516
+ function observer(result: Result<A, E>) {
3517
+ resume(succeed(result))
3518
+ }
3519
+ this.addObserver(observer)
3520
+ return sync(() => {
3521
+ this.removeObserver(observer)
3522
+ })
3523
+ })
3524
+ })
3525
+ }
3526
+
3527
+ get join(): Micro<A, E> {
3528
+ return flatMap(this.await, fromResult)
3529
+ }
3530
+
3531
+ get abort(): Micro<Result<A, E>> {
3532
+ return suspend(() => {
3533
+ this.unsafeAbort()
3534
+ return this.await
3535
+ })
3536
+ }
3537
+ }
3538
+
3539
+ /**
3540
+ * Run the `Micro` effect in a new `Handle` that can be awaited, joined, or
3541
+ * aborted.
3542
+ *
3543
+ * When the parent `Micro` finishes, this `Micro` will be aborted.
3544
+ *
3545
+ * @since 3.4.0
3546
+ * @experimental
3547
+ * @category handle & forking
3548
+ */
3549
+ export const fork = <A, E, R>(self: Micro<A, E, R>): Micro<Handle<A, E>, never, R> =>
3550
+ make(function(env, onResult) {
3551
+ const signal = envGet(env, currentAbortSignal)
3552
+ const handle = new HandleImpl<A, E>(signal)
3553
+ const nextEnv = envMutate(env, (map) => {
3554
+ map[currentAbortController.key] = handle._controller
3555
+ map[currentAbortSignal.key] = handle._controller.signal
3556
+ return map
3557
+ })
3558
+ yieldAdd(() => {
3559
+ self[runSymbol](nextEnv, (result) => {
3560
+ handle.emit(result)
3561
+ })
3562
+ })
3563
+ onResult(Either.right(handle))
3564
+ })
3565
+
3566
+ /**
3567
+ * Run the `Micro` effect in a new `Handle` that can be awaited, joined, or
3568
+ * aborted.
3569
+ *
3570
+ * It will not be aborted when the parent `Micro` finishes.
3571
+ *
3572
+ * @since 3.4.0
3573
+ * @experimental
3574
+ * @category handle & forking
3575
+ */
3576
+ export const forkDaemon = <A, E, R>(self: Micro<A, E, R>): Micro<Handle<A, E>, never, R> =>
3577
+ make(function(env, onResult) {
3578
+ const controller = new AbortController()
3579
+ const handle = new HandleImpl<A, E>(controller.signal, controller)
3580
+ const nextEnv = envMutate(env, (map) => {
3581
+ map[currentAbortController.key] = controller
3582
+ map[currentAbortSignal.key] = controller.signal
3583
+ return map
3584
+ })
3585
+ yieldAdd(() => {
3586
+ self[runSymbol](nextEnv, (result) => {
3587
+ handle.emit(result)
3588
+ })
3589
+ })
3590
+ onResult(Either.right(handle))
3591
+ })
3592
+
3593
+ /**
3594
+ * Run the `Micro` effect in a new `Handle` that can be awaited, joined, or
3595
+ * aborted.
3596
+ *
3597
+ * The lifetime of the handle will be attached to the provided `MicroScope`.
3598
+ *
3599
+ * @since 3.4.0
3600
+ * @experimental
3601
+ * @category handle & forking
3602
+ */
3603
+ export const forkIn: {
3604
+ (scope: MicroScope): <A, E, R>(self: Micro<A, E, R>) => Micro<Handle<A, E>, never, R>
3605
+ <A, E, R>(self: Micro<A, E, R>, scope: MicroScope): Micro<Handle<A, E>, never, R>
3606
+ } = dual(
3607
+ 2,
3608
+ <A, E, R>(self: Micro<A, E, R>, scope: MicroScope): Micro<Handle<A, E>, never, R> =>
3609
+ uninterruptibleMask((restore) =>
3610
+ flatMap(scope.fork, (scope) =>
3611
+ tap(
3612
+ restore(forkDaemon(onResult(self, (result) => scope.close(result)))),
3613
+ (fiber) => scope.addFinalizer((_) => asVoid(fiber.abort))
3614
+ ))
3615
+ )
3616
+ )
3617
+
3618
+ /**
3619
+ * Run the `Micro` effect in a new `Handle` that can be awaited, joined, or
3620
+ * aborted.
3621
+ *
3622
+ * The lifetime of the handle will be attached to the current `MicroScope`.
3623
+ *
3624
+ * @since 3.4.0
3625
+ * @experimental
3626
+ * @category handle & forking
3627
+ */
3628
+ export const forkScoped = <A, E, R>(self: Micro<A, E, R>): Micro<Handle<A, E>, never, R | MicroScope> =>
3629
+ flatMap(scope, (scope) => forkIn(self, scope))
3630
+
3631
+ // ----------------------------------------------------------------------------
3632
+ // execution
3633
+ // ----------------------------------------------------------------------------
3634
+
3635
+ /**
3636
+ * Execute the `Micro` effect and return a `Handle` that can be awaited, joined,
3637
+ * or aborted.
3638
+ *
3639
+ * You can listen for the result by adding an observer using the handle's
3640
+ * `addObserver` method.
3641
+ *
3642
+ * @since 3.4.0
3643
+ * @experimental
3644
+ * @category execution
3645
+ * @example
3646
+ * import * as Micro from "effect/Micro"
3647
+ *
3648
+ * const handle = Micro.succeed(42).pipe(
3649
+ * Micro.delay(1000),
3650
+ * Micro.runFork
3651
+ * )
3652
+ *
3653
+ * handle.addObserver((result) => {
3654
+ * console.log(result)
3655
+ * })
3656
+ */
3657
+ export const runFork = <A, E>(
3658
+ effect: Micro<A, E>,
3659
+ options?: {
3660
+ readonly signal?: AbortSignal | undefined
3661
+ } | undefined
3662
+ ): Handle<A, E> => {
3663
+ const controller = new AbortController()
3664
+ const refs = Object.create(null)
3665
+ refs[currentAbortController.key] = controller
3666
+ refs[currentAbortSignal.key] = controller.signal
3667
+ const env = envMake(refs)
3668
+ const handle = new HandleImpl<A, E>(controller.signal, controller)
3669
+ effect[runSymbol](envSet(env, currentAbortSignal, handle._controller.signal), (result) => {
3670
+ handle.emit(result)
3671
+ })
3672
+ if (options?.signal) {
3673
+ if (options.signal.aborted) {
3674
+ handle.unsafeAbort()
3675
+ } else {
3676
+ options.signal.addEventListener("abort", () => handle.unsafeAbort())
3677
+ }
3678
+ }
3679
+ return handle
3680
+ }
3681
+
3682
+ /**
3683
+ * Execute the `Micro` effect and return a `Promise` that resolves with the
3684
+ * `Result` of the computation.
3685
+ *
3686
+ * @since 3.4.0
3687
+ * @experimental
3688
+ * @category execution
3689
+ */
3690
+ export const runPromiseResult = <A, E>(
3691
+ effect: Micro<A, E>,
3692
+ options?: {
3693
+ readonly signal?: AbortSignal | undefined
3694
+ } | undefined
3695
+ ): Promise<Result<A, E>> =>
3696
+ new Promise((resolve, _reject) => {
3697
+ const handle = runFork(effect, options)
3698
+ handle.addObserver(resolve)
3699
+ })
3700
+
3701
+ /**
3702
+ * Execute the `Micro` effect and return a `Promise` that resolves with the
3703
+ * successful value of the computation.
3704
+ *
3705
+ * @since 3.4.0
3706
+ * @experimental
3707
+ * @category execution
3708
+ */
3709
+ export const runPromise = <A, E>(
3710
+ effect: Micro<A, E>,
3711
+ options?: {
3712
+ readonly signal?: AbortSignal | undefined
3713
+ } | undefined
3714
+ ): Promise<A> =>
3715
+ runPromiseResult(effect, options).then((result) => {
3716
+ if (result._tag === "Left") {
3717
+ throw result.left
3718
+ }
3719
+ return result.right
3720
+ })
3721
+
3722
+ /**
3723
+ * Attempt to execute the `Micro` effect synchronously and return the `Result`.
3724
+ *
3725
+ * If any asynchronous effects are encountered, the function will return a
3726
+ * FailureUnexpected containing the `Handle`.
3727
+ *
3728
+ * @since 3.4.0
3729
+ * @experimental
3730
+ * @category execution
3731
+ */
3732
+ export const runSyncResult = <A, E>(effect: Micro<A, E>): Result<A, E> => {
3733
+ const handle = runFork(effect)
3734
+ while (yieldState.tasks.length > 0) {
3735
+ yieldRunTasks()
3736
+ }
3737
+ const result = handle.unsafePoll()
3738
+ if (result === null) {
3739
+ return ResultFailUnexpected(handle)
3740
+ }
3741
+ return result
3742
+ }
3743
+
3744
+ /**
3745
+ * Attempt to execute the `Micro` effect synchronously and return the success
3746
+ * value.
3747
+ *
3748
+ * @since 3.4.0
3749
+ * @experimental
3750
+ * @category execution
3751
+ */
3752
+ export const runSync = <A, E>(effect: Micro<A, E>): A => {
3753
+ const result = runSyncResult(effect)
3754
+ if (result._tag === "Left") {
3755
+ throw result.left
3756
+ }
3757
+ return result.right
3758
+ }
3759
+
3760
+ // ----------------------------------------------------------------------------
3761
+ // Errors
3762
+ // ----------------------------------------------------------------------------
3763
+
3764
+ /**
3765
+ * @since 3.4.0
3766
+ * @experimental
3767
+ * @category errors
3768
+ */
3769
+ export interface YieldableError extends Pipeable, Inspectable, Readonly<Error> {
3770
+ readonly [EffectTypeId]: Effect.VarianceStruct<never, this, never>
3771
+ readonly [StreamTypeId]: Stream.VarianceStruct<never, this, never>
3772
+ readonly [SinkTypeId]: Sink.VarianceStruct<never, unknown, never, this, never>
3773
+ readonly [ChannelTypeId]: Channel.VarianceStruct<never, unknown, this, unknown, never, unknown, never>
3774
+ readonly [TypeId]: Micro.Variance<never, this, never>
3775
+ readonly [runSymbol]: (env: Env<any>, onResult: (result: Result<never, this>) => void) => void
3776
+ [Symbol.iterator](): MicroIterator<Micro<never, this, never>>
3777
+ }
3778
+
3779
+ const YieldableError: new(message?: string) => YieldableError = (function() {
3780
+ class YieldableError extends globalThis.Error {
3781
+ [runSymbol](_env: any, onResult: any) {
3782
+ onResult(ResultFail(this))
3783
+ }
3784
+ toString() {
3785
+ return this.message ? `${this.name}: ${this.message}` : this.name
3786
+ }
3787
+ toJSON() {
3788
+ return { ...this }
3789
+ }
3790
+ [NodeInspectSymbol](): string {
3791
+ const stack = this.stack
3792
+ if (stack) {
3793
+ return `${this.toString()}\n${stack.split("\n").slice(1).join("\n")}`
3794
+ }
3795
+ return this.toString()
3796
+ }
3797
+ }
3798
+ Object.assign(YieldableError.prototype, MicroProto, StructuralPrototype)
3799
+ return YieldableError as any
3800
+ })()
3801
+
3802
+ /**
3803
+ * @since 3.4.0
3804
+ * @experimental
3805
+ * @category errors
3806
+ */
3807
+ export const Error: new<A extends Record<string, any> = {}>(
3808
+ args: Equals<A, {}> extends true ? void
3809
+ : { readonly [P in keyof A]: A[P] }
3810
+ ) => YieldableError & Readonly<A> = (function() {
3811
+ return class extends YieldableError {
3812
+ constructor(args: any) {
3813
+ super()
3814
+ if (args) {
3815
+ Object.assign(this, args)
3816
+ }
3817
+ }
3818
+ } as any
3819
+ })()
3820
+
3821
+ /**
3822
+ * @since 3.4.0
3823
+ * @experimental
3824
+ * @category errors
3825
+ */
3826
+ export const TaggedError = <Tag extends string>(tag: Tag): new<A extends Record<string, any> = {}>(
3827
+ args: Equals<A, {}> extends true ? void
3828
+ : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }
3829
+ ) => YieldableError & { readonly _tag: Tag } & Readonly<A> => {
3830
+ class Base extends Error<{}> {
3831
+ readonly _tag = tag
3832
+ }
3833
+ ;(Base.prototype as any).name = tag
3834
+ return Base as any
3835
+ }