@emergente-labs/effect-env 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Emergente Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # @emergente-labs/effect-env
2
+
3
+ Type-safe environment variable configuration for [Effect-TS](https://effect.website) applications. The "T3 env" equivalent for Effect -- clean DX, per-environment defaults, proxy access, and test helpers.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @emergente-labs/effect-env effect
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { createEnv } from "@emergente-labs/effect-env";
15
+ import { Config, Effect, Redacted } from "effect";
16
+
17
+ const { env, requiredSecrets } = createEnv({
18
+ vars: {
19
+ // Required in all environments
20
+ databaseUrl: Config.redacted("DATABASE_URL"),
21
+
22
+ // Optional in development, required in production
23
+ apiKey: [Config.string("API_KEY"), "dev-key-123"] as const,
24
+
25
+ // Number config with default
26
+ port: [Config.number("PORT"), 3000] as const,
27
+ },
28
+ });
29
+
30
+ // requiredSecrets = ["DATABASE_URL"]
31
+
32
+ // Access individual variables
33
+ const program = Effect.gen(function* () {
34
+ const dbUrl = yield* env.databaseUrl; // Redacted<string>
35
+ const key = yield* env.apiKey; // string
36
+ const port = yield* env.port; // number
37
+
38
+ // Or access all at once
39
+ const all = yield* env;
40
+ // { databaseUrl: Redacted<string>, apiKey: string, port: number }
41
+ });
42
+ ```
43
+
44
+ ## API
45
+
46
+ ### `createEnv(options)`
47
+
48
+ Creates a typed environment configuration from a record of Config definitions.
49
+
50
+ Each variable can be:
51
+ - `Config.Config<T>` -- required in all environments
52
+ - `[Config.Config<T>, T] as const` -- required only in production, uses default in dev/test
53
+
54
+ Returns `{ env, requiredSecrets }`:
55
+ - `env` -- dual-access proxy: `yield* env.key` for individual values, `yield* env` for all
56
+ - `requiredSecrets` -- array of env var names that must be set in production
57
+
58
+ ### `createEnvVar(config, defaultValueInDevelopment?)`
59
+
60
+ Lower-level function for creating individual environment-aware configs.
61
+
62
+ ### `createTestEnvLayer(envMap)`
63
+
64
+ Creates an Effect Layer that provides mock environment variables for testing.
65
+
66
+ ```typescript
67
+ import { createTestEnvLayer } from "@emergente-labs/effect-env";
68
+
69
+ const testLayer = createTestEnvLayer({
70
+ DATABASE_URL: "postgresql://localhost:5432/test",
71
+ NODE_ENV: "test",
72
+ });
73
+
74
+ // Use in tests
75
+ const result = yield* myEffect.pipe(Effect.provide(testLayer));
76
+ ```
77
+
78
+ ## License
79
+
80
+ MIT
@@ -0,0 +1,121 @@
1
+ import { Config, Layer } from 'effect';
2
+
3
+ /** A config with no default (required in all environments) */
4
+ type RequiredConfig<T> = Config.Config<T>;
5
+ /** A config with a default value (required only in production) */
6
+ type OptionalConfig<T> = readonly [Config.Config<T>, T];
7
+ /** Union of both config types */
8
+ type EnvVarDefinition<T = unknown> = RequiredConfig<T> | OptionalConfig<T>;
9
+ /**
10
+ * The input record type for `createEnv`. Each key maps to either:
11
+ * - `Config.Config<T>` - required in all environments
12
+ * - `readonly [Config.Config<T>, T]` - required only in production, uses default in development
13
+ *
14
+ * @example
15
+ * const vars: EnvVarsInput = {
16
+ * databaseUrl: Config.redacted("DATABASE_URL"),
17
+ * apiKey: [Config.string("API_KEY"), "dev-key"] as const,
18
+ * };
19
+ */
20
+ type EnvVarsInput = Record<string, EnvVarDefinition>;
21
+ /** Extract the success type from a config definition */
22
+ type ExtractConfigType<T> = T extends OptionalConfig<infer U> ? U : T extends RequiredConfig<infer U> ? U : never;
23
+ /** Map input record to resolved Config types */
24
+ type ResolvedEnvVars<T extends EnvVarsInput> = {
25
+ [K in keyof T]: Config.Config<ExtractConfigType<T[K]>>;
26
+ };
27
+ /** The resolved plain values object */
28
+ type ResolvedEnvValues<T extends EnvVarsInput> = {
29
+ [K in keyof T]: ExtractConfigType<T[K]>;
30
+ };
31
+ /** The proxy type that allows both `yield* env.key` and `yield* env` */
32
+ type EnvProxy<T extends EnvVarsInput> = Config.Config<ResolvedEnvValues<T>> & ResolvedEnvVars<T>;
33
+ /** The env proxy combined with metadata about required secrets */
34
+ interface CreateEnvReturn<EnvVars extends EnvVarsInput> {
35
+ /** The env proxy that supports `yield* env.key` and `yield* env` */
36
+ readonly env: EnvProxy<EnvVars>;
37
+ /** Environment variable names that are required (no default value) */
38
+ readonly requiredSecrets: readonly string[];
39
+ }
40
+ /**
41
+ * Options for `createEnv`.
42
+ *
43
+ * @template EnvVars - The record of environment variable definitions
44
+ */
45
+ interface CreateEnvOptions<EnvVars extends EnvVarsInput> {
46
+ /** Record of environment variable definitions */
47
+ vars: EnvVars;
48
+ }
49
+
50
+ /**
51
+ * Creates a typed environment configuration from a record of Config definitions.
52
+ *
53
+ * Each variable can be defined as:
54
+ * - `Config.Config<T>` - required in all environments
55
+ * - `[Config.Config<T>, T] as const` - required only in production, uses the
56
+ * provided default value in development/test environments
57
+ *
58
+ * @template EnvVars - The record of environment variable definitions
59
+ *
60
+ * @param options - Configuration options
61
+ * @param options.vars - Record of environment variable definitions
62
+ *
63
+ * @returns An object containing:
64
+ * - `env`: An Effect Config proxy that supports both `yield* env.key` for
65
+ * individual values and `yield* env` for all values.
66
+ * - `requiredSecrets`: Array of environment variable names that are required
67
+ * (no default value) and must be set for deployment.
68
+ *
69
+ * @example
70
+ * const { env, requiredSecrets } = createEnv({
71
+ * vars: {
72
+ * databaseUrl: Config.redacted("DATABASE_URL"),
73
+ * apiKey: [Config.string("API_KEY"), "dev-key-123"] as const,
74
+ * },
75
+ * });
76
+ *
77
+ * // requiredSecrets = ["DATABASE_URL"]
78
+ *
79
+ * // In an Effect generator:
80
+ * const dbUrl = yield* env.databaseUrl; // Redacted
81
+ * const key = yield* env.apiKey; // string
82
+ * const all = yield* env; // { databaseUrl: Redacted, apiKey: string }
83
+ */
84
+ declare function createEnv<EnvVars extends EnvVarsInput>(options: CreateEnvOptions<EnvVars>): CreateEnvReturn<EnvVars>;
85
+
86
+ /**
87
+ * Creates an environment variable configuration with optional development fallback.
88
+ *
89
+ * @template T - The type of the environment variable value
90
+ * @param config - The Config instance to read the environment variable
91
+ * @param defaultValueInDevelopment - Optional default value to use in non-production environments.
92
+ * - If provided: Variable is required only in production, uses default in development
93
+ * - If omitted: Variable is required in all environments
94
+ * @returns A Config that validates the environment variable based on the current NODE_ENV
95
+ *
96
+ * @example
97
+ * // Required in all environments (no default)
98
+ * const dbUrl = createEnvVar(Config.string("DATABASE_URL"));
99
+ *
100
+ * @example
101
+ * // Required only in production, uses default in development
102
+ * const apiKey = createEnvVar(Config.string("API_KEY"), "dev-key-123");
103
+ */
104
+ declare function createEnvVar<T>(config: Config.Config<T>, defaultValueInDevelopment?: T): Config.Config<T>;
105
+
106
+ /**
107
+ * Creates a test layer with a given set of environment variables.
108
+ * Useful for testing code that depends on environment variables.
109
+ *
110
+ * @param envMap - A Map or Record of environment variable names to their values
111
+ * @returns A Layer that provides the environment variables to the Effect runtime
112
+ *
113
+ * @example
114
+ * const testLayer = createTestEnvLayer(new Map([
115
+ * ["DATABASE_URL", "postgresql://user:password@localhost:5432/db"],
116
+ * ["NODE_ENV", "test"],
117
+ * ]));
118
+ */
119
+ declare function createTestEnvLayer(envMap: Map<string, string> | Record<string, string>): Layer.Layer<never>;
120
+
121
+ export { type CreateEnvOptions, type CreateEnvReturn, type EnvProxy, type EnvVarsInput, type ResolvedEnvValues, type ResolvedEnvVars, createEnv, createEnvVar, createTestEnvLayer };
package/dist/index.js ADDED
@@ -0,0 +1,142 @@
1
+ // src/createEnv.ts
2
+ import { Config as Config2 } from "effect";
3
+
4
+ // src/createEnvVar.ts
5
+ import { Config, Option, ConfigError, Either, Schema } from "effect";
6
+ var environment = Config.string("NODE_ENV");
7
+ var configSchema = Schema.Union(
8
+ Schema.Struct({
9
+ name: Schema.String
10
+ }),
11
+ Schema.Struct({
12
+ original: Schema.suspend(() => configSchema)
13
+ }),
14
+ Schema.Struct({
15
+ config: Schema.suspend(() => configSchema)
16
+ }),
17
+ Schema.Struct({
18
+ first: Schema.suspend(() => configSchema),
19
+ second: Schema.suspend(() => configSchema)
20
+ })
21
+ );
22
+ var extractPath = (v) => {
23
+ if ("name" in v) {
24
+ return [v.name];
25
+ }
26
+ if ("original" in v) {
27
+ const extracted = extractPath(v.original);
28
+ if (extracted.length) {
29
+ return extracted;
30
+ }
31
+ }
32
+ if ("first" in v) {
33
+ const first = extractPath(v.first);
34
+ if (first.length > 0) return first;
35
+ return extractPath(v.second);
36
+ }
37
+ if ("config" in v) {
38
+ const extracted = extractPath(v.config);
39
+ if (extracted.length) {
40
+ return extracted;
41
+ }
42
+ }
43
+ return [];
44
+ };
45
+ function getConfigPath(config) {
46
+ const decoded = Schema.decodeUnknownEither(configSchema)(config);
47
+ return Either.match(decoded, {
48
+ onLeft: () => [],
49
+ onRight: extractPath
50
+ });
51
+ }
52
+ function createMissingDataError(config, optionalInDevelopment) {
53
+ const path = getConfigPath(config);
54
+ const message = optionalInDevelopment ? "Environment variable required in production" : "Environment variable required in all environments";
55
+ return ConfigError.MissingData(path, message);
56
+ }
57
+ function isValueRequired(env, optionalInDevelopment) {
58
+ if (optionalInDevelopment) {
59
+ return env === "production";
60
+ }
61
+ return true;
62
+ }
63
+ function createEnvVar(config, defaultValueInDevelopment) {
64
+ const optionalInDevelopment = defaultValueInDevelopment !== void 0;
65
+ return Config.all({
66
+ env: environment,
67
+ value: Config.option(config)
68
+ }).pipe(
69
+ Config.mapOrFail(({ env, value }) => {
70
+ const isRequired = isValueRequired(env, optionalInDevelopment);
71
+ if (isRequired && Option.isNone(value)) {
72
+ return Either.left(createMissingDataError(config, optionalInDevelopment));
73
+ }
74
+ return Either.right(
75
+ Option.getOrElse(() => defaultValueInDevelopment)(value)
76
+ );
77
+ })
78
+ );
79
+ }
80
+
81
+ // src/createEnv.ts
82
+ function isOptionalConfig(value) {
83
+ return Array.isArray(value) && value.length === 2;
84
+ }
85
+ function hasName(config) {
86
+ return "name" in config && typeof config.name === "string";
87
+ }
88
+ function hasOriginal(config) {
89
+ return "original" in config && config.original !== null && typeof config.original === "object";
90
+ }
91
+ function hasFirst(config) {
92
+ return "first" in config && config.first !== null && typeof config.first === "object";
93
+ }
94
+ function extractConfigName(config) {
95
+ if (hasName(config)) return config.name;
96
+ if (hasOriginal(config)) return extractConfigName(config.original);
97
+ if (hasFirst(config)) return extractConfigName(config.first);
98
+ return void 0;
99
+ }
100
+ function createEnv(options) {
101
+ const processedVars = {};
102
+ const requiredSecrets = [];
103
+ for (const key of Object.keys(options.vars)) {
104
+ const value = options.vars[key];
105
+ if (value === void 0) continue;
106
+ if (isOptionalConfig(value)) {
107
+ processedVars[key] = createEnvVar(value[0], value[1]);
108
+ } else {
109
+ processedVars[key] = createEnvVar(value);
110
+ const envVarName = extractConfigName(value);
111
+ if (envVarName) {
112
+ requiredSecrets.push(envVarName);
113
+ }
114
+ }
115
+ }
116
+ const allEnvVars = Config2.all(processedVars);
117
+ const env = new Proxy(allEnvVars, {
118
+ get(target, prop) {
119
+ if (typeof prop === "string" && prop in processedVars) {
120
+ return Config2.map(
121
+ target,
122
+ (allValues) => allValues[prop]
123
+ );
124
+ }
125
+ return target[prop];
126
+ }
127
+ });
128
+ return { env, requiredSecrets };
129
+ }
130
+
131
+ // src/createTestEnvLayer.ts
132
+ import { Layer, ConfigProvider } from "effect";
133
+ function createTestEnvLayer(envMap) {
134
+ const map = envMap instanceof Map ? envMap : new Map(Object.entries(envMap));
135
+ return Layer.setConfigProvider(ConfigProvider.fromMap(map));
136
+ }
137
+ export {
138
+ createEnv,
139
+ createEnvVar,
140
+ createTestEnvLayer
141
+ };
142
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/createEnv.ts","../src/createEnvVar.ts","../src/createTestEnvLayer.ts"],"sourcesContent":["import { Config } from \"effect\";\nimport { createEnvVar } from \"./createEnvVar\";\nimport type {\n EnvVarsInput,\n EnvVarDefinition,\n OptionalConfig,\n CreateEnvOptions,\n CreateEnvReturn,\n ResolvedEnvValues,\n EnvProxy,\n} from \"./types\";\n\nfunction isOptionalConfig<T>(\n value: EnvVarDefinition<T>,\n): value is OptionalConfig<T> {\n return Array.isArray(value) && value.length === 2;\n}\n\n/** Config with a direct name property (primitive configs like string, number, etc.) */\ninterface ConfigWithName {\n readonly name: string;\n}\n\n/** Config that wraps another config (mapped, validated, branded) */\ninterface ConfigWithOriginal {\n readonly original: Config.Config<unknown>;\n}\n\n/** Config with a fallback (orElse, withDefault) */\ninterface ConfigWithFirst {\n readonly first: Config.Config<unknown>;\n}\n\nfunction hasName(config: Config.Config<unknown>): config is Config.Config<unknown> & ConfigWithName {\n return \"name\" in config && typeof config.name === \"string\";\n}\n\nfunction hasOriginal(config: Config.Config<unknown>): config is Config.Config<unknown> & ConfigWithOriginal {\n return \"original\" in config && config.original !== null && typeof config.original === \"object\";\n}\n\nfunction hasFirst(config: Config.Config<unknown>): config is Config.Config<unknown> & ConfigWithFirst {\n return \"first\" in config && config.first !== null && typeof config.first === \"object\";\n}\n\n/**\n * Extracts the environment variable name from a Config object.\n * Works with nested, mapped, validated, and other transformed configs.\n */\nfunction extractConfigName(config: Config.Config<unknown>): string | undefined {\n if (hasName(config)) return config.name;\n if (hasOriginal(config)) return extractConfigName(config.original);\n if (hasFirst(config)) return extractConfigName(config.first);\n return undefined;\n}\n\n/**\n * Creates a typed environment configuration from a record of Config definitions.\n *\n * Each variable can be defined as:\n * - `Config.Config<T>` - required in all environments\n * - `[Config.Config<T>, T] as const` - required only in production, uses the\n * provided default value in development/test environments\n *\n * @template EnvVars - The record of environment variable definitions\n *\n * @param options - Configuration options\n * @param options.vars - Record of environment variable definitions\n *\n * @returns An object containing:\n * - `env`: An Effect Config proxy that supports both `yield* env.key` for\n * individual values and `yield* env` for all values.\n * - `requiredSecrets`: Array of environment variable names that are required\n * (no default value) and must be set for deployment.\n *\n * @example\n * const { env, requiredSecrets } = createEnv({\n * vars: {\n * databaseUrl: Config.redacted(\"DATABASE_URL\"),\n * apiKey: [Config.string(\"API_KEY\"), \"dev-key-123\"] as const,\n * },\n * });\n *\n * // requiredSecrets = [\"DATABASE_URL\"]\n *\n * // In an Effect generator:\n * const dbUrl = yield* env.databaseUrl; // Redacted\n * const key = yield* env.apiKey; // string\n * const all = yield* env; // { databaseUrl: Redacted, apiKey: string }\n */\nexport function createEnv<EnvVars extends EnvVarsInput>(\n options: CreateEnvOptions<EnvVars>,\n): CreateEnvReturn<EnvVars> {\n const processedVars: Record<string, Config.Config<unknown>> = {};\n const requiredSecrets: string[] = [];\n\n for (const key of Object.keys(options.vars)) {\n const value = options.vars[key];\n if (value === undefined) continue;\n\n if (isOptionalConfig(value)) {\n // Tuple: [Config, defaultValue] - optional, has a default\n processedVars[key] = createEnvVar(value[0], value[1]);\n } else {\n // Just a Config (required in all environments)\n processedVars[key] = createEnvVar(value);\n // Extract the env var name for required secrets\n const envVarName = extractConfigName(value);\n if (envVarName) {\n requiredSecrets.push(envVarName);\n }\n }\n }\n\n const allEnvVars = Config.all(processedVars) as Config.Config<\n ResolvedEnvValues<EnvVars>\n >;\n\n const env = new Proxy(allEnvVars, {\n get(target, prop: string | symbol) {\n if (typeof prop === \"string\" && prop in processedVars) {\n return Config.map(\n target,\n (allValues) => allValues[prop as keyof typeof allValues],\n );\n }\n return target[prop as keyof typeof target];\n },\n }) as EnvProxy<EnvVars>;\n\n return { env, requiredSecrets };\n}\n","import { Config, Option, ConfigError, Either, Schema } from \"effect\";\n\nconst environment = Config.string(\"NODE_ENV\");\n\n/* walker to get the path from a config type that has transformations, like `Config.string(\"SECRET_KEY\").pipe(Config.array)` */\ninterface ConfigName {\n name: string;\n}\n\ninterface ConfigOriginal {\n original: ConfigType;\n}\n\ninterface ConfigFirstSecond {\n first: ConfigType;\n second: ConfigType;\n}\n\ninterface ConfigBuried {\n config: ConfigType;\n}\n\ntype ConfigType =\n | ConfigName\n | ConfigOriginal\n | ConfigFirstSecond\n | ConfigBuried;\n\nconst configSchema = Schema.Union(\n Schema.Struct({\n name: Schema.String,\n }),\n Schema.Struct({\n original: Schema.suspend((): Schema.Schema<ConfigType> => configSchema),\n }),\n Schema.Struct({\n config: Schema.suspend((): Schema.Schema<ConfigType> => configSchema),\n }),\n Schema.Struct({\n first: Schema.suspend((): Schema.Schema<ConfigType> => configSchema),\n second: Schema.suspend((): Schema.Schema<ConfigType> => configSchema),\n }),\n);\n\nconst extractPath = (v: typeof configSchema.Type): string[] => {\n if (\"name\" in v) {\n return [v.name];\n }\n\n if (\"original\" in v) {\n const extracted = extractPath(v.original);\n if (extracted.length) {\n return extracted;\n }\n }\n\n if (\"first\" in v) {\n const first = extractPath(v.first);\n if (first.length > 0) return first;\n return extractPath(v.second);\n }\n\n if (\"config\" in v) {\n const extracted = extractPath(v.config);\n if (extracted.length) {\n return extracted;\n }\n }\n\n return [];\n};\n/* end of walker */\n\nfunction getConfigPath(config: Config.Config<unknown>): string[] {\n const decoded = Schema.decodeUnknownEither(configSchema)(config);\n return Either.match(decoded, {\n onLeft: () => [],\n onRight: extractPath,\n });\n}\n\nfunction createMissingDataError(\n config: Config.Config<unknown>,\n optionalInDevelopment: boolean,\n): ConfigError.ConfigError {\n const path = getConfigPath(config);\n const message = optionalInDevelopment\n ? \"Environment variable required in production\"\n : \"Environment variable required in all environments\";\n return ConfigError.MissingData(path, message);\n}\n\nfunction isValueRequired(env: string, optionalInDevelopment: boolean): boolean {\n if (optionalInDevelopment) {\n return env === \"production\";\n }\n return true;\n}\n\n/**\n * Creates an environment variable configuration with optional development fallback.\n *\n * @template T - The type of the environment variable value\n * @param config - The Config instance to read the environment variable\n * @param defaultValueInDevelopment - Optional default value to use in non-production environments.\n * - If provided: Variable is required only in production, uses default in development\n * - If omitted: Variable is required in all environments\n * @returns A Config that validates the environment variable based on the current NODE_ENV\n *\n * @example\n * // Required in all environments (no default)\n * const dbUrl = createEnvVar(Config.string(\"DATABASE_URL\"));\n *\n * @example\n * // Required only in production, uses default in development\n * const apiKey = createEnvVar(Config.string(\"API_KEY\"), \"dev-key-123\");\n */\nexport function createEnvVar<T>(\n config: Config.Config<T>,\n defaultValueInDevelopment?: T,\n): Config.Config<T> {\n const optionalInDevelopment = defaultValueInDevelopment !== undefined;\n\n return Config.all({\n env: environment,\n value: Config.option(config),\n }).pipe(\n Config.mapOrFail(({ env, value }) => {\n const isRequired = isValueRequired(env, optionalInDevelopment);\n\n if (isRequired && Option.isNone(value)) {\n return Either.left(createMissingDataError(config, optionalInDevelopment));\n }\n\n return Either.right(\n Option.getOrElse(() => defaultValueInDevelopment as T)(value),\n );\n }),\n );\n}\n","import { Layer, ConfigProvider } from \"effect\";\n\n/**\n * Creates a test layer with a given set of environment variables.\n * Useful for testing code that depends on environment variables.\n *\n * @param envMap - A Map or Record of environment variable names to their values\n * @returns A Layer that provides the environment variables to the Effect runtime\n *\n * @example\n * const testLayer = createTestEnvLayer(new Map([\n * [\"DATABASE_URL\", \"postgresql://user:password@localhost:5432/db\"],\n * [\"NODE_ENV\", \"test\"],\n * ]));\n */\nexport function createTestEnvLayer(\n envMap: Map<string, string> | Record<string, string>,\n): Layer.Layer<never> {\n const map = envMap instanceof Map ? envMap : new Map(Object.entries(envMap));\n return Layer.setConfigProvider(ConfigProvider.fromMap(map));\n}\n"],"mappings":"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","names":["Config","Config"]}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@emergente-labs/effect-env",
3
+ "version": "0.1.1",
4
+ "description": "Type-safe Effect-TS environment variable configuration with development fallbacks",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Emergente Labs",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/emergente-labs/effect-env"
11
+ },
12
+ "bugs": "https://github.com/emergente-labs/effect-env/issues",
13
+ "homepage": "https://github.com/emergente-labs/effect-env#readme",
14
+ "keywords": ["effect", "effect-ts", "environment", "config", "env", "type-safe", "typed-env"],
15
+ "engines": {
16
+ "node": ">=18.0.0"
17
+ },
18
+ "files": ["dist", "README.md", "LICENSE"],
19
+ "types": "./dist/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "default": "./dist/index.js"
24
+ }
25
+ },
26
+ "scripts": {
27
+ "prepare": "pnpm build",
28
+ "build": "tsup",
29
+ "test": "vitest run",
30
+ "test:watch": "vitest",
31
+ "typecheck": "tsc --noEmit",
32
+ "prepublishOnly": "pnpm run build && pnpm run test"
33
+ },
34
+ "dependencies": {
35
+ "effect": "^3.19.8"
36
+ },
37
+ "devDependencies": {
38
+ "@effect/vitest": "^0.27.0",
39
+ "tsup": "^8.4.0",
40
+ "typescript": "^5.9.3",
41
+ "vitest": "^4.0.16"
42
+ }
43
+ }