/** * Data sources used by `Config` to load raw configuration values. A * `ConfigProvider` reads paths from places such as environment variables, * JavaScript objects, `.env` contents, or directories, and returns a uniform * `Node` shape that config schemas can decode. The module also includes helpers * for composing providers, changing paths, and installing providers through * layers. * * @stability stable * @since 4.0.0 */ import * as Context from "./Context.ts"; import * as Effect from "./Effect.ts"; import * as FileSystem from "./FileSystem.ts"; import * as Layer from "./Layer.ts"; import * as Path_ from "./Path.ts"; import type { Pipeable } from "./Pipeable.ts"; import type { PlatformError } from "./PlatformError.ts"; import type { Scope } from "./Scope.ts"; /** * A discriminated union describing the shape of a configuration value at a * given path. * * **When to use** * * Use when implementing a custom `ConfigProvider` by returning raw * nodes from the `get` callback passed to {@link make}, or when inspecting raw * provider output before schema parsing. * * **Details** * * `Value` is a terminal string leaf. `Record` is an object-like container * whose immediate child keys are known and may carry an optional co-located * `value`. `Array` is an indexed container with a known `length` and may also * carry an optional co-located `value`. * * Provider lookups return `undefined` when no node exists at the requested * path. Within a node that was found, `value: undefined` has a narrower * structural meaning: the container exists but has no co-located scalar value. * * @see {@link makeValue} – construct a `Value` node * @see {@link makeRecord} – construct a `Record` node * @see {@link makeArray} – construct an `Array` node * * @stability stable * @category models * @since 4.0.0 */ export type Node = /** A terminal string value */ { readonly _tag: "Value"; readonly value: string; } /** An object; keys are unordered */ | { readonly _tag: "Record"; readonly keys: ReadonlySet; readonly value: string | undefined; } /** An array-like container; length is the number of elements */ | { readonly _tag: "Array"; readonly length: number; readonly value: string | undefined; }; /** * Creates a `Value` node representing a terminal string leaf. * * **When to use** * * Use when building nodes inside a custom `ConfigProvider`'s `get` * callback. * * **Details** * * The function returns a new plain object. * * **Example** (Creating a value node) * * ```ts import.meta.vitest * import { ConfigProvider } from "effect" * * ConfigProvider.makeValue("3000") // => { _tag: "Value", value: "3000" } * ``` * * @see {@link makeRecord} – for object-like containers * @see {@link makeArray} – for array-like containers * * @stability stable * @category constructors * @since 4.0.0 */ export declare function makeValue(value: string): Node; /** * Creates a `Record` node representing an object-like container with known * child keys. * * **When to use** * * Use when you need to describe a directory or JSON object inside a custom * provider. * * **Details** * * The optional `value` allows a node to be both a container and a leaf at the * same time (for example, an env var `A=x` that also has children `A_FOO` and * `A_BAR`). * * **Example** (Creating a record node) * * ```ts import.meta.vitest * import { ConfigProvider } from "effect" * * const node = ConfigProvider.makeRecord(new Set(["host", "port"])) * node._tag // => "Record" * if (node._tag === "Record") { * node.keys // => new Set(["host", "port"]) * node.value // => undefined * } * ``` * * @see {@link makeValue} – for terminal leaves * @see {@link makeArray} – for array-like containers * * @stability stable * @category constructors * @since 4.0.0 */ export declare function makeRecord(keys: ReadonlySet, value?: string): Node; /** * Creates an `Array` node representing an indexed container with a known * length. * * **When to use** * * Use when you need to describe a JSON array or numerically indexed env vars * inside a custom provider. * * **Details** * * The optional `value` allows a node to be both a container and a leaf at the * same time. * * **Example** (Creating an array node) * * ```ts import.meta.vitest * import { ConfigProvider } from "effect" * * ConfigProvider.makeArray(3) // => { _tag: "Array", length: 3, value: undefined } * ``` * * @see {@link makeValue} – for terminal leaves * @see {@link makeRecord} – for object-like containers * * @stability stable * @category constructors * @since 4.0.0 */ export declare function makeArray(length: number, value?: string): Node; declare const SourceError_base: new = {}>(args: import("./Types.ts").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("./Cause.ts").YieldableError & { readonly _tag: "SourceError"; } & Readonly; /** * Typed error indicating that a configuration source could not be read. * * **When to use** * * Use when you need to report that a custom provider's underlying store is * unreachable or produced an I/O error while reading configuration data. * * **Gotchas** * * Do not use `SourceError` for "key not found". That case is represented by * returning `undefined` from `load`. * * **Example** (Failing with a SourceError) * * ```ts import.meta.vitest * import { ConfigProvider, Effect } from "effect" * * const provider = ConfigProvider.make((_path) => * Effect.fail( * new ConfigProvider.SourceError({ message: "connection refused" }) * ) * ) * * Effect.runSync(Effect.flip(provider.load(["host"]))).message // => "connection refused" * ``` * * @see {@link ConfigProvider} – the interface whose `load` may fail with this * error * * @stability stable * @category errors * @since 4.0.0 */ export declare class SourceError extends SourceError_base<{ readonly message: string; readonly cause?: unknown; }> { } /** * An ordered sequence of string or numeric segments that addresses a node in * the configuration tree. String segments name object keys; numeric segments * index into arrays. * * **When to use** * * Use to address raw configuration nodes when implementing or transforming a * `ConfigProvider`. * * **Example** (A typical config path) * * ```ts import.meta.vitest * import type { ConfigProvider } from "effect" * * const path: ConfigProvider.Path = ["database", "replicas", 0, "host"] * path.join(".") // => "database.replicas.0.host" * ``` * * @stability stable * @category models * @since 4.0.0 */ export type Path = ReadonlyArray; /** * The core interface for loading raw configuration data. * * **When to use** * * Use to type-annotate variables that hold a provider or to implement a * custom provider via {@link make}. * * **Details** * * `load(path)` is the semantic lookup operation used by the `Config` module. * It applies provider transformations and composition before consulting the * underlying source. `undefined` means "not found", a `Node` means the path * exists, and `SourceError` means the source itself failed. * * `mapInput(f)` is the provider's path-transformation capability. Keeping this * capability on the provider allows source and composite providers to preserve * their own lookup behavior without exposing an internal representation. * Transformations compose in application order: `f` receives the path produced * by earlier transformations. * * `load` deliberately accepts only a `Path`. Path transformation is modeled by * returning another provider through `mapInput`, rather than by adding a * transformation callback to every lookup. Custom implementations therefore * expose lookup and transformation behavior, but no source or composition * state. * * @see {@link make} – construct a provider from a lookup function * @see {@link orElse} – compose providers with fallback * * @stability stable * @category services * @since 4.0.0 */ export interface ConfigProvider extends Pipeable { /** * Returns a `Node` when `path` exists or `undefined` when it does not. Fails * with `SourceError` when the underlying source cannot be read. * * **When to use** * * Use to resolve a path through this provider's path transformations before * reading the backing source. * * **Details** * * Lookup absence controls provider composition, such as whether * {@link orElse} consults its fallback. An optional `value` inside a found * `Record` or `Array` node remains `undefined` because it describes the shape * of that node rather than the outcome of the lookup. */ readonly load: (path: Path) => Effect.Effect; /** * Returns a provider that applies `f` to lookup paths after any existing path * transformations. * * **When to use** * * Use to implement provider-specific path transformation behavior. Most * callers should use the pipeable {@link mapInput} combinator. * * **Details** * * This capability is part of the provider interface so composite providers * can distribute transformations to their operands while preserving each * operand's behavior. Providers created with {@link make} implement it * automatically. */ readonly mapInput: (f: (path: Path) => Path) => ConfigProvider; } /** * Context reference for the active raw configuration provider, registered in the context with a * default value of `fromEnv()`. Because it is a `Context.Reference`, it is * available without explicit provision; `Config` schemas automatically resolve * it. * * **When to use** * * Use to override the active raw configuration provider for an entire program, * or retrieve the current provider inside an Effect. * * **Example** (Providing a custom provider) * * ```ts import.meta.vitest * import { ConfigProvider, Effect } from "effect" * * const provider = ConfigProvider.fromUnknown({ port: 8080 }) * * const program = Effect.gen(function*() { * const current = yield* ConfigProvider.ConfigProvider * return current * }).pipe( * Effect.provideService(ConfigProvider.ConfigProvider, provider) * ) * * Effect.runSync(program) === provider // => true * ``` * * @see {@link layer} – install a provider as a Layer * @see {@link layerAdd} – add a fallback provider as a Layer * * @stability stable * @category services * @since 4.0.0 */ export declare const ConfigProvider: Context.Reference; /** * Creates a `ConfigProvider` from a raw lookup function. * * **When to use** * * Use when implementing a provider backed by a custom store, such as a * database, remote API, or in-memory map. * * **Details** * * The `get` callback receives a `Path` and must return * `Effect`. Return `undefined` when the path does * not exist, a `Node` when it does, and fail with `SourceError` only when the * source cannot be read. * * Providers created by `make` also implement the path-transformation * capability used by {@link mapInput}, {@link constantCase}, and * {@link nested}. * * **Example** (Creating a simple in-memory provider) * * ```ts import.meta.vitest * import { ConfigProvider, Effect } from "effect" * * const data: Record = { * host: "localhost", * port: "5432" * } * * const provider = ConfigProvider.make((path) => { * const key = path.join(".") * const value = data[key] * return Effect.succeed( * value !== undefined ? ConfigProvider.makeValue(value) : undefined * ) * }) * * Effect.runSync(provider.load(["host"])) // => ConfigProvider.makeValue("localhost") * ``` * * @see {@link fromEnv} – pre-built provider for environment variables * @see {@link fromUnknown} – pre-built provider for JSON objects * * @stability stable * @category constructors * @since 4.0.0 */ export declare function make(get: (path: Path) => Effect.Effect): ConfigProvider; /** * Returns a provider that falls back to `that` when `self` returns `undefined` * for a path. * * **When to use** * * Use to layer multiple config sources, such as env vars plus a defaults file, * or provide partial overrides on top of a base config. * * **Details** * * Each provider keeps its own path transformations. If the combined provider * is later transformed with {@link mapInput} or {@link nested}, the * transformation is applied to both sides. * * **Gotchas** * * The fallback only runs when the path is not found (`undefined`). A * `SourceError` from `self` is not caught; it propagates immediately. * * **Example** (Falling back to a default provider) * * ```ts import.meta.vitest * import { ConfigProvider, Effect } from "effect" * * const envProvider = ConfigProvider.fromEnv({ * env: { HOST: "prod.example.com" } * }) * const defaults = ConfigProvider.fromUnknown({ HOST: "localhost", PORT: "3000" }) * * const combined = ConfigProvider.orElse(envProvider, defaults) * * const host = Effect.runSync(combined.load(["HOST"])) * const port = Effect.runSync(combined.load(["PORT"])) * const values = [host?.value, port?.value] // => ["prod.example.com", "3000"] * ``` * * @see {@link layerAdd} – install a fallback provider via a Layer * * @stability stable * @category combinators * @since 2.0.0 */ export declare const orElse: { /** * Returns a provider that falls back to `that` when `self` returns `undefined` * for a path. * * **When to use** * * Use to layer multiple config sources, such as env vars plus a defaults file, * or provide partial overrides on top of a base config. * * **Details** * * Each provider keeps its own path transformations. If the combined provider * is later transformed with {@link mapInput} or {@link nested}, the * transformation is applied to both sides. * * **Gotchas** * * The fallback only runs when the path is not found (`undefined`). A * `SourceError` from `self` is not caught; it propagates immediately. * * **Example** (Falling back to a default provider) * * ```ts import.meta.vitest * import { ConfigProvider, Effect } from "effect" * * const envProvider = ConfigProvider.fromEnv({ * env: { HOST: "prod.example.com" } * }) * const defaults = ConfigProvider.fromUnknown({ HOST: "localhost", PORT: "3000" }) * * const combined = ConfigProvider.orElse(envProvider, defaults) * * const host = Effect.runSync(combined.load(["HOST"])) * const port = Effect.runSync(combined.load(["PORT"])) * const values = [host?.value, port?.value] // => ["prod.example.com", "3000"] * ``` * * @see {@link layerAdd} – install a fallback provider via a Layer * * @stability stable * @category combinators * @since 2.0.0 */ (that: ConfigProvider): (self: ConfigProvider) => ConfigProvider; /** * Returns a provider that falls back to `that` when `self` returns `undefined` * for a path. * * **When to use** * * Use to layer multiple config sources, such as env vars plus a defaults file, * or provide partial overrides on top of a base config. * * **Details** * * Each provider keeps its own path transformations. If the combined provider * is later transformed with {@link mapInput} or {@link nested}, the * transformation is applied to both sides. * * **Gotchas** * * The fallback only runs when the path is not found (`undefined`). A * `SourceError` from `self` is not caught; it propagates immediately. * * **Example** (Falling back to a default provider) * * ```ts import.meta.vitest * import { ConfigProvider, Effect } from "effect" * * const envProvider = ConfigProvider.fromEnv({ * env: { HOST: "prod.example.com" } * }) * const defaults = ConfigProvider.fromUnknown({ HOST: "localhost", PORT: "3000" }) * * const combined = ConfigProvider.orElse(envProvider, defaults) * * const host = Effect.runSync(combined.load(["HOST"])) * const port = Effect.runSync(combined.load(["PORT"])) * const values = [host?.value, port?.value] // => ["prod.example.com", "3000"] * ``` * * @see {@link layerAdd} – install a fallback provider via a Layer * * @stability stable * @category combinators * @since 2.0.0 */ (self: ConfigProvider, that: ConfigProvider): ConfigProvider; }; /** * Transforms the path segments before they reach the underlying store. * * **When to use** * * Use when you need to rename, re-case, or otherwise transform config path * segments before lookup. * * **Details** * * The function `f` receives the whole path produced by earlier provider * transformations and must return a new path. Lookup path transformations * compose in application order: the existing transformation runs first, then * `f` runs. For providers composed with {@link orElse}, the transformation is * applied to each operand. * * The combinator delegates transformation to the provider itself. Use * {@link make} for custom sources so this capability is implemented * automatically. * * **Example** (Uppercasing path segments) * * ```ts import.meta.vitest * import { ConfigProvider, Effect } from "effect" * * const provider = ConfigProvider.fromEnv({ * env: { APP_HOST: "localhost" } * }) * * const upper = ConfigProvider.mapInput(provider, (path) => * path.map((seg) => * typeof seg === "string" ? seg.toUpperCase() : seg * ) * ) * * const node = Effect.runSync(upper.load(["app_host"])) * node?.value // => "localhost" * ``` * * @see {@link constantCase} – a preset that converts to `CONSTANT_CASE` * @see {@link nested} – for prepending a prefix instead of transforming * * @stability stable * @category combinators * @since 4.0.0 */ export declare const mapInput: { /** * Transforms the path segments before they reach the underlying store. * * **When to use** * * Use when you need to rename, re-case, or otherwise transform config path * segments before lookup. * * **Details** * * The function `f` receives the whole path produced by earlier provider * transformations and must return a new path. Lookup path transformations * compose in application order: the existing transformation runs first, then * `f` runs. For providers composed with {@link orElse}, the transformation is * applied to each operand. * * The combinator delegates transformation to the provider itself. Use * {@link make} for custom sources so this capability is implemented * automatically. * * **Example** (Uppercasing path segments) * * ```ts import.meta.vitest * import { ConfigProvider, Effect } from "effect" * * const provider = ConfigProvider.fromEnv({ * env: { APP_HOST: "localhost" } * }) * * const upper = ConfigProvider.mapInput(provider, (path) => * path.map((seg) => * typeof seg === "string" ? seg.toUpperCase() : seg * ) * ) * * const node = Effect.runSync(upper.load(["app_host"])) * node?.value // => "localhost" * ``` * * @see {@link constantCase} – a preset that converts to `CONSTANT_CASE` * @see {@link nested} – for prepending a prefix instead of transforming * * @stability stable * @category combinators * @since 4.0.0 */ (f: (path: Path) => Path): (self: ConfigProvider) => ConfigProvider; /** * Transforms the path segments before they reach the underlying store. * * **When to use** * * Use when you need to rename, re-case, or otherwise transform config path * segments before lookup. * * **Details** * * The function `f` receives the whole path produced by earlier provider * transformations and must return a new path. Lookup path transformations * compose in application order: the existing transformation runs first, then * `f` runs. For providers composed with {@link orElse}, the transformation is * applied to each operand. * * The combinator delegates transformation to the provider itself. Use * {@link make} for custom sources so this capability is implemented * automatically. * * **Example** (Uppercasing path segments) * * ```ts import.meta.vitest * import { ConfigProvider, Effect } from "effect" * * const provider = ConfigProvider.fromEnv({ * env: { APP_HOST: "localhost" } * }) * * const upper = ConfigProvider.mapInput(provider, (path) => * path.map((seg) => * typeof seg === "string" ? seg.toUpperCase() : seg * ) * ) * * const node = Effect.runSync(upper.load(["app_host"])) * node?.value // => "localhost" * ``` * * @see {@link constantCase} – a preset that converts to `CONSTANT_CASE` * @see {@link nested} – for prepending a prefix instead of transforming * * @stability stable * @category combinators * @since 4.0.0 */ (self: ConfigProvider, f: (path: Path) => Path): ConfigProvider; }; /** * Converts all string path segments to `CONSTANT_CASE` before lookup. * * **When to use** * * Use to bridge camelCase schema keys to `SCREAMING_SNAKE_CASE` * environment variables. * * **Details** * * Numeric segments are left unchanged. String segments use `String.configCase` * so numeric word groups such as `v2` are preserved for environment variable * names. This is a specialization of {@link mapInput}. * * **Example** (Resolving camelCase keys to env vars) * * ```ts import.meta.vitest * import { ConfigProvider, Effect } from "effect" * * const provider = ConfigProvider.fromEnv({ * env: { DATABASE_HOST: "localhost" } * }).pipe(ConfigProvider.constantCase) * * // path ["databaseHost"] now resolves to env var DATABASE_HOST * const node = Effect.runSync(provider.load(["databaseHost"])) * node?.value // => "localhost" * ``` * * @see {@link mapInput} – for arbitrary path transformations * * @stability stable * @category combinators * @since 2.0.0 */ export declare const constantCase: (self: ConfigProvider) => ConfigProvider; /** * Scopes a provider so that all lookups are prefixed with the given path * segments. * * **When to use** * * Use to namespace config under a prefix like `"app"` or `"database"`, or * reuse the same provider shape for multiple sub-configs. * * **Details** * * Accepts a single string or a full `Path` array. For providers composed with * {@link orElse}, the prefix is applied to each operand. Supports both * data-last and data-first calling conventions. * * **Gotchas** * * Ordering matters when composing with {@link mapInput} or * {@link constantCase}. Later provider transformations run after earlier ones: * a later `nested` becomes the outer prefix, and a later `mapInput` sees the * whole path produced by previous transformations. * * **Example** (Nesting under a prefix) * * ```ts import.meta.vitest * import { ConfigProvider, Effect } from "effect" * * const provider = ConfigProvider.fromEnv({ * env: { APP_HOST: "localhost", APP_PORT: "3000" } * }) * * // Lookups for ["HOST"] now resolve to ["APP", "HOST"] * const scoped = ConfigProvider.nested(provider, "APP") * const node = Effect.runSync(scoped.load(["HOST"])) * node?.value // => "localhost" * ``` * * @see {@link mapInput} – for arbitrary path transformations * * @stability stable * @category combinators * @since 2.0.0 */ export declare const nested: { /** * Scopes a provider so that all lookups are prefixed with the given path * segments. * * **When to use** * * Use to namespace config under a prefix like `"app"` or `"database"`, or * reuse the same provider shape for multiple sub-configs. * * **Details** * * Accepts a single string or a full `Path` array. For providers composed with * {@link orElse}, the prefix is applied to each operand. Supports both * data-last and data-first calling conventions. * * **Gotchas** * * Ordering matters when composing with {@link mapInput} or * {@link constantCase}. Later provider transformations run after earlier ones: * a later `nested` becomes the outer prefix, and a later `mapInput` sees the * whole path produced by previous transformations. * * **Example** (Nesting under a prefix) * * ```ts import.meta.vitest * import { ConfigProvider, Effect } from "effect" * * const provider = ConfigProvider.fromEnv({ * env: { APP_HOST: "localhost", APP_PORT: "3000" } * }) * * // Lookups for ["HOST"] now resolve to ["APP", "HOST"] * const scoped = ConfigProvider.nested(provider, "APP") * const node = Effect.runSync(scoped.load(["HOST"])) * node?.value // => "localhost" * ``` * * @see {@link mapInput} – for arbitrary path transformations * * @stability stable * @category combinators * @since 2.0.0 */ (prefix: string | Path): (self: ConfigProvider) => ConfigProvider; /** * Scopes a provider so that all lookups are prefixed with the given path * segments. * * **When to use** * * Use to namespace config under a prefix like `"app"` or `"database"`, or * reuse the same provider shape for multiple sub-configs. * * **Details** * * Accepts a single string or a full `Path` array. For providers composed with * {@link orElse}, the prefix is applied to each operand. Supports both * data-last and data-first calling conventions. * * **Gotchas** * * Ordering matters when composing with {@link mapInput} or * {@link constantCase}. Later provider transformations run after earlier ones: * a later `nested` becomes the outer prefix, and a later `mapInput` sees the * whole path produced by previous transformations. * * **Example** (Nesting under a prefix) * * ```ts import.meta.vitest * import { ConfigProvider, Effect } from "effect" * * const provider = ConfigProvider.fromEnv({ * env: { APP_HOST: "localhost", APP_PORT: "3000" } * }) * * // Lookups for ["HOST"] now resolve to ["APP", "HOST"] * const scoped = ConfigProvider.nested(provider, "APP") * const node = Effect.runSync(scoped.load(["HOST"])) * node?.value // => "localhost" * ``` * * @see {@link mapInput} – for arbitrary path transformations * * @stability stable * @category combinators * @since 2.0.0 */ (self: ConfigProvider, prefix: string | Path): ConfigProvider; }; /** * Provides a layer that installs a `ConfigProvider` as the active provider for * all downstream effects, replacing any previously installed provider. * * **When to use** * * Use to set the config source for an entire application or test suite. * * **Details** * * Accepts either a plain `ConfigProvider` or an `Effect` that produces one. * When given an Effect, it is evaluated once when the layer is built. * * **Example** (Reading config from a JSON object) * * ```ts import.meta.vitest * import { Config, ConfigProvider, Effect, Layer } from "effect" * * const TestLayer = ConfigProvider.layer( * ConfigProvider.fromUnknown({ port: 8080 }) * ) * * const program = Effect.gen(function*() { * const port = yield* Config.Number("port") * return port * }) * * Effect.runSync(Effect.provide(program, TestLayer)) // => 8080 * ``` * * @see {@link layerAdd} – add a provider without replacing the existing one * * @stability stable * @category layers * @since 4.0.0 */ export declare const layer: (self: ConfigProvider | Effect.Effect) => Layer.Layer>; /** * Creates a Layer that composes a new `ConfigProvider` with the currently * active one, rather than replacing it. * * **When to use** * * Use to add defaults that should only apply when the primary provider has no * value for a path, or override specific keys while keeping the rest from the * existing provider by setting `asPrimary: true`. * * **Details** * * By default, the new provider acts as a fallback and is consulted only when * the current provider returns `undefined`. Set `asPrimary: true` to make * the new provider the primary source, with the existing one as fallback. * * **Example** (Adding default values) * * ```ts import.meta.vitest * import { Config, ConfigProvider, Effect, Layer } from "effect" * * const defaults = ConfigProvider.fromUnknown({ * HOST: "localhost", * PORT: "3000" * }) * * // The current env provider is tried first; `defaults` is the fallback * const DefaultsLayer = ConfigProvider.layerAdd(defaults) * const BaseLayer = ConfigProvider.layer(ConfigProvider.fromUnknown({})) * const program = Config.String("HOST") * * const layer = Layer.provide(DefaultsLayer, BaseLayer) * Effect.runSync(Effect.provide(program, layer)) // => "localhost" * ``` * * @see {@link layer} – replace the provider entirely * @see {@link orElse} – compose providers without layers * * @stability stable * @category layers * @since 4.0.0 */ export declare const layerAdd: (self: ConfigProvider | Effect.Effect, options?: { readonly asPrimary?: boolean | undefined; } | undefined) => Layer.Layer>; /** * Creates a `ConfigProvider` backed by an in-memory JavaScript value * (typically a parsed JSON object). * * **When to use** * * Use when you need deterministic config from an in-memory JavaScript value, * such as in tests, embedded config, or parsed JSON. * * **Details** * * Path traversal follows standard JS rules: string segments index into object * keys, numeric segments index into arrays. Returns `undefined` for any * path that cannot be resolved. Never fails with `SourceError`. * * Primitive values (`number`, `boolean`, `bigint`) are stringified via * `String(...)`. * * Literal empty strings are treated as missing values when loaded as values by * default. Pass `{ preserveEmptyStrings: true }` to keep empty strings as * explicit values. * * **Gotchas** * * Object keys and array lengths reflect the original input shape. A leaf value * of `""` is treated as missing when that leaf is loaded, but the parent * container still reports its original keys or length. * * **Example** (Providing config from a plain object) * * ```ts import.meta.vitest * import { Config, ConfigProvider, Effect } from "effect" * * const provider = ConfigProvider.fromUnknown({ * database: { * host: "localhost", * port: 5432 * } * }) * * const host = Config.String("host").parse( * provider.pipe(ConfigProvider.nested("database")) * ) * * Effect.runSync(host) // => "localhost" * ``` * * @see {@link fromEnv} – for environment variables * @see {@link make} – for custom backing stores * * @stability stable * @category constructors * @since 4.0.0 */ export declare function fromUnknown(root: unknown, options?: { readonly preserveEmptyStrings?: boolean | undefined; }): ConfigProvider; /** * Creates a `ConfigProvider` backed by an explicit environment record. * * **When to use** * * Use when a restricted runtime cannot evaluate the automatic environment * detection performed by {@link fromEnv}, or whenever the environment record * must be supplied explicitly. * * **Details** * * `undefined` values are ignored. Path lookup and child discovery otherwise * use the same environment-variable semantics as {@link fromEnv}. * * Environment variable names are captured at construction time to establish * record keys and array lengths. The supplied record remains live for value * lookups, so updates to known paths are observed by later loads. Keys added * after construction can be loaded directly, but do not appear in captured * parent record keys or array lengths. * * Literal empty strings are treated as missing values by default. Pass * `{ preserveEmptyStrings: true }` to keep empty strings as explicit values. * * @see {@link fromEnv} – automatically reads the runtime environment * * @stability stable * @category constructors * @since 4.0.0 */ export declare function fromEnvRecord(env: Record, options?: { readonly preserveEmptyStrings?: boolean | undefined; }): ConfigProvider; /** * Creates a `ConfigProvider` backed by environment variables. * * **When to use** * * Use to read configuration from `process.env`, which is the default when no * provider is explicitly set, or pass a custom env record for testing. * * **Details** * * Path segments are joined with `_` for direct lookup, and env var names are * also split on `_` to build a trie for child key discovery. This means * `DATABASE_HOST=localhost` is accessible at both path `["DATABASE_HOST"]` * and `["DATABASE", "HOST"]`. If all immediate children of a trie node have * purely numeric names, the node is reported as an `Array`; otherwise as a * `Record`. * * The default environment merges `process.env` and `import.meta.env` (when * available). Override by passing `{ env: { ... } }`. * * Literal empty strings are treated as missing values when loaded as values by * default. Pass `{ preserveEmptyStrings: true }` to keep empty strings as * explicit values. Child discovery still reflects the environment variable * names present in the source. * * Never fails with `SourceError` — all lookups are synchronous. * * **Example** (Reading from a custom env record) * * ```ts import.meta.vitest * import { Config, ConfigProvider, Effect } from "effect" * * const provider = ConfigProvider.fromEnv({ * env: { * DATABASE_HOST: "localhost", * DATABASE_PORT: "5432" * } * }) * * const host = Config.String("HOST").parse( * provider.pipe(ConfigProvider.nested("DATABASE")) * ) * * Effect.runSync(host) // => "localhost" * ``` * * @see {@link fromUnknown} – for JSON objects * @see {@link fromEnvRecord} – for explicit records in restricted runtimes * @see {@link constantCase} – bridge camelCase keys to SCREAMING_SNAKE_CASE * * @stability stable * @category constructors * @since 2.0.0 */ export declare function fromEnv(options?: { readonly env?: Record | undefined; readonly preserveEmptyStrings?: boolean | undefined; }): ConfigProvider; /** * Creates a `ConfigProvider` by parsing the string contents of a `.env` file. * * **When to use** * * Use when you already have the `.env` contents as a string, such as contents * fetched from a remote store or embedded in a test. * * **Details** * * Supports `export` prefixes, single/double/backtick quoting, inline comments, * and escaped newlines. Variable expansion (for example, `${VAR}`) is disabled * by default; enable with `{ expandVariables: true }`. * * Literal empty strings are treated as missing values when loaded as values by * default. Pass `{ preserveEmptyStrings: true }` to keep empty strings as * explicit values. Child discovery still reflects the keys present in the * parsed `.env` source. * * Parsing is based on the `dotenv` / `dotenv-expand` algorithm. * * Internally delegates to {@link fromEnvRecord} with the parsed key-value pairs. * * **Example** (Parsing .env contents) * * ```ts import.meta.vitest * import { ConfigProvider, Effect } from "effect" * * const contents = ` * HOST=localhost * PORT=3000 * # this is a comment * ` * * const provider = ConfigProvider.fromDotEnvContents(contents) * const port = Effect.runSync(provider.load(["PORT"])) * port?.value // => "3000" * ``` * * @see {@link fromDotEnv} – loads a `.env` file from disk * @see {@link fromEnvRecord} – for explicit environment records * @see {@link fromEnv} – for raw environment variable access * * @stability stable * @category constructors * @since 4.0.0 */ export declare function fromDotEnvContents(lines: string, options?: { readonly expandVariables?: boolean | undefined; readonly preserveEmptyStrings?: boolean | undefined; }): ConfigProvider; /** * Creates a `ConfigProvider` by reading and parsing a `.env` file from the * file system. * * **When to use** * * Use to load environment config from a `.env` file at application startup. * * **Details** * * Requires `FileSystem` in the Effect context. Defaults to reading `".env"` in * the current directory; override with `{ path: "/custom/.env" }`. * Variable expansion (for example, `${VAR}`) is disabled by default; enable * with `{ expandVariables: true }`. * * Literal empty strings are treated as missing values when loaded as values by * default. Pass `{ preserveEmptyStrings: true }` to keep empty strings as * explicit values. Child discovery still reflects the keys present in the * parsed `.env` source. * * Returns an `Effect` that resolves to a `ConfigProvider`. Fails with a * `PlatformError` if the file cannot be read. * * **Example** (Loading a .env file) * * ```ts import.meta.vitest * import { ConfigProvider, Effect, FileSystem } from "effect" * * const fileSystem = FileSystem.makeNoop({ * readFileString: () => Effect.succeed("HOST=localhost") * }) * * const program = Effect.gen(function*() { * const provider = yield* ConfigProvider.fromDotEnv() * return yield* provider.load(["HOST"]) * }) * * const node = await Effect.runPromise( * Effect.provideService(program, FileSystem.FileSystem, fileSystem) * ) * node?.value // => "localhost" * ``` * * @see {@link fromDotEnvContents} – parse a `.env` string directly * @see {@link fromEnv} – read from the runtime environment * * @stability unstable * @category constructors * @since 4.0.0 */ export declare const fromDotEnv: (options?: { readonly path?: string | undefined; readonly expandVariables?: boolean | undefined; readonly preserveEmptyStrings?: boolean | undefined; }) => Effect.Effect; /** * Creates a `ConfigProvider` that reads configuration from a directory tree * on disk, where each file is a leaf value and each directory is a container. * * **When to use** * * Use when you expose each config key as a file under a directory, such as * Kubernetes ConfigMap or Secret volume mounts. * * **Details** * * Resolution tries a regular file first and returns a `Value` node for * non-empty trimmed file contents. If the file read fails, it tries a directory * and returns a `Record` node with immediate child names as keys. If both fail * with `NotFound`, it returns `undefined`. Other platform failures return * `SourceError`. * * Requires `Path` and `FileSystem` in the Effect context. Defaults to root * path `/`; override with `{ rootPath: "/etc/config" }`. * * Literal empty strings are treated as missing values by default after file * contents are trimmed. Pass `{ preserveEmptyStrings: true }` to keep empty * strings as explicit values. Directory listings still reflect the file names * present on disk. * * **Example** (Reading config from a directory) * * ```ts import.meta.vitest * import { ConfigProvider, Effect, FileSystem, Path } from "effect" * * const fileSystem = FileSystem.makeNoop({ * readFileString: (path) => * path === "/etc/myapp/host" * ? Effect.succeed("localhost") * : Effect.die("unexpected path") * }) * * const program = Effect.gen(function*() { * const provider = yield* ConfigProvider.fromDir({ * rootPath: "/etc/myapp" * }) * return yield* provider.load(["host"]) * }) * * const node = await Effect.runPromise( * program.pipe( * Effect.provide(Path.layer), * Effect.provideService(FileSystem.FileSystem, fileSystem) * ) * ) * node?.value // => "localhost" * ``` * * @see {@link fromEnv} – for environment variables * @see {@link fromDotEnv} – for `.env` files * * @stability unstable * @category constructors * @since 4.0.0 */ export declare const fromDir: (options?: { readonly rootPath?: string | undefined; readonly preserveEmptyStrings?: boolean | undefined; }) => Effect.Effect; export {}; //# sourceMappingURL=ConfigProvider.d.ts.map