1/**
2 * Builds and wires services for Effect applications.
3 *
4 * A `Layer<ROut, E, RIn>` describes how to acquire one or more services, which
5 * services are required to build them, and which errors can occur during
6 * acquisition. Layers can manage scoped resources, memoize shared services,
7 * combine with other layers, provide services to effects or streams, and attach
8 * error handling, tracing, or lifecycle hooks.
9 *
10 * @since 2.0.0
11 */
12import type { NonEmptyArray, NonEmptyReadonlyArray } from "./Array.ts"
13import type * as Cause from "./Cause.ts"
14import type * as Channel from "./Channel.ts"
15import * as Context from "./Context.ts"
16import * as Deferred from "./Deferred.ts"
17import type { Effect } from "./Effect.ts"
18import type * as Exit from "./Exit.ts"
19import type { LazyArg } from "./Function.ts"
20import { constant, constTrue, constUndefined, dual, identity } from "./Function.ts"
21import * as core from "./internal/core.ts"
22import * as internalEffect from "./internal/effect.ts"
23import { getStackTraceLimit, setStackTraceLimit } from "./internal/stackTraceLimit.ts"
24import * as internalTracer from "./internal/tracer.ts"
25import { type Pipeable, pipeArguments } from "./Pipeable.ts"
26import { hasProperty } from "./Predicate.ts"
27import { CurrentStackFrame } from "./References.ts"
28import * as Scope from "./Scope.ts"
29import type * as Stream from "./Stream.ts"
30import * as Tracer from "./Tracer.ts"
31import type * as Types from "./Types.ts"
32import type * as Unify from "./Unify.ts"
33
34const TypeId = "~effect/Layer"
35
36/**
37 * A `Layer` describes how to build one or more services for dependency injection.
38 *
39 * **When to use**
40 *
41 * Use to model construction of application services for dependency injection,
42 * especially when services have dependencies, can fail during construction, or
43 * need scoped setup and release.
44 *
45 * **Details**
46 *
47 * A `Layer<ROut, E, RIn>` represents `ROut` as the services this layer
48 * provides, `E` as the possible errors during layer construction, and `RIn` as
49 * the services this layer requires as dependencies.
50 *
51 * @category models
52 * @since 2.0.0
53 */
54export interface Layer<in ROut, out E = never, out RIn = never> extends Variance<ROut, E, RIn>, Pipeable {
55 /** @internal */
56 build(memoMap: MemoMap, scope: Scope.Scope): Effect<Context.Context<ROut>, E, RIn>
57 [Unify.typeSymbol]?: unknown
58 [Unify.unifySymbol]?: LayerUnify<this>
59 [Unify.ignoreSymbol]?: LayerUnifyIgnore
60}
61
62/**
63 * Type-level hook that allows `Layer` values to participate in `Unify`
64 * inference.
65 *
66 * **Details**
67 *
68 * This is used by Effect's pipe and unification machinery to preserve the
69 * provided services, error, and requirements of a `Layer`.
70 *
71 * @category models
72 * @since 4.0.0
73 */
74export interface LayerUnify<A extends { [Unify.typeSymbol]?: any }> {
75 Layer?: () => A[Unify.typeSymbol] extends Layer<any, any, any> | infer _ ? Layer<
76 Success<Extract<A[Unify.typeSymbol], Any>>,
77 Error<Extract<A[Unify.typeSymbol], Any>>,
78 Services<Extract<A[Unify.typeSymbol], Any>>
79 >
80 : never
81}
82
83/**
84 * Type-level marker used by `Unify` for `Layer` types that should be ignored
85 * during unification.
86 *
87 * @category models
88 * @since 4.0.0
89 */
90export interface LayerUnifyIgnore {}
91
92/**
93 * The variance interface for Layer type parameters.
94 *
95 * @category models
96 * @since 2.0.0
97 */
98export interface Variance<in ROut, out E, out RIn> {
99 readonly [TypeId]: {
100 readonly _ROut: Types.Contravariant<ROut>
101 readonly _E: Types.Covariant<E>
102 readonly _RIn: Types.Covariant<RIn>
103 }
104}
105/**
106 * A type-level constraint for working with any `Layer` type.
107 *
108 * **When to use**
109 *
110 * Use to constrain generic parameters or layer collections to any `Layer`
111 * value while preserving its provided, error, and required service types for
112 * inference.
113 *
114 * **Details**
115 *
116 * This interface is used to constrain generic types to `Layer` values without
117 * specifying exact type parameters.
118 *
119 * @see {@link Layer} for the concrete layer interface
120 * @see {@link Services} for extracting required services from a layer type
121 * @see {@link Error} for extracting construction errors from a layer type
122 * @see {@link Success} for extracting provided services from a layer type
123 *
124 * @category utility types
125 * @since 3.9.0
126 */
127export interface Any {
128 readonly [TypeId]: {
129 readonly _ROut: any
130 readonly _E: any
131 readonly _RIn: any
132 }
133}
134/**
135 * Extracts the service requirements (`RIn`) from a `Layer` type.
136 *
137 * **When to use**
138 *
139 * Use to derive the dependency requirements of a generic or inferred `Layer`
140 * without restating its `RIn` type parameter.
141 *
142 * @see {@link Success} for extracting the services provided by the same `Layer`
143 * @see {@link Error} for extracting the construction failure type from the same `Layer`
144 *
145 * @category utility types
146 * @since 4.0.0
147 */
148export type Services<T extends Any> = T extends infer L
149 ? L extends Layer<infer _ROut, infer _E, infer _RIn> ? _RIn : never
150 : never
151/**
152 * Extracts the error type (`E`) from a `Layer` type.
153 *
154 * **When to use**
155 *
156 * Use to derive a layer construction error type for helper types, wrappers, or
157 * APIs that preserve a layer failure channel.
158 *
159 * @see {@link Success} for extracting the services provided by the same `Layer`
160 * @see {@link Services} for extracting the dependency requirements of the same `Layer`
161 *
162 * @category utility types
163 * @since 2.0.0
164 */
165export type Error<T extends Any> = T extends Layer<infer _ROut, infer _E, infer _RIn> ? _E : never
166/**
167 * Extracts the service output type (`ROut`) from a `Layer` type.
168 *
169 * **When to use**
170 *
171 * Use to derive the services provided by an existing or generic `Layer` without
172 * restating its `ROut` type parameter.
173 *
174 * @see {@link Error} for extracting the layer construction error type instead
175 * @see {@link Services} for extracting the layer input service requirements instead
176 *
177 * @category utility types
178 * @since 2.0.0
179 */
180export type Success<T extends Any> = T extends Layer<infer _ROut, infer _E, infer _RIn> ? _ROut : never
181
182const MemoMapTypeId = "~effect/Layer/MemoMap"
183
184/**
185 * A `MemoMap` is used to memoize layer construction and ensure sharing of
186 * layers.
187 *
188 * **Details**
189 *
190 * The `MemoMap` prevents duplicate construction of the same layer instance,
191 * enabling efficient resource sharing across layer dependencies.
192 *
193 * **Example** (Sharing layer construction with a memo map)
194 *
195 * ```ts import.meta.vitest
196 * import { Context, Effect, Layer } from "effect"
197 *
198 * class Database extends Context.Service<Database, {
199 * readonly query: (sql: string) => Effect.Effect<string>
200 * }>()("Database") {}
201 *
202 * // Create a custom MemoMap for manual layer building
203 * const program = Effect.gen(function*() {
204 * const memoMap = yield* Layer.makeMemoMap
205 * const scope = yield* Effect.scope
206 *
207 * const dbLayer = Layer.succeed(Database, {
208 * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result"))
209 * })
210 * const context = yield* Layer.buildWithMemoMap(dbLayer, memoMap, scope)
211 *
212 * return Context.get(context, Database)
213 * })
214 *
215 * const database = Effect.runSync(Effect.scoped(program))
216 * Effect.runSync(database.query("SELECT 1")) // => "result"
217 * ```
218 *
219 * @category models
220 * @since 2.0.0
221 */
222export interface MemoMap {
223 readonly [MemoMapTypeId]: typeof MemoMapTypeId
224 readonly get: <RIn, E, ROut>(
225 layer: Layer<ROut, E, RIn>,
226 scope: Scope.Scope
227 ) => Effect<Context.Context<ROut>, E, RIn> | undefined
228 readonly getOrElseMemoize: <RIn, E, ROut>(
229 layer: Layer<ROut, E, RIn>,
230 scope: Scope.Scope,
231 build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<ROut>, E, RIn>
232 ) => Effect<Context.Context<ROut>, E, RIn>
233}
234
235type MemoMapEntry = {
236 observers: number
237 readonly deferred: Deferred.Deferred<Context.Context<any>, any>
238 readonly scope: Scope.Closeable
239 readonly finalizer: (exit: Exit.Exit<unknown, unknown>) => Effect<void>
240}
241
242// The finalizer must not retain the caller of `getOrElseMemoize`.
243const makeMemoMapEntry = (memoMap: MemoMapImpl, layer: Layer<any, any, any>): MemoMapEntry => {
244 const entry: MemoMapEntry = {
245 observers: 0,
246 deferred: Deferred.makeUnsafe(),
247 scope: Scope.makeUnsafe(),
248 finalizer: (exit) =>
249 internalEffect.suspend(() => {
250 if (--entry.observers > 0) return internalEffect.void
251 memoMap.map.delete(layer)
252 return Scope.close(entry.scope, exit)
253 })
254 }
255 return entry
256}
257
258// Count and register synchronously so interruption cannot strand an observer.
259// A closed scope cannot own an entry.
260const memoMapObserve = (entry: MemoMapEntry, scope: Scope.Scope): boolean => {
261 if (scope.state._tag === "Closed") return false
262 entry.observers++
263 internalEffect.scopeAddFinalizerUnsafe(scope, {}, entry.finalizer)
264 return true
265}
266
267/**
268 * Returns `true` if the specified value is a `Layer`, `false` otherwise.
269 *
270 * **Example** (Checking whether a value is a layer)
271 *
272 * ```ts import.meta.vitest
273 * import { Context, Effect, Layer } from "effect"
274 *
275 * class Database extends Context.Service<Database, {
276 * readonly query: (sql: string) => Effect.Effect<string>
277 * }>()("Database") {}
278 *
279 * const dbLayer = Layer.succeed(Database, {
280 * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result"))
281 * })
282 * const notALayer = { someProperty: "value" }
283 *
284 * Layer.isLayer(dbLayer) // => true
285 * Layer.isLayer(notALayer) // => false
286 * ```
287 *
288 * @category guards
289 * @since 2.0.0
290 */
291export const isLayer = (u: unknown): u is Layer<unknown, unknown, unknown> => hasProperty(u, TypeId)
292
293const LayerProto = {
294 [TypeId]: {
295 _ROut: identity,
296 _E: identity,
297 _RIn: identity
298 },
299 pipe() {
300 return pipeArguments(this, arguments)
301 }
302}
303
304const fromBuildUnsafe = <ROut, E, RIn>(
305 build: (
306 memoMap: MemoMap,
307 scope: Scope.Scope
308 ) => Effect<Context.Context<ROut>, E, RIn>
309): Layer<ROut, E, RIn> => {
310 const self = Object.create(LayerProto)
311 self.build = build
312 return self
313}
314
315/**
316 * Constructs a `Layer` from a function that uses a `MemoMap` and `Scope` to
317 * build the layer.
318 *
319 * **Details**
320 *
321 * The function receives a `MemoMap` for memoization and a `Scope` for resource management.
322 * A child scope is created, and if the build fails, the child scope is closed.
323 *
324 * **Example** (Constructing a layer from a build function)
325 *
326 * ```ts import.meta.vitest
327 * import { Context, Effect, Layer } from "effect"
328 *
329 * class Database extends Context.Service<Database, {
330 * readonly query: (sql: string) => Effect.Effect<string>
331 * }>()("Database") {}
332 *
333 * const databaseLayer = Layer.fromBuild(() =>
334 * Effect.sync(() =>
335 * Context.make(Database, {
336 * query: (sql: string) => Effect.succeed("result")
337 * })
338 * )
339 * )
340 *
341 * const program = Database.use((database) => database.query("SELECT 1"))
342 * Effect.runSync(Effect.provide(program, databaseLayer)) // => "result"
343 * ```
344 *
345 * @category constructors
346 * @since 4.0.0
347 */
348export const fromBuild = <ROut, E, RIn>(
349 build: (
350 memoMap: MemoMap,
351 scope: Scope.Scope
352 ) => Effect<Context.Context<ROut>, E, RIn>
353): Layer<ROut, E, RIn> =>
354 fromBuildUnsafe((memoMap: MemoMap, scope: Scope.Scope) => {
355 const layerScope = Scope.forkUnsafe(scope)
356 return internalEffect.onExit(
357 build(memoMap, layerScope),
358 (exit) => exit._tag === "Failure" ? Scope.close(layerScope, exit) : internalEffect.void
359 )
360 })
361
362/**
363 * Constructs a `Layer` from a function that uses a `MemoMap` and `Scope` to
364 * build the layer, with automatic memoization.
365 *
366 * **Details**
367 *
368 * This is similar to `fromBuild` but provides automatic memoization of the layer construction.
369 * The layer will be memoized based on the provided `MemoMap`.
370 *
371 * **Example** (Memoizing layer construction)
372 *
373 * ```ts import.meta.vitest
374 * import { Context, Effect, Layer } from "effect"
375 *
376 * class Database extends Context.Service<Database, {
377 * readonly query: (sql: string) => Effect.Effect<string>
378 * }>()("Database") {}
379 *
380 * const databaseLayer = Layer.fromBuildMemo(() =>
381 * Effect.sync(() =>
382 * Context.make(Database, {
383 * query: (sql: string) => Effect.succeed("result")
384 * })
385 * )
386 * )
387 *
388 * const program = Database.use((database) => database.query("SELECT 1"))
389 * Effect.runSync(Effect.provide(program, databaseLayer)) // => "result"
390 * ```
391 *
392 * @category constructors
393 * @since 4.0.0
394 */
395export const fromBuildMemo = <ROut, E, RIn>(
396 build: (
397 memoMap: MemoMap,
398 scope: Scope.Scope
399 ) => Effect<Context.Context<ROut>, E, RIn>
400): Layer<ROut, E, RIn> => {
401 const self: Layer<ROut, E, RIn> = fromBuild((memoMap, scope) => memoMap.getOrElseMemoize(self, scope, build))
402 return self
403}
404
405class MemoMapImpl implements MemoMap {
406 get [MemoMapTypeId](): typeof MemoMapTypeId {
407 return MemoMapTypeId
408 }
409
410 readonly parent: MemoMap | undefined
411
412 constructor(parent?: MemoMap) {
413 this.parent = parent
414 }
415
416 readonly map = new Map<Layer<any, any, any>, MemoMapEntry>()
417
418 get<RIn, E, ROut>(
419 layer: Layer<ROut, E, RIn>,
420 scope: Scope.Scope
421 ): Effect<Context.Context<ROut>, E, RIn> | undefined {
422 const local = this.map.get(layer)
423 if (local) {
424 memoMapObserve(local, scope)
425 return local.deferred.effect ?? Deferred.await(local.deferred)
426 }
427 return this.parent?.get(layer, scope)
428 }
429
430 getOrElseMemoize<RIn, E, ROut>(
431 layer: Layer<ROut, E, RIn>,
432 scope: Scope.Scope,
433 build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<ROut>, E, RIn>
434 ): Effect<Context.Context<ROut>, E, RIn> {
435 return internalEffect.suspend(() => {
436 // Install the exit handler before publishing an entry: it must complete
437 // the Deferred even if the first requester is interrupted.
438 let deferred: Deferred.Deferred<Context.Context<ROut>, E> | undefined
439 return internalEffect.onExitPrimitive(
440 internalEffect.suspend(() => {
441 const existing = this.get(layer, scope)
442 if (existing) return existing
443 const entry = makeMemoMapEntry(this, layer)
444 // A closed scope cannot own a shared entry; build in that scope instead.
445 if (!memoMapObserve(entry, scope)) return build(this, scope)
446 deferred = entry.deferred
447 this.map.set(layer, entry)
448 return build(this, entry.scope)
449 }),
450 (exit) => {
451 if (deferred) Deferred.doneUnsafe(deferred, exit)
452 }
453 )
454 })
455 }
456}
457
458/**
459 * Constructs a `MemoMap` synchronously so it can be used to build additional layers.
460 *
461 * **Example** (Creating a memo map unsafely)
462 *
463 * ```ts import.meta.vitest
464 * import { Context, Effect, Layer } from "effect"
465 *
466 * class Database extends Context.Service<Database, {
467 * readonly query: (sql: string) => Effect.Effect<string>
468 * }>()("Database") {}
469 *
470 * // Create a memo map for manual layer building
471 * const program = Effect.gen(function*() {
472 * const memoMap = Layer.makeMemoMapUnsafe()
473 * const scope = yield* Effect.scope
474 *
475 * const dbLayer = Layer.succeed(Database, {
476 * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result"))
477 * })
478 * const context = yield* Layer.buildWithMemoMap(dbLayer, memoMap, scope)
479 *
480 * return Context.get(context, Database)
481 * })
482 *
483 * const database = Effect.runSync(Effect.scoped(program))
484 * Effect.runSync(database.query("SELECT 1")) // => "result"
485 * ```
486 *
487 * @category constructors
488 * @since 4.0.0
489 */
490export const makeMemoMapUnsafe = (): MemoMap => new MemoMapImpl()
491
492/**
493 * Constructs a child `MemoMap` synchronously, allowing it to reuse layers
494 * already memoized in the parent while isolating any new layer allocations to
495 * the child map.
496 *
497 * **When to use**
498 *
499 * Use to synchronously fork a memo map for manual layer building when child
500 * builds should see parent memoized layers without writing newly built layers
501 * back to the parent.
502 *
503 * @see {@link forkMemoMap} for allocating the child memo map inside `Effect`
504 * @see {@link makeMemoMapUnsafe} for creating a root memo map without a parent
505 *
506 * @category constructors
507 * @since 4.0.0
508 */
509export const forkMemoMapUnsafe = (parent: MemoMap): MemoMap => new MemoMapImpl(parent)
510
511/**
512 * Constructs a `MemoMap` effectfully so it can be used to build additional layers.
513 *
514 * **Example** (Creating a memo map in an effect)
515 *
516 * ```ts import.meta.vitest
517 * import { Context, Effect, Layer } from "effect"
518 *
519 * class Database extends Context.Service<Database, {
520 * readonly query: (sql: string) => Effect.Effect<string>
521 * }>()("Database") {}
522 *
523 * // Create a memo map safely within an Effect
524 * const program = Effect.gen(function*() {
525 * const memoMap = yield* Layer.makeMemoMap
526 * const scope = yield* Effect.scope
527 *
528 * const dbLayer = Layer.succeed(Database, {
529 * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result"))
530 * })
531 * const context = yield* Layer.buildWithMemoMap(dbLayer, memoMap, scope)
532 *
533 * return Context.get(context, Database)
534 * })
535 *
536 * const database = Effect.runSync(Effect.scoped(program))
537 * Effect.runSync(database.query("SELECT 1")) // => "result"
538 * ```
539 *
540 * @category constructors
541 * @since 2.0.0
542 */
543export const makeMemoMap: Effect<MemoMap> = internalEffect.sync(makeMemoMapUnsafe)
544
545/**
546 * Constructs a child `MemoMap` effectfully, allowing it to reuse layers already
547 * memoized in the parent while isolating any new layer allocations to the child
548 * map.
549 *
550 * **When to use**
551 *
552 * Use when a layer build should inherit already memoized layers from an
553 * existing `MemoMap` while keeping newly memoized layers out of the parent map.
554 *
555 * @see {@link makeMemoMap} for creating a root memo map in an `Effect`
556 * @see {@link forkMemoMapUnsafe} for the synchronous constructor variant
557 * @see {@link buildWithMemoMap} for building layers with an explicit memo map
558 *
559 * @category constructors
560 * @since 4.0.0
561 */
562export const forkMemoMap = (parent: MemoMap): Effect<MemoMap> => internalEffect.sync(() => forkMemoMapUnsafe(parent))
563
564/**
565 * Context service for the current `MemoMap` used in layer construction.
566 *
567 * **When to use**
568 *
569 * Use when building custom layer operations that need to access the current
570 * memoization map from the fiber context.
571 *
572 * **Details**
573 *
574 * This service wraps a `MemoMap` as a `Context.Service`, making it available
575 * for dependency injection during layer construction.
576 *
577 * @see {@link MemoMap} the memoization map type wrapped by this service
578 *
579 * @category services
580 * @since 3.13.0
581 */
582export class CurrentMemoMap extends Context.Service<CurrentMemoMap, MemoMap>()("effect/Layer/CurrentMemoMap") {
583 static forkOrCreate<Services>(self: Context.Context<Services>): MemoMap {
584 const current = Context.getOrUndefined(self, CurrentMemoMap)
585 return current ? forkMemoMapUnsafe(current) : makeMemoMapUnsafe()
586 }
587}
588
589/**
590 * Builds a layer into an `Effect` value, using the specified `MemoMap` to memoize
591 * the layer construction.
592 *
593 * **Example** (Building layers with an explicit memo map)
594 *
595 * ```ts import.meta.vitest
596 * import { Context, Effect, Layer } from "effect"
597 *
598 * class Database extends Context.Service<Database, {
599 * readonly query: (sql: string) => Effect.Effect<string>
600 * }>()("Database") {}
601 *
602 * class Logger extends Context.Service<Logger, {
603 * readonly log: (msg: string) => Effect.Effect<void>
604 * }>()("Logger") {}
605 *
606 * const logs: Array<string> = []
607 *
608 * // Build layers with explicit memoization control
609 * const program = Effect.gen(function*() {
610 * const memoMap = yield* Layer.makeMemoMap
611 * const scope = yield* Effect.scope
612 *
613 * // Build database layer with memoization
614 * const dbLayer = Layer.succeed(Database, {
615 * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result"))
616 * })
617 * const dbContext = yield* Layer.buildWithMemoMap(dbLayer, memoMap, scope)
618 *
619 * // Build logger layer with same memoization (reuses memo if same layer)
620 * const loggerLayer = Layer.succeed(Logger, {
621 * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(msg)))
622 * })
623 * const loggerContext = yield* Layer.buildWithMemoMap(
624 * loggerLayer,
625 * memoMap,
626 * scope
627 * )
628 *
629 * return {
630 * database: Context.get(dbContext, Database),
631 * logger: Context.get(loggerContext, Logger)
632 * }
633 * })
634 *
635 * const services = Effect.runSync(Effect.scoped(program))
636 * Effect.runSync(services.logger.log("ready"))
637 * logs // => ["ready"]
638 * ```
639 *
640 * @category destructors
641 * @since 2.0.0
642 */
643export const buildWithMemoMap: {
644 (
645 memoMap: MemoMap,
646 scope: Scope.Scope
647 ): <RIn, E, ROut>(self: Layer<ROut, E, RIn>) => Effect<Context.Context<ROut>, E, RIn>
648 <RIn, E, ROut>(
649 self: Layer<ROut, E, RIn>,
650 memoMap: MemoMap,
651 scope: Scope.Scope
652 ): Effect<Context.Context<ROut>, E, RIn>
653} = dual(3, <RIn, E, ROut>(
654 self: Layer<ROut, E, RIn>,
655 memoMap: MemoMap,
656 scope: Scope.Scope
657): Effect<Context.Context<ROut>, E, RIn> =>
658 internalEffect.provideService(
659 internalEffect.map(self.build(memoMap, scope), Context.add(CurrentMemoMap, memoMap)),
660 CurrentMemoMap,
661 memoMap
662 ))
663
664/**
665 * Builds a layer into a scoped value.
666 *
667 * **Example** (Building a layer into a context)
668 *
669 * ```ts import.meta.vitest
670 * import { Context, Effect, Layer } from "effect"
671 *
672 * class Database extends Context.Service<Database, {
673 * readonly query: (sql: string) => Effect.Effect<string>
674 * }>()("Database") {}
675 *
676 * // Build a layer to get its services
677 * const program = Effect.gen(function*() {
678 * const dbLayer = Layer.succeed(Database, {
679 * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result"))
680 * })
681 *
682 * // Build the layer into Context - automatically manages scope and memoization
683 * const context = yield* Layer.build(dbLayer)
684 *
685 * // Extract the specific service from the built layer
686 * const database = Context.get(context, Database)
687 *
688 * return yield* database.query("SELECT * FROM users")
689 * })
690 *
691 * Effect.runSync(Effect.scoped(program)) // => "result"
692 * ```
693 *
694 * @category destructors
695 * @since 2.0.0
696 */
697export const build = <RIn, E, ROut>(
698 self: Layer<ROut, E, RIn>
699): Effect<Context.Context<ROut>, E, RIn | Scope.Scope> =>
700 core.withFiber((fiber) =>
701 buildWithMemoMap(
702 self,
703 CurrentMemoMap.forkOrCreate(fiber.context),
704 Context.getUnsafe(fiber.context, Scope.Scope)
705 )
706 )
707
708/**
709 * Builds a layer using an explicit scope.
710 *
711 * **When to use**
712 *
713 * Use to control the lifetime of layer resources with a scope supplied by the
714 * caller.
715 *
716 * **Details**
717 *
718 * Resources created by the layer are released when the supplied scope is
719 * closed, unless a resource extends its own scope.
720 *
721 * **Example** (Building a layer with an explicit scope)
722 *
723 * ```ts import.meta.vitest
724 * import { Context, Effect, Layer, Scope } from "effect"
725 *
726 * class Database extends Context.Service<Database, {
727 * readonly query: (sql: string) => Effect.Effect<string>
728 * }>()("Database") {}
729 *
730 * const logs: Array<string> = []
731 *
732 * // Build a layer with explicit scope control
733 * const program = Effect.gen(function*() {
734 * const scope = yield* Effect.scope
735 *
736 * const dbLayer = Layer.effect(Database, Effect.gen(function*() {
737 * logs.push("Initializing database...")
738 * yield* Scope.addFinalizer(
739 * scope,
740 * Effect.sync(() => logs.push("Database closed"))
741 * )
742 * return { query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result: ${sql}`)) }
743 * }))
744 *
745 * // Build with specific scope - resources tied to this scope
746 * const context = yield* Layer.buildWithScope(dbLayer, scope)
747 * const database = Context.get(context, Database)
748 *
749 * return yield* database.query("SELECT * FROM users")
750 * // Database will be closed when scope is closed
751 * })
752 *
753 * Effect.runSync(Effect.scoped(program)) // => "Result: SELECT * FROM users"
754 * logs // => ["Initializing database...", "Database closed"]
755 * ```
756 *
757 * @category destructors
758 * @since 2.0.0
759 */
760export const buildWithScope: {
761 (scope: Scope.Scope): <RIn, E, ROut>(self: Layer<ROut, E, RIn>) => Effect<Context.Context<ROut>, E, RIn>
762 <RIn, E, ROut>(self: Layer<ROut, E, RIn>, scope: Scope.Scope): Effect<Context.Context<ROut>, E, RIn>
763} = dual(2, <RIn, E, ROut>(
764 self: Layer<ROut, E, RIn>,
765 scope: Scope.Scope
766): Effect<Context.Context<ROut>, E, RIn> =>
767 core.withFiber((fiber) =>
768 buildWithMemoMap(
769 self,
770 CurrentMemoMap.forkOrCreate(fiber.context),
771 scope
772 )
773 ))
774
775/**
776 * Constructs a layer that provides a single service from an already available
777 * value.
778 *
779 * **When to use**
780 *
781 * Use when you need a `Layer` that provides a service from an already
782 * constructed implementation without effectful acquisition.
783 *
784 * **Example** (Creating a layer from a service implementation)
785 *
786 * ```ts import.meta.vitest
787 * import { Context, Effect, Layer } from "effect"
788 *
789 * class Database extends Context.Service<Database, {
790 * readonly query: (sql: string) => Effect.Effect<string>
791 * }>()("Database") {}
792 *
793 * const DatabaseLayer = Layer.succeed(Database, {
794 * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Query result: ${sql}`))
795 * })
796 * const program = Database.use((database) => database.query("SELECT 1"))
797 * Effect.runSync(Effect.provide(program, DatabaseLayer)) // => "Query result: SELECT 1"
798 * ```
799 *
800 * @see {@link sync} for constructing layers from lazy values
801 *
802 * @category constructors
803 * @since 2.0.0
804 */
805export const succeed: {
806 <I, S>(service: Context.Key<I, S>): (resource: S) => Layer<I>
807 <I, S>(service: Context.Key<I, S>, resource: Types.NoInfer<S>): Layer<I>
808} = function() {
809 if (arguments.length === 1) {
810 return (resource: any) => succeedContext(Context.make(arguments[0], resource))
811 }
812 return succeedContext(Context.make(arguments[0], arguments[1]))
813} as any
814
815/**
816 * Constructs a layer that provides all services in an already available
817 * `Context`.
818 *
819 * **When to use**
820 *
821 * Use when you need a `Layer` built from an existing `Context`, including when
822 * you need to provide multiple services at once.
823 *
824 * **Details**
825 *
826 * This is a more general version of `succeed` that allows you to provide
827 * multiple services at once through a `Context`.
828 *
829 * **Example** (Providing multiple services from a context)
830 *
831 * ```ts import.meta.vitest
832 * import { Context, Effect, Layer } from "effect"
833 *
834 * class Database extends Context.Service<Database, {
835 * readonly query: (sql: string) => Effect.Effect<string>
836 * }>()("Database") {}
837 *
838 * class Logger extends Context.Service<Logger, {
839 * readonly log: (msg: string) => Effect.Effect<void>
840 * }>()("Logger") {}
841 *
842 * const logs: Array<string> = []
843 * const context = Context.make(Database, {
844 * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result"))
845 * }).pipe(
846 * Context.add(Logger, {
847 * log: (msg: string) => Effect.sync(() => logs.push(msg))
848 * })
849 * )
850 *
851 * const layer = Layer.succeedContext(context)
852 * const program = Logger.use((logger) => logger.log("ready"))
853 * Effect.runSync(Effect.provide(program, layer))
854 * logs // => ["ready"]
855 * ```
856 *
857 * @see {@link succeed} for providing a single service from a value
858 *
859 * @category constructors
860 * @since 2.0.0
861 */
862export const succeedContext = <A>(context: Context.Context<A>): Layer<A> =>
863 fromBuildUnsafe(constant(internalEffect.succeed(context)))
864
865/**
866 * An empty layer that provides no services, cannot fail, has no requirements,
867 * and performs no construction or finalization work.
868 *
869 * **When to use**
870 *
871 * Use as the no-op branch when conditionally composing layers.
872 *
873 * **Example** (Disabling optional lifecycle work)
874 *
875 * ```ts import.meta.vitest
876 * import { Context, Effect, Layer, Option } from "effect"
877 *
878 * const Service = Context.Service<string>("Service")
879 * const context = Effect.runSync(Effect.scoped(Layer.build(Layer.empty)))
880 * Context.getOption(context, Service) // => Option.none()
881 * ```
882 *
883 * @see {@link effectDiscard} for running an effect while providing no services
884 *
885 * @category constructors
886 * @since 2.0.0
887 */
888export const empty: Layer<never> = succeedContext(Context.empty())
889
890/**
891 * Constructs a layer lazily that provides a single service.
892 *
893 * **When to use**
894 *
895 * Use when you need a `Layer` that provides one service whose value is created
896 * synchronously, but creation should be deferred until the layer is built.
897 *
898 * **Details**
899 *
900 * This is a lazy version of `succeed` where the service value is computed
901 * synchronously only when the layer is built.
902 *
903 * **Example** (Lazily providing a service)
904 *
905 * ```ts import.meta.vitest
906 * import { Context, Effect, Layer } from "effect"
907 *
908 * class Database extends Context.Service<Database, {
909 * readonly query: (sql: string) => Effect.Effect<string>
910 * }>()("Database") {}
911 *
912 * const layer = Layer.sync(Database, () => ({
913 * query: (sql: string) => Effect.succeed(`Query: ${sql}`)
914 * }))
915 * const program = Database.use((database) => database.query("SELECT 1"))
916 * Effect.runSync(Effect.provide(program, layer)) // => "Query: SELECT 1"
917 * ```
918 *
919 * @see {@link succeed} for constructing layers from static values
920 *
921 * @category constructors
922 * @since 2.0.0
923 */
924export const sync: {
925 <I, S>(service: Context.Key<I, S>): (evaluate: LazyArg<S>) => Layer<I>
926 <I, S>(service: Context.Key<I, S>, evaluate: LazyArg<Types.NoInfer<S>>): Layer<I>
927} = function() {
928 if (arguments.length === 1) {
929 return (evaluate: LazyArg<any>) => syncContext(() => Context.make(arguments[0], evaluate()))
930 }
931 return syncContext(() => Context.make(arguments[0], arguments[1]()))
932} as any
933
934/**
935 * Constructs a layer lazily that provides all services in a `Context`.
936 *
937 * **When to use**
938 *
939 * Use when you need a `Layer` that creates multiple services synchronously but
940 * defers that work until the layer is built.
941 *
942 * **Details**
943 *
944 * This is a lazy version of `succeedContext` where the `Context` is computed
945 * synchronously only when the layer is built.
946 *
947 * **Example** (Lazily providing a context)
948 *
949 * ```ts import.meta.vitest
950 * import { Context, Effect, Layer } from "effect"
951 *
952 * class Database extends Context.Service<Database, {
953 * readonly query: (sql: string) => Effect.Effect<string>
954 * }>()("Database") {}
955 *
956 * const layer = Layer.syncContext(() =>
957 * Context.make(Database, {
958 * query: (sql: string) => Effect.succeed(`Query: ${sql}`)
959 * })
960 * )
961 * const program = Database.use((database) => database.query("SELECT 1"))
962 * Effect.runSync(Effect.provide(program, layer)) // => "Query: SELECT 1"
963 * ```
964 *
965 * @see {@link sync} for lazily providing a single service
966 * @see {@link succeedContext} for providing an already available context
967 *
968 * @category constructors
969 * @since 2.0.0
970 */
971export const syncContext = <A>(evaluate: LazyArg<Context.Context<A>>): Layer<A> =>
972 fromBuildMemo(constant(internalEffect.sync(evaluate)))
973
974/**
975 * Constructs a layer from an effect that produces a single service.
976 *
977 * **When to use**
978 *
979 * Use when you need to construct a `Layer`-provided service with an `Effect`,
980 * dependencies, or scoped resource acquisition.
981 *
982 * **Details**
983 *
984 * This allows you to create a `Layer` from an `Effect` that produces a service.
985 * The `Effect` is executed in the scope of the layer, allowing for proper
986 * resource management.
987 *
988 * **Example** (Creating a layer from an effect)
989 *
990 * ```ts import.meta.vitest
991 * import { Context, Effect, Layer } from "effect"
992 *
993 * class Database extends Context.Service<Database, {
994 * readonly query: (sql: string) => Effect.Effect<string>
995 * }>()("Database") {}
996 *
997 * const layer = Layer.effect(Database,
998 * Effect.sync(() => ({
999 * query: (sql: string) => Effect.succeed(`Query: ${sql}`)
1000 * }))
1001 * )
1002 * const program = Database.use((database) => database.query("SELECT 1"))
1003 * Effect.runSync(Effect.provide(program, layer)) // => "Query: SELECT 1"
1004 * ```
1005 *
1006 * @see {@link effectContext} for effectfully providing multiple services
1007 * @see {@link effectDiscard} for running construction work without providing services
1008 *
1009 * @category constructors
1010 * @since 2.0.0
1011 */
1012export const effect: {
1013 <I, S>(service: Context.Key<I, S>): <E, R>(
1014 effect: Effect<S, E, R>
1015 ) => Layer<I, E, Exclude<R, Scope.Scope>>
1016 <I, S, E, R>(
1017 service: Context.Key<I, S>,
1018 effect: Effect<Types.NoInfer<S>, E, R>
1019 ): Layer<I, E, Exclude<R, Scope.Scope>>
1020} = function() {
1021 if (arguments.length === 1) {
1022 return (effect: any) => effectImpl(arguments[0], effect)
1023 }
1024 return effectImpl(arguments[0], arguments[1])
1025} as any
1026
1027const effectImpl = <I, S, E, R>(
1028 service: Context.Key<I, S>,
1029 effect: Effect<S, E, R>
1030): Layer<I, E, Exclude<R, Scope.Scope>> =>
1031 effectContext(internalEffect.map(effect, (value) => Context.make(service, value)))
1032
1033/**
1034 * Constructs a layer from an effect that produces all services in a `Context`.
1035 *
1036 * **When to use**
1037 *
1038 * Use when you need a `Layer` that effectfully constructs a `Context` with
1039 * multiple services.
1040 *
1041 * **Details**
1042 *
1043 * This allows you to create a `Layer` from an effectful computation that
1044 * returns multiple services. The `Effect` is executed in the scope of the
1045 * layer.
1046 *
1047 * **Example** (Creating a layer from an effectful context)
1048 *
1049 * ```ts import.meta.vitest
1050 * import { Context, Effect, Layer } from "effect"
1051 *
1052 * class Database extends Context.Service<
1053 * Database,
1054 * { readonly query: (sql: string) => Effect.Effect<string> }
1055 * >()("Database") {}
1056 *
1057 * const layer = Layer.effectContext(
1058 * Effect.succeed(Context.make(Database, {
1059 * query: (sql: string) => Effect.succeed(`Query: ${sql}`)
1060 * }))
1061 * )
1062 * const program = Database.use((database) => database.query("SELECT 1"))
1063 * Effect.runSync(Effect.provide(program, layer)) // => "Query: SELECT 1"
1064 * ```
1065 *
1066 * @see {@link effect} for effectfully providing a single service
1067 *
1068 * @category constructors
1069 * @since 2.0.0
1070 */
1071export const effectContext = <A, E, R>(
1072 effect: Effect<Context.Context<A>, E, R>
1073): Layer<A, E, Exclude<R, Scope.Scope>> => fromBuildMemo((_, scope) => Scope.provide(effect, scope))
1074
1075/**
1076 * Constructs a layer from an effect, discarding its value and providing no
1077 * services.
1078 *
1079 * **When to use**
1080 *
1081 * Use when layer construction should run an Effect for its side effects while providing no
1082 * services.
1083 *
1084 * **Example** (Running an effect during layer construction)
1085 *
1086 * ```ts import.meta.vitest
1087 * import { Effect, Layer } from "effect"
1088 *
1089 * const logs: Array<string> = []
1090 * const initLayer = Layer.effectDiscard(
1091 * Effect.sync(() => {
1092 * logs.push("Initializing application...")
1093 * })
1094 * )
1095 * Effect.runSync(Effect.scoped(Layer.build(initLayer)))
1096 * logs // => ["Initializing application..."]
1097 * ```
1098 *
1099 * @see {@link empty} for a no-op layer that performs no construction work
1100 *
1101 * @category constructors
1102 * @since 2.0.0
1103 */
1104export const effectDiscard = <X, E, R>(effect: Effect<X, E, R>): Layer<never, E, Exclude<R, Scope.Scope>> =>
1105 effectContext(internalEffect.as(effect, Context.empty()))
1106
1107/**
1108 * Constructs a layer lazily using the specified factory.
1109 *
1110 * **Details**
1111 *
1112 * The factory is evaluated only when the suspended layer is first built, and
1113 * the result is memoized with normal layer sharing semantics.
1114 *
1115 * **Example** (Choosing a layer lazily)
1116 *
1117 * ```ts import.meta.vitest
1118 * import { Context, Effect, Layer } from "effect"
1119 *
1120 * class Config extends Context.Service<Config, string>()("Config") {}
1121 *
1122 * const useProd = true
1123 *
1124 * const layer = Layer.suspend(() =>
1125 * useProd
1126 * ? Layer.succeed(Config, "https://api.example.com")
1127 * : Layer.succeed(Config, "http://localhost:3000")
1128 * )
1129 * Effect.runSync(Effect.provide(Config, layer)) // => "https://api.example.com"
1130 * ```
1131 *
1132 * @category constructors
1133 * @since 2.0.0
1134 */
1135export const suspend = <A, E, R>(evaluate: LazyArg<Layer<A, E, R>>): Layer<A, E, R> =>
1136 fromBuildMemo((memoMap, scope) => internalEffect.suspend(() => evaluate().build(memoMap, scope)))
1137
1138const unwrapKey = Context.Service<Layer<any, any, any>>("effect/Layer/unwrap")
1139
1140/**
1141 * Unwraps a `Layer` from an `Effect`, flattening the nested structure.
1142 *
1143 * **When to use**
1144 *
1145 * Use when you have an `Effect` that produces a `Layer` and you want to
1146 * use that layer directly.
1147 *
1148 * **Details**
1149 *
1150 * The resulting Layer will have the combined error and dependency types from
1151 * both the outer Effect and the inner Layer.
1152 *
1153 * **Example** (Unwrapping an effectful layer)
1154 *
1155 * ```ts import.meta.vitest
1156 * import { Context, Effect, Layer } from "effect"
1157 *
1158 * class Database extends Context.Service<Database, {
1159 * readonly query: (sql: string) => Effect.Effect<string>
1160 * }>()("Database") {}
1161 *
1162 * const layerEffect = Effect.succeed(
1163 * Layer.succeed(Database, { query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) })
1164 * )
1165 *
1166 * const unwrappedLayer = Layer.unwrap(layerEffect)
1167 * const program = Database.use((database) => database.query("SELECT 1"))
1168 * Effect.runSync(Effect.provide(program, unwrappedLayer)) // => "result"
1169 * ```
1170 *
1171 * @category converting
1172 * @since 4.0.0
1173 */
1174export const unwrap = <A, E1, R1, E, R>(
1175 self: Effect<Layer<A, E1, R1>, E, R>
1176): Layer<A, E | E1, R1 | Exclude<R, Scope.Scope>> => flatMap(effect(unwrapKey)(self), Context.get(unwrapKey))
1177
1178const mergeAllEffect = <Layers extends [Layer<never, any, any>, ...Array<Layer<never, any, any>>]>(
1179 layers: Layers,
1180 memoMap: MemoMap,
1181 scope: Scope.Scope
1182): Effect<
1183 Context.Context<{ [k in keyof Layers]: Success<Layers[k]> }[number]>,
1184 { [k in keyof Layers]: Error<Layers[k]> }[number],
1185 { [k in keyof Layers]: Services<Layers[k]> }[number]
1186> => {
1187 const parentScope = Scope.forkUnsafe(scope, "parallel")
1188 return internalEffect.forEach(layers, (layer) => layer.build(memoMap, Scope.forkUnsafe(parentScope, "sequential")), {
1189 concurrency: layers.length
1190 }).pipe(
1191 internalEffect.map((context) => Context.mergeAll(...(context as any)))
1192 )
1193}
1194
1195/**
1196 * Combines all the provided layers concurrently, creating a new layer with
1197 * merged input, error, and output types.
1198 *
1199 * **When to use**
1200 *
1201 * Use when you need to combine multiple independent layers.
1202 *
1203 * **Details**
1204 *
1205 * All layers are built concurrently, and their outputs are merged into a single layer.
1206 *
1207 * If multiple merged layers depend on the same layer value, that dependency is
1208 * shared by default. Reuse a named layer value when you want services to share
1209 * the same resource, such as one database pool.
1210 *
1211 * **Example** (Merging independent layers)
1212 *
1213 * ```ts import.meta.vitest
1214 * import { Context, Effect, Layer } from "effect"
1215 *
1216 * class Database extends Context.Service<Database, {
1217 * readonly query: (sql: string) => Effect.Effect<string>
1218 * }>()("Database") {}
1219 *
1220 * class Logger extends Context.Service<Logger, {
1221 * readonly log: (msg: string) => Effect.Effect<void>
1222 * }>()("Logger") {}
1223 *
1224 * const dbLayer = Layer.succeed(Database, {
1225 * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result"))
1226 * })
1227 * const logs: Array<string> = []
1228 * const loggerLayer = Layer.succeed(Logger, {
1229 * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(msg)))
1230 * })
1231 *
1232 * const mergedLayer = Layer.mergeAll(dbLayer, loggerLayer)
1233 * const program = Logger.use((logger) => logger.log("ready"))
1234 * Effect.runSync(Effect.provide(program, mergedLayer))
1235 * logs // => ["ready"]
1236 * ```
1237 *
1238 * @see {@link merge} for merging one layer with another layer or array
1239 *
1240 * @category zipping
1241 * @since 2.0.0
1242 */
1243export const mergeAll = <Layers extends [Layer<never, any, any>, ...Array<Layer<never, any, any>>]>(
1244 ...layers: Layers
1245): Layer<
1246 Success<Layers[number]>,
1247 Error<Layers[number]>,
1248 Services<Layers[number]>
1249> => fromBuild((memoMap, scope) => mergeAllEffect(layers, memoMap, scope))
1250
1251/**
1252 * Merges this layer with another layer concurrently, producing a new layer with
1253 * combined input, error, and output types.
1254 *
1255 * **When to use**
1256 *
1257 * Use to combine an existing `Layer` with another `Layer` or an array of
1258 * layers while preserving pipeline style.
1259 *
1260 * **Details**
1261 *
1262 * This is a binary version of `mergeAll` that merges exactly two layers or one
1263 * layer with an array of layers. The layers are built concurrently and their
1264 * outputs are combined.
1265 *
1266 * **Example** (Merging two layers)
1267 *
1268 * ```ts import.meta.vitest
1269 * import { Context, Effect, Layer } from "effect"
1270 *
1271 * class Database extends Context.Service<Database, {
1272 * readonly query: (sql: string) => Effect.Effect<string>
1273 * }>()("Database") {}
1274 *
1275 * class Logger extends Context.Service<Logger, {
1276 * readonly log: (msg: string) => Effect.Effect<void>
1277 * }>()("Logger") {}
1278 *
1279 * const dbLayer = Layer.succeed(Database, {
1280 * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result"))
1281 * })
1282 * const loggerLayer = Layer.succeed(Logger, {
1283 * log: Effect.fn("Logger.log")((_msg: string) => Effect.void)
1284 * })
1285 *
1286 * const mergedLayer = Layer.merge(dbLayer, loggerLayer)
1287 * const program = Database.use((database) => database.query("SELECT 1"))
1288 * Effect.runSync(Effect.provide(program, mergedLayer)) // => "result"
1289 * ```
1290 *
1291 * @see {@link mergeAll} for merging several layers at once
1292 *
1293 * @category zipping
1294 * @since 2.0.0
1295 */
1296export const merge: {
1297 <RIn, E, ROut>(
1298 that: Layer<ROut, E, RIn>
1299 ): <RIn2, E2, ROut2>(self: Layer<ROut2, E2, RIn2>) => Layer<ROut | ROut2, E | E2, RIn | RIn2>
1300 <const Layers extends [Any, ...Array<Any>]>(
1301 that: Layers
1302 ): <A, E, R>(
1303 self: Layer<A, E, R>
1304 ) => Layer<
1305 A | Success<Layers[number]>,
1306 E | Error<Layers[number]>,
1307 | Services<Layers[number]>
1308 | R
1309 >
1310 <RIn2, E2, ROut2, RIn, E, ROut>(
1311 self: Layer<ROut2, E2, RIn2>,
1312 that: Layer<ROut, E, RIn>
1313 ): Layer<ROut | ROut2, E | E2, RIn | RIn2>
1314 <A, E, R, const Layers extends [Any, ...Array<Any>]>(
1315 self: Layer<A, E, R>,
1316 that: Layers
1317 ): Layer<
1318 A | Success<Layers[number]>,
1319 E | Error<Layers[number]>,
1320 | Services<Layers[number]>
1321 | R
1322 >
1323} = dual(2, (
1324 self: Layer<any, any, any>,
1325 that: Layer<any, any, any> | ReadonlyArray<Layer<any, any, any>>
1326) => mergeAll(self, ...(Array.isArray(that) ? that : [that])))
1327
1328const provideWith = (
1329 self: Layer<any, any, any>,
1330 that: Layer<any, any, any> | ReadonlyArray<Layer<any, any, any>>,
1331 f: (
1332 selfContext: Context.Context<any>,
1333 thatContext: Context.Context<any>
1334 ) => Context.Context<any>
1335) =>
1336 fromBuild((memoMap, scope) =>
1337 internalEffect.flatMap(
1338 Array.isArray(that)
1339 ? mergeAllEffect(that as NonEmptyArray<Layer<any, any, any>>, memoMap, scope)
1340 : (that as Layer<any, any, any>).build(memoMap, scope),
1341 (context) =>
1342 self.build(memoMap, scope).pipe(
1343 internalEffect.provideContext(context),
1344 internalEffect.map((merged) => f(merged, context))
1345 )
1346 )
1347 )
1348
1349/**
1350 * Feeds the output services of the dependency layer into the requirements of
1351 * this layer, returning a layer that only provides the services from this layer.
1352 *
1353 * **When to use**
1354 *
1355 * Use when you need to hide an implementation dependency layer from callers.
1356 *
1357 * **Details**
1358 *
1359 * In `serviceLayer.pipe(Layer.provide(dependencyLayer))`, the dependency layer is
1360 * built first and is used to satisfy the requirements of `serviceLayer`.
1361 *
1362 * **Example** (Providing layer dependencies)
1363 *
1364 * ```ts import.meta.vitest
1365 * import { Context, Effect, Layer } from "effect"
1366 *
1367 * class Database extends Context.Service<Database, {
1368 * readonly query: (sql: string) => Effect.Effect<string>
1369 * }>()("Database") {}
1370 *
1371 * class UserService extends Context.Service<UserService, {
1372 * readonly getUser: (id: string) => Effect.Effect<{
1373 * id: string
1374 * name: string
1375 * }>
1376 * }>()("UserService") {}
1377 *
1378 * class Logger extends Context.Service<Logger, {
1379 * readonly log: (msg: string) => Effect.Effect<void>
1380 * }>()("Logger") {}
1381 *
1382 * // Create dependency layers
1383 * const databaseLayer = Layer.succeed(Database, {
1384 * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
1385 * })
1386 *
1387 * const logs: Array<string> = []
1388 * const loggerLayer = Layer.succeed(Logger, {
1389 * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(`[LOG] ${msg}`)))
1390 * })
1391 *
1392 * // UserService depends on Database and Logger
1393 * const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
1394 * const database = yield* Database
1395 * const logger = yield* Logger
1396 *
1397 * return {
1398 * getUser: Effect.fn("UserService.getUser")(function*(id: string) {
1399 * yield* logger.log(`Looking up user ${id}`)
1400 * const result = yield* database.query(
1401 * `SELECT * FROM users WHERE id = ${id}`
1402 * )
1403 * return { id, name: result }
1404 * })
1405 * }
1406 * }))
1407 *
1408 * // Provide dependencies to UserService layer
1409 * const userServiceWithDependencies = userServiceLayer.pipe(
1410 * Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
1411 * )
1412 *
1413 * // Now UserService layer has no dependencies
1414 * const program = Effect.gen(function*() {
1415 * const userService = yield* UserService
1416 * return yield* userService.getUser("123")
1417 * }).pipe(
1418 * Effect.provide(userServiceWithDependencies)
1419 * )
1420 * Effect.runSync(program) // => { id: "123", name: "DB: SELECT * FROM users WHERE id = 123" }
1421 * logs // => ["[LOG] Looking up user 123"]
1422 * ```
1423 *
1424 * @see {@link provideMerge} for retaining the dependency services
1425 *
1426 * @category providing services
1427 * @since 2.0.0
1428 */
1429export const provide: {
1430 <RIn, E, ROut>(
1431 that: Layer<ROut, E, RIn>
1432 ): <RIn2, E2, ROut2>(self: Layer<ROut2, E2, RIn2>) => Layer<ROut2, E | E2, RIn | Exclude<RIn2, ROut>>
1433 <const Layers extends [Any, ...Array<Any>]>(
1434 that: Layers
1435 ): <A, E, R>(
1436 self: Layer<A, E, R>
1437 ) => Layer<
1438 A,
1439 E | Error<Layers[number]>,
1440 | Services<Layers[number]>
1441 | Exclude<R, Success<Layers[number]>>
1442 >
1443 <RIn2, E2, ROut2, RIn, E, ROut>(
1444 self: Layer<ROut2, E2, RIn2>,
1445 that: Layer<ROut, E, RIn>
1446 ): Layer<ROut2, E | E2, RIn | Exclude<RIn2, ROut>>
1447 <A, E, R, const Layers extends [Any, ...Array<Any>]>(
1448 self: Layer<A, E, R>,
1449 that: Layers
1450 ): Layer<
1451 A,
1452 E | Error<Layers[number]>,
1453 | Services<Layers[number]>
1454 | Exclude<R, Success<Layers[number]>>
1455 >
1456} = dual(2, (
1457 self: Layer<any, any, any>,
1458 that: Layer<any, any, any> | ReadonlyArray<Layer<any, any, any>>
1459) => provideWith(self, that, identity))
1460
1461/**
1462 * Feeds the output services of the dependency layer into the requirements of
1463 * this layer, returning a layer that provides both sets of services.
1464 *
1465 * **When to use**
1466 *
1467 * Use when you need to compose `Layer`s while keeping both the constructed
1468 * service and the dependency used to build it available.
1469 *
1470 * **Details**
1471 *
1472 * Prefer {@link provide} when the dependency should stay private.
1473 *
1474 * **Example** (Providing dependencies while retaining services)
1475 *
1476 * ```ts import.meta.vitest
1477 * import { Context, Effect, Layer } from "effect"
1478 *
1479 * class Database extends Context.Service<Database, {
1480 * readonly query: (sql: string) => Effect.Effect<string>
1481 * }>()("Database") {}
1482 *
1483 * class Logger extends Context.Service<Logger, {
1484 * readonly log: (msg: string) => Effect.Effect<void>
1485 * }>()("Logger") {}
1486 *
1487 * class UserService extends Context.Service<UserService, {
1488 * readonly getUser: (id: string) => Effect.Effect<{
1489 * id: string
1490 * name: string
1491 * }>
1492 * }>()("UserService") {}
1493 *
1494 * // Create dependency layers
1495 * const databaseLayer = Layer.succeed(Database, {
1496 * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
1497 * })
1498 *
1499 * const logs: Array<string> = []
1500 * const loggerLayer = Layer.succeed(Logger, {
1501 * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(`[LOG] ${msg}`)))
1502 * })
1503 *
1504 * // UserService depends on Database and Logger
1505 * const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
1506 * const database = yield* Database
1507 * const logger = yield* Logger
1508 *
1509 * return {
1510 * getUser: Effect.fn("UserService.getUser")(function*(id: string) {
1511 * yield* logger.log(`Looking up user ${id}`)
1512 * const result = yield* database.query(
1513 * `SELECT * FROM users WHERE id = ${id}`
1514 * )
1515 * return { id, name: result }
1516 * })
1517 * }
1518 * }))
1519 *
1520 * // Provide dependencies and merge all services together
1521 * const allServicesLayer = userServiceLayer.pipe(
1522 * Layer.provideMerge(Layer.mergeAll(databaseLayer, loggerLayer))
1523 * )
1524 *
1525 * // Now the resulting layer provides UserService, Database, AND Logger
1526 * const program = Effect.gen(function*() {
1527 * const userService = yield* UserService
1528 * const logger = yield* Logger // Still available!
1529 * const database = yield* Database // Still available!
1530 *
1531 * const user = yield* userService.getUser("123")
1532 * yield* logger.log(`Found user: ${user.name}`)
1533 *
1534 * return user
1535 * }).pipe(
1536 * Effect.provide(allServicesLayer)
1537 * )
1538 * Effect.runSync(program) // => { id: "123", name: "DB: SELECT * FROM users WHERE id = 123" }
1539 * logs // => ["[LOG] Looking up user 123", "[LOG] Found user: DB: SELECT * FROM users WHERE id = 123"]
1540 * ```
1541 *
1542 * @see {@link provide} for keeping dependency services private
1543 *
1544 * @category providing services
1545 * @since 2.0.0
1546 */
1547export const provideMerge: {
1548 <RIn, E, ROut>(
1549 that: Layer<ROut, E, RIn>
1550 ): <RIn2, E2, ROut2>(self: Layer<ROut2, E2, RIn2>) => Layer<ROut | ROut2, E | E2, RIn | Exclude<RIn2, ROut>>
1551 <const Layers extends [Any, ...Array<Any>]>(
1552 that: Layers
1553 ): <A, E, R>(
1554 self: Layer<A, E, R>
1555 ) => Layer<
1556 A | Success<Layers[number]>,
1557 E | Error<Layers[number]>,
1558 | Services<Layers[number]>
1559 | Exclude<R, Success<Layers[number]>>
1560 >
1561 <RIn2, E2, ROut2, RIn, E, ROut>(
1562 self: Layer<ROut2, E2, RIn2>,
1563 that: Layer<ROut, E, RIn>
1564 ): Layer<ROut | ROut2, E | E2, RIn | Exclude<RIn2, ROut>>
1565 <A, E, R, const Layers extends [Any, ...Array<Any>]>(
1566 self: Layer<A, E, R>,
1567 that: Layers
1568 ): Layer<
1569 A | Success<Layers[number]>,
1570 E | Error<Layers[number]>,
1571 | Services<Layers[number]>
1572 | Exclude<R, Success<Layers[number]>>
1573 >
1574} = dual(2, (
1575 self: Layer<any, any, any>,
1576 that: Layer<any, any, any> | ReadonlyArray<Layer<any, any, any>>
1577) =>
1578 provideWith(
1579 self,
1580 that,
1581 (self, that) => Context.merge(that, self)
1582 ))
1583
1584/**
1585 * Constructs a layer dynamically based on the output of this layer.
1586 *
1587 * **Example** (Creating services from layer output)
1588 *
1589 * ```ts import.meta.vitest
1590 * import { Context, Effect, Layer } from "effect"
1591 *
1592 * class Config extends Context.Service<Config, {
1593 * readonly dbUrl: string
1594 * readonly logLevel: string
1595 * }>()("Config") {}
1596 *
1597 * class Database extends Context.Service<Database, {
1598 * readonly query: (sql: string) => Effect.Effect<string>
1599 * }>()("Database") {}
1600 *
1601 * class Logger extends Context.Service<Logger, {
1602 * readonly log: (msg: string) => Effect.Effect<void>
1603 * }>()("Logger") {}
1604 *
1605 * const logs: Array<string> = []
1606 *
1607 * // Base config layer
1608 * const configLayer = Layer.succeed(Config, {
1609 * dbUrl: "postgres://localhost:5432/mydb",
1610 * logLevel: "debug"
1611 * })
1612 *
1613 * // Dynamically create services based on config
1614 * const dynamicServiceLayer = configLayer.pipe(
1615 * Layer.flatMap((context) => {
1616 * const config = Context.get(context, Config)
1617 *
1618 * // Create database layer based on config
1619 * const dbLayer = Layer.succeed(Database, {
1620 * query: Effect.fn("Database.query")((sql: string) =>
1621 * Effect.succeed(
1622 * `Querying ${config.dbUrl}: ${sql}`
1623 * ))
1624 * })
1625 *
1626 * // Create logger layer based on config
1627 * const loggerLayer = Layer.succeed(Logger, {
1628 * log: Effect.fn("Logger.log")((msg: string) =>
1629 * config.logLevel === "debug"
1630 * ? Effect.sync(() => logs.push(`[DEBUG] ${msg}`))
1631 * : Effect.sync(() => logs.push(msg))
1632 * )
1633 * })
1634 *
1635 * // Return combined layer
1636 * return Layer.mergeAll(dbLayer, loggerLayer)
1637 * })
1638 * )
1639 *
1640 * // Use the dynamic services
1641 * const program = Effect.gen(function*() {
1642 * const database = yield* Database
1643 * const logger = yield* Logger
1644 *
1645 * yield* logger.log("Starting database query")
1646 * const result = yield* database.query("SELECT * FROM users")
1647 *
1648 * return result
1649 * }).pipe(
1650 * Effect.provide(dynamicServiceLayer)
1651 * )
1652 * Effect.runSync(program) // => "Querying postgres://localhost:5432/mydb: SELECT * FROM users"
1653 * logs // => ["[DEBUG] Starting database query"]
1654 * ```
1655 *
1656 * @category sequencing
1657 * @since 2.0.0
1658 */
1659export const flatMap: {
1660 <A, A2, E2, R2>(
1661 f: (context: Context.Context<A>) => Layer<A2, E2, R2>
1662 ): <E, R>(self: Layer<A, E, R>) => Layer<A2, E2 | E, R2 | R>
1663 <A, E, R, A2, E2, R2>(
1664 self: Layer<A, E, R>,
1665 f: (context: Context.Context<A>) => Layer<A2, E2, R2>
1666 ): Layer<A2, E | E2, R | R2>
1667} = dual(2, <A, E, R, A2, E2, R2>(
1668 self: Layer<A, E, R>,
1669 f: (context: Context.Context<A>) => Layer<A2, E2, R2>
1670): Layer<A2, E | E2, R | R2> =>
1671 fromBuild((memoMap, scope) =>
1672 internalEffect.flatMap(
1673 self.build(memoMap, scope),
1674 (context) => f(context).build(memoMap, scope)
1675 )
1676 ))
1677
1678/**
1679 * Performs the specified effect if this layer succeeds.
1680 *
1681 * **When to use**
1682 *
1683 * Use to run an effectful observation after a layer has been built
1684 * successfully, such as logging or metrics, without changing the services the
1685 * layer provides.
1686 *
1687 * **Details**
1688 *
1689 * The callback receives the services produced by this layer. Its result is
1690 * discarded, and the original layer output is preserved.
1691 *
1692 * @see {@link tapError} for running an effect when layer construction fails with a typed error
1693 * @see {@link tapCause} for running an effect when layer construction fails with any cause
1694 *
1695 * @category sequencing
1696 * @since 2.0.0
1697 */
1698export const tap: {
1699 <ROut, XR extends ROut, RIn2, E2, X>(
1700 f: (context: Context.Context<XR>) => Effect<X, E2, RIn2>
1701 ): <RIn, E>(self: Layer<ROut, E, RIn>) => Layer<ROut, E | E2, RIn | Exclude<RIn2, Scope.Scope>>
1702 <RIn, E, ROut, XR extends ROut, RIn2, E2, X>(
1703 self: Layer<ROut, E, RIn>,
1704 f: (context: Context.Context<XR>) => Effect<X, E2, RIn2>
1705 ): Layer<ROut, E | E2, RIn | Exclude<RIn2, Scope.Scope>>
1706} = dual(2, <RIn, E, ROut, XR extends ROut, RIn2, E2, X>(
1707 self: Layer<ROut, E, RIn>,
1708 f: (context: Context.Context<XR>) => Effect<X, E2, RIn2>
1709): Layer<ROut, E | E2, RIn | Exclude<RIn2, Scope.Scope>> =>
1710 fromBuild((memoMap, scope) =>
1711 internalEffect.flatMap(
1712 self.build(memoMap, scope),
1713 (context) => Scope.provide(internalEffect.as(f(context as Context.Context<XR>), context), scope)
1714 )
1715 ))
1716
1717/**
1718 * Performs the specified effect if this layer fails.
1719 *
1720 * **When to use**
1721 *
1722 * Use to run logging, metrics, or other effects when layer construction fails
1723 * while preserving the original typed error.
1724 *
1725 * **Details**
1726 *
1727 * The callback receives the typed error. If the callback succeeds, the layer
1728 * still fails with the original error; if the callback fails, that failure is
1729 * added to the layer's error type.
1730 *
1731 * @see {@link tap} for running an effect when layer construction succeeds
1732 * @see {@link tapCause} for inspecting the full failure cause, including defects and interruption
1733 *
1734 * @category sequencing
1735 * @since 2.0.0
1736 */
1737export const tapError: {
1738 <E, _XE extends E, RIn2, E2, X>(
1739 f: (e: Types.NoInfer<E>) => Effect<X, E2, RIn2>
1740 ): <RIn, ROut>(self: Layer<ROut, E, RIn>) => Layer<ROut, E | E2, RIn | Exclude<RIn2, Scope.Scope>>
1741 <E, RIn2, E2, X>(
1742 f: (e: E) => Effect<X, E2, RIn2>
1743 ): <RIn, ROut, E1 extends E = E>(self: Layer<ROut, E1, RIn>) => Layer<ROut, E1 | E2, RIn | Exclude<RIn2, Scope.Scope>>
1744 <RIn, E, _XE extends E, ROut, RIn2, E2, X>(
1745 self: Layer<ROut, E, RIn>,
1746 f: (e: Types.NoInfer<E>) => Effect<X, E2, RIn2>
1747 ): Layer<ROut, E | E2, RIn | Exclude<RIn2, Scope.Scope>>
1748} = dual(2, <RIn, E, ROut, RIn2, E2, X>(
1749 self: Layer<ROut, E, RIn>,
1750 f: (e: E) => Effect<X, E2, RIn2>
1751): Layer<ROut, E | E2, RIn | Exclude<RIn2, Scope.Scope>> =>
1752 fromBuild((memoMap, scope) =>
1753 internalEffect.catch_(
1754 self.build(memoMap, scope),
1755 (error) => Scope.provide(internalEffect.andThen(f(error), internalEffect.fail(error)), scope)
1756 )
1757 ))
1758
1759/**
1760 * Performs the specified effect when this layer fails with any cause.
1761 *
1762 * **When to use**
1763 *
1764 * Use to run diagnostics or reporting when layer construction fails and the
1765 * full `Cause` is needed.
1766 *
1767 * **Details**
1768 *
1769 * The callback receives the layer's `Cause`, so it can inspect typed errors,
1770 * defects, and interruption information. If the callback succeeds, the layer
1771 * fails again with the original cause; if the callback fails, that failure is
1772 * added to the layer's error type.
1773 *
1774 * @see {@link tapError} for observing only typed layer construction errors
1775 * @see {@link catchCause} for recovering from a layer construction failure by switching to another layer
1776 *
1777 * @category sequencing
1778 * @since 4.0.0
1779 */
1780export const tapCause: {
1781 <E, _XE extends E, RIn2, E2, X>(
1782 f: (cause: Cause.Cause<Types.NoInfer<E>>) => Effect<X, E2, RIn2>
1783 ): <RIn, ROut>(self: Layer<ROut, E, RIn>) => Layer<ROut, E | E2, RIn | Exclude<RIn2, Scope.Scope>>
1784 <E, RIn2, E2, X>(
1785 f: (cause: Cause.Cause<E>) => Effect<X, E2, RIn2>
1786 ): <RIn, ROut, E1 extends E = E>(self: Layer<ROut, E1, RIn>) => Layer<ROut, E1 | E2, RIn | Exclude<RIn2, Scope.Scope>>
1787 <RIn, E, _XE extends E, ROut, RIn2, E2, X>(
1788 self: Layer<ROut, E, RIn>,
1789 f: (cause: Cause.Cause<Types.NoInfer<E>>) => Effect<X, E2, RIn2>
1790 ): Layer<ROut, E | E2, RIn | Exclude<RIn2, Scope.Scope>>
1791} = dual(2, <RIn, E, ROut, RIn2, E2, X>(
1792 self: Layer<ROut, E, RIn>,
1793 f: (cause: Cause.Cause<E>) => Effect<X, E2, RIn2>
1794): Layer<ROut, E | E2, RIn | Exclude<RIn2, Scope.Scope>> =>
1795 fromBuild((memoMap, scope) =>
1796 internalEffect.catchCause(
1797 self.build(memoMap, scope),
1798 (cause) => Scope.provide(internalEffect.andThen(f(cause), internalEffect.failCause(cause)), scope)
1799 )
1800 ))
1801
1802/**
1803 * Converts layer construction failures into defects, removing them from the
1804 * layer's error type.
1805 *
1806 * **Details**
1807 *
1808 * Use this only when failures should be treated as unrecoverable defects rather
1809 * than typed errors that callers can handle.
1810 *
1811 * **Example** (Converting layer failures to defects)
1812 *
1813 * ```ts import.meta.vitest
1814 * import { Context, Data, Effect, Exit, Layer } from "effect"
1815 *
1816 * class DatabaseError extends Data.TaggedError("DatabaseError")<{
1817 * message: string
1818 * }> {}
1819 *
1820 * class Database extends Context.Service<Database, {
1821 * readonly query: (sql: string) => Effect.Effect<string>
1822 * }>()("Database") {}
1823 *
1824 * // Layer that can fail during construction
1825 * const error = new DatabaseError({ message: "Connection failed" })
1826 * const flakyDatabaseLayer = Layer.effect(
1827 * Database,
1828 * Effect.fail(error)
1829 * )
1830 *
1831 * // Convert failures to fiber death - removes error from type
1832 * const reliableDatabaseLayer = flakyDatabaseLayer.pipe(Layer.orDie)
1833 *
1834 * // Now the layer type is Layer<Database, never, never> - no error in type
1835 * const program = Effect.gen(function*() {
1836 * const database = yield* Database
1837 * return yield* database.query("SELECT * FROM users")
1838 * }).pipe(
1839 * Effect.provide(reliableDatabaseLayer)
1840 * )
1841 *
1842 * Effect.runSync(Effect.exit(program)) // => Exit.die(error)
1843 * ```
1844 *
1845 * @category error handling
1846 * @since 2.0.0
1847 */
1848export const orDie = <A, E, R>(self: Layer<A, E, R>): Layer<A, never, R> =>
1849 fromBuildUnsafe((memoMap, scope) => internalEffect.orDie(self.build(memoMap, scope)))
1850
1851const catch_: {
1852 <E, RIn2, E2, ROut2>(
1853 onError: (error: E) => Layer<ROut2, E2, RIn2>
1854 ): <RIn, ROut>(self: Layer<ROut, E, RIn>) => Layer<ROut & ROut2, E2, RIn2 | RIn>
1855 <RIn, E, ROut, RIn2, E2, ROut2>(
1856 self: Layer<ROut, E, RIn>,
1857 onError: (error: E) => Layer<ROut2, E2, RIn2>
1858 ): Layer<ROut & ROut2, E2, RIn | RIn2>
1859} = dual(2, <RIn, E, ROut, RIn2, E2, ROut2>(
1860 self: Layer<ROut, E, RIn>,
1861 onError: (error: E) => Layer<ROut2, E2, RIn2>
1862): Layer<ROut & ROut2, E2, RIn | RIn2> =>
1863 fromBuildUnsafe((memoMap, scope) =>
1864 internalEffect.catch_(
1865 self.build(memoMap, scope),
1866 (e) => onError(e).build(memoMap, scope)
1867 ) as any
1868 ))
1869
1870export {
1871 /**
1872 * Recovers from all typed errors by switching to another layer.
1873 *
1874 * **When to use**
1875 *
1876 * Use when every typed `Layer` construction error should use the same
1877 * recovery path.
1878 *
1879 * @see {@link catchTag} for recovering from specific tagged errors
1880 * @see {@link catchCause} for recovering with access to the full cause
1881 *
1882 * @category error handling
1883 * @since 4.0.0
1884 */
1885 catch_ as catch
1886}
1887
1888/**
1889 * Recovers from specific tagged errors.
1890 *
1891 * **When to use**
1892 *
1893 * Use when only some tagged `Layer` construction errors should be recovered.
1894 *
1895 * **Example** (Recovering from tagged layer errors)
1896 *
1897 * ```ts import.meta.vitest
1898 * import { Context, Data, Effect, Layer } from "effect"
1899 *
1900 * class ConfigError extends Data.TaggedError("ConfigError") {}
1901 *
1902 * class Config extends Context.Service<Config, {
1903 * readonly apiUrl: string
1904 * }>()("Config") {}
1905 *
1906 * const configLayer = Layer.effect(Config, Effect.fail(new ConfigError()))
1907 *
1908 * const fallbackLayer = Layer.succeed(Config, { apiUrl: "http://localhost" })
1909 *
1910 * const recovered = configLayer.pipe(
1911 * Layer.catchTag("ConfigError", () => fallbackLayer)
1912 * )
1913 * const program = Config.useSync((config) => config.apiUrl)
1914 * Effect.runSync(Effect.provide(program, recovered)) // => "http://localhost"
1915 * ```
1916 *
1917 * @see {@link catchCause} for recovering with access to the full cause
1918 *
1919 * @category error handling
1920 * @since 4.0.0
1921 */
1922export const catchTag: {
1923 <const K extends Types.Tags<E> | NonEmptyReadonlyArray<Types.Tags<E>>, E, RIn2, E2, ROut2>(
1924 k: K,
1925 f: (
1926 e: Types.ExtractTag<Types.NoInfer<E>, K extends NonEmptyReadonlyArray<string> ? K[number] : K>
1927 ) => Layer<ROut2, E2, RIn2>
1928 ): <RIn, ROut>(
1929 self: Layer<ROut, E, RIn>
1930 ) => Layer<
1931 ROut & ROut2,
1932 E2 | Types.ExcludeTag<E, K extends NonEmptyReadonlyArray<string> ? K[number] : K>,
1933 RIn2 | RIn
1934 >
1935 <
1936 RIn,
1937 E,
1938 ROut,
1939 const K extends Types.Tags<E> | NonEmptyReadonlyArray<Types.Tags<E>>,
1940 RIn2,
1941 E2,
1942 ROut2
1943 >(
1944 self: Layer<ROut, E, RIn>,
1945 k: K,
1946 f: (e: Types.ExtractTag<E, K extends NonEmptyReadonlyArray<string> ? K[number] : K>) => Layer<ROut2, E2, RIn2>
1947 ): Layer<
1948 ROut & ROut2,
1949 E2 | Types.ExcludeTag<E, K extends NonEmptyReadonlyArray<string> ? K[number] : K>,
1950 RIn | RIn2
1951 >
1952} = dual(3, <
1953 RIn,
1954 E,
1955 ROut,
1956 const K extends Types.Tags<E> | NonEmptyReadonlyArray<Types.Tags<E>>,
1957 RIn2,
1958 E2,
1959 ROut2
1960>(
1961 self: Layer<ROut, E, RIn>,
1962 k: K,
1963 f: (e: Types.ExtractTag<E, K extends NonEmptyReadonlyArray<string> ? K[number] : K>) => Layer<ROut2, E2, RIn2>
1964): Layer<ROut & ROut2, E2 | Types.ExcludeTag<E, K extends NonEmptyReadonlyArray<string> ? K[number] : K>, RIn | RIn2> =>
1965 fromBuildUnsafe((memoMap, scope) =>
1966 internalEffect.catchTag(
1967 self.build(memoMap, scope),
1968 k,
1969 (error) => f(error).build(memoMap, scope)
1970 ) as any
1971 ))
1972
1973/**
1974 * Recovers from any failure cause by switching to another layer.
1975 *
1976 * **When to use**
1977 *
1978 * Use when you need `Layer` recovery to inspect more than the typed error,
1979 * such as defects or interruption information.
1980 *
1981 * **Details**
1982 *
1983 * The handler receives the full `Cause` of the failed layer, including typed
1984 * errors, unexpected defects, and interruption information, and returns the
1985 * fallback layer to build instead. Finalizers for resources acquired by the
1986 * failed layer are still run before the fallback layer is acquired.
1987 *
1988 * **Example** (Recovering from layer failures by cause)
1989 *
1990 * ```ts import.meta.vitest
1991 * import { Context, Data, Effect, Layer } from "effect"
1992 *
1993 * class DatabaseError extends Data.TaggedError("DatabaseError")<{
1994 * message: string
1995 * }> {}
1996 *
1997 * class Database extends Context.Service<Database, {
1998 * readonly query: (sql: string) => Effect.Effect<string>
1999 * }>()("Database") {}
2000 *
2001 * const primaryDatabaseLayer = Layer.effect(Database,
2002 * Effect.fail(new DatabaseError({ message: "Primary DB unreachable" }))
2003 * )
2004 *
2005 * const databaseWithFallback = primaryDatabaseLayer.pipe(
2006 * Layer.catchCause(() => {
2007 * return Layer.succeed(Database, {
2008 * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Memory: ${sql}`))
2009 * })
2010 * })
2011 * )
2012 *
2013 * const program = Effect.gen(function*() {
2014 * const database = yield* Database
2015 * return yield* database.query("SELECT * FROM users")
2016 * }).pipe(
2017 * Effect.provide(databaseWithFallback)
2018 * )
2019 *
2020 * await Effect.runPromise(program) // => "Memory: SELECT * FROM users"
2021 * ```
2022 *
2023 * @see {@link catchTag} for recovering from specific tagged errors
2024 *
2025 * @category error handling
2026 * @since 4.0.0
2027 */
2028export const catchCause: {
2029 <E, RIn2, E2, ROut2>(
2030 onError: (cause: Cause.Cause<E>) => Layer<ROut2, E2, RIn2>
2031 ): <RIn, ROut>(self: Layer<ROut, E, RIn>) => Layer<ROut & ROut2, E2, RIn2 | RIn>
2032 <RIn, E, ROut, RIn2, E2, ROut22>(
2033 self: Layer<ROut, E, RIn>,
2034 onError: (cause: Cause.Cause<E>) => Layer<ROut22, E2, RIn2>
2035 ): Layer<ROut & ROut22, E2, RIn | RIn2>
2036} = dual(2, <RIn, E, ROut, RIn2, E2, ROut2>(
2037 self: Layer<ROut, E, RIn>,
2038 onError: (cause: Cause.Cause<E>) => Layer<ROut2, E2, RIn2>
2039): Layer<ROut & ROut2, E2, RIn | RIn2> =>
2040 fromBuildUnsafe((memoMap, scope) =>
2041 internalEffect.catchCause(
2042 self.build(memoMap, scope),
2043 (cause) => onError(cause).build(memoMap, scope)
2044 ) as any
2045 ))
2046
2047/**
2048 * Updates a service in the context with a new implementation.
2049 *
2050 * **When to use**
2051 *
2052 * Use to adapt or extend a service's behavior during the creation of a
2053 * layer.
2054 *
2055 * **Details**
2056 *
2057 * This function modifies the existing implementation of a service in the
2058 * context. It retrieves the current service, applies the provided
2059 * transformation function `f`, and replaces the old service with the
2060 * transformed one.
2061 *
2062 * @category providing services
2063 * @since 3.13.0
2064 */
2065export const updateService: {
2066 <I, A>(
2067 service: Context.Key<I, A>,
2068 f: (a: Types.NoInfer<A>) => A
2069 ): <A1, E1, R1>(layer: Layer<A1, E1, R1>) => Layer<A1, E1, I | R1>
2070 <A1, E1, R1, I, A>(
2071 layer: Layer<A1, E1, R1>,
2072 service: Context.Key<I, A>,
2073 f: (a: Types.NoInfer<A>) => A
2074 ): Layer<A1, E1, I | R1>
2075} = dual(
2076 3,
2077 <A1, E1, R1, I, A>(
2078 layer: Layer<A1, E1, R1>,
2079 service: Context.Key<I, A>,
2080 f: (a: Types.NoInfer<A>) => A
2081 ): Layer<A1, E1, I | R1> => provide(layer, effect(service, internalEffect.map(service, f)))
2082)
2083
2084/**
2085 * Creates a fresh version of this layer that will not be shared.
2086 *
2087 * **When to use**
2088 *
2089 * Use when you need two parts of an application to receive separate instances
2090 * of a resource, such as two independent client sessions.
2091 *
2092 * **Gotchas**
2093 *
2094 * Do not use it just to work around confusing composition. By default, sharing
2095 * the same layer value is usually the desired behavior.
2096 *
2097 * **Example** (Creating non-shared layer instances)
2098 *
2099 * ```ts import.meta.vitest
2100 * import { Context, Effect, Layer, Ref } from "effect"
2101 *
2102 * class Counter extends Context.Service<Counter, {
2103 * readonly id: number
2104 * }>()("Counter") {}
2105 *
2106 * class Left extends Context.Service<Left, {
2107 * readonly counterId: number
2108 * }>()("Left") {}
2109 *
2110 * class Right extends Context.Service<Right, {
2111 * readonly counterId: number
2112 * }>()("Right") {}
2113 *
2114 * const leftLayer = Layer.effect(Left, Effect.gen(function*() {
2115 * const counter = yield* Counter
2116 * return { counterId: counter.id }
2117 * }))
2118 *
2119 * const rightLayer = Layer.effect(Right, Effect.gen(function*() {
2120 * const counter = yield* Counter
2121 * return { counterId: counter.id }
2122 * }))
2123 *
2124 * const compareIds = Effect.gen(function*() {
2125 * const left = yield* Left
2126 * const right = yield* Right
2127 * return left.counterId === right.counterId
2128 * })
2129 *
2130 * const program = Effect.gen(function*() {
2131 * const nextId = yield* Ref.make(0)
2132 *
2133 * const counterLayer = Layer.effect(Counter, Effect.gen(function*() {
2134 * const id = yield* Ref.updateAndGet(nextId, (n) => n + 1)
2135 * return { id }
2136 * }))
2137 *
2138 * const shared = Layer.merge(
2139 * Layer.provide(leftLayer, counterLayer),
2140 * Layer.provide(rightLayer, counterLayer)
2141 * )
2142 *
2143 * const sharedResult = yield* Effect.provide(compareIds, shared)
2144 *
2145 * const freshCounterLayer = Layer.fresh(counterLayer)
2146 * const fresh = Layer.merge(
2147 * Layer.provide(leftLayer, freshCounterLayer),
2148 * Layer.provide(rightLayer, freshCounterLayer)
2149 * )
2150 *
2151 * const freshResult = yield* Effect.provide(compareIds, fresh)
2152 *
2153 * return { shared: sharedResult, fresh: freshResult }
2154 * })
2155 *
2156 * await Effect.runPromise(program) // => { shared: true, fresh: false }
2157 * ```
2158 *
2159 * @category layers
2160 * @since 2.0.0
2161 */
2162export const fresh = <A, E, R>(self: Layer<A, E, R>): Layer<A, E, R> =>
2163 fromBuildUnsafe((_, scope) => self.build(makeMemoMapUnsafe(), scope))
2164
2165/**
2166 * Builds this layer and keeps it alive until the returned effect is interrupted.
2167 *
2168 * **When to use**
2169 *
2170 * Use when you model your entire application as a layer, such as an HTTP
2171 * server.
2172 *
2173 * **Details**
2174 *
2175 * When the returned effect is interrupted, the layer scope is closed and all
2176 * finalizers registered during layer acquisition are run.
2177 *
2178 * **Example** (Launching an application layer)
2179 *
2180 * ```ts import.meta.vitest
2181 * import { Context, Deferred, Effect, Fiber, Layer, Ref } from "effect"
2182 *
2183 * class HttpServer extends Context.Service<HttpServer, {
2184 * readonly port: number
2185 * }>()("HttpServer") {}
2186 *
2187 * const program = Effect.gen(function*() {
2188 * const events = yield* Ref.make<Array<string>>([])
2189 * const started = yield* Deferred.make<void>()
2190 *
2191 * const serverLayer = Layer.effect(HttpServer, Effect.gen(function*() {
2192 * yield* Ref.update(events, (events) => [...events, "Starting HTTP server..."])
2193 * yield* Deferred.succeed(started, undefined)
2194 * return { port: 3000 }
2195 * }))
2196 *
2197 * const fiber = yield* Effect.forkChild(Layer.launch(serverLayer))
2198 * yield* Deferred.await(started)
2199 * yield* Fiber.interrupt(fiber)
2200 * return yield* Ref.get(events)
2201 * })
2202 *
2203 * await Effect.runPromise(program) // => ["Starting HTTP server..."]
2204 * ```
2205 *
2206 * @category converting
2207 * @since 2.0.0
2208 */
2209export const launch = <RIn, E, ROut>(self: Layer<ROut, E, RIn>): Effect<never, E, RIn> =>
2210 internalEffect.scoped(internalEffect.andThen(build(self), internalEffect.never))
2211
2212/**
2213 * A utility type for creating partial mocks of services in testing.
2214 *
2215 * **When to use**
2216 *
2217 * Use to type partial test service implementations where only exercised
2218 * effectful members are stubbed.
2219 *
2220 * **Details**
2221 *
2222 * This type makes `Effect`, `Stream`, and `Channel` values and functions
2223 * returning them optional, while keeping non-effectful properties required.
2224 * This allows you to provide only the methods you need to test while leaving
2225 * others unimplemented.
2226 *
2227 * @see {@link mock} for creating a mock layer from a partial service implementation
2228 *
2229 * @category testing
2230 * @since 3.17.0
2231 */
2232export type PartialEffectful<A extends object> = Types.Simplify<
2233 & {
2234 [K in keyof A as A[K] extends AnyEffectOrStream ? K : never]?: A[K]
2235 }
2236 & {
2237 [K in keyof A as A[K] extends AnyEffectOrStream ? never : K]: A[K]
2238 }
2239>
2240
2241type AnyEffectOrStream =
2242 | Effect<any, any, any>
2243 | Stream.Stream<any, any, any>
2244 | Channel.Channel<any, any, any, any, any, any, any>
2245 | ((...args: any) => Effect<any, any, any>)
2246 | ((...args: any) => Stream.Stream<any, any, any>)
2247 | ((...args: any) => Channel.Channel<any, any, any, any, any, any, any>)
2248
2249/**
2250 * Creates a mock layer for testing purposes. You can provide a partial
2251 * implementation of the service. Any missing members that are `Effect`s,
2252 * `Stream`s, `Channel`s, or functions returning them will fail with an
2253 * unimplemented defect when used.
2254 *
2255 * **Details**
2256 *
2257 * Missing members are represented by a value that can be used as an `Effect`,
2258 * `Stream`, `Channel`, or as a function returning an `Effect`. This lets the
2259 * mock preserve the shape of common service methods while still failing loudly
2260 * when an unimplemented member is exercised.
2261 *
2262 * **Example** (Mocking services for tests)
2263 *
2264 * ```ts import.meta.vitest
2265 * import { Context, Effect, Layer } from "effect"
2266 *
2267 * class UserService extends Context.Service<UserService, {
2268 * readonly config: { apiUrl: string }
2269 * readonly getUser: (
2270 * id: string
2271 * ) => Effect.Effect<{ id: string; name: string }, Error>
2272 * readonly deleteUser: (id: string) => Effect.Effect<void, Error>
2273 * readonly updateUser: (
2274 * id: string,
2275 * data: object
2276 * ) => Effect.Effect<{ id: string; name: string }, Error>
2277 * }>()("UserService") {}
2278 *
2279 * // Create a partial mock - only implement what you need for testing
2280 * const testUserLayer = Layer.mock(UserService, {
2281 * config: { apiUrl: "https://test-api.com" }, // Required - non-Effect property
2282 * getUser: (id: string) => Effect.succeed({ id, name: "Test User" }) // Mock implementation
2283 * // deleteUser and updateUser are omitted - will throw UnimplementedError if called
2284 * })
2285 *
2286 * // Use in tests
2287 * const testProgram = Effect.gen(function*() {
2288 * const userService = yield* UserService
2289 *
2290 * // This works - we provided an implementation
2291 * const user = yield* userService.getUser("123")
2292 *
2293 * // This would throw - we didn't implement deleteUser
2294 * // yield* userService.deleteUser("123") // UnimplementedError
2295 *
2296 * return user.name
2297 * }).pipe(
2298 * Effect.provide(testUserLayer)
2299 * )
2300 * Effect.runSync(testProgram) // => "Test User"
2301 * ```
2302 *
2303 * @category testing
2304 * @since 3.17.0
2305 */
2306export const mock: {
2307 <I, S extends object>(service: Context.Key<I, S>): (implementation: PartialEffectful<S>) => Layer<I>
2308 <I, S extends object>(service: Context.Key<I, S>, implementation: Types.NoInfer<PartialEffectful<S>>): Layer<I>
2309} = function() {
2310 if (arguments.length === 1) {
2311 return (implementation: any) => mockImpl(arguments[0], implementation)
2312 }
2313 return mockImpl(arguments[0], arguments[1])
2314} as any
2315
2316const mockImpl = <I, S extends object>(service: Context.Key<I, S>, implementation: PartialEffectful<S>): Layer<I> =>
2317 succeed(service)(
2318 new Proxy({ ...implementation as object } as S, {
2319 get(target, prop, _receiver) {
2320 if (prop in target) {
2321 return target[prop as keyof S]
2322 }
2323 const prevLimit = getStackTraceLimit()
2324 setStackTraceLimit(2)
2325 const error = new Error(`${service.key}: Unimplemented method "${prop.toString()}"`)
2326 setStackTraceLimit(prevLimit)
2327 error.name = "UnimplementedError"
2328 return makeUnimplemented(error)
2329 },
2330 has: constTrue
2331 })
2332 )
2333
2334const makeUnimplemented = (error: globalThis.Error) => {
2335 const dead = Object.assign(internalEffect.die(error), {
2336 [StreamTypeId]: StreamTypeId,
2337 channel: {
2338 [ChannelTypeId]: ChannelTypeId,
2339 transform: () => internalEffect.succeed(dead),
2340 pipe() {
2341 return pipeArguments(this, arguments)
2342 }
2343 },
2344 [ChannelTypeId]: ChannelTypeId,
2345 transform: () => internalEffect.succeed(dead)
2346 })
2347 function unimplemented() {
2348 return dead
2349 }
2350 // @effect-diagnostics-next-line floatingEffect:off
2351 Object.assign(unimplemented, dead)
2352 Object.setPrototypeOf(unimplemented, Object.getPrototypeOf(dead))
2353 return unimplemented
2354}
2355
2356const StreamTypeId: Stream.TypeId = "~effect/Stream"
2357const ChannelTypeId: Channel.TypeId = "~effect/Channel"
2358
2359// -----------------------------------------------------------------------------
2360// Type constraints
2361// -----------------------------------------------------------------------------
2362
2363/**
2364 * Ensures that a layer's success type extends a given type `ROut`.
2365 *
2366 * **Details**
2367 *
2368 * This function provides compile-time type checking to ensure that the success
2369 * value of a layer conforms to a specific type constraint.
2370 *
2371 * **Example** (Constraining layer success types)
2372 *
2373 * ```ts import.meta.vitest
2374 * import { Context, Layer } from "effect"
2375 *
2376 * const NumberService = Context.Service<number>("Number")
2377 * const numberLayer = Layer.succeed(NumberService, 42)
2378 *
2379 * // Define a constraint that the success type must be a number
2380 * const satisfiesNumber = Layer.satisfiesSuccessType<number>()
2381 *
2382 * // This works - Layer<42, never, never> extends Layer<number, never, never>
2383 * const validLayer = satisfiesNumber(numberLayer)
2384 * ```
2385 *
2386 * @category utility types
2387 * @since 4.0.0
2388 */
2389export const satisfiesSuccessType =
2390 <ROut>() => <ROut2 extends ROut, E, RIn>(layer: Layer<ROut2, E, RIn>): Layer<ROut2, E, RIn> => layer
2391
2392/**
2393 * Ensures that a layer's error type extends a given type `E`.
2394 *
2395 * **Details**
2396 *
2397 * This function provides compile-time type checking to ensure that the error
2398 * type of a layer conforms to a specific type constraint.
2399 *
2400 * **Example** (Constraining layer error types)
2401 *
2402 * ```ts import.meta.vitest
2403 * import { Effect, Layer } from "effect"
2404 *
2405 * const typeErrorLayer = Layer.effectDiscard(Effect.fail(new TypeError("boom")))
2406 *
2407 * // Define a constraint that the error type must be an Error
2408 * const satisfiesError = Layer.satisfiesErrorType<Error>()
2409 *
2410 * // This works - Layer<never, TypeError, never> extends Layer<never, Error, never>
2411 * const validLayer = satisfiesError(typeErrorLayer)
2412 * ```
2413 *
2414 * @category utility types
2415 * @since 4.0.0
2416 */
2417export const satisfiesErrorType =
2418 <E>() => <ROut, E2 extends E, RIn>(layer: Layer<ROut, E2, RIn>): Layer<ROut, E2, RIn> => layer
2419
2420/**
2421 * Ensures that a layer's requirements type extends a given type `R`.
2422 *
2423 * **Details**
2424 *
2425 * This function provides compile-time type checking to ensure that the
2426 * requirements type of a layer conforms to a specific type constraint.
2427 *
2428 * **Example** (Constraining layer service requirements)
2429 *
2430 * ```ts import.meta.vitest
2431 * import { Context, Effect, Layer } from "effect"
2432 *
2433 * const NumberService = Context.Service<number>("Number")
2434 * const numberLayer = Layer.effectDiscard(Effect.asVoid(NumberService))
2435 *
2436 * // Define a constraint that the service requirements must be numbers
2437 * const satisfiesNumber = Layer.satisfiesServicesType<number>()
2438 *
2439 * // This works - Layer<never, never, 42> extends Layer<never, never, number>
2440 * const validLayer = satisfiesNumber(numberLayer)
2441 * ```
2442 *
2443 * @category utility types
2444 * @since 4.0.0
2445 */
2446export const satisfiesServicesType =
2447 <RIn>() => <ROut, E, RIn2 extends RIn>(layer: Layer<ROut, E, RIn2>): Layer<ROut, E, RIn2> => layer
2448
2449// -----------------------------------------------------------------------------
2450// Tracing
2451// -----------------------------------------------------------------------------
2452
2453/**
2454 * Represents options that can be used to control the behavior of spans created
2455 * for layers.
2456 *
2457 * **When to use**
2458 *
2459 * Use to configure tracing metadata, stack trace capture, and `onEnd`
2460 * finalization for spans created by `Layer.span` and `Layer.withSpan` during
2461 * layer construction.
2462 *
2463 * **Details**
2464 *
2465 * Extends `Tracer.SpanOptions` with `onEnd`, which runs when the layer span
2466 * ends as the layer scope closes.
2467 *
2468 * @see {@link span} for creating a layer span
2469 * @see {@link withSpan} for wrapping layer construction in a span
2470 *
2471 * @category options
2472 * @since 4.0.0
2473 */
2474export interface SpanOptions extends Tracer.SpanOptions {
2475 /**
2476 * Runs when the span associated with the layer ends, which happens when the
2477 * layer scope is closed.
2478 */
2479 readonly onEnd?:
2480 | ((span: Tracer.Span, exit: Exit.Exit<unknown, unknown>) => Effect<void>)
2481 | undefined
2482}
2483
2484/**
2485 * Constructs a new `Layer` which creates a span and registers it as the current
2486 * parent span.
2487 *
2488 * **Details**
2489 *
2490 * This allows you to create a traced scope for layer construction, making all
2491 * operations within the layer constructor part of the same trace span. The span
2492 * is automatically ended when the layer's scope is closed. If `onEnd` is
2493 * provided, it receives the span and the layer scope's exit value when the span
2494 * ends.
2495 *
2496 * **Example** (Tracing layer construction with a span)
2497 *
2498 * ```ts import.meta.vitest
2499 * import { Context, Effect, Layer } from "effect"
2500 * import type { Tracer } from "effect"
2501 *
2502 * class Database extends Context.Service<Database, {
2503 * readonly query: (sql: string) => Effect.Effect<string>
2504 * }>()("Database") {}
2505 *
2506 * const logs: Array<string> = []
2507 *
2508 * // Create a traced layer - all operations performed during construction of
2509 * // the `Database` service are part of the "database-init" span
2510 * const databaseLayer = Layer.effect(Database, Effect.gen(function*() {
2511 * // These operations are traced under "database-init" span
2512 * logs.push("Connecting to database")
2513 * logs.push("Database connected")
2514 *
2515 * const parentSpan = yield* Effect.currentParentSpan
2516 * logs.push((parentSpan as Tracer.Span).name)
2517 *
2518 * return {
2519 * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result: ${sql}`))
2520 * }
2521 * })).pipe(Layer.provide(Layer.span("database-init", {
2522 * onEnd: (span, exit) =>
2523 * Effect.sync(() => logs.push(`Span ${span.name} ended with: ${exit._tag}`))
2524 * })))
2525 *
2526 * const program = Database.use((database) => database.query("SELECT 1"))
2527 * Effect.runSync(Effect.provide(program, databaseLayer)) // => "Result: SELECT 1"
2528 * logs // => ["Connecting to database", "Database connected", "database-init", "Span database-init ended with: Success"]
2529 * ```
2530 *
2531 * @category tracing
2532 * @since 2.0.0
2533 */
2534export const span = (
2535 name: string,
2536 options?: SpanOptions
2537): Layer<Tracer.ParentSpan> => {
2538 options = internalTracer.addSpanStackTrace(options)
2539 return effect(
2540 Tracer.ParentSpan,
2541 options?.onEnd
2542 ? internalEffect.tap(
2543 internalEffect.makeSpanScoped(name, options),
2544 (span) => internalEffect.addFinalizer((exit) => options.onEnd!(span, exit))
2545 )
2546 : internalEffect.makeSpanScoped(name, options)
2547 )
2548}
2549
2550/**
2551 * Constructs a layer that provides an existing span as the current parent span.
2552 *
2553 * **Details**
2554 *
2555 * The supplied span is made available through `Tracer.ParentSpan` for layers
2556 * that are built with this layer. This API does not create, end, or close the
2557 * span; the caller remains responsible for the span's lifetime.
2558 *
2559 * **Example** (Referencing an existing parent span)
2560 *
2561 * ```ts import.meta.vitest
2562 * import { Context, Effect, Layer, Tracer } from "effect"
2563 *
2564 * class Database extends Context.Service<Database, {
2565 * readonly spanId: string
2566 * readonly query: (sql: string) => Effect.Effect<string>
2567 * }>()("Database") {}
2568 *
2569 * // Create a layer that uses an existing span as parent
2570 * const databaseLayer = Layer.effect(
2571 * Database,
2572 * Effect.gen(function*() {
2573 * const parentSpan = yield* Effect.currentParentSpan
2574 *
2575 * return {
2576 * spanId: parentSpan.spanId,
2577 * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result: ${sql}`))
2578 * }
2579 * })
2580 * ).pipe(Layer.provide(Layer.parentSpan(Tracer.externalSpan({
2581 * spanId: "42",
2582 * traceId: "000"
2583 * }))))
2584 * const program = Database.use((database) =>
2585 * Effect.map(database.query("SELECT 1"), (result) => ({ spanId: database.spanId, result })))
2586 * Effect.runSync(Effect.provide(program, databaseLayer)) // => { spanId: "42", result: "Result: SELECT 1" }
2587 * ```
2588 *
2589 * @category tracing
2590 * @since 2.0.0
2591 */
2592export const parentSpan = (span: Tracer.AnySpan): Layer<Tracer.ParentSpan> =>
2593 succeedContext(Tracer.ParentSpan.context(span))
2594
2595/**
2596 * Wraps a `Layer` with a new tracing span, making all operations in the layer
2597 * constructor part of the named trace span.
2598 *
2599 * **Details**
2600 *
2601 * This creates a new span for the layer's construction and execution. The span
2602 * is automatically ended when the layer's scope is closed. This is useful for
2603 * tracking the lifecycle and performance of layer initialization.
2604 *
2605 * **Example** (Wrapping a layer with a span)
2606 *
2607 * ```ts import.meta.vitest
2608 * import { Context, Effect, Layer } from "effect"
2609 *
2610 * class Database extends Context.Service<Database, {
2611 * readonly query: (sql: string) => Effect.Effect<string>
2612 * }>()("Database") {}
2613 *
2614 * class Logger extends Context.Service<Logger, {
2615 * readonly log: (msg: string) => Effect.Effect<void>
2616 * }>()("Logger") {}
2617 *
2618 * const logs: Array<string> = []
2619 *
2620 * // Create layers with tracing
2621 * const databaseLayer = Layer.effect(Database, Effect.gen(function*() {
2622 * return {
2623 * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result: ${sql}`))
2624 * }
2625 * })).pipe(Layer.withSpan("database-initialization", {
2626 * attributes: { dbType: "postgres" }
2627 * }))
2628 *
2629 * const loggerLayer = Layer.succeed(Logger, {
2630 * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(msg)))
2631 * }).pipe(Layer.withSpan("logger-initialization"))
2632 *
2633 * // Combine traced layers
2634 * const appLayer = Layer.mergeAll(databaseLayer, loggerLayer).pipe(
2635 * Layer.withSpan("app-initialization", {
2636 * onEnd: (span, exit) =>
2637 * Effect.sync(() => logs.push(`Application initialization completed: ${exit._tag}`))
2638 * })
2639 * )
2640 *
2641 * const program = Effect.gen(function*() {
2642 * const database = yield* Database
2643 * const logger = yield* Logger
2644 *
2645 * yield* logger.log("Application ready")
2646 * return yield* database.query("SELECT * FROM users")
2647 * }).pipe(Effect.provide(appLayer))
2648 * Effect.runSync(program) // => "Result: SELECT * FROM users"
2649 * logs // => ["Application ready", "Application initialization completed: Success"]
2650 * ```
2651 *
2652 * @category tracing
2653 * @since 2.0.0
2654 */
2655export const withSpan: {
2656 (
2657 name: string,
2658 options?: SpanOptions
2659 ): <A, E, R>(
2660 self: Layer<A, E, R>
2661 ) => Layer<A, E, Exclude<R, Tracer.ParentSpan>>
2662 <A, E, R>(
2663 self: Layer<A, E, R>,
2664 name: string,
2665 options?: SpanOptions
2666 ): Layer<A, E, Exclude<R, Tracer.ParentSpan>>
2667} = function() {
2668 const dataFirst = typeof arguments[0] !== "string"
2669 const name = dataFirst ? arguments[1] : arguments[0]
2670 const options = internalTracer.addSpanStackTrace(dataFirst ? arguments[2] : arguments[1]) as SpanOptions
2671 if (dataFirst) {
2672 const self = arguments[0]
2673 return unwrap(
2674 internalEffect.map(
2675 options?.onEnd !== undefined
2676 ? internalEffect.tap(
2677 internalEffect.makeSpanScoped(name, options),
2678 (span) => internalEffect.addFinalizer((exit) => options.onEnd!(span, exit))
2679 )
2680 : internalEffect.makeSpanScoped(name, options),
2681 (span) => withParentSpan(self, span, options)
2682 )
2683 )
2684 }
2685 return (self: Layer<any, any, any>) =>
2686 unwrap(
2687 internalEffect.map(
2688 options?.onEnd !== undefined
2689 ? internalEffect.tap(
2690 internalEffect.makeSpanScoped(name, options),
2691 (span) => internalEffect.addFinalizer((exit) => options.onEnd!(span, exit))
2692 )
2693 : internalEffect.makeSpanScoped(name, options),
2694 (span) => withParentSpan(self, span, options)
2695 )
2696 )
2697} as any
2698
2699/**
2700 * Wraps a layer so spans created during its construction use the supplied span
2701 * as their parent.
2702 *
2703 * **Details**
2704 *
2705 * Use this to attach layer construction to an existing trace hierarchy. This API
2706 * does not create or end the supplied parent span.
2707 *
2708 * When the supplied span is a native `Span`, layer construction also receives
2709 * diagnostic information that helps associate failures with the layer call site.
2710 * External spans are only installed as the parent span and do not add this
2711 * diagnostic call-site information.
2712 *
2713 * **Example** (Attaching layers to an existing parent span)
2714 *
2715 * ```ts import.meta.vitest
2716 * import { Context, Effect, Layer, Tracer } from "effect"
2717 *
2718 * class Database extends Context.Service<Database, {
2719 * readonly query: (sql: string) => Effect.Effect<string>
2720 * }>()("Database") {}
2721 *
2722 * class Cache extends Context.Service<Cache, {
2723 * readonly get: (key: string) => Effect.Effect<string | null>
2724 * }>()("Cache") {}
2725 *
2726 * // Create layers
2727 * const DatabaseLayer = Layer.effect(Database, Effect.gen(function*() {
2728 * return {
2729 * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
2730 * }
2731 * }))
2732 *
2733 * const CacheLayer = Layer.effect(Cache, Effect.gen(function*() {
2734 * return {
2735 * get: Effect.fn("Cache.get")((key: string) => Effect.succeed(`Cache: ${key}`))
2736 * }
2737 * }))
2738 *
2739 * // Use with an existing parent span from Effect.withSpan
2740 * const program = Effect.withSpan("application-startup")(
2741 * Effect.gen(function*() {
2742 * const parentSpan = yield* Tracer.ParentSpan
2743 *
2744 * // Both layers will be children of "application-startup" span
2745 * const AppLayer = Layer.mergeAll(DatabaseLayer, CacheLayer).pipe(
2746 * Layer.withParentSpan(parentSpan)
2747 * )
2748 *
2749 * const context = yield* Layer.build(AppLayer)
2750 * const database = Context.get(context, Database)
2751 * const cache = Context.get(context, Cache)
2752 *
2753 * const dbResult = yield* database.query("SELECT * FROM users")
2754 * const cacheResult = yield* cache.get("user:123")
2755 *
2756 * return { dbResult, cacheResult }
2757 * })
2758 * )
2759 * Effect.runSync(Effect.scoped(program)) // => { dbResult: "DB: SELECT * FROM users", cacheResult: "Cache: user:123" }
2760 * ```
2761 *
2762 * @category tracing
2763 * @since 2.0.0
2764 */
2765export const withParentSpan: {
2766 (
2767 span: Tracer.AnySpan,
2768 options?: Tracer.TraceOptions
2769 ): <A, E, R>(
2770 self: Layer<A, E, R>
2771 ) => Layer<A, E, Exclude<R, Tracer.ParentSpan>>
2772 <A, E, R>(
2773 self: Layer<A, E, R>,
2774 span: Tracer.AnySpan,
2775 options?: Tracer.TraceOptions
2776 ): Layer<A, E, Exclude<R, Tracer.ParentSpan>>
2777} = function() {
2778 const dataFirst = isLayer(arguments[0])
2779 const span: Tracer.AnySpan = dataFirst ? arguments[1] : arguments[0]
2780 let options = dataFirst ? arguments[2] : arguments[1]
2781 let provideStackFrame: <A, E, R>(self: Layer<A, E, R>) => Layer<A, E, R> = identity
2782 if (span._tag === "Span") {
2783 options = internalTracer.addSpanStackTrace(options)
2784 provideStackFrame = provideSpanStackFrame(span.name, options?.captureStackTrace)
2785 }
2786 const parentSpanLayer = parentSpan(span)
2787 if (dataFirst) {
2788 return provide(provideStackFrame(arguments[0]), parentSpanLayer)
2789 }
2790 return (self: Layer<any, any, any>) => provide(provideStackFrame(self), parentSpanLayer)
2791} as any
2792
2793const provideSpanStackFrame = (name: string, stack: (() => string | undefined) | undefined) => {
2794 stack = typeof stack === "function" ? stack : constUndefined
2795 return updateService(CurrentStackFrame, (parent) => ({
2796 name,
2797 stack,
2798 parent
2799 }))
2800}