effect 2.4.0 → 2.4.2

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 (103) hide show
  1. package/dist/cjs/Context.js.map +1 -1
  2. package/dist/cjs/Duration.js +9 -1
  3. package/dist/cjs/Duration.js.map +1 -1
  4. package/dist/cjs/Effect.js +83 -5
  5. package/dist/cjs/Effect.js.map +1 -1
  6. package/dist/cjs/Either.js.map +1 -1
  7. package/dist/cjs/FiberMap.js +31 -5
  8. package/dist/cjs/FiberMap.js.map +1 -1
  9. package/dist/cjs/FiberSet.js +31 -5
  10. package/dist/cjs/FiberSet.js.map +1 -1
  11. package/dist/cjs/Logger.js +50 -1
  12. package/dist/cjs/Logger.js.map +1 -1
  13. package/dist/cjs/Option.js.map +1 -1
  14. package/dist/cjs/Predicate.js +40 -3
  15. package/dist/cjs/Predicate.js.map +1 -1
  16. package/dist/cjs/Request.js +4 -4
  17. package/dist/cjs/SortedSet.js +7 -1
  18. package/dist/cjs/SortedSet.js.map +1 -1
  19. package/dist/cjs/Struct.js +7 -6
  20. package/dist/cjs/Struct.js.map +1 -1
  21. package/dist/cjs/internal/core-effect.js.map +1 -1
  22. package/dist/cjs/internal/fiberRuntime.js +26 -1
  23. package/dist/cjs/internal/fiberRuntime.js.map +1 -1
  24. package/dist/cjs/internal/logger.js +64 -2
  25. package/dist/cjs/internal/logger.js.map +1 -1
  26. package/dist/cjs/internal/version.js +1 -1
  27. package/dist/dts/Context.d.ts +10 -11
  28. package/dist/dts/Context.d.ts.map +1 -1
  29. package/dist/dts/Duration.d.ts +1 -1
  30. package/dist/dts/Duration.d.ts.map +1 -1
  31. package/dist/dts/Effect.d.ts +55 -15
  32. package/dist/dts/Effect.d.ts.map +1 -1
  33. package/dist/dts/Either.d.ts +18 -3
  34. package/dist/dts/Either.d.ts.map +1 -1
  35. package/dist/dts/FiberMap.d.ts +22 -2
  36. package/dist/dts/FiberMap.d.ts.map +1 -1
  37. package/dist/dts/FiberSet.d.ts +20 -0
  38. package/dist/dts/FiberSet.d.ts.map +1 -1
  39. package/dist/dts/Logger.d.ts +61 -0
  40. package/dist/dts/Logger.d.ts.map +1 -1
  41. package/dist/dts/Option.d.ts +13 -3
  42. package/dist/dts/Option.d.ts.map +1 -1
  43. package/dist/dts/Predicate.d.ts +37 -2
  44. package/dist/dts/Predicate.d.ts.map +1 -1
  45. package/dist/dts/Request.d.ts +7 -7
  46. package/dist/dts/Request.d.ts.map +1 -1
  47. package/dist/dts/STM.d.ts +1 -1
  48. package/dist/dts/STM.d.ts.map +1 -1
  49. package/dist/dts/SortedSet.d.ts +6 -0
  50. package/dist/dts/SortedSet.d.ts.map +1 -1
  51. package/dist/dts/Struct.d.ts +18 -2
  52. package/dist/dts/Struct.d.ts.map +1 -1
  53. package/dist/dts/Types.d.ts +4 -0
  54. package/dist/dts/Types.d.ts.map +1 -1
  55. package/dist/dts/internal/logger.d.ts +1 -0
  56. package/dist/dts/internal/logger.d.ts.map +1 -1
  57. package/dist/esm/Context.js.map +1 -1
  58. package/dist/esm/Duration.js +9 -1
  59. package/dist/esm/Duration.js.map +1 -1
  60. package/dist/esm/Effect.js +78 -1
  61. package/dist/esm/Effect.js.map +1 -1
  62. package/dist/esm/Either.js.map +1 -1
  63. package/dist/esm/FiberMap.js +29 -4
  64. package/dist/esm/FiberMap.js.map +1 -1
  65. package/dist/esm/FiberSet.js +29 -4
  66. package/dist/esm/FiberSet.js.map +1 -1
  67. package/dist/esm/Logger.js +49 -0
  68. package/dist/esm/Logger.js.map +1 -1
  69. package/dist/esm/Option.js.map +1 -1
  70. package/dist/esm/Predicate.js +37 -2
  71. package/dist/esm/Predicate.js.map +1 -1
  72. package/dist/esm/Request.js +4 -4
  73. package/dist/esm/SortedSet.js +5 -0
  74. package/dist/esm/SortedSet.js.map +1 -1
  75. package/dist/esm/Struct.js +7 -4
  76. package/dist/esm/Struct.js.map +1 -1
  77. package/dist/esm/internal/core-effect.js.map +1 -1
  78. package/dist/esm/internal/fiberRuntime.js +25 -0
  79. package/dist/esm/internal/fiberRuntime.js.map +1 -1
  80. package/dist/esm/internal/logger.js +61 -1
  81. package/dist/esm/internal/logger.js.map +1 -1
  82. package/dist/esm/internal/version.js +1 -1
  83. package/package.json +2 -2
  84. package/src/Context.ts +10 -11
  85. package/src/Duration.ts +17 -1
  86. package/src/Effect.ts +124 -22
  87. package/src/Either.ts +19 -3
  88. package/src/FiberMap.ts +44 -6
  89. package/src/FiberSet.ts +38 -4
  90. package/src/Logger.ts +77 -0
  91. package/src/Option.ts +14 -3
  92. package/src/Predicate.ts +39 -2
  93. package/src/Request.ts +7 -7
  94. package/src/STM.ts +1 -1
  95. package/src/SortedSet.ts +7 -0
  96. package/src/Struct.ts +40 -21
  97. package/src/Types.ts +5 -0
  98. package/src/internal/core-effect.ts +9 -9
  99. package/src/internal/core.ts +5 -5
  100. package/src/internal/fiberRuntime.ts +68 -0
  101. package/src/internal/logger.ts +76 -1
  102. package/src/internal/request.ts +2 -2
  103. package/src/internal/version.ts +1 -1
