/** * Builds and wires services for Effect applications. * * A `Layer` describes how to acquire one or more services, which * services are required to build them, and which errors can occur during * acquisition. Layers can manage scoped resources, memoize shared services, * combine with other layers, provide services to effects or streams, and attach * error handling, tracing, or lifecycle hooks. * * @stability stable * @since 2.0.0 */ import type { NonEmptyReadonlyArray } from "./Array.ts"; import type * as Cause from "./Cause.ts"; import type * as Channel from "./Channel.ts"; import * as Context from "./Context.ts"; import type { Effect } from "./Effect.ts"; import type * as Exit from "./Exit.ts"; import type { LazyArg } from "./Function.ts"; import { type Pipeable } from "./Pipeable.ts"; import * as Scope from "./Scope.ts"; import type * as Stream from "./Stream.ts"; import * as Tracer from "./Tracer.ts"; import type * as Types from "./Types.ts"; import type * as Unify from "./Unify.ts"; declare const TypeId = "~effect/Layer"; /** * A `Layer` describes how to build one or more services for dependency injection. * * **When to use** * * Use to model construction of application services for dependency injection, * especially when services have dependencies, can fail during construction, or * need scoped setup and release. * * **Details** * * A `Layer` represents `ROut` as the services this layer * provides, `E` as the possible errors during layer construction, and `RIn` as * the services this layer requires as dependencies. * * @stability stable * @category models * @since 2.0.0 */ export interface Layer extends Variance, Pipeable { [Unify.typeSymbol]?: unknown; [Unify.unifySymbol]?: LayerUnify; [Unify.ignoreSymbol]?: LayerUnifyIgnore; } /** * Type-level hook that allows `Layer` values to participate in `Unify` * inference. * * **Details** * * This is used by Effect's pipe and unification machinery to preserve the * provided services, error, and requirements of a `Layer`. * * @stability stable * @category models * @since 4.0.0 */ export interface LayerUnify { Layer?: () => A[Unify.typeSymbol] extends Layer | infer _ ? Layer>, Error>, Services>> : never; } /** * Type-level marker used by `Unify` for `Layer` types that should be ignored * during unification. * * @stability stable * @category models * @since 4.0.0 */ export interface LayerUnifyIgnore { } /** * The variance interface for Layer type parameters. * * @stability stable * @category models * @since 2.0.0 */ export interface Variance { readonly [TypeId]: { readonly _ROut: Types.Contravariant; readonly _E: Types.Covariant; readonly _RIn: Types.Covariant; }; } /** * A type-level constraint for working with any `Layer` type. * * **When to use** * * Use to constrain generic parameters or layer collections to any `Layer` * value while preserving its provided, error, and required service types for * inference. * * **Details** * * This interface is used to constrain generic types to `Layer` values without * specifying exact type parameters. * * @see {@link Layer} for the concrete layer interface * @see {@link Services} for extracting required services from a layer type * @see {@link Error} for extracting construction errors from a layer type * @see {@link Success} for extracting provided services from a layer type * * @stability stable * @category utility types * @since 3.9.0 */ export interface Any { readonly [TypeId]: { readonly _ROut: any; readonly _E: any; readonly _RIn: any; }; } /** * Extracts the service requirements (`RIn`) from a `Layer` type. * * **When to use** * * Use to derive the dependency requirements of a generic or inferred `Layer` * without restating its `RIn` type parameter. * * @see {@link Success} for extracting the services provided by the same `Layer` * @see {@link Error} for extracting the construction failure type from the same `Layer` * * @stability stable * @category utility types * @since 4.0.0 */ export type Services = T extends infer L ? L extends Layer ? _RIn : never : never; /** * Extracts the error type (`E`) from a `Layer` type. * * **When to use** * * Use to derive a layer construction error type for helper types, wrappers, or * APIs that preserve a layer failure channel. * * @see {@link Success} for extracting the services provided by the same `Layer` * @see {@link Services} for extracting the dependency requirements of the same `Layer` * * @stability stable * @category utility types * @since 2.0.0 */ export type Error = T extends Layer ? _E : never; /** * Extracts the service output type (`ROut`) from a `Layer` type. * * **When to use** * * Use to derive the services provided by an existing or generic `Layer` without * restating its `ROut` type parameter. * * @see {@link Error} for extracting the layer construction error type instead * @see {@link Services} for extracting the layer input service requirements instead * * @stability stable * @category utility types * @since 2.0.0 */ export type Success = T extends Layer ? _ROut : never; declare const MemoMapTypeId = "~effect/Layer/MemoMap"; /** * A `MemoMap` is used to memoize layer construction and ensure sharing of * layers. * * **Details** * * The `MemoMap` prevents duplicate construction of the same layer instance, * enabling efficient resource sharing across layer dependencies. * * **Example** (Sharing layer construction with a memo map) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * // Create a custom MemoMap for manual layer building * const program = Effect.gen(function*() { * const memoMap = yield* Layer.makeMemoMap * const scope = yield* Effect.scope * * const dbLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) * }) * const context = yield* Layer.buildWithMemoMap(dbLayer, memoMap, scope) * * return Context.get(context, Database) * }) * * const database = Effect.runSync(Effect.scoped(program)) * Effect.runSync(database.query("SELECT 1")) // => "result" * ``` * * @stability stable * @category models * @since 2.0.0 */ export interface MemoMap { readonly [MemoMapTypeId]: typeof MemoMapTypeId; readonly get: (layer: Layer, scope: Scope.Scope) => Effect, E, RIn> | undefined; readonly getOrElseMemoize: (layer: Layer, scope: Scope.Scope, build: (memoMap: MemoMap, scope: Scope.Scope) => Effect, E, RIn>) => Effect, E, RIn>; } /** * Returns `true` if the specified value is a `Layer`, `false` otherwise. * * **Example** (Checking whether a value is a layer) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const dbLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) * }) * const notALayer = { someProperty: "value" } * * Layer.isLayer(dbLayer) // => true * Layer.isLayer(notALayer) // => false * ``` * * @stability stable * @category guards * @since 2.0.0 */ export declare const isLayer: (u: unknown) => u is Layer; /** * Constructs a `Layer` from a function that uses a `MemoMap` and `Scope` to * build the layer. * * **Details** * * The function receives a `MemoMap` for memoization and a `Scope` for resource management. * A child scope is created, and if the build fails, the child scope is closed. * * **Example** (Constructing a layer from a build function) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const databaseLayer = Layer.fromBuild(() => * Effect.sync(() => * Context.make(Database, { * query: (sql: string) => Effect.succeed("result") * }) * ) * ) * * const program = Database.use((database) => database.query("SELECT 1")) * Effect.runSync(Effect.provide(program, databaseLayer)) // => "result" * ``` * * @stability stable * @category constructors * @since 4.0.0 */ export declare const fromBuild: (build: (memoMap: MemoMap, scope: Scope.Scope) => Effect, E, RIn>) => Layer; /** * Constructs a `Layer` from a function that uses a `MemoMap` and `Scope` to * build the layer, with automatic memoization. * * **Details** * * This is similar to `fromBuild` but provides automatic memoization of the layer construction. * The layer will be memoized based on the provided `MemoMap`. * * **Example** (Memoizing layer construction) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const databaseLayer = Layer.fromBuildMemo(() => * Effect.sync(() => * Context.make(Database, { * query: (sql: string) => Effect.succeed("result") * }) * ) * ) * * const program = Database.use((database) => database.query("SELECT 1")) * Effect.runSync(Effect.provide(program, databaseLayer)) // => "result" * ``` * * @stability stable * @category constructors * @since 4.0.0 */ export declare const fromBuildMemo: (build: (memoMap: MemoMap, scope: Scope.Scope) => Effect, E, RIn>) => Layer; /** * Constructs a `MemoMap` synchronously so it can be used to build additional layers. * * **Example** (Creating a memo map unsafely) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * // Create a memo map for manual layer building * const program = Effect.gen(function*() { * const memoMap = Layer.makeMemoMapUnsafe() * const scope = yield* Effect.scope * * const dbLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) * }) * const context = yield* Layer.buildWithMemoMap(dbLayer, memoMap, scope) * * return Context.get(context, Database) * }) * * const database = Effect.runSync(Effect.scoped(program)) * Effect.runSync(database.query("SELECT 1")) // => "result" * ``` * * @stability stable * @category constructors * @since 4.0.0 */ export declare const makeMemoMapUnsafe: () => MemoMap; /** * Constructs a child `MemoMap` synchronously, allowing it to reuse layers * already memoized in the parent while isolating any new layer allocations to * the child map. * * **When to use** * * Use to synchronously fork a memo map for manual layer building when child * builds should see parent memoized layers without writing newly built layers * back to the parent. * * @see {@link forkMemoMap} for allocating the child memo map inside `Effect` * @see {@link makeMemoMapUnsafe} for creating a root memo map without a parent * * @stability stable * @category constructors * @since 4.0.0 */ export declare const forkMemoMapUnsafe: (parent: MemoMap) => MemoMap; /** * Constructs a `MemoMap` effectfully so it can be used to build additional layers. * * **Example** (Creating a memo map in an effect) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * // Create a memo map safely within an Effect * const program = Effect.gen(function*() { * const memoMap = yield* Layer.makeMemoMap * const scope = yield* Effect.scope * * const dbLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) * }) * const context = yield* Layer.buildWithMemoMap(dbLayer, memoMap, scope) * * return Context.get(context, Database) * }) * * const database = Effect.runSync(Effect.scoped(program)) * Effect.runSync(database.query("SELECT 1")) // => "result" * ``` * * @stability stable * @category constructors * @since 2.0.0 */ export declare const makeMemoMap: Effect; /** * Constructs a child `MemoMap` effectfully, allowing it to reuse layers already * memoized in the parent while isolating any new layer allocations to the child * map. * * **When to use** * * Use when a layer build should inherit already memoized layers from an * existing `MemoMap` while keeping newly memoized layers out of the parent map. * * @see {@link makeMemoMap} for creating a root memo map in an `Effect` * @see {@link forkMemoMapUnsafe} for the synchronous constructor variant * @see {@link buildWithMemoMap} for building layers with an explicit memo map * * @stability stable * @category constructors * @since 4.0.0 */ export declare const forkMemoMap: (parent: MemoMap) => Effect; declare const CurrentMemoMap_base: Context.ServiceClass; /** * Context service for the current `MemoMap` used in layer construction. * * **When to use** * * Use when building custom layer operations that need to access the current * memoization map from the fiber context. * * **Details** * * This service wraps a `MemoMap` as a `Context.Service`, making it available * for dependency injection during layer construction. * * @see {@link MemoMap} the memoization map type wrapped by this service * * @stability stable * @category services * @since 3.13.0 */ export declare class CurrentMemoMap extends CurrentMemoMap_base { static forkOrCreate(self: Context.Context): MemoMap; } /** * Builds a layer into an `Effect` value, using the specified `MemoMap` to memoize * the layer construction. * * **Example** (Building layers with an explicit memo map) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * const logs: Array = [] * * // Build layers with explicit memoization control * const program = Effect.gen(function*() { * const memoMap = yield* Layer.makeMemoMap * const scope = yield* Effect.scope * * // Build database layer with memoization * const dbLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) * }) * const dbContext = yield* Layer.buildWithMemoMap(dbLayer, memoMap, scope) * * // Build logger layer with same memoization (reuses memo if same layer) * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(msg))) * }) * const loggerContext = yield* Layer.buildWithMemoMap( * loggerLayer, * memoMap, * scope * ) * * return { * database: Context.get(dbContext, Database), * logger: Context.get(loggerContext, Logger) * } * }) * * const services = Effect.runSync(Effect.scoped(program)) * Effect.runSync(services.logger.log("ready")) * logs // => ["ready"] * ``` * * @stability stable * @category destructors * @since 2.0.0 */ export declare const buildWithMemoMap: { /** * Builds a layer into an `Effect` value, using the specified `MemoMap` to memoize * the layer construction. * * **Example** (Building layers with an explicit memo map) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * const logs: Array = [] * * // Build layers with explicit memoization control * const program = Effect.gen(function*() { * const memoMap = yield* Layer.makeMemoMap * const scope = yield* Effect.scope * * // Build database layer with memoization * const dbLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) * }) * const dbContext = yield* Layer.buildWithMemoMap(dbLayer, memoMap, scope) * * // Build logger layer with same memoization (reuses memo if same layer) * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(msg))) * }) * const loggerContext = yield* Layer.buildWithMemoMap( * loggerLayer, * memoMap, * scope * ) * * return { * database: Context.get(dbContext, Database), * logger: Context.get(loggerContext, Logger) * } * }) * * const services = Effect.runSync(Effect.scoped(program)) * Effect.runSync(services.logger.log("ready")) * logs // => ["ready"] * ``` * * @stability stable * @category destructors * @since 2.0.0 */ (memoMap: MemoMap, scope: Scope.Scope): (self: Layer) => Effect, E, RIn>; /** * Builds a layer into an `Effect` value, using the specified `MemoMap` to memoize * the layer construction. * * **Example** (Building layers with an explicit memo map) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * const logs: Array = [] * * // Build layers with explicit memoization control * const program = Effect.gen(function*() { * const memoMap = yield* Layer.makeMemoMap * const scope = yield* Effect.scope * * // Build database layer with memoization * const dbLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) * }) * const dbContext = yield* Layer.buildWithMemoMap(dbLayer, memoMap, scope) * * // Build logger layer with same memoization (reuses memo if same layer) * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(msg))) * }) * const loggerContext = yield* Layer.buildWithMemoMap( * loggerLayer, * memoMap, * scope * ) * * return { * database: Context.get(dbContext, Database), * logger: Context.get(loggerContext, Logger) * } * }) * * const services = Effect.runSync(Effect.scoped(program)) * Effect.runSync(services.logger.log("ready")) * logs // => ["ready"] * ``` * * @stability stable * @category destructors * @since 2.0.0 */ (self: Layer, memoMap: MemoMap, scope: Scope.Scope): Effect, E, RIn>; }; /** * Builds a layer into a scoped value. * * **Example** (Building a layer into a context) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * // Build a layer to get its services * const program = Effect.gen(function*() { * const dbLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) * }) * * // Build the layer into Context - automatically manages scope and memoization * const context = yield* Layer.build(dbLayer) * * // Extract the specific service from the built layer * const database = Context.get(context, Database) * * return yield* database.query("SELECT * FROM users") * }) * * Effect.runSync(Effect.scoped(program)) // => "result" * ``` * * @stability stable * @category destructors * @since 2.0.0 */ export declare const build: (self: Layer) => Effect, E, RIn | Scope.Scope>; /** * Builds a layer using an explicit scope. * * **When to use** * * Use to control the lifetime of layer resources with a scope supplied by the * caller. * * **Details** * * Resources created by the layer are released when the supplied scope is * closed, unless a resource extends its own scope. * * **Example** (Building a layer with an explicit scope) * * ```ts import.meta.vitest * import { Context, Effect, Layer, Scope } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const logs: Array = [] * * // Build a layer with explicit scope control * const program = Effect.gen(function*() { * const scope = yield* Effect.scope * * const dbLayer = Layer.effect(Database, Effect.gen(function*() { * logs.push("Initializing database...") * yield* Scope.addFinalizer( * scope, * Effect.sync(() => logs.push("Database closed")) * ) * return { query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result: ${sql}`)) } * })) * * // Build with specific scope - resources tied to this scope * const context = yield* Layer.buildWithScope(dbLayer, scope) * const database = Context.get(context, Database) * * return yield* database.query("SELECT * FROM users") * // Database will be closed when scope is closed * }) * * Effect.runSync(Effect.scoped(program)) // => "Result: SELECT * FROM users" * logs // => ["Initializing database...", "Database closed"] * ``` * * @stability stable * @category destructors * @since 2.0.0 */ export declare const buildWithScope: { /** * Builds a layer using an explicit scope. * * **When to use** * * Use to control the lifetime of layer resources with a scope supplied by the * caller. * * **Details** * * Resources created by the layer are released when the supplied scope is * closed, unless a resource extends its own scope. * * **Example** (Building a layer with an explicit scope) * * ```ts import.meta.vitest * import { Context, Effect, Layer, Scope } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const logs: Array = [] * * // Build a layer with explicit scope control * const program = Effect.gen(function*() { * const scope = yield* Effect.scope * * const dbLayer = Layer.effect(Database, Effect.gen(function*() { * logs.push("Initializing database...") * yield* Scope.addFinalizer( * scope, * Effect.sync(() => logs.push("Database closed")) * ) * return { query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result: ${sql}`)) } * })) * * // Build with specific scope - resources tied to this scope * const context = yield* Layer.buildWithScope(dbLayer, scope) * const database = Context.get(context, Database) * * return yield* database.query("SELECT * FROM users") * // Database will be closed when scope is closed * }) * * Effect.runSync(Effect.scoped(program)) // => "Result: SELECT * FROM users" * logs // => ["Initializing database...", "Database closed"] * ``` * * @stability stable * @category destructors * @since 2.0.0 */ (scope: Scope.Scope): (self: Layer) => Effect, E, RIn>; /** * Builds a layer using an explicit scope. * * **When to use** * * Use to control the lifetime of layer resources with a scope supplied by the * caller. * * **Details** * * Resources created by the layer are released when the supplied scope is * closed, unless a resource extends its own scope. * * **Example** (Building a layer with an explicit scope) * * ```ts import.meta.vitest * import { Context, Effect, Layer, Scope } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const logs: Array = [] * * // Build a layer with explicit scope control * const program = Effect.gen(function*() { * const scope = yield* Effect.scope * * const dbLayer = Layer.effect(Database, Effect.gen(function*() { * logs.push("Initializing database...") * yield* Scope.addFinalizer( * scope, * Effect.sync(() => logs.push("Database closed")) * ) * return { query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result: ${sql}`)) } * })) * * // Build with specific scope - resources tied to this scope * const context = yield* Layer.buildWithScope(dbLayer, scope) * const database = Context.get(context, Database) * * return yield* database.query("SELECT * FROM users") * // Database will be closed when scope is closed * }) * * Effect.runSync(Effect.scoped(program)) // => "Result: SELECT * FROM users" * logs // => ["Initializing database...", "Database closed"] * ``` * * @stability stable * @category destructors * @since 2.0.0 */ (self: Layer, scope: Scope.Scope): Effect, E, RIn>; }; /** * Constructs a layer that provides a single service from an already available * value. * * **When to use** * * Use when you need a `Layer` that provides a service from an already * constructed implementation without effectful acquisition. * * **Example** (Creating a layer from a service implementation) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const DatabaseLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Query result: ${sql}`)) * }) * const program = Database.use((database) => database.query("SELECT 1")) * Effect.runSync(Effect.provide(program, DatabaseLayer)) // => "Query result: SELECT 1" * ``` * * @see {@link sync} for constructing layers from lazy values * * @stability stable * @category constructors * @since 2.0.0 */ export declare const succeed: { /** * Constructs a layer that provides a single service from an already available * value. * * **When to use** * * Use when you need a `Layer` that provides a service from an already * constructed implementation without effectful acquisition. * * **Example** (Creating a layer from a service implementation) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const DatabaseLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Query result: ${sql}`)) * }) * const program = Database.use((database) => database.query("SELECT 1")) * Effect.runSync(Effect.provide(program, DatabaseLayer)) // => "Query result: SELECT 1" * ``` * * @see {@link sync} for constructing layers from lazy values * * @stability stable * @category constructors * @since 2.0.0 */ (service: Context.Key): (resource: S) => Layer; /** * Constructs a layer that provides a single service from an already available * value. * * **When to use** * * Use when you need a `Layer` that provides a service from an already * constructed implementation without effectful acquisition. * * **Example** (Creating a layer from a service implementation) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const DatabaseLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Query result: ${sql}`)) * }) * const program = Database.use((database) => database.query("SELECT 1")) * Effect.runSync(Effect.provide(program, DatabaseLayer)) // => "Query result: SELECT 1" * ``` * * @see {@link sync} for constructing layers from lazy values * * @stability stable * @category constructors * @since 2.0.0 */ (service: Context.Key, resource: Types.NoInfer): Layer; }; /** * Constructs a layer that provides all services in an already available * `Context`. * * **When to use** * * Use when you need a `Layer` built from an existing `Context`, including when * you need to provide multiple services at once. * * **Details** * * This is a more general version of `succeed` that allows you to provide * multiple services at once through a `Context`. * * **Example** (Providing multiple services from a context) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * const logs: Array = [] * const context = Context.make(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) * }).pipe( * Context.add(Logger, { * log: (msg: string) => Effect.sync(() => logs.push(msg)) * }) * ) * * const layer = Layer.succeedContext(context) * const program = Logger.use((logger) => logger.log("ready")) * Effect.runSync(Effect.provide(program, layer)) * logs // => ["ready"] * ``` * * @see {@link succeed} for providing a single service from a value * * @stability stable * @category constructors * @since 2.0.0 */ export declare const succeedContext: (context: Context.Context) => Layer; /** * An empty layer that provides no services, cannot fail, has no requirements, * and performs no construction or finalization work. * * **When to use** * * Use as the no-op branch when conditionally composing layers. * * **Example** (Disabling optional lifecycle work) * * ```ts import.meta.vitest * import { Context, Effect, Layer, Option } from "effect" * * const Service = Context.Service("Service") * const context = Effect.runSync(Effect.scoped(Layer.build(Layer.empty))) * Context.getOption(context, Service) // => Option.none() * ``` * * @see {@link effectDiscard} for running an effect while providing no services * * @stability stable * @category constructors * @since 2.0.0 */ export declare const empty: Layer; /** * Constructs a layer lazily that provides a single service. * * **When to use** * * Use when you need a `Layer` that provides one service whose value is created * synchronously, but creation should be deferred until the layer is built. * * **Details** * * This is a lazy version of `succeed` where the service value is computed * synchronously only when the layer is built. * * **Example** (Lazily providing a service) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const layer = Layer.sync(Database, () => ({ * query: (sql: string) => Effect.succeed(`Query: ${sql}`) * })) * const program = Database.use((database) => database.query("SELECT 1")) * Effect.runSync(Effect.provide(program, layer)) // => "Query: SELECT 1" * ``` * * @see {@link succeed} for constructing layers from static values * * @stability stable * @category constructors * @since 2.0.0 */ export declare const sync: { /** * Constructs a layer lazily that provides a single service. * * **When to use** * * Use when you need a `Layer` that provides one service whose value is created * synchronously, but creation should be deferred until the layer is built. * * **Details** * * This is a lazy version of `succeed` where the service value is computed * synchronously only when the layer is built. * * **Example** (Lazily providing a service) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const layer = Layer.sync(Database, () => ({ * query: (sql: string) => Effect.succeed(`Query: ${sql}`) * })) * const program = Database.use((database) => database.query("SELECT 1")) * Effect.runSync(Effect.provide(program, layer)) // => "Query: SELECT 1" * ``` * * @see {@link succeed} for constructing layers from static values * * @stability stable * @category constructors * @since 2.0.0 */ (service: Context.Key): (evaluate: LazyArg) => Layer; /** * Constructs a layer lazily that provides a single service. * * **When to use** * * Use when you need a `Layer` that provides one service whose value is created * synchronously, but creation should be deferred until the layer is built. * * **Details** * * This is a lazy version of `succeed` where the service value is computed * synchronously only when the layer is built. * * **Example** (Lazily providing a service) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const layer = Layer.sync(Database, () => ({ * query: (sql: string) => Effect.succeed(`Query: ${sql}`) * })) * const program = Database.use((database) => database.query("SELECT 1")) * Effect.runSync(Effect.provide(program, layer)) // => "Query: SELECT 1" * ``` * * @see {@link succeed} for constructing layers from static values * * @stability stable * @category constructors * @since 2.0.0 */ (service: Context.Key, evaluate: LazyArg>): Layer; }; /** * Constructs a layer lazily that provides all services in a `Context`. * * **When to use** * * Use when you need a `Layer` that creates multiple services synchronously but * defers that work until the layer is built. * * **Details** * * This is a lazy version of `succeedContext` where the `Context` is computed * synchronously only when the layer is built. * * **Example** (Lazily providing a context) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const layer = Layer.syncContext(() => * Context.make(Database, { * query: (sql: string) => Effect.succeed(`Query: ${sql}`) * }) * ) * const program = Database.use((database) => database.query("SELECT 1")) * Effect.runSync(Effect.provide(program, layer)) // => "Query: SELECT 1" * ``` * * @see {@link sync} for lazily providing a single service * @see {@link succeedContext} for providing an already available context * * @stability stable * @category constructors * @since 2.0.0 */ export declare const syncContext: (evaluate: LazyArg>) => Layer; /** * Constructs a layer from an effect that produces a single service. * * **When to use** * * Use when you need to construct a `Layer`-provided service with an `Effect`, * dependencies, or scoped resource acquisition. * * **Details** * * This allows you to create a `Layer` from an `Effect` that produces a service. * The `Effect` is executed in the scope of the layer, allowing for proper * resource management. * * **Example** (Creating a layer from an effect) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const layer = Layer.effect(Database, * Effect.sync(() => ({ * query: (sql: string) => Effect.succeed(`Query: ${sql}`) * })) * ) * const program = Database.use((database) => database.query("SELECT 1")) * Effect.runSync(Effect.provide(program, layer)) // => "Query: SELECT 1" * ``` * * @see {@link effectContext} for effectfully providing multiple services * @see {@link effectDiscard} for running construction work without providing services * * @stability stable * @category constructors * @since 2.0.0 */ export declare const effect: { /** * Constructs a layer from an effect that produces a single service. * * **When to use** * * Use when you need to construct a `Layer`-provided service with an `Effect`, * dependencies, or scoped resource acquisition. * * **Details** * * This allows you to create a `Layer` from an `Effect` that produces a service. * The `Effect` is executed in the scope of the layer, allowing for proper * resource management. * * **Example** (Creating a layer from an effect) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const layer = Layer.effect(Database, * Effect.sync(() => ({ * query: (sql: string) => Effect.succeed(`Query: ${sql}`) * })) * ) * const program = Database.use((database) => database.query("SELECT 1")) * Effect.runSync(Effect.provide(program, layer)) // => "Query: SELECT 1" * ``` * * @see {@link effectContext} for effectfully providing multiple services * @see {@link effectDiscard} for running construction work without providing services * * @stability stable * @category constructors * @since 2.0.0 */ (service: Context.Key): (effect: Effect) => Layer>; /** * Constructs a layer from an effect that produces a single service. * * **When to use** * * Use when you need to construct a `Layer`-provided service with an `Effect`, * dependencies, or scoped resource acquisition. * * **Details** * * This allows you to create a `Layer` from an `Effect` that produces a service. * The `Effect` is executed in the scope of the layer, allowing for proper * resource management. * * **Example** (Creating a layer from an effect) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const layer = Layer.effect(Database, * Effect.sync(() => ({ * query: (sql: string) => Effect.succeed(`Query: ${sql}`) * })) * ) * const program = Database.use((database) => database.query("SELECT 1")) * Effect.runSync(Effect.provide(program, layer)) // => "Query: SELECT 1" * ``` * * @see {@link effectContext} for effectfully providing multiple services * @see {@link effectDiscard} for running construction work without providing services * * @stability stable * @category constructors * @since 2.0.0 */ (service: Context.Key, effect: Effect, E, R>): Layer>; }; /** * Constructs a layer from an effect that produces all services in a `Context`. * * **When to use** * * Use when you need a `Layer` that effectfully constructs a `Context` with * multiple services. * * **Details** * * This allows you to create a `Layer` from an effectful computation that * returns multiple services. The `Effect` is executed in the scope of the * layer. * * **Example** (Creating a layer from an effectful context) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service< * Database, * { readonly query: (sql: string) => Effect.Effect } * >()("Database") {} * * const layer = Layer.effectContext( * Effect.succeed(Context.make(Database, { * query: (sql: string) => Effect.succeed(`Query: ${sql}`) * })) * ) * const program = Database.use((database) => database.query("SELECT 1")) * Effect.runSync(Effect.provide(program, layer)) // => "Query: SELECT 1" * ``` * * @see {@link effect} for effectfully providing a single service * * @stability stable * @category constructors * @since 2.0.0 */ export declare const effectContext: (effect: Effect, E, R>) => Layer>; /** * Constructs a layer from an effect, discarding its value and providing no * services. * * **When to use** * * Use when layer construction should run an Effect for its side effects while providing no * services. * * **Example** (Running an effect during layer construction) * * ```ts import.meta.vitest * import { Effect, Layer } from "effect" * * const logs: Array = [] * const initLayer = Layer.effectDiscard( * Effect.sync(() => { * logs.push("Initializing application...") * }) * ) * Effect.runSync(Effect.scoped(Layer.build(initLayer))) * logs // => ["Initializing application..."] * ``` * * @see {@link empty} for a no-op layer that performs no construction work * * @stability stable * @category constructors * @since 2.0.0 */ export declare const effectDiscard: (effect: Effect) => Layer>; /** * Constructs a layer lazily using the specified factory. * * **Details** * * The factory is evaluated only when the suspended layer is first built, and * the result is memoized with normal layer sharing semantics. * * **Example** (Choosing a layer lazily) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Config extends Context.Service()("Config") {} * * const useProd = true * * const layer = Layer.suspend(() => * useProd * ? Layer.succeed(Config, "https://api.example.com") * : Layer.succeed(Config, "http://localhost:3000") * ) * Effect.runSync(Effect.provide(Config, layer)) // => "https://api.example.com" * ``` * * @stability stable * @category constructors * @since 2.0.0 */ export declare const suspend: (evaluate: LazyArg>) => Layer; /** * Unwraps a `Layer` from an `Effect`, flattening the nested structure. * * **When to use** * * Use when you have an `Effect` that produces a `Layer` and you want to * use that layer directly. * * **Details** * * The resulting Layer will have the combined error and dependency types from * both the outer Effect and the inner Layer. * * **Example** (Unwrapping an effectful layer) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const layerEffect = Effect.succeed( * Layer.succeed(Database, { query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) }) * ) * * const unwrappedLayer = Layer.unwrap(layerEffect) * const program = Database.use((database) => database.query("SELECT 1")) * Effect.runSync(Effect.provide(program, unwrappedLayer)) // => "result" * ``` * * @stability stable * @category converting * @since 4.0.0 */ export declare const unwrap: (self: Effect, E, R>) => Layer>; /** * Combines all the provided layers concurrently, creating a new layer with * merged input, error, and output types. * * **When to use** * * Use when you need to combine multiple independent layers. * * **Details** * * All layers are built concurrently, and their outputs are merged into a single layer. * * If multiple merged layers depend on the same layer value, that dependency is * shared by default. Reuse a named layer value when you want services to share * the same resource, such as one database pool. * * **Example** (Merging independent layers) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * const dbLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) * }) * const logs: Array = [] * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(msg))) * }) * * const mergedLayer = Layer.mergeAll(dbLayer, loggerLayer) * const program = Logger.use((logger) => logger.log("ready")) * Effect.runSync(Effect.provide(program, mergedLayer)) * logs // => ["ready"] * ``` * * @see {@link merge} for merging one layer with another layer or array * * @stability stable * @category zipping * @since 2.0.0 */ export declare const mergeAll: , ...Array>]>(...layers: Layers) => Layer, Error, Services>; /** * Merges this layer with another layer concurrently, producing a new layer with * combined input, error, and output types. * * **When to use** * * Use to combine an existing `Layer` with another `Layer` or an array of * layers while preserving pipeline style. * * **Details** * * This is a binary version of `mergeAll` that merges exactly two layers or one * layer with an array of layers. The layers are built concurrently and their * outputs are combined. * * **Example** (Merging two layers) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * const dbLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) * }) * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((_msg: string) => Effect.void) * }) * * const mergedLayer = Layer.merge(dbLayer, loggerLayer) * const program = Database.use((database) => database.query("SELECT 1")) * Effect.runSync(Effect.provide(program, mergedLayer)) // => "result" * ``` * * @see {@link mergeAll} for merging several layers at once * * @stability stable * @category zipping * @since 2.0.0 */ export declare const merge: { /** * Merges this layer with another layer concurrently, producing a new layer with * combined input, error, and output types. * * **When to use** * * Use to combine an existing `Layer` with another `Layer` or an array of * layers while preserving pipeline style. * * **Details** * * This is a binary version of `mergeAll` that merges exactly two layers or one * layer with an array of layers. The layers are built concurrently and their * outputs are combined. * * **Example** (Merging two layers) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * const dbLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) * }) * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((_msg: string) => Effect.void) * }) * * const mergedLayer = Layer.merge(dbLayer, loggerLayer) * const program = Database.use((database) => database.query("SELECT 1")) * Effect.runSync(Effect.provide(program, mergedLayer)) // => "result" * ``` * * @see {@link mergeAll} for merging several layers at once * * @stability stable * @category zipping * @since 2.0.0 */ (that: Layer): (self: Layer) => Layer; /** * Merges this layer with another layer concurrently, producing a new layer with * combined input, error, and output types. * * **When to use** * * Use to combine an existing `Layer` with another `Layer` or an array of * layers while preserving pipeline style. * * **Details** * * This is a binary version of `mergeAll` that merges exactly two layers or one * layer with an array of layers. The layers are built concurrently and their * outputs are combined. * * **Example** (Merging two layers) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * const dbLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) * }) * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((_msg: string) => Effect.void) * }) * * const mergedLayer = Layer.merge(dbLayer, loggerLayer) * const program = Database.use((database) => database.query("SELECT 1")) * Effect.runSync(Effect.provide(program, mergedLayer)) // => "result" * ``` * * @see {@link mergeAll} for merging several layers at once * * @stability stable * @category zipping * @since 2.0.0 */ ]>(that: Layers): (self: Layer) => Layer, E | Error, Services | R>; /** * Merges this layer with another layer concurrently, producing a new layer with * combined input, error, and output types. * * **When to use** * * Use to combine an existing `Layer` with another `Layer` or an array of * layers while preserving pipeline style. * * **Details** * * This is a binary version of `mergeAll` that merges exactly two layers or one * layer with an array of layers. The layers are built concurrently and their * outputs are combined. * * **Example** (Merging two layers) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * const dbLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) * }) * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((_msg: string) => Effect.void) * }) * * const mergedLayer = Layer.merge(dbLayer, loggerLayer) * const program = Database.use((database) => database.query("SELECT 1")) * Effect.runSync(Effect.provide(program, mergedLayer)) // => "result" * ``` * * @see {@link mergeAll} for merging several layers at once * * @stability stable * @category zipping * @since 2.0.0 */ (self: Layer, that: Layer): Layer; /** * Merges this layer with another layer concurrently, producing a new layer with * combined input, error, and output types. * * **When to use** * * Use to combine an existing `Layer` with another `Layer` or an array of * layers while preserving pipeline style. * * **Details** * * This is a binary version of `mergeAll` that merges exactly two layers or one * layer with an array of layers. The layers are built concurrently and their * outputs are combined. * * **Example** (Merging two layers) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * const dbLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) * }) * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((_msg: string) => Effect.void) * }) * * const mergedLayer = Layer.merge(dbLayer, loggerLayer) * const program = Database.use((database) => database.query("SELECT 1")) * Effect.runSync(Effect.provide(program, mergedLayer)) // => "result" * ``` * * @see {@link mergeAll} for merging several layers at once * * @stability stable * @category zipping * @since 2.0.0 */ ]>(self: Layer, that: Layers): Layer, E | Error, Services | R>; }; /** * Feeds the output services of the dependency layer into the requirements of * this layer, returning a layer that only provides the services from this layer. * * **When to use** * * Use when you need to hide an implementation dependency layer from callers. * * **Details** * * In `serviceLayer.pipe(Layer.provide(dependencyLayer))`, the dependency layer is * built first and is used to satisfy the requirements of `serviceLayer`. * * **Example** (Providing layer dependencies) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class UserService extends Context.Service Effect.Effect<{ * id: string * name: string * }> * }>()("UserService") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * // Create dependency layers * const databaseLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`)) * }) * * const logs: Array = [] * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(`[LOG] ${msg}`))) * }) * * // UserService depends on Database and Logger * const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() { * const database = yield* Database * const logger = yield* Logger * * return { * getUser: Effect.fn("UserService.getUser")(function*(id: string) { * yield* logger.log(`Looking up user ${id}`) * const result = yield* database.query( * `SELECT * FROM users WHERE id = ${id}` * ) * return { id, name: result } * }) * } * })) * * // Provide dependencies to UserService layer * const userServiceWithDependencies = userServiceLayer.pipe( * Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer)) * ) * * // Now UserService layer has no dependencies * const program = Effect.gen(function*() { * const userService = yield* UserService * return yield* userService.getUser("123") * }).pipe( * Effect.provide(userServiceWithDependencies) * ) * Effect.runSync(program) // => { id: "123", name: "DB: SELECT * FROM users WHERE id = 123" } * logs // => ["[LOG] Looking up user 123"] * ``` * * @see {@link provideMerge} for retaining the dependency services * * @stability stable * @category providing services * @since 2.0.0 */ export declare const provide: { /** * Feeds the output services of the dependency layer into the requirements of * this layer, returning a layer that only provides the services from this layer. * * **When to use** * * Use when you need to hide an implementation dependency layer from callers. * * **Details** * * In `serviceLayer.pipe(Layer.provide(dependencyLayer))`, the dependency layer is * built first and is used to satisfy the requirements of `serviceLayer`. * * **Example** (Providing layer dependencies) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class UserService extends Context.Service Effect.Effect<{ * id: string * name: string * }> * }>()("UserService") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * // Create dependency layers * const databaseLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`)) * }) * * const logs: Array = [] * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(`[LOG] ${msg}`))) * }) * * // UserService depends on Database and Logger * const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() { * const database = yield* Database * const logger = yield* Logger * * return { * getUser: Effect.fn("UserService.getUser")(function*(id: string) { * yield* logger.log(`Looking up user ${id}`) * const result = yield* database.query( * `SELECT * FROM users WHERE id = ${id}` * ) * return { id, name: result } * }) * } * })) * * // Provide dependencies to UserService layer * const userServiceWithDependencies = userServiceLayer.pipe( * Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer)) * ) * * // Now UserService layer has no dependencies * const program = Effect.gen(function*() { * const userService = yield* UserService * return yield* userService.getUser("123") * }).pipe( * Effect.provide(userServiceWithDependencies) * ) * Effect.runSync(program) // => { id: "123", name: "DB: SELECT * FROM users WHERE id = 123" } * logs // => ["[LOG] Looking up user 123"] * ``` * * @see {@link provideMerge} for retaining the dependency services * * @stability stable * @category providing services * @since 2.0.0 */ (that: Layer): (self: Layer) => Layer>; /** * Feeds the output services of the dependency layer into the requirements of * this layer, returning a layer that only provides the services from this layer. * * **When to use** * * Use when you need to hide an implementation dependency layer from callers. * * **Details** * * In `serviceLayer.pipe(Layer.provide(dependencyLayer))`, the dependency layer is * built first and is used to satisfy the requirements of `serviceLayer`. * * **Example** (Providing layer dependencies) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class UserService extends Context.Service Effect.Effect<{ * id: string * name: string * }> * }>()("UserService") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * // Create dependency layers * const databaseLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`)) * }) * * const logs: Array = [] * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(`[LOG] ${msg}`))) * }) * * // UserService depends on Database and Logger * const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() { * const database = yield* Database * const logger = yield* Logger * * return { * getUser: Effect.fn("UserService.getUser")(function*(id: string) { * yield* logger.log(`Looking up user ${id}`) * const result = yield* database.query( * `SELECT * FROM users WHERE id = ${id}` * ) * return { id, name: result } * }) * } * })) * * // Provide dependencies to UserService layer * const userServiceWithDependencies = userServiceLayer.pipe( * Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer)) * ) * * // Now UserService layer has no dependencies * const program = Effect.gen(function*() { * const userService = yield* UserService * return yield* userService.getUser("123") * }).pipe( * Effect.provide(userServiceWithDependencies) * ) * Effect.runSync(program) // => { id: "123", name: "DB: SELECT * FROM users WHERE id = 123" } * logs // => ["[LOG] Looking up user 123"] * ``` * * @see {@link provideMerge} for retaining the dependency services * * @stability stable * @category providing services * @since 2.0.0 */ ]>(that: Layers): (self: Layer) => Layer, Services | Exclude>>; /** * Feeds the output services of the dependency layer into the requirements of * this layer, returning a layer that only provides the services from this layer. * * **When to use** * * Use when you need to hide an implementation dependency layer from callers. * * **Details** * * In `serviceLayer.pipe(Layer.provide(dependencyLayer))`, the dependency layer is * built first and is used to satisfy the requirements of `serviceLayer`. * * **Example** (Providing layer dependencies) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class UserService extends Context.Service Effect.Effect<{ * id: string * name: string * }> * }>()("UserService") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * // Create dependency layers * const databaseLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`)) * }) * * const logs: Array = [] * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(`[LOG] ${msg}`))) * }) * * // UserService depends on Database and Logger * const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() { * const database = yield* Database * const logger = yield* Logger * * return { * getUser: Effect.fn("UserService.getUser")(function*(id: string) { * yield* logger.log(`Looking up user ${id}`) * const result = yield* database.query( * `SELECT * FROM users WHERE id = ${id}` * ) * return { id, name: result } * }) * } * })) * * // Provide dependencies to UserService layer * const userServiceWithDependencies = userServiceLayer.pipe( * Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer)) * ) * * // Now UserService layer has no dependencies * const program = Effect.gen(function*() { * const userService = yield* UserService * return yield* userService.getUser("123") * }).pipe( * Effect.provide(userServiceWithDependencies) * ) * Effect.runSync(program) // => { id: "123", name: "DB: SELECT * FROM users WHERE id = 123" } * logs // => ["[LOG] Looking up user 123"] * ``` * * @see {@link provideMerge} for retaining the dependency services * * @stability stable * @category providing services * @since 2.0.0 */ (self: Layer, that: Layer): Layer>; /** * Feeds the output services of the dependency layer into the requirements of * this layer, returning a layer that only provides the services from this layer. * * **When to use** * * Use when you need to hide an implementation dependency layer from callers. * * **Details** * * In `serviceLayer.pipe(Layer.provide(dependencyLayer))`, the dependency layer is * built first and is used to satisfy the requirements of `serviceLayer`. * * **Example** (Providing layer dependencies) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class UserService extends Context.Service Effect.Effect<{ * id: string * name: string * }> * }>()("UserService") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * // Create dependency layers * const databaseLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`)) * }) * * const logs: Array = [] * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(`[LOG] ${msg}`))) * }) * * // UserService depends on Database and Logger * const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() { * const database = yield* Database * const logger = yield* Logger * * return { * getUser: Effect.fn("UserService.getUser")(function*(id: string) { * yield* logger.log(`Looking up user ${id}`) * const result = yield* database.query( * `SELECT * FROM users WHERE id = ${id}` * ) * return { id, name: result } * }) * } * })) * * // Provide dependencies to UserService layer * const userServiceWithDependencies = userServiceLayer.pipe( * Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer)) * ) * * // Now UserService layer has no dependencies * const program = Effect.gen(function*() { * const userService = yield* UserService * return yield* userService.getUser("123") * }).pipe( * Effect.provide(userServiceWithDependencies) * ) * Effect.runSync(program) // => { id: "123", name: "DB: SELECT * FROM users WHERE id = 123" } * logs // => ["[LOG] Looking up user 123"] * ``` * * @see {@link provideMerge} for retaining the dependency services * * @stability stable * @category providing services * @since 2.0.0 */ ]>(self: Layer, that: Layers): Layer, Services | Exclude>>; }; /** * Feeds the output services of the dependency layer into the requirements of * this layer, returning a layer that provides both sets of services. * * **When to use** * * Use when you need to compose `Layer`s while keeping both the constructed * service and the dependency used to build it available. * * **Details** * * Prefer {@link provide} when the dependency should stay private. * * **Example** (Providing dependencies while retaining services) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * class UserService extends Context.Service Effect.Effect<{ * id: string * name: string * }> * }>()("UserService") {} * * // Create dependency layers * const databaseLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`)) * }) * * const logs: Array = [] * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(`[LOG] ${msg}`))) * }) * * // UserService depends on Database and Logger * const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() { * const database = yield* Database * const logger = yield* Logger * * return { * getUser: Effect.fn("UserService.getUser")(function*(id: string) { * yield* logger.log(`Looking up user ${id}`) * const result = yield* database.query( * `SELECT * FROM users WHERE id = ${id}` * ) * return { id, name: result } * }) * } * })) * * // Provide dependencies and merge all services together * const allServicesLayer = userServiceLayer.pipe( * Layer.provideMerge(Layer.mergeAll(databaseLayer, loggerLayer)) * ) * * // Now the resulting layer provides UserService, Database, AND Logger * const program = Effect.gen(function*() { * const userService = yield* UserService * const logger = yield* Logger // Still available! * const database = yield* Database // Still available! * * const user = yield* userService.getUser("123") * yield* logger.log(`Found user: ${user.name}`) * * return user * }).pipe( * Effect.provide(allServicesLayer) * ) * Effect.runSync(program) // => { id: "123", name: "DB: SELECT * FROM users WHERE id = 123" } * logs // => ["[LOG] Looking up user 123", "[LOG] Found user: DB: SELECT * FROM users WHERE id = 123"] * ``` * * @see {@link provide} for keeping dependency services private * * @stability stable * @category providing services * @since 2.0.0 */ export declare const provideMerge: { /** * Feeds the output services of the dependency layer into the requirements of * this layer, returning a layer that provides both sets of services. * * **When to use** * * Use when you need to compose `Layer`s while keeping both the constructed * service and the dependency used to build it available. * * **Details** * * Prefer {@link provide} when the dependency should stay private. * * **Example** (Providing dependencies while retaining services) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * class UserService extends Context.Service Effect.Effect<{ * id: string * name: string * }> * }>()("UserService") {} * * // Create dependency layers * const databaseLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`)) * }) * * const logs: Array = [] * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(`[LOG] ${msg}`))) * }) * * // UserService depends on Database and Logger * const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() { * const database = yield* Database * const logger = yield* Logger * * return { * getUser: Effect.fn("UserService.getUser")(function*(id: string) { * yield* logger.log(`Looking up user ${id}`) * const result = yield* database.query( * `SELECT * FROM users WHERE id = ${id}` * ) * return { id, name: result } * }) * } * })) * * // Provide dependencies and merge all services together * const allServicesLayer = userServiceLayer.pipe( * Layer.provideMerge(Layer.mergeAll(databaseLayer, loggerLayer)) * ) * * // Now the resulting layer provides UserService, Database, AND Logger * const program = Effect.gen(function*() { * const userService = yield* UserService * const logger = yield* Logger // Still available! * const database = yield* Database // Still available! * * const user = yield* userService.getUser("123") * yield* logger.log(`Found user: ${user.name}`) * * return user * }).pipe( * Effect.provide(allServicesLayer) * ) * Effect.runSync(program) // => { id: "123", name: "DB: SELECT * FROM users WHERE id = 123" } * logs // => ["[LOG] Looking up user 123", "[LOG] Found user: DB: SELECT * FROM users WHERE id = 123"] * ``` * * @see {@link provide} for keeping dependency services private * * @stability stable * @category providing services * @since 2.0.0 */ (that: Layer): (self: Layer) => Layer>; /** * Feeds the output services of the dependency layer into the requirements of * this layer, returning a layer that provides both sets of services. * * **When to use** * * Use when you need to compose `Layer`s while keeping both the constructed * service and the dependency used to build it available. * * **Details** * * Prefer {@link provide} when the dependency should stay private. * * **Example** (Providing dependencies while retaining services) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * class UserService extends Context.Service Effect.Effect<{ * id: string * name: string * }> * }>()("UserService") {} * * // Create dependency layers * const databaseLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`)) * }) * * const logs: Array = [] * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(`[LOG] ${msg}`))) * }) * * // UserService depends on Database and Logger * const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() { * const database = yield* Database * const logger = yield* Logger * * return { * getUser: Effect.fn("UserService.getUser")(function*(id: string) { * yield* logger.log(`Looking up user ${id}`) * const result = yield* database.query( * `SELECT * FROM users WHERE id = ${id}` * ) * return { id, name: result } * }) * } * })) * * // Provide dependencies and merge all services together * const allServicesLayer = userServiceLayer.pipe( * Layer.provideMerge(Layer.mergeAll(databaseLayer, loggerLayer)) * ) * * // Now the resulting layer provides UserService, Database, AND Logger * const program = Effect.gen(function*() { * const userService = yield* UserService * const logger = yield* Logger // Still available! * const database = yield* Database // Still available! * * const user = yield* userService.getUser("123") * yield* logger.log(`Found user: ${user.name}`) * * return user * }).pipe( * Effect.provide(allServicesLayer) * ) * Effect.runSync(program) // => { id: "123", name: "DB: SELECT * FROM users WHERE id = 123" } * logs // => ["[LOG] Looking up user 123", "[LOG] Found user: DB: SELECT * FROM users WHERE id = 123"] * ``` * * @see {@link provide} for keeping dependency services private * * @stability stable * @category providing services * @since 2.0.0 */ ]>(that: Layers): (self: Layer) => Layer, E | Error, Services | Exclude>>; /** * Feeds the output services of the dependency layer into the requirements of * this layer, returning a layer that provides both sets of services. * * **When to use** * * Use when you need to compose `Layer`s while keeping both the constructed * service and the dependency used to build it available. * * **Details** * * Prefer {@link provide} when the dependency should stay private. * * **Example** (Providing dependencies while retaining services) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * class UserService extends Context.Service Effect.Effect<{ * id: string * name: string * }> * }>()("UserService") {} * * // Create dependency layers * const databaseLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`)) * }) * * const logs: Array = [] * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(`[LOG] ${msg}`))) * }) * * // UserService depends on Database and Logger * const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() { * const database = yield* Database * const logger = yield* Logger * * return { * getUser: Effect.fn("UserService.getUser")(function*(id: string) { * yield* logger.log(`Looking up user ${id}`) * const result = yield* database.query( * `SELECT * FROM users WHERE id = ${id}` * ) * return { id, name: result } * }) * } * })) * * // Provide dependencies and merge all services together * const allServicesLayer = userServiceLayer.pipe( * Layer.provideMerge(Layer.mergeAll(databaseLayer, loggerLayer)) * ) * * // Now the resulting layer provides UserService, Database, AND Logger * const program = Effect.gen(function*() { * const userService = yield* UserService * const logger = yield* Logger // Still available! * const database = yield* Database // Still available! * * const user = yield* userService.getUser("123") * yield* logger.log(`Found user: ${user.name}`) * * return user * }).pipe( * Effect.provide(allServicesLayer) * ) * Effect.runSync(program) // => { id: "123", name: "DB: SELECT * FROM users WHERE id = 123" } * logs // => ["[LOG] Looking up user 123", "[LOG] Found user: DB: SELECT * FROM users WHERE id = 123"] * ``` * * @see {@link provide} for keeping dependency services private * * @stability stable * @category providing services * @since 2.0.0 */ (self: Layer, that: Layer): Layer>; /** * Feeds the output services of the dependency layer into the requirements of * this layer, returning a layer that provides both sets of services. * * **When to use** * * Use when you need to compose `Layer`s while keeping both the constructed * service and the dependency used to build it available. * * **Details** * * Prefer {@link provide} when the dependency should stay private. * * **Example** (Providing dependencies while retaining services) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * class UserService extends Context.Service Effect.Effect<{ * id: string * name: string * }> * }>()("UserService") {} * * // Create dependency layers * const databaseLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`)) * }) * * const logs: Array = [] * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(`[LOG] ${msg}`))) * }) * * // UserService depends on Database and Logger * const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() { * const database = yield* Database * const logger = yield* Logger * * return { * getUser: Effect.fn("UserService.getUser")(function*(id: string) { * yield* logger.log(`Looking up user ${id}`) * const result = yield* database.query( * `SELECT * FROM users WHERE id = ${id}` * ) * return { id, name: result } * }) * } * })) * * // Provide dependencies and merge all services together * const allServicesLayer = userServiceLayer.pipe( * Layer.provideMerge(Layer.mergeAll(databaseLayer, loggerLayer)) * ) * * // Now the resulting layer provides UserService, Database, AND Logger * const program = Effect.gen(function*() { * const userService = yield* UserService * const logger = yield* Logger // Still available! * const database = yield* Database // Still available! * * const user = yield* userService.getUser("123") * yield* logger.log(`Found user: ${user.name}`) * * return user * }).pipe( * Effect.provide(allServicesLayer) * ) * Effect.runSync(program) // => { id: "123", name: "DB: SELECT * FROM users WHERE id = 123" } * logs // => ["[LOG] Looking up user 123", "[LOG] Found user: DB: SELECT * FROM users WHERE id = 123"] * ``` * * @see {@link provide} for keeping dependency services private * * @stability stable * @category providing services * @since 2.0.0 */ ]>(self: Layer, that: Layers): Layer, E | Error, Services | Exclude>>; }; /** * Constructs a layer dynamically based on the output of this layer. * * **Example** (Creating services from layer output) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Config extends Context.Service()("Config") {} * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * const logs: Array = [] * * // Base config layer * const configLayer = Layer.succeed(Config, { * dbUrl: "postgres://localhost:5432/mydb", * logLevel: "debug" * }) * * // Dynamically create services based on config * const dynamicServiceLayer = configLayer.pipe( * Layer.flatMap((context) => { * const config = Context.get(context, Config) * * // Create database layer based on config * const dbLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => * Effect.succeed( * `Querying ${config.dbUrl}: ${sql}` * )) * }) * * // Create logger layer based on config * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((msg: string) => * config.logLevel === "debug" * ? Effect.sync(() => logs.push(`[DEBUG] ${msg}`)) * : Effect.sync(() => logs.push(msg)) * ) * }) * * // Return combined layer * return Layer.mergeAll(dbLayer, loggerLayer) * }) * ) * * // Use the dynamic services * const program = Effect.gen(function*() { * const database = yield* Database * const logger = yield* Logger * * yield* logger.log("Starting database query") * const result = yield* database.query("SELECT * FROM users") * * return result * }).pipe( * Effect.provide(dynamicServiceLayer) * ) * Effect.runSync(program) // => "Querying postgres://localhost:5432/mydb: SELECT * FROM users" * logs // => ["[DEBUG] Starting database query"] * ``` * * @stability stable * @category sequencing * @since 2.0.0 */ export declare const flatMap: { /** * Constructs a layer dynamically based on the output of this layer. * * **Example** (Creating services from layer output) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Config extends Context.Service()("Config") {} * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * const logs: Array = [] * * // Base config layer * const configLayer = Layer.succeed(Config, { * dbUrl: "postgres://localhost:5432/mydb", * logLevel: "debug" * }) * * // Dynamically create services based on config * const dynamicServiceLayer = configLayer.pipe( * Layer.flatMap((context) => { * const config = Context.get(context, Config) * * // Create database layer based on config * const dbLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => * Effect.succeed( * `Querying ${config.dbUrl}: ${sql}` * )) * }) * * // Create logger layer based on config * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((msg: string) => * config.logLevel === "debug" * ? Effect.sync(() => logs.push(`[DEBUG] ${msg}`)) * : Effect.sync(() => logs.push(msg)) * ) * }) * * // Return combined layer * return Layer.mergeAll(dbLayer, loggerLayer) * }) * ) * * // Use the dynamic services * const program = Effect.gen(function*() { * const database = yield* Database * const logger = yield* Logger * * yield* logger.log("Starting database query") * const result = yield* database.query("SELECT * FROM users") * * return result * }).pipe( * Effect.provide(dynamicServiceLayer) * ) * Effect.runSync(program) // => "Querying postgres://localhost:5432/mydb: SELECT * FROM users" * logs // => ["[DEBUG] Starting database query"] * ``` * * @stability stable * @category sequencing * @since 2.0.0 */ (f: (context: Context.Context) => Layer): (self: Layer) => Layer; /** * Constructs a layer dynamically based on the output of this layer. * * **Example** (Creating services from layer output) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Config extends Context.Service()("Config") {} * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * const logs: Array = [] * * // Base config layer * const configLayer = Layer.succeed(Config, { * dbUrl: "postgres://localhost:5432/mydb", * logLevel: "debug" * }) * * // Dynamically create services based on config * const dynamicServiceLayer = configLayer.pipe( * Layer.flatMap((context) => { * const config = Context.get(context, Config) * * // Create database layer based on config * const dbLayer = Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => * Effect.succeed( * `Querying ${config.dbUrl}: ${sql}` * )) * }) * * // Create logger layer based on config * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((msg: string) => * config.logLevel === "debug" * ? Effect.sync(() => logs.push(`[DEBUG] ${msg}`)) * : Effect.sync(() => logs.push(msg)) * ) * }) * * // Return combined layer * return Layer.mergeAll(dbLayer, loggerLayer) * }) * ) * * // Use the dynamic services * const program = Effect.gen(function*() { * const database = yield* Database * const logger = yield* Logger * * yield* logger.log("Starting database query") * const result = yield* database.query("SELECT * FROM users") * * return result * }).pipe( * Effect.provide(dynamicServiceLayer) * ) * Effect.runSync(program) // => "Querying postgres://localhost:5432/mydb: SELECT * FROM users" * logs // => ["[DEBUG] Starting database query"] * ``` * * @stability stable * @category sequencing * @since 2.0.0 */ (self: Layer, f: (context: Context.Context) => Layer): Layer; }; /** * Performs the specified effect if this layer succeeds. * * **When to use** * * Use to run an effectful observation after a layer has been built * successfully, such as logging or metrics, without changing the services the * layer provides. * * **Details** * * The callback receives the services produced by this layer. Its result is * discarded, and the original layer output is preserved. * * @see {@link tapError} for running an effect when layer construction fails with a typed error * @see {@link tapCause} for running an effect when layer construction fails with any cause * * @stability stable * @category sequencing * @since 2.0.0 */ export declare const tap: { /** * Performs the specified effect if this layer succeeds. * * **When to use** * * Use to run an effectful observation after a layer has been built * successfully, such as logging or metrics, without changing the services the * layer provides. * * **Details** * * The callback receives the services produced by this layer. Its result is * discarded, and the original layer output is preserved. * * @see {@link tapError} for running an effect when layer construction fails with a typed error * @see {@link tapCause} for running an effect when layer construction fails with any cause * * @stability stable * @category sequencing * @since 2.0.0 */ (f: (context: Context.Context) => Effect): (self: Layer) => Layer>; /** * Performs the specified effect if this layer succeeds. * * **When to use** * * Use to run an effectful observation after a layer has been built * successfully, such as logging or metrics, without changing the services the * layer provides. * * **Details** * * The callback receives the services produced by this layer. Its result is * discarded, and the original layer output is preserved. * * @see {@link tapError} for running an effect when layer construction fails with a typed error * @see {@link tapCause} for running an effect when layer construction fails with any cause * * @stability stable * @category sequencing * @since 2.0.0 */ (self: Layer, f: (context: Context.Context) => Effect): Layer>; }; /** * Performs the specified effect if this layer fails. * * **When to use** * * Use to run logging, metrics, or other effects when layer construction fails * while preserving the original typed error. * * **Details** * * The callback receives the typed error. If the callback succeeds, the layer * still fails with the original error; if the callback fails, that failure is * added to the layer's error type. * * @see {@link tap} for running an effect when layer construction succeeds * @see {@link tapCause} for inspecting the full failure cause, including defects and interruption * * @stability stable * @category sequencing * @since 2.0.0 */ export declare const tapError: { /** * Performs the specified effect if this layer fails. * * **When to use** * * Use to run logging, metrics, or other effects when layer construction fails * while preserving the original typed error. * * **Details** * * The callback receives the typed error. If the callback succeeds, the layer * still fails with the original error; if the callback fails, that failure is * added to the layer's error type. * * @see {@link tap} for running an effect when layer construction succeeds * @see {@link tapCause} for inspecting the full failure cause, including defects and interruption * * @stability stable * @category sequencing * @since 2.0.0 */ (f: (e: Types.NoInfer) => Effect): (self: Layer) => Layer>; /** * Performs the specified effect if this layer fails. * * **When to use** * * Use to run logging, metrics, or other effects when layer construction fails * while preserving the original typed error. * * **Details** * * The callback receives the typed error. If the callback succeeds, the layer * still fails with the original error; if the callback fails, that failure is * added to the layer's error type. * * @see {@link tap} for running an effect when layer construction succeeds * @see {@link tapCause} for inspecting the full failure cause, including defects and interruption * * @stability stable * @category sequencing * @since 2.0.0 */ (f: (e: E) => Effect): (self: Layer) => Layer>; /** * Performs the specified effect if this layer fails. * * **When to use** * * Use to run logging, metrics, or other effects when layer construction fails * while preserving the original typed error. * * **Details** * * The callback receives the typed error. If the callback succeeds, the layer * still fails with the original error; if the callback fails, that failure is * added to the layer's error type. * * @see {@link tap} for running an effect when layer construction succeeds * @see {@link tapCause} for inspecting the full failure cause, including defects and interruption * * @stability stable * @category sequencing * @since 2.0.0 */ (self: Layer, f: (e: Types.NoInfer) => Effect): Layer>; }; /** * Performs the specified effect when this layer fails with any cause. * * **When to use** * * Use to run diagnostics or reporting when layer construction fails and the * full `Cause` is needed. * * **Details** * * The callback receives the layer's `Cause`, so it can inspect typed errors, * defects, and interruption information. If the callback succeeds, the layer * fails again with the original cause; if the callback fails, that failure is * added to the layer's error type. * * @see {@link tapError} for observing only typed layer construction errors * @see {@link catchCause} for recovering from a layer construction failure by switching to another layer * * @stability stable * @category sequencing * @since 4.0.0 */ export declare const tapCause: { /** * Performs the specified effect when this layer fails with any cause. * * **When to use** * * Use to run diagnostics or reporting when layer construction fails and the * full `Cause` is needed. * * **Details** * * The callback receives the layer's `Cause`, so it can inspect typed errors, * defects, and interruption information. If the callback succeeds, the layer * fails again with the original cause; if the callback fails, that failure is * added to the layer's error type. * * @see {@link tapError} for observing only typed layer construction errors * @see {@link catchCause} for recovering from a layer construction failure by switching to another layer * * @stability stable * @category sequencing * @since 4.0.0 */ (f: (cause: Cause.Cause>) => Effect): (self: Layer) => Layer>; /** * Performs the specified effect when this layer fails with any cause. * * **When to use** * * Use to run diagnostics or reporting when layer construction fails and the * full `Cause` is needed. * * **Details** * * The callback receives the layer's `Cause`, so it can inspect typed errors, * defects, and interruption information. If the callback succeeds, the layer * fails again with the original cause; if the callback fails, that failure is * added to the layer's error type. * * @see {@link tapError} for observing only typed layer construction errors * @see {@link catchCause} for recovering from a layer construction failure by switching to another layer * * @stability stable * @category sequencing * @since 4.0.0 */ (f: (cause: Cause.Cause) => Effect): (self: Layer) => Layer>; /** * Performs the specified effect when this layer fails with any cause. * * **When to use** * * Use to run diagnostics or reporting when layer construction fails and the * full `Cause` is needed. * * **Details** * * The callback receives the layer's `Cause`, so it can inspect typed errors, * defects, and interruption information. If the callback succeeds, the layer * fails again with the original cause; if the callback fails, that failure is * added to the layer's error type. * * @see {@link tapError} for observing only typed layer construction errors * @see {@link catchCause} for recovering from a layer construction failure by switching to another layer * * @stability stable * @category sequencing * @since 4.0.0 */ (self: Layer, f: (cause: Cause.Cause>) => Effect): Layer>; }; /** * Converts layer construction failures into defects, removing them from the * layer's error type. * * **Details** * * Use this only when failures should be treated as unrecoverable defects rather * than typed errors that callers can handle. * * **Example** (Converting layer failures to defects) * * ```ts import.meta.vitest * import { Context, Data, Effect, Exit, Layer } from "effect" * * class DatabaseError extends Data.TaggedError("DatabaseError")<{ * message: string * }> {} * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * // Layer that can fail during construction * const error = new DatabaseError({ message: "Connection failed" }) * const flakyDatabaseLayer = Layer.effect( * Database, * Effect.fail(error) * ) * * // Convert failures to fiber death - removes error from type * const reliableDatabaseLayer = flakyDatabaseLayer.pipe(Layer.orDie) * * // Now the layer type is Layer - no error in type * const program = Effect.gen(function*() { * const database = yield* Database * return yield* database.query("SELECT * FROM users") * }).pipe( * Effect.provide(reliableDatabaseLayer) * ) * * Effect.runSync(Effect.exit(program)) // => Exit.die(error) * ``` * * @stability stable * @category error handling * @since 2.0.0 */ export declare const orDie: (self: Layer) => Layer; declare const catch_: { (onError: (error: E) => Layer): (self: Layer) => Layer; (self: Layer, onError: (error: E) => Layer): Layer; }; export { /** * Recovers from all typed errors by switching to another layer. * * **When to use** * * Use when every typed `Layer` construction error should use the same * recovery path. * * @see {@link catchTag} for recovering from specific tagged errors * @see {@link catchCause} for recovering with access to the full cause * * @stability stable * @category error handling * @since 4.0.0 */ catch_ as catch }; /** * Recovers from specific tagged errors. * * **When to use** * * Use when only some tagged `Layer` construction errors should be recovered. * * **Example** (Recovering from tagged layer errors) * * ```ts import.meta.vitest * import { Context, Data, Effect, Layer } from "effect" * * class ConfigError extends Data.TaggedError("ConfigError") {} * * class Config extends Context.Service()("Config") {} * * const configLayer = Layer.effect(Config, Effect.fail(new ConfigError())) * * const fallbackLayer = Layer.succeed(Config, { apiUrl: "http://localhost" }) * * const recovered = configLayer.pipe( * Layer.catchTag("ConfigError", () => fallbackLayer) * ) * const program = Config.useSync((config) => config.apiUrl) * Effect.runSync(Effect.provide(program, recovered)) // => "http://localhost" * ``` * * @see {@link catchCause} for recovering with access to the full cause * * @stability stable * @category error handling * @since 4.0.0 */ export declare const catchTag: { /** * Recovers from specific tagged errors. * * **When to use** * * Use when only some tagged `Layer` construction errors should be recovered. * * **Example** (Recovering from tagged layer errors) * * ```ts import.meta.vitest * import { Context, Data, Effect, Layer } from "effect" * * class ConfigError extends Data.TaggedError("ConfigError") {} * * class Config extends Context.Service()("Config") {} * * const configLayer = Layer.effect(Config, Effect.fail(new ConfigError())) * * const fallbackLayer = Layer.succeed(Config, { apiUrl: "http://localhost" }) * * const recovered = configLayer.pipe( * Layer.catchTag("ConfigError", () => fallbackLayer) * ) * const program = Config.useSync((config) => config.apiUrl) * Effect.runSync(Effect.provide(program, recovered)) // => "http://localhost" * ``` * * @see {@link catchCause} for recovering with access to the full cause * * @stability stable * @category error handling * @since 4.0.0 */ | NonEmptyReadonlyArray>, E, RIn2, E2, ROut2>(k: K, f: (e: Types.ExtractTag, K extends NonEmptyReadonlyArray ? K[number] : K>) => Layer): (self: Layer) => Layer ? K[number] : K>, RIn2 | RIn>; /** * Recovers from specific tagged errors. * * **When to use** * * Use when only some tagged `Layer` construction errors should be recovered. * * **Example** (Recovering from tagged layer errors) * * ```ts import.meta.vitest * import { Context, Data, Effect, Layer } from "effect" * * class ConfigError extends Data.TaggedError("ConfigError") {} * * class Config extends Context.Service()("Config") {} * * const configLayer = Layer.effect(Config, Effect.fail(new ConfigError())) * * const fallbackLayer = Layer.succeed(Config, { apiUrl: "http://localhost" }) * * const recovered = configLayer.pipe( * Layer.catchTag("ConfigError", () => fallbackLayer) * ) * const program = Config.useSync((config) => config.apiUrl) * Effect.runSync(Effect.provide(program, recovered)) // => "http://localhost" * ``` * * @see {@link catchCause} for recovering with access to the full cause * * @stability stable * @category error handling * @since 4.0.0 */ | NonEmptyReadonlyArray>, RIn2, E2, ROut2>(self: Layer, k: K, f: (e: Types.ExtractTag ? K[number] : K>) => Layer): Layer ? K[number] : K>, RIn | RIn2>; }; /** * Recovers from any failure cause by switching to another layer. * * **When to use** * * Use when you need `Layer` recovery to inspect more than the typed error, * such as defects or interruption information. * * **Details** * * The handler receives the full `Cause` of the failed layer, including typed * errors, unexpected defects, and interruption information, and returns the * fallback layer to build instead. Finalizers for resources acquired by the * failed layer are still run before the fallback layer is acquired. * * **Example** (Recovering from layer failures by cause) * * ```ts import.meta.vitest * import { Context, Data, Effect, Layer } from "effect" * * class DatabaseError extends Data.TaggedError("DatabaseError")<{ * message: string * }> {} * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const primaryDatabaseLayer = Layer.effect(Database, * Effect.fail(new DatabaseError({ message: "Primary DB unreachable" })) * ) * * const databaseWithFallback = primaryDatabaseLayer.pipe( * Layer.catchCause(() => { * return Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Memory: ${sql}`)) * }) * }) * ) * * const program = Effect.gen(function*() { * const database = yield* Database * return yield* database.query("SELECT * FROM users") * }).pipe( * Effect.provide(databaseWithFallback) * ) * * await Effect.runPromise(program) // => "Memory: SELECT * FROM users" * ``` * * @see {@link catchTag} for recovering from specific tagged errors * * @stability stable * @category error handling * @since 4.0.0 */ export declare const catchCause: { /** * Recovers from any failure cause by switching to another layer. * * **When to use** * * Use when you need `Layer` recovery to inspect more than the typed error, * such as defects or interruption information. * * **Details** * * The handler receives the full `Cause` of the failed layer, including typed * errors, unexpected defects, and interruption information, and returns the * fallback layer to build instead. Finalizers for resources acquired by the * failed layer are still run before the fallback layer is acquired. * * **Example** (Recovering from layer failures by cause) * * ```ts import.meta.vitest * import { Context, Data, Effect, Layer } from "effect" * * class DatabaseError extends Data.TaggedError("DatabaseError")<{ * message: string * }> {} * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const primaryDatabaseLayer = Layer.effect(Database, * Effect.fail(new DatabaseError({ message: "Primary DB unreachable" })) * ) * * const databaseWithFallback = primaryDatabaseLayer.pipe( * Layer.catchCause(() => { * return Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Memory: ${sql}`)) * }) * }) * ) * * const program = Effect.gen(function*() { * const database = yield* Database * return yield* database.query("SELECT * FROM users") * }).pipe( * Effect.provide(databaseWithFallback) * ) * * await Effect.runPromise(program) // => "Memory: SELECT * FROM users" * ``` * * @see {@link catchTag} for recovering from specific tagged errors * * @stability stable * @category error handling * @since 4.0.0 */ (onError: (cause: Cause.Cause) => Layer): (self: Layer) => Layer; /** * Recovers from any failure cause by switching to another layer. * * **When to use** * * Use when you need `Layer` recovery to inspect more than the typed error, * such as defects or interruption information. * * **Details** * * The handler receives the full `Cause` of the failed layer, including typed * errors, unexpected defects, and interruption information, and returns the * fallback layer to build instead. Finalizers for resources acquired by the * failed layer are still run before the fallback layer is acquired. * * **Example** (Recovering from layer failures by cause) * * ```ts import.meta.vitest * import { Context, Data, Effect, Layer } from "effect" * * class DatabaseError extends Data.TaggedError("DatabaseError")<{ * message: string * }> {} * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const primaryDatabaseLayer = Layer.effect(Database, * Effect.fail(new DatabaseError({ message: "Primary DB unreachable" })) * ) * * const databaseWithFallback = primaryDatabaseLayer.pipe( * Layer.catchCause(() => { * return Layer.succeed(Database, { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Memory: ${sql}`)) * }) * }) * ) * * const program = Effect.gen(function*() { * const database = yield* Database * return yield* database.query("SELECT * FROM users") * }).pipe( * Effect.provide(databaseWithFallback) * ) * * await Effect.runPromise(program) // => "Memory: SELECT * FROM users" * ``` * * @see {@link catchTag} for recovering from specific tagged errors * * @stability stable * @category error handling * @since 4.0.0 */ (self: Layer, onError: (cause: Cause.Cause) => Layer): Layer; }; /** * Updates a service in the context with a new implementation. * * **When to use** * * Use to adapt or extend a service's behavior during the creation of a * layer. * * **Details** * * This function modifies the existing implementation of a service in the * context. It retrieves the current service, applies the provided * transformation function `f`, and replaces the old service with the * transformed one. * * @stability stable * @category providing services * @since 3.13.0 */ export declare const updateService: { /** * Updates a service in the context with a new implementation. * * **When to use** * * Use to adapt or extend a service's behavior during the creation of a * layer. * * **Details** * * This function modifies the existing implementation of a service in the * context. It retrieves the current service, applies the provided * transformation function `f`, and replaces the old service with the * transformed one. * * @stability stable * @category providing services * @since 3.13.0 */ (service: Context.Key, f: (a: Types.NoInfer) => A): (layer: Layer) => Layer; /** * Updates a service in the context with a new implementation. * * **When to use** * * Use to adapt or extend a service's behavior during the creation of a * layer. * * **Details** * * This function modifies the existing implementation of a service in the * context. It retrieves the current service, applies the provided * transformation function `f`, and replaces the old service with the * transformed one. * * @stability stable * @category providing services * @since 3.13.0 */ (layer: Layer, service: Context.Key, f: (a: Types.NoInfer) => A): Layer; }; /** * Creates a fresh version of this layer that will not be shared. * * **When to use** * * Use when you need two parts of an application to receive separate instances * of a resource, such as two independent client sessions. * * **Gotchas** * * Do not use it just to work around confusing composition. By default, sharing * the same layer value is usually the desired behavior. * * **Example** (Creating non-shared layer instances) * * ```ts import.meta.vitest * import { Context, Effect, Layer, Ref } from "effect" * * class Counter extends Context.Service()("Counter") {} * * class Left extends Context.Service()("Left") {} * * class Right extends Context.Service()("Right") {} * * const leftLayer = Layer.effect(Left, Effect.gen(function*() { * const counter = yield* Counter * return { counterId: counter.id } * })) * * const rightLayer = Layer.effect(Right, Effect.gen(function*() { * const counter = yield* Counter * return { counterId: counter.id } * })) * * const compareIds = Effect.gen(function*() { * const left = yield* Left * const right = yield* Right * return left.counterId === right.counterId * }) * * const program = Effect.gen(function*() { * const nextId = yield* Ref.make(0) * * const counterLayer = Layer.effect(Counter, Effect.gen(function*() { * const id = yield* Ref.updateAndGet(nextId, (n) => n + 1) * return { id } * })) * * const shared = Layer.merge( * Layer.provide(leftLayer, counterLayer), * Layer.provide(rightLayer, counterLayer) * ) * * const sharedResult = yield* Effect.provide(compareIds, shared) * * const freshCounterLayer = Layer.fresh(counterLayer) * const fresh = Layer.merge( * Layer.provide(leftLayer, freshCounterLayer), * Layer.provide(rightLayer, freshCounterLayer) * ) * * const freshResult = yield* Effect.provide(compareIds, fresh) * * return { shared: sharedResult, fresh: freshResult } * }) * * await Effect.runPromise(program) // => { shared: true, fresh: false } * ``` * * @stability stable * @category layers * @since 2.0.0 */ export declare const fresh: (self: Layer) => Layer; /** * Builds this layer and keeps it alive until the returned effect is interrupted. * * **When to use** * * Use when you model your entire application as a layer, such as an HTTP * server. * * **Details** * * When the returned effect is interrupted, the layer scope is closed and all * finalizers registered during layer acquisition are run. * * **Example** (Launching an application layer) * * ```ts import.meta.vitest * import { Context, Deferred, Effect, Fiber, Layer, Ref } from "effect" * * class HttpServer extends Context.Service()("HttpServer") {} * * const program = Effect.gen(function*() { * const events = yield* Ref.make>([]) * const started = yield* Deferred.make() * * const serverLayer = Layer.effect(HttpServer, Effect.gen(function*() { * yield* Ref.update(events, (events) => [...events, "Starting HTTP server..."]) * yield* Deferred.succeed(started, undefined) * return { port: 3000 } * })) * * const fiber = yield* Effect.forkChild(Layer.launch(serverLayer)) * yield* Deferred.await(started) * yield* Fiber.interrupt(fiber) * return yield* Ref.get(events) * }) * * await Effect.runPromise(program) // => ["Starting HTTP server..."] * ``` * * @stability stable * @category converting * @since 2.0.0 */ export declare const launch: (self: Layer) => Effect; /** * A utility type for creating partial mocks of services in testing. * * **When to use** * * Use to type partial test service implementations where only exercised * effectful members are stubbed. * * **Details** * * This type makes `Effect`, `Stream`, and `Channel` values and functions * returning them optional, while keeping non-effectful properties required. * This allows you to provide only the methods you need to test while leaving * others unimplemented. * * @see {@link mock} for creating a mock layer from a partial service implementation * * @stability stable * @category testing * @since 3.17.0 */ export type PartialEffectful = Types.Simplify<{ [K in keyof A as A[K] extends AnyEffectOrStream ? K : never]?: A[K]; } & { [K in keyof A as A[K] extends AnyEffectOrStream ? never : K]: A[K]; }>; type AnyEffectOrStream = Effect | Stream.Stream | Channel.Channel | ((...args: any) => Effect) | ((...args: any) => Stream.Stream) | ((...args: any) => Channel.Channel); /** * Creates a mock layer for testing purposes. You can provide a partial * implementation of the service. Any missing members that are `Effect`s, * `Stream`s, `Channel`s, or functions returning them will fail with an * unimplemented defect when used. * * **Details** * * Missing members are represented by a value that can be used as an `Effect`, * `Stream`, `Channel`, or as a function returning an `Effect`. This lets the * mock preserve the shape of common service methods while still failing loudly * when an unimplemented member is exercised. * * **Example** (Mocking services for tests) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class UserService extends Context.Service Effect.Effect<{ id: string; name: string }, Error> * readonly deleteUser: (id: string) => Effect.Effect * readonly updateUser: ( * id: string, * data: object * ) => Effect.Effect<{ id: string; name: string }, Error> * }>()("UserService") {} * * // Create a partial mock - only implement what you need for testing * const testUserLayer = Layer.mock(UserService, { * config: { apiUrl: "https://test-api.com" }, // Required - non-Effect property * getUser: (id: string) => Effect.succeed({ id, name: "Test User" }) // Mock implementation * // deleteUser and updateUser are omitted - will throw UnimplementedError if called * }) * * // Use in tests * const testProgram = Effect.gen(function*() { * const userService = yield* UserService * * // This works - we provided an implementation * const user = yield* userService.getUser("123") * * // This would throw - we didn't implement deleteUser * // yield* userService.deleteUser("123") // UnimplementedError * * return user.name * }).pipe( * Effect.provide(testUserLayer) * ) * Effect.runSync(testProgram) // => "Test User" * ``` * * @stability stable * @category testing * @since 3.17.0 */ export declare const mock: { /** * Creates a mock layer for testing purposes. You can provide a partial * implementation of the service. Any missing members that are `Effect`s, * `Stream`s, `Channel`s, or functions returning them will fail with an * unimplemented defect when used. * * **Details** * * Missing members are represented by a value that can be used as an `Effect`, * `Stream`, `Channel`, or as a function returning an `Effect`. This lets the * mock preserve the shape of common service methods while still failing loudly * when an unimplemented member is exercised. * * **Example** (Mocking services for tests) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class UserService extends Context.Service Effect.Effect<{ id: string; name: string }, Error> * readonly deleteUser: (id: string) => Effect.Effect * readonly updateUser: ( * id: string, * data: object * ) => Effect.Effect<{ id: string; name: string }, Error> * }>()("UserService") {} * * // Create a partial mock - only implement what you need for testing * const testUserLayer = Layer.mock(UserService, { * config: { apiUrl: "https://test-api.com" }, // Required - non-Effect property * getUser: (id: string) => Effect.succeed({ id, name: "Test User" }) // Mock implementation * // deleteUser and updateUser are omitted - will throw UnimplementedError if called * }) * * // Use in tests * const testProgram = Effect.gen(function*() { * const userService = yield* UserService * * // This works - we provided an implementation * const user = yield* userService.getUser("123") * * // This would throw - we didn't implement deleteUser * // yield* userService.deleteUser("123") // UnimplementedError * * return user.name * }).pipe( * Effect.provide(testUserLayer) * ) * Effect.runSync(testProgram) // => "Test User" * ``` * * @stability stable * @category testing * @since 3.17.0 */ (service: Context.Key): (implementation: PartialEffectful) => Layer; /** * Creates a mock layer for testing purposes. You can provide a partial * implementation of the service. Any missing members that are `Effect`s, * `Stream`s, `Channel`s, or functions returning them will fail with an * unimplemented defect when used. * * **Details** * * Missing members are represented by a value that can be used as an `Effect`, * `Stream`, `Channel`, or as a function returning an `Effect`. This lets the * mock preserve the shape of common service methods while still failing loudly * when an unimplemented member is exercised. * * **Example** (Mocking services for tests) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class UserService extends Context.Service Effect.Effect<{ id: string; name: string }, Error> * readonly deleteUser: (id: string) => Effect.Effect * readonly updateUser: ( * id: string, * data: object * ) => Effect.Effect<{ id: string; name: string }, Error> * }>()("UserService") {} * * // Create a partial mock - only implement what you need for testing * const testUserLayer = Layer.mock(UserService, { * config: { apiUrl: "https://test-api.com" }, // Required - non-Effect property * getUser: (id: string) => Effect.succeed({ id, name: "Test User" }) // Mock implementation * // deleteUser and updateUser are omitted - will throw UnimplementedError if called * }) * * // Use in tests * const testProgram = Effect.gen(function*() { * const userService = yield* UserService * * // This works - we provided an implementation * const user = yield* userService.getUser("123") * * // This would throw - we didn't implement deleteUser * // yield* userService.deleteUser("123") // UnimplementedError * * return user.name * }).pipe( * Effect.provide(testUserLayer) * ) * Effect.runSync(testProgram) // => "Test User" * ``` * * @stability stable * @category testing * @since 3.17.0 */ (service: Context.Key, implementation: Types.NoInfer>): Layer; }; /** * Ensures that a layer's success type extends a given type `ROut`. * * **Details** * * This function provides compile-time type checking to ensure that the success * value of a layer conforms to a specific type constraint. * * **Example** (Constraining layer success types) * * ```ts import.meta.vitest * import { Context, Layer } from "effect" * * const NumberService = Context.Service("Number") * const numberLayer = Layer.succeed(NumberService, 42) * * // Define a constraint that the success type must be a number * const satisfiesNumber = Layer.satisfiesSuccessType() * * // This works - Layer<42, never, never> extends Layer * const validLayer = satisfiesNumber(numberLayer) * ``` * * @stability stable * @category utility types * @since 4.0.0 */ export declare const satisfiesSuccessType: () => (layer: Layer) => Layer; /** * Ensures that a layer's error type extends a given type `E`. * * **Details** * * This function provides compile-time type checking to ensure that the error * type of a layer conforms to a specific type constraint. * * **Example** (Constraining layer error types) * * ```ts import.meta.vitest * import { Effect, Layer } from "effect" * * const typeErrorLayer = Layer.effectDiscard(Effect.fail(new TypeError("boom"))) * * // Define a constraint that the error type must be an Error * const satisfiesError = Layer.satisfiesErrorType() * * // This works - Layer extends Layer * const validLayer = satisfiesError(typeErrorLayer) * ``` * * @stability stable * @category utility types * @since 4.0.0 */ export declare const satisfiesErrorType: () => (layer: Layer) => Layer; /** * Ensures that a layer's requirements type extends a given type `R`. * * **Details** * * This function provides compile-time type checking to ensure that the * requirements type of a layer conforms to a specific type constraint. * * **Example** (Constraining layer service requirements) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * const NumberService = Context.Service("Number") * const numberLayer = Layer.effectDiscard(Effect.asVoid(NumberService)) * * // Define a constraint that the service requirements must be numbers * const satisfiesNumber = Layer.satisfiesServicesType() * * // This works - Layer extends Layer * const validLayer = satisfiesNumber(numberLayer) * ``` * * @stability stable * @category utility types * @since 4.0.0 */ export declare const satisfiesServicesType: () => (layer: Layer) => Layer; /** * Represents options that can be used to control the behavior of spans created * for layers. * * **When to use** * * Use to configure tracing metadata, stack trace capture, and `onEnd` * finalization for spans created by `Layer.span` and `Layer.withSpan` during * layer construction. * * **Details** * * Extends `Tracer.SpanOptions` with `onEnd`, which runs when the layer span * ends as the layer scope closes. * * @see {@link span} for creating a layer span * @see {@link withSpan} for wrapping layer construction in a span * * @stability stable * @category options * @since 4.0.0 */ export interface SpanOptions extends Tracer.SpanOptions { /** * Runs when the span associated with the layer ends, which happens when the * layer scope is closed. */ readonly onEnd?: ((span: Tracer.Span, exit: Exit.Exit) => Effect) | undefined; } /** * Constructs a new `Layer` which creates a span and registers it as the current * parent span. * * **Details** * * This allows you to create a traced scope for layer construction, making all * operations within the layer constructor part of the same trace span. The span * is automatically ended when the layer's scope is closed. If `onEnd` is * provided, it receives the span and the layer scope's exit value when the span * ends. * * **Example** (Tracing layer construction with a span) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * import type { Tracer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * const logs: Array = [] * * // Create a traced layer - all operations performed during construction of * // the `Database` service are part of the "database-init" span * const databaseLayer = Layer.effect(Database, Effect.gen(function*() { * // These operations are traced under "database-init" span * logs.push("Connecting to database") * logs.push("Database connected") * * const parentSpan = yield* Effect.currentParentSpan * logs.push((parentSpan as Tracer.Span).name) * * return { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result: ${sql}`)) * } * })).pipe(Layer.provide(Layer.span("database-init", { * onEnd: (span, exit) => * Effect.sync(() => logs.push(`Span ${span.name} ended with: ${exit._tag}`)) * }))) * * const program = Database.use((database) => database.query("SELECT 1")) * Effect.runSync(Effect.provide(program, databaseLayer)) // => "Result: SELECT 1" * logs // => ["Connecting to database", "Database connected", "database-init", "Span database-init ended with: Success"] * ``` * * @stability stable * @category tracing * @since 2.0.0 */ export declare const span: (name: string, options?: SpanOptions) => Layer; /** * Constructs a layer that provides an existing span as the current parent span. * * **Details** * * The supplied span is made available through `Tracer.ParentSpan` for layers * that are built with this layer. This API does not create, end, or close the * span; the caller remains responsible for the span's lifetime. * * **Example** (Referencing an existing parent span) * * ```ts import.meta.vitest * import { Context, Effect, Layer, Tracer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * // Create a layer that uses an existing span as parent * const databaseLayer = Layer.effect( * Database, * Effect.gen(function*() { * const parentSpan = yield* Effect.currentParentSpan * * return { * spanId: parentSpan.spanId, * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result: ${sql}`)) * } * }) * ).pipe(Layer.provide(Layer.parentSpan(Tracer.externalSpan({ * spanId: "42", * traceId: "000" * })))) * const program = Database.use((database) => * Effect.map(database.query("SELECT 1"), (result) => ({ spanId: database.spanId, result }))) * Effect.runSync(Effect.provide(program, databaseLayer)) // => { spanId: "42", result: "Result: SELECT 1" } * ``` * * @stability stable * @category tracing * @since 2.0.0 */ export declare const parentSpan: (span: Tracer.AnySpan) => Layer; /** * Wraps a `Layer` with a new tracing span, making all operations in the layer * constructor part of the named trace span. * * **Details** * * This creates a new span for the layer's construction and execution. The span * is automatically ended when the layer's scope is closed. This is useful for * tracking the lifecycle and performance of layer initialization. * * **Example** (Wrapping a layer with a span) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * const logs: Array = [] * * // Create layers with tracing * const databaseLayer = Layer.effect(Database, Effect.gen(function*() { * return { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result: ${sql}`)) * } * })).pipe(Layer.withSpan("database-initialization", { * attributes: { dbType: "postgres" } * })) * * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(msg))) * }).pipe(Layer.withSpan("logger-initialization")) * * // Combine traced layers * const appLayer = Layer.mergeAll(databaseLayer, loggerLayer).pipe( * Layer.withSpan("app-initialization", { * onEnd: (span, exit) => * Effect.sync(() => logs.push(`Application initialization completed: ${exit._tag}`)) * }) * ) * * const program = Effect.gen(function*() { * const database = yield* Database * const logger = yield* Logger * * yield* logger.log("Application ready") * return yield* database.query("SELECT * FROM users") * }).pipe(Effect.provide(appLayer)) * Effect.runSync(program) // => "Result: SELECT * FROM users" * logs // => ["Application ready", "Application initialization completed: Success"] * ``` * * @stability stable * @category tracing * @since 2.0.0 */ export declare const withSpan: { /** * Wraps a `Layer` with a new tracing span, making all operations in the layer * constructor part of the named trace span. * * **Details** * * This creates a new span for the layer's construction and execution. The span * is automatically ended when the layer's scope is closed. This is useful for * tracking the lifecycle and performance of layer initialization. * * **Example** (Wrapping a layer with a span) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * const logs: Array = [] * * // Create layers with tracing * const databaseLayer = Layer.effect(Database, Effect.gen(function*() { * return { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result: ${sql}`)) * } * })).pipe(Layer.withSpan("database-initialization", { * attributes: { dbType: "postgres" } * })) * * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(msg))) * }).pipe(Layer.withSpan("logger-initialization")) * * // Combine traced layers * const appLayer = Layer.mergeAll(databaseLayer, loggerLayer).pipe( * Layer.withSpan("app-initialization", { * onEnd: (span, exit) => * Effect.sync(() => logs.push(`Application initialization completed: ${exit._tag}`)) * }) * ) * * const program = Effect.gen(function*() { * const database = yield* Database * const logger = yield* Logger * * yield* logger.log("Application ready") * return yield* database.query("SELECT * FROM users") * }).pipe(Effect.provide(appLayer)) * Effect.runSync(program) // => "Result: SELECT * FROM users" * logs // => ["Application ready", "Application initialization completed: Success"] * ``` * * @stability stable * @category tracing * @since 2.0.0 */ (name: string, options?: SpanOptions): (self: Layer) => Layer>; /** * Wraps a `Layer` with a new tracing span, making all operations in the layer * constructor part of the named trace span. * * **Details** * * This creates a new span for the layer's construction and execution. The span * is automatically ended when the layer's scope is closed. This is useful for * tracking the lifecycle and performance of layer initialization. * * **Example** (Wrapping a layer with a span) * * ```ts import.meta.vitest * import { Context, Effect, Layer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Logger extends Context.Service Effect.Effect * }>()("Logger") {} * * const logs: Array = [] * * // Create layers with tracing * const databaseLayer = Layer.effect(Database, Effect.gen(function*() { * return { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result: ${sql}`)) * } * })).pipe(Layer.withSpan("database-initialization", { * attributes: { dbType: "postgres" } * })) * * const loggerLayer = Layer.succeed(Logger, { * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(msg))) * }).pipe(Layer.withSpan("logger-initialization")) * * // Combine traced layers * const appLayer = Layer.mergeAll(databaseLayer, loggerLayer).pipe( * Layer.withSpan("app-initialization", { * onEnd: (span, exit) => * Effect.sync(() => logs.push(`Application initialization completed: ${exit._tag}`)) * }) * ) * * const program = Effect.gen(function*() { * const database = yield* Database * const logger = yield* Logger * * yield* logger.log("Application ready") * return yield* database.query("SELECT * FROM users") * }).pipe(Effect.provide(appLayer)) * Effect.runSync(program) // => "Result: SELECT * FROM users" * logs // => ["Application ready", "Application initialization completed: Success"] * ``` * * @stability stable * @category tracing * @since 2.0.0 */ (self: Layer, name: string, options?: SpanOptions): Layer>; }; /** * Wraps a layer so spans created during its construction use the supplied span * as their parent. * * **Details** * * Use this to attach layer construction to an existing trace hierarchy. This API * does not create or end the supplied parent span. * * When the supplied span is a native `Span`, layer construction also receives * diagnostic information that helps associate failures with the layer call site. * External spans are only installed as the parent span and do not add this * diagnostic call-site information. * * **Example** (Attaching layers to an existing parent span) * * ```ts import.meta.vitest * import { Context, Effect, Layer, Tracer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Cache extends Context.Service Effect.Effect * }>()("Cache") {} * * // Create layers * const DatabaseLayer = Layer.effect(Database, Effect.gen(function*() { * return { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`)) * } * })) * * const CacheLayer = Layer.effect(Cache, Effect.gen(function*() { * return { * get: Effect.fn("Cache.get")((key: string) => Effect.succeed(`Cache: ${key}`)) * } * })) * * // Use with an existing parent span from Effect.withSpan * const program = Effect.withSpan("application-startup")( * Effect.gen(function*() { * const parentSpan = yield* Tracer.ParentSpan * * // Both layers will be children of "application-startup" span * const AppLayer = Layer.mergeAll(DatabaseLayer, CacheLayer).pipe( * Layer.withParentSpan(parentSpan) * ) * * const context = yield* Layer.build(AppLayer) * const database = Context.get(context, Database) * const cache = Context.get(context, Cache) * * const dbResult = yield* database.query("SELECT * FROM users") * const cacheResult = yield* cache.get("user:123") * * return { dbResult, cacheResult } * }) * ) * Effect.runSync(Effect.scoped(program)) // => { dbResult: "DB: SELECT * FROM users", cacheResult: "Cache: user:123" } * ``` * * @stability stable * @category tracing * @since 2.0.0 */ export declare const withParentSpan: { /** * Wraps a layer so spans created during its construction use the supplied span * as their parent. * * **Details** * * Use this to attach layer construction to an existing trace hierarchy. This API * does not create or end the supplied parent span. * * When the supplied span is a native `Span`, layer construction also receives * diagnostic information that helps associate failures with the layer call site. * External spans are only installed as the parent span and do not add this * diagnostic call-site information. * * **Example** (Attaching layers to an existing parent span) * * ```ts import.meta.vitest * import { Context, Effect, Layer, Tracer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Cache extends Context.Service Effect.Effect * }>()("Cache") {} * * // Create layers * const DatabaseLayer = Layer.effect(Database, Effect.gen(function*() { * return { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`)) * } * })) * * const CacheLayer = Layer.effect(Cache, Effect.gen(function*() { * return { * get: Effect.fn("Cache.get")((key: string) => Effect.succeed(`Cache: ${key}`)) * } * })) * * // Use with an existing parent span from Effect.withSpan * const program = Effect.withSpan("application-startup")( * Effect.gen(function*() { * const parentSpan = yield* Tracer.ParentSpan * * // Both layers will be children of "application-startup" span * const AppLayer = Layer.mergeAll(DatabaseLayer, CacheLayer).pipe( * Layer.withParentSpan(parentSpan) * ) * * const context = yield* Layer.build(AppLayer) * const database = Context.get(context, Database) * const cache = Context.get(context, Cache) * * const dbResult = yield* database.query("SELECT * FROM users") * const cacheResult = yield* cache.get("user:123") * * return { dbResult, cacheResult } * }) * ) * Effect.runSync(Effect.scoped(program)) // => { dbResult: "DB: SELECT * FROM users", cacheResult: "Cache: user:123" } * ``` * * @stability stable * @category tracing * @since 2.0.0 */ (span: Tracer.AnySpan, options?: Tracer.TraceOptions): (self: Layer) => Layer>; /** * Wraps a layer so spans created during its construction use the supplied span * as their parent. * * **Details** * * Use this to attach layer construction to an existing trace hierarchy. This API * does not create or end the supplied parent span. * * When the supplied span is a native `Span`, layer construction also receives * diagnostic information that helps associate failures with the layer call site. * External spans are only installed as the parent span and do not add this * diagnostic call-site information. * * **Example** (Attaching layers to an existing parent span) * * ```ts import.meta.vitest * import { Context, Effect, Layer, Tracer } from "effect" * * class Database extends Context.Service Effect.Effect * }>()("Database") {} * * class Cache extends Context.Service Effect.Effect * }>()("Cache") {} * * // Create layers * const DatabaseLayer = Layer.effect(Database, Effect.gen(function*() { * return { * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`)) * } * })) * * const CacheLayer = Layer.effect(Cache, Effect.gen(function*() { * return { * get: Effect.fn("Cache.get")((key: string) => Effect.succeed(`Cache: ${key}`)) * } * })) * * // Use with an existing parent span from Effect.withSpan * const program = Effect.withSpan("application-startup")( * Effect.gen(function*() { * const parentSpan = yield* Tracer.ParentSpan * * // Both layers will be children of "application-startup" span * const AppLayer = Layer.mergeAll(DatabaseLayer, CacheLayer).pipe( * Layer.withParentSpan(parentSpan) * ) * * const context = yield* Layer.build(AppLayer) * const database = Context.get(context, Database) * const cache = Context.get(context, Cache) * * const dbResult = yield* database.query("SELECT * FROM users") * const cacheResult = yield* cache.get("user:123") * * return { dbResult, cacheResult } * }) * ) * Effect.runSync(Effect.scoped(program)) // => { dbResult: "DB: SELECT * FROM users", cacheResult: "Cache: user:123" } * ``` * * @stability stable * @category tracing * @since 2.0.0 */ (self: Layer, span: Tracer.AnySpan, options?: Tracer.TraceOptions): Layer>; }; //# sourceMappingURL=Layer.d.ts.map