effect 3.15.4 → 3.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/ExecutionPlan/package.json +6 -0
  2. package/dist/cjs/Array.js +67 -5
  3. package/dist/cjs/Array.js.map +1 -1
  4. package/dist/cjs/BigDecimal.js +150 -1
  5. package/dist/cjs/BigDecimal.js.map +1 -1
  6. package/dist/cjs/Chunk.js +16 -3
  7. package/dist/cjs/Chunk.js.map +1 -1
  8. package/dist/cjs/Config.js +16 -2
  9. package/dist/cjs/Config.js.map +1 -1
  10. package/dist/cjs/Effect.js +31 -3
  11. package/dist/cjs/Effect.js.map +1 -1
  12. package/dist/cjs/ExecutionPlan.js +108 -0
  13. package/dist/cjs/ExecutionPlan.js.map +1 -0
  14. package/dist/cjs/HashMap.js +18 -1
  15. package/dist/cjs/HashMap.js.map +1 -1
  16. package/dist/cjs/Iterable.js +27 -1
  17. package/dist/cjs/Iterable.js.map +1 -1
  18. package/dist/cjs/LayerMap.js +86 -64
  19. package/dist/cjs/LayerMap.js.map +1 -1
  20. package/dist/cjs/Schedule.js +7 -1
  21. package/dist/cjs/Schedule.js.map +1 -1
  22. package/dist/cjs/Stream.js +15 -2
  23. package/dist/cjs/Stream.js.map +1 -1
  24. package/dist/cjs/index.js +4 -2
  25. package/dist/cjs/index.js.map +1 -1
  26. package/dist/cjs/internal/config.js +18 -1
  27. package/dist/cjs/internal/config.js.map +1 -1
  28. package/dist/cjs/internal/effect/circular.js +1 -4
  29. package/dist/cjs/internal/effect/circular.js.map +1 -1
  30. package/dist/cjs/internal/executionPlan.js +68 -0
  31. package/dist/cjs/internal/executionPlan.js.map +1 -0
  32. package/dist/cjs/internal/hashMap.js +3 -1
  33. package/dist/cjs/internal/hashMap.js.map +1 -1
  34. package/dist/cjs/internal/metric/polling.js +3 -4
  35. package/dist/cjs/internal/metric/polling.js.map +1 -1
  36. package/dist/cjs/internal/schedule.js +66 -25
  37. package/dist/cjs/internal/schedule.js.map +1 -1
  38. package/dist/cjs/internal/stream.js +60 -10
  39. package/dist/cjs/internal/stream.js.map +1 -1
  40. package/dist/cjs/internal/version.js +1 -1
  41. package/dist/dts/Array.d.ts +110 -0
  42. package/dist/dts/Array.d.ts.map +1 -1
  43. package/dist/dts/BigDecimal.d.ts +235 -0
  44. package/dist/dts/BigDecimal.d.ts.map +1 -1
  45. package/dist/dts/Chunk.d.ts +13 -0
  46. package/dist/dts/Chunk.d.ts.map +1 -1
  47. package/dist/dts/Config.d.ts +38 -1
  48. package/dist/dts/Config.d.ts.map +1 -1
  49. package/dist/dts/Effect.d.ts +99 -27
  50. package/dist/dts/Effect.d.ts.map +1 -1
  51. package/dist/dts/ExecutionPlan.d.ts +213 -0
  52. package/dist/dts/ExecutionPlan.d.ts.map +1 -0
  53. package/dist/dts/HashMap.d.ts +52 -0
  54. package/dist/dts/HashMap.d.ts.map +1 -1
  55. package/dist/dts/Iterable.d.ts +49 -0
  56. package/dist/dts/Iterable.d.ts.map +1 -1
  57. package/dist/dts/LayerMap.d.ts +79 -72
  58. package/dist/dts/LayerMap.d.ts.map +1 -1
  59. package/dist/dts/Schedule.d.ts +26 -0
  60. package/dist/dts/Schedule.d.ts.map +1 -1
  61. package/dist/dts/Stream.d.ts +57 -2
  62. package/dist/dts/Stream.d.ts.map +1 -1
  63. package/dist/dts/index.d.ts +5 -0
  64. package/dist/dts/index.d.ts.map +1 -1
  65. package/dist/dts/internal/executionPlan.d.ts +2 -0
  66. package/dist/dts/internal/executionPlan.d.ts.map +1 -0
  67. package/dist/dts/internal/hashMap.d.ts.map +1 -1
  68. package/dist/dts/internal/stream.d.ts.map +1 -1
  69. package/dist/esm/Array.js +65 -3
  70. package/dist/esm/Array.js.map +1 -1
  71. package/dist/esm/BigDecimal.js +148 -0
  72. package/dist/esm/BigDecimal.js.map +1 -1
  73. package/dist/esm/Chunk.js +15 -2
  74. package/dist/esm/Chunk.js.map +1 -1
  75. package/dist/esm/Config.js +15 -1
  76. package/dist/esm/Config.js.map +1 -1
  77. package/dist/esm/Effect.js +29 -1
  78. package/dist/esm/Effect.js.map +1 -1
  79. package/dist/esm/ExecutionPlan.js +99 -0
  80. package/dist/esm/ExecutionPlan.js.map +1 -0
  81. package/dist/esm/HashMap.js +17 -0
  82. package/dist/esm/HashMap.js.map +1 -1
  83. package/dist/esm/Iterable.js +26 -0
  84. package/dist/esm/Iterable.js.map +1 -1
  85. package/dist/esm/LayerMap.js +86 -64
  86. package/dist/esm/LayerMap.js.map +1 -1
  87. package/dist/esm/Schedule.js +5 -0
  88. package/dist/esm/Schedule.js.map +1 -1
  89. package/dist/esm/Stream.js +13 -0
  90. package/dist/esm/Stream.js.map +1 -1
  91. package/dist/esm/index.js +5 -0
  92. package/dist/esm/index.js.map +1 -1
  93. package/dist/esm/internal/config.js +16 -0
  94. package/dist/esm/internal/config.js.map +1 -1
  95. package/dist/esm/internal/effect/circular.js +0 -3
  96. package/dist/esm/internal/effect/circular.js.map +1 -1
  97. package/dist/esm/internal/executionPlan.js +59 -0
  98. package/dist/esm/internal/executionPlan.js.map +1 -0
  99. package/dist/esm/internal/hashMap.js +2 -0
  100. package/dist/esm/internal/hashMap.js.map +1 -1
  101. package/dist/esm/internal/metric/polling.js +3 -4
  102. package/dist/esm/internal/metric/polling.js.map +1 -1
  103. package/dist/esm/internal/schedule.js +61 -23
  104. package/dist/esm/internal/schedule.js.map +1 -1
  105. package/dist/esm/internal/stream.js +57 -7
  106. package/dist/esm/internal/stream.js.map +1 -1
  107. package/dist/esm/internal/version.js +1 -1
  108. package/package.json +9 -1
  109. package/src/Array.ts +147 -4
  110. package/src/BigDecimal.ts +355 -0
  111. package/src/Chunk.ts +28 -3
  112. package/src/Config.ts +40 -1
  113. package/src/Effect.ts +145 -36
  114. package/src/ExecutionPlan.ts +302 -0
  115. package/src/HashMap.ts +56 -0
  116. package/src/Iterable.ts +66 -0
  117. package/src/LayerMap.ts +126 -114
  118. package/src/Schedule.ts +32 -0
  119. package/src/Stream.ts +51 -2
  120. package/src/index.ts +6 -0
  121. package/src/internal/config.ts +55 -0
  122. package/src/internal/effect/circular.ts +0 -15
  123. package/src/internal/executionPlan.ts +114 -0
  124. package/src/internal/hashMap.ts +6 -0
  125. package/src/internal/metric/polling.ts +3 -4
  126. package/src/internal/schedule.ts +169 -50
  127. package/src/internal/stream.ts +140 -15
  128. package/src/internal/version.ts +1 -1