package/src/Context.ts CHANGED
@@ -27,15 +27,15 @@ export type TagTypeId = typeof TagTypeId
27
27
  * @since 2.0.0
28
28
  * @category models
29
29
  */
30
- export interface Tag<in out Identifier, in out Service> extends Pipeable, Inspectable {
30
+ export interface Tag<in out Id, in out Value> extends Pipeable, Inspectable {
31
31
  readonly _tag: "Tag"
32
32
  readonly _op: "Tag"
33
33
  readonly [TagTypeId]: {
34
- readonly _Service: Types.Invariant<Service>
35
- readonly _Identifier: Types.Invariant<Identifier>
34
+ readonly _Service: Types.Invariant<Value>
35
+ readonly _Identifier: Types.Invariant<Id>
36
36
  }
37
- of(self: Service): Service
38
- context(self: Service): Context<Identifier>
37
+ of(self: Value): Value
38
+ context(self: Value): Context<Id>
39
39
  readonly stack?: string | undefined
40
40
  readonly key: string
41
41
  [Unify.typeSymbol]?: unknown
@@ -48,18 +48,17 @@ export interface Tag<in out Identifier, in out Service> extends Pipeable, Inspec
48
48
  * @category models
49
49
  */
50
50
  export interface TagClassShape<Id, Shape> {
51
- readonly [TagTypeId]: {
52
- readonly Id: Id
53
- readonly Shape: Shape
54
- }
51
+ readonly [TagTypeId]: TagTypeId
52
+ readonly Type: Shape
53
+ readonly Id: Id
55
54
  }
56
55
 
57
56
  /**
58
57
  * @since 2.0.0
59
58
  * @category models
60
59
  */
61
- export interface TagClass<Self, Id, Shape> extends Tag<Self, Shape> {
62
- new(_: never): TagClassShape<Id, Shape>
60
+ export interface TagClass<Self, Id, Type> extends Tag<Self, Type> {
61
+ new(_: never): TagClassShape<Id, Type>
63
62
  }
64
63
 
65
64
  /**
package/src/Duration.ts CHANGED
@@ -46,13 +46,21 @@ export type DurationValue =
46
46
  * @category models
47
47
  */
48
48
  export type Unit =
49
+ | "nano"
49
50
  | "nanos"
51
+ | "micro"
50
52
  | "micros"
53
+ | "milli"
51
54
  | "millis"
55
+ | "second"
52
56
  | "seconds"
57
+ | "minute"
53
58
  | "minutes"
59
+ | "hour"
54
60
  | "hours"
61
+ | "day"
55
62
  | "days"
63
+ | "week"
56
64
  | "weeks"
57
65
 
58
66
  /**
@@ -66,7 +74,7 @@ export type DurationInput =
66
74
  | [seconds: number, nanos: number]
67
75
  | `${number} ${Unit}`
68
76
 
69
- const DURATION_REGEX = /^(-?\d+(?:\.\d+)?)\s+(nanos|micros|millis|seconds|minutes|hours|days|weeks)$/
77
+ const DURATION_REGEX = /^(-?\d+(?:\.\d+)?)\s+(nanos?|micros?|millis?|seconds?|minutes?|hours?|days?|weeks?)$/
70
78
 
71
79
  /**
72
80
  * @since 2.0.0
@@ -89,20 +97,28 @@ export const decode = (input: DurationInput): Duration => {
89
97
  const [_, valueStr, unit] = match
90
98
  const value = Number(valueStr)
91
99
  switch (unit) {
100
+ case "nano":
92
101
  case "nanos":
93
102
  return nanos(BigInt(valueStr))
103
+ case "micro":
94
104
  case "micros":
95
105
  return micros(BigInt(valueStr))
106
+ case "milli":
96
107
  case "millis":
97
108
  return millis(value)
109
+ case "second":
98
110
  case "seconds":
99
111
  return seconds(value)
112
+ case "minute":
100
113
  case "minutes":
101
114
  return minutes(value)
115
+ case "hour":
102
116
  case "hours":
103
117
  return hours(value)
118
+ case "day":
104
119
  case "days":
105
120
  return days(value)
121
+ case "week":
106
122
  case "weeks":
107
123
  return weeks(value)
108
124
  }
package/src/Effect.ts CHANGED
@@ -24,6 +24,7 @@ import type * as HashMap from "./HashMap.js"
24
24
  import type * as HashSet from "./HashSet.js"
25
25
  import type { TypeLambda } from "./HKT.js"
26
26
  import * as _console from "./internal/console.js"
27
+ import { TagProto } from "./internal/context.js"
27
28
  import * as effect from "./internal/core-effect.js"
28
29
  import * as core from "./internal/core.js"
29
30
  import * as defaultServices from "./internal/defaultServices.js"
@@ -42,7 +43,7 @@ import type { Pipeable } from "./Pipeable.js"
42
43
  import type { Predicate, Refinement } from "./Predicate.js"
43
44
  import type * as Random from "./Random.js"
44
45
  import type * as Ref from "./Ref.js"
45
- import type * as Request from "./Request.js"
46
+ import * as Request from "./Request.js"
46
47
  import type { RequestBlock } from "./RequestBlock.js"
47
48
  import type { RequestResolver } from "./RequestResolver.js"
48
49
  import type * as Runtime from "./Runtime.js"
@@ -53,7 +54,7 @@ import * as Scheduler from "./Scheduler.js"
53
54
  import type * as Scope from "./Scope.js"
54
55
  import type * as Supervisor from "./Supervisor.js"
55
56
  import type * as Tracer from "./Tracer.js"
56
- import type { Concurrency, Covariant, MergeRecord, NoInfer } from "./Types.js"
57
+ import type { Concurrency, Covariant, MergeRecord, NoInfer, NotFunction } from "./Types.js"
57
58
  import type * as Unify from "./Unify.js"
58
59
 
59
60
  // -------------------------------------------------------------------------------------
@@ -137,7 +138,7 @@ export interface Blocked<out A, out E> extends Effect<A, E> {
137
138
  * @category models
138
139
  */
139
140
  declare module "./Context.js" {
140
- interface Tag<Identifier, Service> extends Effect<Service, never, Identifier> {}
141
+ interface Tag<Id, Value> extends Effect<Value, never, Id> {}
141
142
  interface TagUnifyIgnore {
142
143
  Effect?: true
143
144
  Either?: true
@@ -3103,11 +3104,10 @@ export const serviceFunctionEffect: <T extends Effect<any, any, any>, Args exten
3103
3104
  export const serviceFunctions: <S, SE, SR>(
3104
3105
  getService: Effect<S, SE, SR>
3105
3106
  ) => {
3106
- [k in { [k in keyof S]: S[k] extends (...args: Array<any>) => Effect<any, any, any> ? k : never }[keyof S]]:
3107
- S[k] extends (...args: infer Args) => Effect<infer A, infer E, infer R> ?
3108
- (...args: Args) => Effect<A, SE | E, SR | R> :
3109
- never
3110
- } = effect.serviceFunctions
3107
+ [k in keyof S as S[k] extends (...args: Array<any>) => Effect<any, any, any> ? k : never]: S[k] extends
3108
+ (...args: infer Args) => Effect<infer A, infer E, infer R> ? (...args: Args) => Effect<A, SE | E, SR | R>
3109
+ : never
3110
+ } = effect.serviceFunctions as any
3111
3111
 
3112
3112
  /**
3113
3113
  * @since 2.0.0
@@ -3124,20 +3124,19 @@ export const serviceConstants: <S, SE, SR>(
3124
3124
  * @since 2.0.0
3125
3125
  * @category context
3126
3126
  */
3127
- export const serviceMembers: <SR, SE, S>(
3127
+ export const serviceMembers: <S, SE, SR>(
3128
3128
  getService: Effect<S, SE, SR>
3129
3129
  ) => {
3130
3130
  functions: {
3131
- [k in { [k in keyof S]: S[k] extends (...args: Array<any>) => Effect<any, any, any> ? k : never }[keyof S]]:
3132
- S[k] extends (...args: infer Args) => Effect<infer A, infer E, infer R> ?
3133
- (...args: Args) => Effect<A, SE | E, SR | R>
3134
- : never
3131
+ [k in keyof S as S[k] extends (...args: Array<any>) => Effect<any, any, any> ? k : never]: S[k] extends
3132
+ (...args: infer Args) => Effect<infer A, infer E, infer R> ? (...args: Args) => Effect<A, SE | E, SR | R>
3133
+ : never
3135
3134
  }
3136
3135
  constants: {
3137
3136
  [k in { [k in keyof S]: k }[keyof S]]: S[k] extends Effect<infer A, infer E, infer R> ? Effect<A, SE | E, SR | R>
3138
3137
  : Effect<S[k], SE, SR>
3139
3138
  }
3140
- } = effect.serviceMembers
3139
+ } = effect.serviceMembers as any
3141
3140
 
3142
3141
  /**
3143
3142
  * @since 2.0.0
@@ -3558,7 +3557,7 @@ export const andThen: {
3558
3557
  : [X] extends [Promise<infer A1>] ? Effect<A1, E | Cause.UnknownException, R>
3559
3558
  : Effect<X, E, R>
3560
3559
  <X>(
3561
- f: X
3560
+ f: NotFunction<X>
3562
3561
  ): <A, E, R>(
3563
3562
  self: Effect<A, E, R>
3564
3563
  ) => [X] extends [Effect<infer A1, infer E1, infer R1>] ? Effect<A1, E | E1, R | R1>
@@ -3572,7 +3571,7 @@ export const andThen: {
3572
3571
  : Effect<X, E, R>
3573
3572
  <A, E, R, X>(
3574
3573
  self: Effect<A, E, R>,
3575
- f: X
3574
+ f: NotFunction<X>
3576
3575
  ): [X] extends [Effect<infer A1, infer E1, infer R1>] ? Effect<A1, E | E1, R | R1>
3577
3576
  : [X] extends [Promise<infer A1>] ? Effect<A1, E | Cause.UnknownException, R>
3578
3577
  : Effect<X, E, R>
@@ -3687,7 +3686,7 @@ export const tap: {
3687
3686
  : [X] extends [Promise<infer _A1>] ? Effect<A, E | Cause.UnknownException, R>
3688
3687
  : Effect<A, E, R>
3689
3688
  <X>(
3690
- f: X
3689
+ f: NotFunction<X>
3691
3690
  ): <A, E, R>(
3692
3691
  self: Effect<A, E, R>
3693
3692
  ) => [X] extends [Effect<infer _A1, infer E1, infer R1>] ? Effect<A, E | E1, R | R1>
@@ -3701,7 +3700,7 @@ export const tap: {
3701
3700
  : Effect<A, E, R>
3702
3701
  <A, E, R, X>(
3703
3702
  self: Effect<A, E, R>,
3704
- f: X
3703
+ f: NotFunction<X>
3705
3704
  ): [X] extends [Effect<infer _A1, infer E1, infer R1>] ? Effect<A, E | E1, R | R1>
3706
3705
  : [X] extends [Promise<infer _A1>] ? Effect<A, E | Cause.UnknownException, R>
3707
3706
  : Effect<A, E, R>
@@ -4775,6 +4774,22 @@ export const zip: {
4775
4774
  } = fiberRuntime.zipOptions
4776
4775
 
4777
4776
  /**
4777
+ * Sequentially run this effect with the specified effect, _discarding_ the result
4778
+ * of the second effect (`that`) in the chain.
4779
+ *
4780
+ * `{ concurrent: true }` can be passed to the options to make it a concurrent execution
4781
+ * of both effects instead of sequential.
4782
+ *
4783
+ * @example
4784
+ *
4785
+ * import { Effect } from 'effect';
4786
+ *
4787
+ * const effect = Effect.succeed("a message").pipe(
4788
+ * Effect.zipLeft(Effect.succeed(42)),
4789
+ * )
4790
+ *
4791
+ * assert.deepStrictEqual(Effect.runSync(effect), "a message");
4792
+ *
4778
4793
  * @since 2.0.0
4779
4794
  * @category zipping
4780
4795
  */
@@ -4795,6 +4810,22 @@ export const zipLeft: {
4795
4810
  } = fiberRuntime.zipLeftOptions
4796
4811
 
4797
4812
  /**
4813
+ * Sequentially run this effect with the specified effect, _returning_ the result
4814
+ * of the second effect (`that`) in the chain.
4815
+ *
4816
+ * `{ concurrent: true }` can be passed to the options to make it a concurrent execution
4817
+ * of both effects instead of sequential.
4818
+ *
4819
+ * @example
4820
+ *
4821
+ * import { Effect } from 'effect';
4822
+ *
4823
+ * const effect = Effect.succeed("a message").pipe(
4824
+ * Effect.zipRight(Effect.succeed(42)),
4825
+ * )
4826
+ *
4827
+ * assert.deepStrictEqual(Effect.runSync(effect), 42);
4828
+ *
4798
4829
  * @since 2.0.0
4799
4830
  * @category zipping
4800
4831
  */
@@ -4882,18 +4913,27 @@ export const step: <A, E, R>(self: Effect<A, E, R>) => Effect<Exit.Exit<A, E> |
4882
4913
  * @category requests & batching
4883
4914
  */
4884
4915
  export const request: {
4916
+ <A extends Request.Request<any, any>, Ds extends RequestResolver<A> | Effect<RequestResolver<A>, any, any>>(
4917
+ dataSource: Ds
4918
+ ): (
4919
+ self: A
4920
+ ) => Effect<
4921
+ Request.Request.Success<A>,
4922
+ Request.Request.Error<A>,
4923
+ [Ds] extends [Effect<any, any, any>] ? Effect.Context<Ds> : never
4924
+ >
4885
4925
  <
4886
- A extends Request.Request<any, any>,
4887
- Ds extends RequestResolver<A> | Effect<RequestResolver<A>, any, any>
4926
+ Ds extends RequestResolver<A> | Effect<RequestResolver<A>, any, any>,
4927
+ A extends Request.Request<any, any>
4888
4928
  >(
4889
- request: A,
4929
+ self: A,
4890
4930
  dataSource: Ds
4891
4931
  ): Effect<
4892
4932
  Request.Request.Success<A>,
4893
4933
  Request.Request.Error<A>,
4894
4934
  [Ds] extends [Effect<any, any, any>] ? Effect.Context<Ds> : never
4895
4935
  >
4896
- } = query.fromRequest as any
4936
+ } = dual((args) => Request.isRequest(args[0]), query.fromRequest)
4897
4937
 
4898
4938
  /**
4899
4939
  * @since 2.0.0
@@ -5198,3 +5238,65 @@ export const fromNullable: <A>(value: A) => Effect<NonNullable<A>, Cause.NoSuchE
5198
5238
  export const optionFromOptional: <A, E, R>(
5199
5239
  self: Effect<A, E, R>
5200
5240
  ) => Effect<Option.Option<A>, Exclude<E, Cause.NoSuchElementException>, R> = effect.optionFromOptional
5241
+
5242
+ /**
5243
+ * @since 2.0.0
5244
+ * @category constructors
5245
+ */
5246
+ export const Tag: <const Id extends string>(id: Id) => <Self, Type>() =>
5247
+ & Context.TagClass<Self, Id, Type>
5248
+ & (Type extends Record<PropertyKey, any> ? {
5249
+ [
5250
+ k in keyof Type as Type[k] extends ((...args: [...infer Args]) => infer Ret) ?
5251
+ ((...args: Readonly<Args>) => Ret) extends Type[k] ? k : never
5252
+ : k
5253
+ ]: Type[k] extends (...args: [...infer Args]) => Effect<infer A, infer E, infer R> ?
5254
+ (...args: Readonly<Args>) => Effect<A, E, Self | R>
5255
+ : Type[k] extends (...args: [...infer Args]) => infer A ? (...args: Readonly<Args>) => Effect<A, never, Self>
5256
+ : Type[k] extends Effect<infer A, infer E, infer R> ? Effect<A, E, Self | R>
5257
+ : Effect<Type[k], never, Self>
5258
+ } :
5259
+ {})
5260
+ & {
5261
+ use: <X>(
5262
+ body: (_: Type) => X
5263
+ ) => X extends Effect<infer A, infer E, infer R> ? Effect<A, E, R | Self> : Effect<X, never, Self>
5264
+ } = (id) => () => {
5265
+ const limit = Error.stackTraceLimit
5266
+ Error.stackTraceLimit = 2
5267
+ const creationError = new Error()
5268
+ Error.stackTraceLimit = limit
5269
+ function TagClass() {}
5270
+ Object.setPrototypeOf(TagClass, TagProto)
5271
+ TagClass.key = id
5272
+ Object.defineProperty(TagClass, "stack", {
5273
+ get() {
5274
+ return creationError.stack
5275
+ }
5276
+ })
5277
+ const cache = new Map()
5278
+ const done = new Proxy(TagClass, {
5279
+ get(_target: any, prop: any, _receiver) {
5280
+ if (prop === "use") {
5281
+ // @ts-expect-error
5282
+ return (body) => core.andThen(TagClass, body)
5283
+ }
5284
+ if (prop in TagClass) {
5285
+ // @ts-expect-error
5286
+ return TagClass[prop]
5287
+ }
5288
+ if (cache.has(prop)) {
5289
+ return cache.get(prop)
5290
+ }
5291
+ // @ts-expect-error
5292
+ const fn = (...args: Array<any>) => core.andThen(TagClass, (s: any) => s[prop](...args))
5293
+ // @ts-expect-error
5294
+ const cn = core.andThen(TagClass, (s) => s[prop])
5295
+ Object.assign(fn, cn)
5296
+ Object.setPrototypeOf(fn, Object.getPrototypeOf(cn))
5297
+ cache.set(prop, fn)
5298
+ return fn
5299
+ }
5300
+ })
5301
+ return done
5302
+ }
package/src/Either.ts CHANGED
@@ -12,7 +12,7 @@ import type { Option } from "./Option.js"
12
12
  import type { Pipeable } from "./Pipeable.js"
13
13
  import type { Predicate, Refinement } from "./Predicate.js"
14
14
  import { isFunction } from "./Predicate.js"
15
- import type { Covariant, MergeRecord, NoInfer } from "./Types.js"
15
+ import type { Covariant, MergeRecord, NoInfer, NotFunction } from "./Types.js"
16
16
  import type * as Unify from "./Unify.js"
17
17
  import * as Gen from "./Utils.js"
18
18
 
@@ -90,6 +90,22 @@ export interface EitherTypeLambda extends TypeLambda {
90
90
  readonly type: Either<this["Target"], this["Out1"]>
91
91
  }
92
92
 
93
+ /**
94
+ * @since 2.0.0
95
+ */
96
+ export declare namespace Either {
97
+ /**
98
+ * @since 2.0.0
99
+ * @category type-level
100
+ */
101
+ export type Left<T extends Either<any, any>> = [T] extends [Either<infer _A, infer _E>] ? _E : never
102
+ /**
103
+ * @since 2.0.0
104
+ * @category type-level
105
+ */
106
+ export type Right<T extends Either<any, any>> = [T] extends [Either<infer _A, infer _E>] ? _A : never
107
+ }
108
+
93
109
  /**
94
110
  * Constructs a new `Either` holding a `Right` value. This usually represents a successful value due to the right bias
95
111
  * of this structure.
@@ -571,11 +587,11 @@ export const andThen: {
571
587
  <R, R2, L2>(f: (right: R) => Either<R2, L2>): <L>(self: Either<R, L>) => Either<R2, L | L2>
572
588
  <R2, L2>(f: Either<R2, L2>): <L, R1>(self: Either<R1, L>) => Either<R2, L | L2>
573
589
  <R, R2>(f: (right: R) => R2): <L>(self: Either<R, L>) => Either<R2, L>
574
- <R2>(right: R2): <R1, L>(self: Either<R1, L>) => Either<R2, L>
590
+ <R2>(right: NotFunction<R2>): <R1, L>(self: Either<R1, L>) => Either<R2, L>
575
591
  <R, L, R2, L2>(self: Either<R, L>, f: (right: R) => Either<R2, L2>): Either<R2, L | L2>
576
592
  <R, L, R2, L2>(self: Either<R, L>, f: Either<R2, L2>): Either<R2, L | L2>
577
593
  <R, L, R2>(self: Either<R, L>, f: (right: R) => R2): Either<R2, L>
578
- <R, L, R2>(self: Either<R, L>, f: R2): Either<R2, L>
594
+ <R, L, R2>(self: Either<R, L>, f: NotFunction<R2>): Either<R2, L>
579
595
  } = dual(
580
596
  2,
581
597
  <R, L, R2, L2>(self: Either<R, L>, f: (right: R) => Either<R2, L2> | Either<R2, L2>): Either<R2, L | L2> =>
package/src/FiberMap.ts CHANGED
@@ -4,6 +4,9 @@
4
4
  import * as Effect from "effect/Effect"
5
5
  import type * as Scope from "effect/Scope"
6
6
  import type { NoSuchElementException } from "./Cause.js"
7
+ import * as Cause from "./Cause.js"
8
+ import * as Deferred from "./Deferred.js"
9
+ import * as Exit from "./Exit.js"
7
10
  import * as Fiber from "./Fiber.js"
8
11
  import * as FiberId from "./FiberId.js"
9
12
  import { dual } from "./Function.js"
@@ -30,11 +33,12 @@ export type TypeId = typeof TypeId
30
33
  * @since 2.0.0
31
34
  * @categories models
32
35
  */
33
- export interface FiberMap<K, A = unknown, E = unknown>
36
+ export interface FiberMap<in out K, out A = unknown, out E = unknown>
34
37
  extends Pipeable, Inspectable.Inspectable, Iterable<[K, Fiber.RuntimeFiber<A, E>]>
35
38
  {
36
39
  readonly [TypeId]: TypeId
37
40
  readonly backing: MutableHashMap.MutableHashMap<K, Fiber.RuntimeFiber<A, E>>
41
+ readonly deferred: Deferred.Deferred<never, unknown>
38
42
  }
39
43
 
40
44
  /**
@@ -65,9 +69,13 @@ const Proto = {
65
69
  }
66
70
  }
67
71
 
68
- const unsafeMake = <K, A = unknown, E = unknown>(): FiberMap<K, A, E> => {
72
+ const unsafeMake = <K, A = unknown, E = unknown>(
73
+ backing: MutableHashMap.MutableHashMap<K, Fiber.RuntimeFiber<A, E>>,
74
+ deferred: Deferred.Deferred<never, E>
75
+ ): FiberMap<K, A, E> => {
69
76
  const self = Object.create(Proto)
70
- self.backing = MutableHashMap.empty()
77
+ self.backing = backing
78
+ self.deferred = deferred
71
79
  return self
72
80
  }
73
81
 
@@ -97,7 +105,14 @@ const unsafeMake = <K, A = unknown, E = unknown>(): FiberMap<K, A, E> => {
97
105
  * @categories constructors
98
106
  */
99
107
  export const make = <K, A = unknown, E = unknown>(): Effect.Effect<FiberMap<K, A, E>, never, Scope.Scope> =>
100
- Effect.acquireRelease(Effect.sync(() => unsafeMake<K, A, E>()), clear)
108
+ Effect.acquireRelease(
109
+ Effect.map(Deferred.make<never, E>(), (deferred) =>
110
+ unsafeMake<K, A, E>(
111
+ MutableHashMap.empty(),
112
+ deferred
113
+ )),
114
+ clear
115
+ )
101
116
 
102
117
  /**
103
118
  * Create an Effect run function that is backed by a FiberMap.
@@ -159,11 +174,14 @@ export const unsafeSet: {
159
174
  previous.value.unsafeInterruptAsFork(interruptAs ?? FiberId.none)
160
175
  }
161
176
  MutableHashMap.set(self.backing, key, fiber)
162
- fiber.addObserver((_) => {
177
+ fiber.addObserver((exit) => {
163
178
  const current = MutableHashMap.get(self.backing, key)
164
179
  if (Option.isSome(current) && fiber === current.value) {
165
180
  MutableHashMap.remove(self.backing, key)
166
181
  }
182
+ if (Exit.isFailure(exit) && !Cause.isInterruptedOnly(exit.cause)) {
183
+ Deferred.unsafeDone(self.deferred, exit as any)
184
+ }
167
185
  })
168
186
  })
169
187
 
@@ -372,5 +390,25 @@ export const runtime: <K, A, E>(
372
390
  * @since 2.0.0
373
391
  * @categories combinators
374
392
  */
375
- export const size = <K, E, A>(self: FiberMap<K, E, A>): Effect.Effect<number> =>
393
+ export const size = <K, A, E>(self: FiberMap<K, A, E>): Effect.Effect<number> =>
376
394
  Effect.sync(() => MutableHashMap.size(self.backing))
395
+
396
+ /**
397
+ * Join all fibers in the FiberMap. If any of the Fiber's in the map terminate with a failure,
398
+ * the returned Effect will terminate with the first failure that occurred.
399
+ *
400
+ * @since 2.0.0
401
+ * @categories combinators
402
+ * @example
403
+ * import { Effect, FiberMap } from "effect";
404
+ *
405
+ * Effect.gen(function* (_) {
406
+ * const map = yield* _(FiberMap.make());
407
+ * yield* _(FiberMap.set(map, "a", Effect.runFork(Effect.fail("error"))));
408
+ *
409
+ * // parent fiber will fail with "error"
410
+ * yield* _(FiberMap.join(map));
411
+ * });
412
+ */
413
+ export const join = <K, A, E>(self: FiberMap<K, A, E>): Effect.Effect<never, E> =>
414
+ Deferred.await(self.deferred as Deferred.Deferred<never, E>)
package/src/FiberSet.ts CHANGED
@@ -3,6 +3,9 @@
3
3
  */
4
4
  import * as Effect from "effect/Effect"
5
5
  import type * as Scope from "effect/Scope"
6
+ import * as Cause from "./Cause.js"
7
+ import * as Deferred from "./Deferred.js"
8
+ import * as Exit from "./Exit.js"
6
9
  import * as Fiber from "./Fiber.js"
7
10
  import { dual } from "./Function.js"
8
11
  import * as Inspectable from "./Inspectable.js"
@@ -31,6 +34,7 @@ export interface FiberSet<out A = unknown, out E = unknown>
31
34
  {
32
35
  readonly [TypeId]: TypeId
33
36
  readonly backing: Set<Fiber.RuntimeFiber<A, E>>
37
+ readonly deferred: Deferred.Deferred<never, unknown>
34
38
  }
35
39
 
36
40
  /**
@@ -61,9 +65,13 @@ const Proto = {
61
65
  }
62
66
  }
63
67
 
64
- const unsafeMake = <A, E>(): FiberSet<A, E> => {
68
+ const unsafeMake = <A, E>(
69
+ backing: Set<Fiber.RuntimeFiber<A, E>>,
70
+ deferred: Deferred.Deferred<never, unknown>
71
+ ): FiberSet<A, E> => {
65
72
  const self = Object.create(Proto)
66
- self.backing = new Set()
73
+ self.backing = backing
74
+ self.deferred = deferred
67
75
  return self
68
76
  }
69
77
 
@@ -93,7 +101,10 @@ const unsafeMake = <A, E>(): FiberSet<A, E> => {
93
101
  * @categories constructors
94
102
  */
95
103
  export const make = <A = unknown, E = unknown>(): Effect.Effect<FiberSet<A, E>, never, Scope.Scope> =>
96
- Effect.acquireRelease(Effect.sync(() => unsafeMake<A, E>()), clear)
104
+ Effect.acquireRelease(
105
+ Effect.map(Deferred.make<never, unknown>(), (deferred) => unsafeMake(new Set(), deferred)),
106
+ clear
107
+ )
97
108
 
98
109
  /**
99
110
  * Create an Effect run function that is backed by a FiberSet.
@@ -136,8 +147,11 @@ export const unsafeAdd: {
136
147
  return
137
148
  }
138
149
  self.backing.add(fiber)
139
- fiber.addObserver((_) => {
150
+ fiber.addObserver((exit) => {
140
151
  self.backing.delete(fiber)
152
+ if (Exit.isFailure(exit) && !Cause.isInterruptedOnly(exit.cause)) {
153
+ Deferred.unsafeDone(self.deferred, exit as any)
154
+ }
141
155
  })
142
156
  })
143
157
 
@@ -264,3 +278,23 @@ export const runtime: <A, E>(
264
278
  * @categories combinators
265
279
  */
266
280
  export const size = <A, E>(self: FiberSet<A, E>): Effect.Effect<number> => Effect.sync(() => self.backing.size)
281
+
282
+ /**
283
+ * Join all fibers in the FiberSet. If any of the Fiber's in the set terminate with a failure,
284
+ * the returned Effect will terminate with the first failure that occurred.
285
+ *
286
+ * @since 2.0.0
287
+ * @categories combinators
288
+ * @example
289
+ * import { Effect, FiberSet } from "effect";
290
+ *
291
+ * Effect.gen(function* (_) {
292
+ * const set = yield* _(FiberSet.make());
293
+ * yield* _(FiberSet.add(set, Effect.runFork(Effect.fail("error"))));
294
+ *
295
+ * // parent fiber will fail with "error"
296
+ * yield* _(FiberSet.join(set));
297
+ * });
298
+ */
299
+ export const join = <A, E>(self: FiberSet<A, E>): Effect.Effect<never, E> =>
300
+ Deferred.await(self.deferred as Deferred.Deferred<never, E>)