Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/configprovider-import-meta-env.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"effect": patch
---

Remove the default `import.meta.env` lookup from `ConfigProvider.fromEnv`, fixing module analysis failures in runtimes that do not support `import.meta`, closes #6358.
7 changes: 3 additions & 4 deletions packages/effect/src/ConfigProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -810,8 +810,8 @@ function emptyStringAsMissing(value: string | undefined, preserveEmptyStrings: b
* 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: { ... } }`.
* The default environment reads `process.env` when available. For runtimes that
* expose environment variables elsewhere, pass `{ env: { ... } }`.
*
* Literal empty strings are treated as missing values when loaded as values by
* default. Pass `{ preserveEmptyStrings: true }` to keep empty strings as
Expand Down Expand Up @@ -850,8 +850,7 @@ export function fromEnv(options?: {
readonly preserveEmptyStrings?: boolean | undefined
}): ConfigProvider {
const env: Record<string, string | undefined> = options?.env ?? {
...globalThis?.process?.env,
...(import.meta as any)?.env
...globalThis?.process?.env
}
const preserveEmptyStrings = options?.preserveEmptyStrings === true
const trie = buildEnvTrie(env)
Expand Down
41 changes: 41 additions & 0 deletions packages/effect/test/ConfigProvider.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { describe, it } from "@effect/vitest"
import { deepStrictEqual } from "@effect/vitest/utils"
import { ConfigProvider, Effect, FileSystem, Layer, Path, PlatformError, Result } from "effect"
import * as Fs from "node:fs"

async function assertSuccess(
provider: ConfigProvider.ConfigProvider,
Expand Down Expand Up @@ -191,6 +192,46 @@ describe("ConfigProvider", () => {
})

describe("fromEnv", () => {
it("uses the default environment when no env is provided", async () => {
const key = "EFFECT_CONFIG_PROVIDER_TEST_DEFAULT_ENV"
const previous = process.env[key]
process.env[key] = "value1"
try {
const provider = ConfigProvider.fromEnv()
await assertSuccess(provider, [key], ConfigProvider.makeValue("value1"))
} finally {
if (previous === undefined) {
delete process.env[key]
} else {
process.env[key] = previous
}
}
})

it("uses an explicit env over the default environment", async () => {
const key = "EFFECT_CONFIG_PROVIDER_TEST_DEFAULT_ENV"
const previous = process.env[key]
process.env[key] = "default"
try {
const provider = ConfigProvider.fromEnv({ env: { [key]: "explicit" } })
await assertSuccess(provider, [key], ConfigProvider.makeValue("explicit"))
} finally {
if (previous === undefined) {
delete process.env[key]
} else {
process.env[key] = previous
}
}
})

it("does not reference import.meta in the common ConfigProvider module", () => {
const sourcePath = Fs.existsSync("src/ConfigProvider.ts")
? "src/ConfigProvider.ts"
: "packages/effect/src/ConfigProvider.ts"
const source = Fs.readFileSync(sourcePath, "utf8")
deepStrictEqual(source.includes("import.meta"), false)
})

it("env without an underscore", async () => {
const env = { A: "value1" }
const provider = ConfigProvider.fromEnv({ env })
Expand Down