package/src/LayerMap.ts CHANGED
@@ -5,9 +5,12 @@
5
5
  import * as Context from "./Context.js"
6
6
  import type * as Duration from "./Duration.js"
7
7
  import * as Effect from "./Effect.js"
8
+ import * as FiberRefsPatch from "./FiberRefsPatch.js"
8
9
  import { identity } from "./Function.js"
10
+ import * as core from "./internal/core.js"
9
11
  import * as Layer from "./Layer.js"
10
12
  import * as RcMap from "./RcMap.js"
13
+ import * as Runtime from "./Runtime.js"
11
14
  import * as Scope from "./Scope.js"
12
15
  import type { Mutable } from "./Types.js"
13
16
 
@@ -28,24 +31,26 @@ export type TypeId = typeof TypeId
28
31
  * @category Models
29
32
  * @experimental
30
33
  */
31
- export interface LayerMap<in K, in out I, out S, out E = never> {
34
+ export interface LayerMap<in K, in out I, out E = never> {
32
35
  readonly [TypeId]: TypeId
33
36
 
34
37
  /**
35
38
  * The internal RcMap that stores the resources.
36
39
  */
37
- readonly rcMap: RcMap.RcMap<K, readonly [Context.Context<I>, S], E>
40
+ readonly rcMap: RcMap.RcMap<K, {
41
+ readonly layer: Layer.Layer<I, E>
42
+ readonly runtimeEffect: Effect.Effect<Runtime.Runtime<I>, E, Scope.Scope>
43
+ }, E>
38
44
 
39
45
  /**
40
- * Retrieves an instance of the resource associated with the key.
46
+ * Retrieves a Layer for the resources associated with the key.
41
47
  */
42
- get(key: K): Effect.Effect<S, E, Scope.Scope>
48
+ get(key: K): Layer.Layer<I, E>
43
49
 
44
50
  /**
45
- * Provides an instance of the resource associated with the key
46
- * to the given effect.
51
+ * Retrieves a Runtime for the resources associated with the key.
47
52
  */
48
- provide(key: K): <A, EX, R>(effect: Effect.Effect<A, EX, R>) => Effect.Effect<A, EX | E, Exclude<R, I>>
53
+ runtime(key: K): Effect.Effect<Runtime.Runtime<I>, E, Scope.Scope>
49
54
 
50
55
  /**
51
56
  * Invalidates the resource associated with the key.
@@ -62,56 +67,54 @@ export interface LayerMap<in K, in out I, out S, out E = never> {
62
67
  * dynamically access resources based on a key.
63
68
  *
64
69
  * ```ts
65
- * import { Completions } from "@effect/ai"
66
- * import { OpenAiClient, OpenAiCompletions } from "@effect/ai-openai"
67
- * import { FetchHttpClient } from "@effect/platform"
68
70
  * import { NodeRuntime } from "@effect/platform-node"
69
- * import { Config, Effect, Layer, LayerMap } from "effect"
71
+ * import { Context, Effect, FiberRef, Layer, LayerMap } from "effect"
70
72
  *
71
- * // create the openai client layer
72
- * const OpenAiLayer = OpenAiClient.layerConfig({
73
- * apiKey: Config.redacted("OPENAI_API_KEY")
74
- * }).pipe(Layer.provide(FetchHttpClient.layer))
73
+ * class Greeter extends Context.Tag("Greeter")<Greeter, {
74
+ * greet: Effect.Effect<string>
75
+ * }>() {}
75
76
  *
76
77
  * // create a service that wraps a LayerMap
77
- * class AiClients extends LayerMap.Service<AiClients>()("AiClients", {
78
- * // this LayerMap will provide the ai Completions service
79
- * provides: Completions.Completions,
80
- *
78
+ * class GreeterMap extends LayerMap.Service<GreeterMap>()("GreeterMap", {
81
79
  * // define the lookup function for the layer map
82
80
  * //
83
- * // The returned Layer will be used to provide the Completions service for the
84
- * // given model.
85
- * lookup: (model: OpenAiCompletions.Model) => OpenAiCompletions.layer({ model }),
81
+ * // The returned Layer will be used to provide the Greeter service for the
82
+ * // given name.
83
+ * lookup: (name: string) =>
84
+ * Layer.succeed(Greeter, {
85
+ * greet: Effect.succeed(`Hello, ${name}!`)
86
+ * }).pipe(
87
+ * Layer.merge(Layer.locallyScoped(FiberRef.currentConcurrency, 123))
88
+ * ),
86
89
  *
87
90
  * // If a layer is not used for a certain amount of time, it can be removed
88
91
  * idleTimeToLive: "5 seconds",
89
92
  *
90
93
  * // Supply the dependencies for the layers in the LayerMap
91
- * dependencies: [OpenAiLayer]
94
+ * dependencies: []
92
95
  * }) {}
93
96
  *
94
97
  * // usage
95
- * Effect.gen(function*() {
96
- * // access and use the generic Completions service
97
- * const ai = yield* Completions.Completions
98
- * const response = yield* ai.create("Hello, world!")
99
- * console.log(response.text)
98
+ * const program: Effect.Effect<void, never, GreeterMap> = Effect.gen(function*() {
99
+ * // access and use the Greeter service
100
+ * const greeter = yield* Greeter
101
+ * yield* Effect.log(yield* greeter.greet)
100
102
  * }).pipe(
101
- * // use the AiClients service to provide a variant of the Completions service
102
- * AiClients.provide("gpt-4o"),
103
- * // provide the LayerMap service
104
- * Effect.provide(AiClients.Default),
103
+ * // use the GreeterMap service to provide a variant of the Greeter service
104
+ * Effect.provide(GreeterMap.get("John"))
105
+ * )
106
+ *
107
+ * // run the program
108
+ * program.pipe(
109
+ * Effect.provide(GreeterMap.Default),
105
110
  * NodeRuntime.runMain
106
111
  * )
107
112
  * ```
108
113
  */
109
114
  export const make: <
110
- Accessor extends Context.Tag<any, any> | Effect.Effect<any, any, any>,
111
115
  K,
112
- L extends Layer.Layer<Exclude<Effect.Effect.Context<Accessor>, Scope.Scope>, any, any>
116
+ L extends Layer.Layer<any, any, any>
113
117
  >(
114
- tagOrAccessor: Accessor,
115
118
  lookup: (key: K) => L,
116
119
  options?: {
117
120
  readonly idleTimeToLive?: Duration.DurationInput | undefined
@@ -119,15 +122,13 @@ export const make: <
119
122
  ) => Effect.Effect<
120
123
  LayerMap<
121
124
  K,
122
- Exclude<Effect.Effect.Context<Accessor>, Scope.Scope>,
123
- Effect.Effect.Success<Accessor>,
124
- Effect.Effect.Error<Accessor> | (L extends Layer.Layer<infer _A, infer _E, infer _R> ? _E : never)
125
+ L extends Layer.Layer<infer _A, infer _E, infer _R> ? _A : never,
126
+ L extends Layer.Layer<infer _A, infer _E, infer _R> ? _E : never
125
127
  >,
126
128
  never,
127
129
  Scope.Scope | (L extends Layer.Layer<infer _A, infer _E, infer _R> ? _R : never)
128
- > = Effect.fnUntraced(function*<I, S, K, EL, RL, E = never>(
129
- tagOrAccessor: Effect.Effect<S, E, I>,
130
- lookup: (key: K) => Layer.Layer<Exclude<I, Scope.Scope>, EL, RL>,
130
+ > = Effect.fnUntraced(function*<I, K, EL, RL>(
131
+ lookup: (key: K) => Layer.Layer<I, EL, RL>,
131
132
  options?: {
132
133
  readonly idleTimeToLive?: Duration.DurationInput | undefined
133
134
  } | undefined
@@ -141,28 +142,43 @@ export const make: <
141
142
  : yield* Layer.makeMemoMap
142
143
 
143
144
  const rcMap = yield* RcMap.make({
144
- lookup: Effect.fnUntraced(function*(key: K) {
145
- const scope = yield* Effect.scope
146
- const context = yield* (Layer.buildWithMemoMap(lookup(key), memoMap, scope) as Effect.Effect<
147
- Context.Context<Exclude<I, Scope.Scope>>
148
- >)
149
- const service = yield* (Effect.provide(tagOrAccessor, context) as Effect.Effect<S>)
150
- return [context, service] as const
151
- }),
145
+ lookup: (key: K) =>
146
+ Effect.scopeWith((scope) => Effect.diffFiberRefs(Layer.buildWithMemoMap(lookup(key), memoMap, scope))).pipe(
147
+ Effect.map(([patch, context]) => ({
148
+ layer: Layer.scopedContext(
149
+ core.withFiberRuntime<Context.Context<I>, any, Scope.Scope>((fiber) => {
150
+ const scope = Context.unsafeGet(fiber.currentContext, Scope.Scope)
151
+ const oldRefs = fiber.getFiberRefs()
152
+ const newRefs = FiberRefsPatch.patch(patch, fiber.id(), oldRefs)
153
+ const revert = FiberRefsPatch.diff(newRefs, oldRefs)
154
+ fiber.setFiberRefs(newRefs)
155
+ return Effect.as(
156
+ Scope.addFinalizerExit(scope, () => {
157
+ fiber.setFiberRefs(FiberRefsPatch.patch(revert, fiber.id(), fiber.getFiberRefs()))
158
+ return Effect.void
159
+ }),
160
+ context
161
+ )
162
+ })
163
+ ),
164
+ runtimeEffect: Effect.withFiberRuntime<Runtime.Runtime<I>, any, Scope.Scope>((fiber) => {
165
+ const fiberRefs = FiberRefsPatch.patch(patch, fiber.id(), fiber.getFiberRefs())
166
+ return Effect.succeed(Runtime.make({
167
+ context,
168
+ fiberRefs,
169
+ runtimeFlags: Runtime.defaultRuntime.runtimeFlags
170
+ }))
171
+ })
172
+ } as const))
173
+ ),
152
174
  idleTimeToLive: options?.idleTimeToLive
153
175
  })
154
176
 
155
- return identity<LayerMap<K, Exclude<I, Scope.Scope>, S, any>>({
177
+ return identity<LayerMap<K, Exclude<I, Scope.Scope>, any>>({
156
178
  [TypeId]: TypeId,
157
179
  rcMap,
158
- get: (key) => Effect.map(RcMap.get(rcMap, key), ([, service]) => service),
159
- provide: (key) => (effect) =>
160
- Effect.scopedWith((scope) =>
161
- Effect.flatMap(
162
- Scope.extend(RcMap.get(rcMap, key), scope),
163
- ([context]) => Effect.provide(effect, context)
164
- )
165
- ),
180
+ get: (key) => Layer.unwrapScoped(Effect.map(RcMap.get(rcMap, key), ({ layer }) => layer)),
181
+ runtime: (key) => Effect.flatMap(RcMap.get(rcMap, key), ({ runtimeEffect }) => runtimeEffect),
166
182
  invalidate: (key) => RcMap.invalidate(rcMap, key)
167
183
  })
168
184
  })
@@ -173,10 +189,8 @@ export const make: <
173
189
  * @experimental
174
190
  */
175
191
  export const fromRecord = <
176
- Accessor extends Context.Tag<any, any> | Effect.Effect<any, any, any>,
177
- const Layers extends Record<string, Layer.Layer<Exclude<Effect.Effect.Context<Accessor>, Scope.Scope>, any, any>>
192
+ const Layers extends Record<string, Layer.Layer<any, any, any>>
178
193
  >(
179
- tagOrAccessor: Accessor,
180
194
  layers: Layers,
181
195
  options?: {
182
196
  readonly idleTimeToLive?: Duration.DurationInput | undefined
@@ -184,14 +198,12 @@ export const fromRecord = <
184
198
  ): Effect.Effect<
185
199
  LayerMap<
186
200
  keyof Layers,
187
- Exclude<Effect.Effect.Context<Accessor>, Scope.Scope>,
188
- Effect.Effect.Success<Accessor>,
189
- | Effect.Effect.Error<Accessor>
190
- | (Layers[keyof Layers] extends Layer.Layer<infer _A, infer _E, infer _R> ? _E : never)
201
+ Layers[keyof Layers] extends Layer.Layer<infer _A, infer _E, infer _R> ? _A : never,
202
+ Layers[keyof Layers] extends Layer.Layer<infer _A, infer _E, infer _R> ? _E : never
191
203
  >,
192
204
  never,
193
205
  Scope.Scope | (Layers[keyof Layers] extends Layer.Layer<infer _A, infer _E, infer _R> ? _R : never)
194
- > => make(tagOrAccessor, (key: keyof Layers) => layers[key], options)
206
+ > => make((key: keyof Layers) => layers[key], options)
195
207
 
196
208
  /**
197
209
  * @since 3.14.0
@@ -202,11 +214,10 @@ export interface TagClass<
202
214
  in out Id extends string,
203
215
  in out K,
204
216
  in out I,
205
- in out S,
206
217
  in out E,
207
218
  in out R,
208
219
  in out Deps extends Layer.Layer<any, any, any>
209
- > extends Context.TagClass<Self, Id, LayerMap<K, I, S, E>> {
220
+ > extends Context.TagClass<Self, Id, LayerMap<K, I, E>> {
210
221
  /**
211
222
  * A default layer for the `LayerMap` service.
212
223
  */
@@ -223,17 +234,14 @@ export interface TagClass<
223
234
  readonly DefaultWithoutDependencies: Layer.Layer<Self, never, R>
224
235
 
225
236
  /**
226
- * Retrieves an instance of the resource associated with the key.
237
+ * Retrieves a Layer for the resources associated with the key.
227
238
  */
228
- readonly get: (key: K) => Effect.Effect<S, E, Scope.Scope | Self>
239
+ readonly get: (key: K) => Layer.Layer<I, E, Self>
229
240
 
230
241
  /**
231
- * Provides an instance of the resource associated with the key to the given
232
- * effect.
242
+ * Retrieves a Runtime for the resources associated with the key.
233
243
  */
234
- readonly provide: (
235
- key: K
236
- ) => <A, EX, R>(effect: Effect.Effect<A, EX, R>) => Effect.Effect<A, EX | E, Exclude<R, I> | Self>
244
+ readonly runtime: (key: K) => Effect.Effect<Runtime.Runtime<I>, E, Scope.Scope | Self>
237
245
 
238
246
  /**
239
247
  * Invalidates the resource associated with the key.
@@ -250,46 +258,46 @@ export interface TagClass<
250
258
  * a key.
251
259
  *
252
260
  * ```ts
253
- * import { Completions } from "@effect/ai"
254
- * import { OpenAiClient, OpenAiCompletions } from "@effect/ai-openai"
255
- * import { FetchHttpClient } from "@effect/platform"
256
261
  * import { NodeRuntime } from "@effect/platform-node"
257
- * import { Config, Effect, Layer, LayerMap } from "effect"
262
+ * import { Context, Effect, FiberRef, Layer, LayerMap } from "effect"
258
263
  *
259
- * // create the openai client layer
260
- * const OpenAiLayer = OpenAiClient.layerConfig({
261
- * apiKey: Config.redacted("OPENAI_API_KEY")
262
- * }).pipe(Layer.provide(FetchHttpClient.layer))
264
+ * class Greeter extends Context.Tag("Greeter")<Greeter, {
265
+ * greet: Effect.Effect<string>
266
+ * }>() {}
263
267
  *
264
268
  * // create a service that wraps a LayerMap
265
- * class AiClients extends LayerMap.Service<AiClients>()("AiClients", {
266
- * // this LayerMap will provide the ai Completions service
267
- * provides: Completions.Completions,
268
- *
269
+ * class GreeterMap extends LayerMap.Service<GreeterMap>()("GreeterMap", {
269
270
  * // define the lookup function for the layer map
270
271
  * //
271
- * // The returned Layer will be used to provide the Completions service for the
272
- * // given model.
273
- * lookup: (model: OpenAiCompletions.Model) => OpenAiCompletions.layer({ model }),
272
+ * // The returned Layer will be used to provide the Greeter service for the
273
+ * // given name.
274
+ * lookup: (name: string) =>
275
+ * Layer.succeed(Greeter, {
276
+ * greet: Effect.succeed(`Hello, ${name}!`)
277
+ * }).pipe(
278
+ * Layer.merge(Layer.locallyScoped(FiberRef.currentConcurrency, 123))
279
+ * ),
274
280
  *
275
281
  * // If a layer is not used for a certain amount of time, it can be removed
276
282
  * idleTimeToLive: "5 seconds",
277
283
  *
278
284
  * // Supply the dependencies for the layers in the LayerMap
279
- * dependencies: [OpenAiLayer]
285
+ * dependencies: []
280
286
  * }) {}
281
287
  *
282
288
  * // usage
283
- * Effect.gen(function*() {
284
- * // access and use the generic Completions service
285
- * const ai = yield* Completions.Completions
286
- * const response = yield* ai.create("Hello, world!")
287
- * console.log(response.text)
289
+ * const program: Effect.Effect<void, never, GreeterMap> = Effect.gen(function*() {
290
+ * // access and use the Greeter service
291
+ * const greeter = yield* Greeter
292
+ * yield* Effect.log(yield* greeter.greet)
288
293
  * }).pipe(
289
- * // use the AiClients service to provide a variant of the Completions service
290
- * AiClients.provide("gpt-4o"),
291
- * // provide the LayerMap service
292
- * Effect.provide(AiClients.Default),
294
+ * // use the GreeterMap service to provide a variant of the Greeter service
295
+ * Effect.provide(GreeterMap.get("John"))
296
+ * )
297
+ *
298
+ * // run the program
299
+ * program.pipe(
300
+ * Effect.provide(GreeterMap.Default),
293
301
  * NodeRuntime.runMain
294
302
  * )
295
303
  * ```
@@ -297,17 +305,15 @@ export interface TagClass<
297
305
  export const Service = <Self>() =>
298
306
  <
299
307
  const Id extends string,
300
- Accessor extends Context.Tag<any, any> | Effect.Effect<any, any, any>,
301
308
  Lookup extends {
302
- readonly lookup: (key: any) => Layer.Layer<Exclude<Effect.Effect.Context<Accessor>, Scope.Scope>, any, any>
309
+ readonly lookup: (key: any) => Layer.Layer<any, any, any>
303
310
  } | {
304
- readonly layers: Record<string, Layer.Layer<Exclude<Effect.Effect.Context<Accessor>, Scope.Scope>, any, any>>
311
+ readonly layers: Record<string, Layer.Layer<any, any, any>>
305
312
  },
306
313
  const Deps extends ReadonlyArray<Layer.Layer<any, any, any>> = []
307
314
  >(
308
315
  id: Id,
309
316
  options: Lookup & {
310
- readonly provides: Accessor
311
317
  readonly dependencies?: Deps | undefined
312
318
  readonly idleTimeToLive?: Duration.DurationInput | undefined
313
319
  }
@@ -317,9 +323,8 @@ export const Service = <Self>() =>
317
323
  Lookup extends { readonly lookup: (key: infer K) => any } ? K
318
324
  : Lookup extends { readonly layers: infer Layers } ? keyof Layers
319
325
  : never,
320
- Exclude<Effect.Effect.Context<Accessor>, Scope.Scope>,
321
- Effect.Effect.Success<Accessor>,
322
- Effect.Effect.Error<Accessor> | Service.Error<Lookup>,
326
+ Service.Success<Lookup>,
327
+ Service.Error<Lookup>,
323
328
  Service.Context<Lookup>,
324
329
  Deps[number]
325
330
  > => {
@@ -330,7 +335,7 @@ export const Service = <Self>() =>
330
335
  Err.stackTraceLimit = limit
331
336
 
332
337
  function TagClass() {}
333
- const TagClass_ = TagClass as any as Mutable<TagClass<Self, Id, string, any, any, any, any, any>>
338
+ const TagClass_ = TagClass as any as Mutable<TagClass<Self, Id, string, any, any, any, any>>
334
339
  Object.setPrototypeOf(TagClass, Object.getPrototypeOf(Context.GenericTag<Self, any>(id)))
335
340
  TagClass.key = id
336
341
  Object.defineProperty(TagClass, "stack", {
@@ -338,21 +343,21 @@ export const Service = <Self>() =>
338
343
  return creationError.stack
339
344
  }
340
345
  })
341
- TagClass_.get = (key: string) => Effect.flatMap(TagClass_, (layerMap) => layerMap.get(key))
342
- TagClass_.provide = (key: string) => (effect) =>
343
- Effect.flatMap(TagClass_, (layerMap) => layerMap.provide(key)(effect))
344
- TagClass_.invalidate = (key: string) => Effect.flatMap(TagClass_, (layerMap) => layerMap.invalidate(key))
345
346
 
346
347
  TagClass_.DefaultWithoutDependencies = Layer.scoped(
347
348
  TagClass_,
348
349
  "lookup" in options
349
- ? make(options.provides, options.lookup, options)
350
- : fromRecord(options.provides, options.layers as any, options)
350
+ ? make(options.lookup, options)
351
+ : fromRecord(options.layers as any, options)
351
352
  )
352
353
  TagClass_.Default = options.dependencies && options.dependencies.length > 0 ?
353
354
  Layer.provide(TagClass_.DefaultWithoutDependencies, options.dependencies as any) :
354
355
  TagClass_.DefaultWithoutDependencies
355
356
 
357
+ TagClass_.get = (key: string) => Layer.unwrapScoped(Effect.map(TagClass_, (layerMap) => layerMap.get(key)))
358
+ TagClass_.runtime = (key: string) => Effect.flatMap(TagClass_, (layerMap) => layerMap.runtime(key))
359
+ TagClass_.invalidate = (key: string) => Effect.flatMap(TagClass_, (layerMap) => layerMap.invalidate(key))
360
+
356
361
  return TagClass as any
357
362
  }
358
363
 
@@ -380,6 +385,13 @@ export declare namespace Service {
380
385
  : Options extends { readonly layers: infer Layers } ? Layers[keyof Layers]
381
386
  : never
382
387
 
388
+ /**
389
+ * @since 3.14.0
390
+ * @category Service
391
+ * @experimental
392
+ */
393
+ export type Success<Options> = Layers<Options> extends Layer.Layer<infer _A, infer _E, infer _R> ? _A : never
394
+
383
395
  /**
384
396
  * @since 3.14.0
385
397
  * @category Service
package/src/Schedule.ts CHANGED
@@ -14,6 +14,7 @@ import * as internal from "./internal/schedule.js"
14
14
  import type * as Option from "./Option.js"
15
15
  import type { Pipeable } from "./Pipeable.js"
16
16
  import type { Predicate } from "./Predicate.js"
17
+ import type * as Ref from "./Ref.js"
17
18
  import type * as ScheduleDecision from "./ScheduleDecision.js"
18
19
  import type * as Intervals from "./ScheduleIntervals.js"
19
20
  import type * as Types from "./Types.js"
@@ -140,6 +141,7 @@ export declare namespace Schedule {
140
141
  */
141
142
  export interface ScheduleDriver<out Out, in In = unknown, out R = never> extends Schedule.DriverVariance<Out, In, R> {
142
143
  readonly state: Effect.Effect<unknown>
144
+ readonly iterationMeta: Ref.Ref<IterationMetadata>
143
145
  readonly last: Effect.Effect<Out, Cause.NoSuchElementException>
144
146
  readonly reset: Effect.Effect<void>
145
147
  next(input: In): Effect.Effect<Out, Option.Option<never>, R>
@@ -3705,3 +3707,33 @@ export const zipWith: {
3705
3707
  f: (out: Out, out2: Out2) => Out3
3706
3708
  ): Schedule<Out3, In & In2, R | R2>
3707
3709
  } = internal.zipWith
3710
+
3711
+ /**
3712
+ * @since 3.15.0
3713
+ * @category models
3714
+ */
3715
+ export interface CurrentIterationMetadata {
3716
+ readonly _: unique symbol
3717
+ }
3718
+
3719
+ /**
3720
+ * @since 3.15.0
3721
+ * @category models
3722
+ */
3723
+ export interface IterationMetadata {
3724
+ readonly input: unknown
3725
+ readonly recurrence: number
3726
+ readonly start: number
3727
+ readonly now: number
3728
+ readonly elapsed: Duration.Duration
3729
+ readonly elapsedSincePrevious: Duration.Duration
3730
+ }
3731
+
3732
+ /**
3733
+ * @since 3.15.0
3734
+ * @category models
3735
+ */
3736
+ export const CurrentIterationMetadata: Context.Reference<
3737
+ CurrentIterationMetadata,
3738
+ IterationMetadata
3739
+ > = internal.CurrentIterationMetadata
package/src/Stream.ts CHANGED
@@ -9,6 +9,7 @@ import type * as Deferred from "./Deferred.js"
9
9
  import type * as Duration from "./Duration.js"
10
10
  import type * as Effect from "./Effect.js"
11
11
  import type * as Either from "./Either.js"
12
+ import type { ExecutionPlan } from "./ExecutionPlan.js"
12
13
  import type * as Exit from "./Exit.js"
13
14
  import type { LazyArg } from "./Function.js"
14
15
  import type * as GroupBy from "./GroupBy.js"
@@ -7351,7 +7352,7 @@ export const retry: {
7351
7352
  * @since 2.0.0
7352
7353
  * @category utils
7353
7354
  */
7354
- <E0 extends E, R2, E, X>(schedule: Schedule.Schedule<X, E0, R2>): <A, R>(self: Stream<A, E, R>) => Stream<A, E, R2 | R>
7355
+ <E, R2, X>(policy: Schedule.Schedule<X, NoInfer<E>, R2>): <A, R>(self: Stream<A, E, R>) => Stream<A, E, R2 | R>
7355
7356
  /**
7356
7357
  * When the stream fails, retry it according to the given schedule
7357
7358
  *
@@ -7364,9 +7365,57 @@ export const retry: {
7364
7365
  * @since 2.0.0
7365
7366
  * @category utils
7366
7367
  */
7367
- <A, E, R, X, E0 extends E, R2>(self: Stream<A, E, R>, schedule: Schedule.Schedule<X, E0, R2>): Stream<A, E, R | R2>
7368
+ <A, E, R, X, R2>(self: Stream<A, E, R>, policy: Schedule.Schedule<X, NoInfer<E>, R2>): Stream<A, E, R2 | R>
7368
7369
  } = internal.retry
7369
7370
 
7371
+ /**
7372
+ * Apply an `ExecutionPlan` to the stream, which allows you to fallback to
7373
+ * different resources in case of failure.
7374
+ *
7375
+ * If you have a stream that could fail with partial results, you can use
7376
+ * the `preventFallbackOnPartialStream` option to prevent contamination of
7377
+ * the final stream with partial results.
7378
+ *
7379
+ * @since 3.16.0
7380
+ * @category Error handling
7381
+ * @experimental
7382
+ */
7383
+ export const withExecutionPlan: {
7384
+ /**
7385
+ * Apply an `ExecutionPlan` to the stream, which allows you to fallback to
7386
+ * different resources in case of failure.
7387
+ *
7388
+ * If you have a stream that could fail with partial results, you can use
7389
+ * the `preventFallbackOnPartialStream` option to prevent contamination of
7390
+ * the final stream with partial results.
7391
+ *
7392
+ * @since 3.16.0
7393
+ * @category Error handling
7394
+ * @experimental
7395
+ */
7396
+ <Input, R2, Provides, PolicyE>(
7397
+ policy: ExecutionPlan<{ provides: Provides; input: Input; error: PolicyE; requirements: R2 }>,
7398
+ options?: { readonly preventFallbackOnPartialStream?: boolean | undefined }
7399
+ ): <A, E extends Input, R>(self: Stream<A, E, R>) => Stream<A, E | PolicyE, R2 | Exclude<R, Provides>>
7400
+ /**
7401
+ * Apply an `ExecutionPlan` to the stream, which allows you to fallback to
7402
+ * different resources in case of failure.
7403
+ *
7404
+ * If you have a stream that could fail with partial results, you can use
7405
+ * the `preventFallbackOnPartialStream` option to prevent contamination of
7406
+ * the final stream with partial results.
7407
+ *
7408
+ * @since 3.16.0
7409
+ * @category Error handling
7410
+ * @experimental
7411
+ */
7412
+ <A, E extends Input, R, R2, Input, Provides, PolicyE>(
7413
+ self: Stream<A, E, R>,
7414
+ policy: ExecutionPlan<{ provides: Provides; input: Input; error: PolicyE; requirements: R2 }>,
7415
+ options?: { readonly preventFallbackOnPartialStream?: boolean | undefined }
7416
+ ): Stream<A, E | PolicyE, R2 | Exclude<R, Provides>>
7417
+ } = internal.withExecutionPlan
7418
+
7370
7419
  /**
7371
7420
  * Runs the sink on the stream to produce either the sink's result or an error.
7372
7421
  *
package/src/index.ts CHANGED
@@ -263,6 +263,12 @@ export * as Equal from "./Equal.js"
263
263
  */
264
264
  export * as Equivalence from "./Equivalence.js"
265
265
 
266
+ /**
267
+ * @since 3.16.0
268
+ * @experimental
269
+ */
270
+ export * as ExecutionPlan from "./ExecutionPlan.js"
271
+
266
272
  /**
267
273
  * @since 2.0.0
268
274
  */
@@ -1,3 +1,4 @@
1
+ import type * as Brand from "../Brand.js"
1
2
  import * as Chunk from "../Chunk.js"
2
3
  import type * as Config from "../Config.js"
3
4
  import * as ConfigError from "../ConfigError.js"
@@ -192,6 +193,33 @@ export const url = (name?: string): Config.Config<URL> => {
192
193
  return name === undefined ? config : nested(config, name)
193
194
  }
194
195
 
196
+ /** @internal */
197
+ export const port = (name?: string): Config.Config<number> => {
198
+ const config = primitive(
199
+ "a network port property",
200
+ (text) => {
201
+ const result = Number(text)
202
+
203
+ if (
204
+ Number.isNaN(result) ||
205
+ result.toString() !== text.toString() ||
206
+ !Number.isInteger(result) ||
207
+ result < 1 ||
208
+ result > 65535
209
+ ) {
210
+ return Either.left(
211
+ configError.InvalidData(
212
+ [],
213
+ `Expected a network port value but received ${text}`
214
+ )
215
+ )
216
+ }
217
+ return Either.right(result)
218
+ }
219
+ )
220
+ return name === undefined ? config : nested(config, name)
221
+ }
222
+
195
223
  /** @internal */
196
224
  export const array = <A>(config: Config.Config<A>, name?: string): Config.Config<Array<A>> => {
197
225
  return pipe(chunk(config, name), map(Chunk.toArray))
@@ -444,6 +472,33 @@ export const redacted = <A>(
444
472
  return map(config, redacted_.make)
445
473
  }
446
474
 
475
+ /** @internal */
476
+ export const branded: {
477
+ <A, B extends Brand.Branded<A, any>>(
478
+ constructor: Brand.Brand.Constructor<B>
479
+ ): (config: Config.Config<A>) => Config.Config<B>
480
+ <B extends Brand.Branded<string, any>>(
481
+ name: string | undefined,
482
+ constructor: Brand.Brand.Constructor<B>
483
+ ): Config.Config<B>
484
+ <A, B extends Brand.Branded<A, any>>(
485
+ config: Config.Config<A>,
486
+ constructor: Brand.Brand.Constructor<B>
487
+ ): Config.Config<B>
488
+ } = dual(2, <A, B extends Brand.Brand.Constructor<any>>(
489
+ nameOrConfig: Config.Config<NoInfer<A>> | string | undefined,
490
+ constructor: B
491
+ ) => {
492
+ const config: Config.Config<string | A> = isConfig(nameOrConfig) ? nameOrConfig : string(nameOrConfig)
493
+
494
+ return mapOrFail(config, (a) =>
495
+ constructor.either(a).pipe(
496
+ Either.mapLeft((brandErrors) =>
497
+ configError.InvalidData([], brandErrors.map((brandError) => brandError.message).join("\n"))
498
+ )
499
+ ))
500
+ })
501
+
447
502
  /** @internal */
448
503
  export const hashSet = <A>(config: Config.Config<A>, name?: string): Config.Config<HashSet.HashSet<A>> => {
449
504
  const newConfig = map(chunk(config), HashSet.fromIterable)
@@ -18,7 +18,6 @@ import { pipeArguments } from "../../Pipeable.js"
18
18
  import * as Predicate from "../../Predicate.js"
19
19
  import * as Readable from "../../Readable.js"
20
20
  import type * as Ref from "../../Ref.js"
21
- import type * as Schedule from "../../Schedule.js"
22
21
  import { currentScheduler } from "../../Scheduler.js"
23
22
  import type * as Scope from "../../Scope.js"
24
23
  import type * as Supervisor from "../../Supervisor.js"
@@ -31,7 +30,6 @@ import * as internalFiber from "../fiber.js"
31
30
  import * as fiberRuntime from "../fiberRuntime.js"
32
31
  import { globalScope } from "../fiberScope.js"
33
32
  import * as internalRef from "../ref.js"
34
- import * as schedule_ from "../schedule.js"
35
33
  import * as supervisor from "../supervisor.js"
36
34
 
37
35
  /** @internal */
@@ -477,19 +475,6 @@ export const raceFirst = dual<
477
475
  (effect: Effect.Effect<Exit.Exit<A | A2, E | E2>, never, R | R2>) => core.flatten(effect)
478
476
  ))
479
477
 
480
- /** @internal */
481
- export const scheduleForked = dual<
482
- <Out, R2>(
483
- schedule: Schedule.Schedule<Out, unknown, R2>
484
- ) => <A, E, R>(
485
- self: Effect.Effect<A, E, R>
486
- ) => Effect.Effect<Fiber.RuntimeFiber<Out, E>, never, R | R2 | Scope.Scope>,
487
- <A, E, R, Out, R2>(
488
- self: Effect.Effect<A, E, R>,
489
- schedule: Schedule.Schedule<Out, unknown, R2>
490
- ) => Effect.Effect<Fiber.RuntimeFiber<Out, E>, never, R | R2 | Scope.Scope>
491
- >(2, (self, schedule) => pipe(self, schedule_.schedule_Effect(schedule), forkScoped))
492
-
493
478
  /** @internal */
494
479
  export const supervised = dual<
495
480
  <X>(supervisor: Supervisor.Supervisor<X>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>,