tyfigo 0.1.0-next.ddcaab3.0 → 0.1.0-next.ffecb89.0
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/README.md +2 -0
- package/dist/bun.mjs +3 -2
- package/dist/bun.mjs.map +1 -1
- package/dist/effect.browser-Bhr-Yr7t.d.mts +61 -0
- package/dist/effect.browser-CO87TEE_.mjs +50 -0
- package/dist/effect.browser-CO87TEE_.mjs.map +1 -0
- package/dist/effect.browser.d.mts +5 -0
- package/dist/effect.browser.mjs +3 -0
- package/dist/effect.d.mts +6 -61
- package/dist/effect.mjs +7 -48
- package/dist/effect.mjs.map +1 -1
- package/dist/env-Bd-1Atoz.mjs +27 -0
- package/dist/env-Bd-1Atoz.mjs.map +1 -0
- package/dist/env-R3_XPW_u.mjs +78 -0
- package/dist/env-R3_XPW_u.mjs.map +1 -0
- package/dist/formats-D_dKXoPf.mjs +900 -0
- package/dist/formats-D_dKXoPf.mjs.map +1 -0
- package/dist/{index-CM4xg0II.d.mts → index-jUM0zKD5.d.mts} +3 -3
- package/dist/index.browser-BUi5xv0g.d.mts +15 -0
- package/dist/index.browser-C5z_VT_3.mjs +17 -0
- package/dist/index.browser-C5z_VT_3.mjs.map +1 -0
- package/dist/index.browser.d.mts +5 -0
- package/dist/index.browser.mjs +3 -0
- package/dist/index.d.mts +5 -15
- package/dist/index.mjs +3 -12
- package/dist/index.mjs.map +1 -1
- package/dist/{load-CKIE0mVT.d.mts → load-C-kweoyY.d.mts} +2 -2
- package/dist/{load-BqGJgpfo.mjs → load-DxIjRpX6.mjs} +7 -4
- package/dist/{load-BqGJgpfo.mjs.map → load-DxIjRpX6.mjs.map} +1 -1
- package/dist/mapper.mjs +5 -2
- package/dist/mapper.mjs.map +1 -1
- package/dist/plugins/esbuild.d.mts +2 -2
- package/dist/plugins/esbuild.mjs +1 -1
- package/dist/plugins/jest.d.mts +1 -1
- package/dist/plugins/jest.mjs +4 -4
- package/dist/plugins/loader.d.mts +4 -3
- package/dist/plugins/loader.mjs +9 -3
- package/dist/plugins/loader.mjs.map +1 -1
- package/dist/plugins/next.d.mts +1 -1
- package/dist/plugins/next.mjs +8 -3
- package/dist/plugins/next.mjs.map +1 -1
- package/dist/plugins/rolldown.d.mts +2 -2
- package/dist/plugins/rolldown.mjs +1 -1
- package/dist/plugins/rollup.d.mts +2 -2
- package/dist/plugins/rollup.mjs +1 -1
- package/dist/plugins/rsbuild.d.mts +2 -2
- package/dist/plugins/rsbuild.mjs +1 -1
- package/dist/plugins/rspack.d.mts +2 -2
- package/dist/plugins/rspack.mjs +1 -1
- package/dist/plugins/vite.d.mts +2 -2
- package/dist/plugins/vite.mjs +1 -1
- package/dist/plugins/webpack.d.mts +2 -2
- package/dist/plugins/webpack.mjs +1 -1
- package/dist/positions-BCTEFZTX.mjs +89 -0
- package/dist/positions-BCTEFZTX.mjs.map +1 -0
- package/dist/problems-BNAqmOzL.mjs +23 -0
- package/dist/problems-BNAqmOzL.mjs.map +1 -0
- package/dist/register.mjs +3 -2
- package/dist/register.mjs.map +1 -1
- package/dist/{resolve-B7e2uGDa.mjs → resolve-D3geHCGs.mjs} +11 -77
- package/dist/resolve-D3geHCGs.mjs.map +1 -0
- package/dist/runtime/index.d.mts +38 -3
- package/dist/runtime/index.mjs +3 -3
- package/dist/{resolve-hzoKURuJ.mjs → runtime-DeRUtPZ9.mjs} +6 -9
- package/dist/runtime-DeRUtPZ9.mjs.map +1 -0
- package/dist/{schema-CkQRd2Uf.d.mts → schema-BsuU_Hup.d.mts} +2 -3
- package/dist/{schema-C_damFGy.mjs → schema-DcD4N9N-.mjs} +4 -25
- package/dist/schema-DcD4N9N-.mjs.map +1 -0
- package/dist/shared-BnK77Zcp.mjs +55 -0
- package/dist/shared-BnK77Zcp.mjs.map +1 -0
- package/dist/{shared-CLa0Be_8.d.mts → shared-CZ44uwQq.d.mts} +5 -4
- package/dist/source-BWf_Y0YZ.d.mts +32 -0
- package/dist/source-CcI86kKk.mjs +9 -0
- package/dist/source-CcI86kKk.mjs.map +1 -0
- package/dist/{sync-DUNHC9W6.mjs → sync-B-HAK-_E.mjs} +2 -2
- package/dist/{sync-DUNHC9W6.mjs.map → sync-B-HAK-_E.mjs.map} +1 -1
- package/dist/unplugin-AC_HM_T2.d.mts +2 -0
- package/dist/{unplugin-DXVarwkX.mjs → unplugin-BQGm_bhA.mjs} +16 -2
- package/dist/unplugin-BQGm_bhA.mjs.map +1 -0
- package/package.json +23 -20
- package/dist/placeholders-MqW2KO9Z.mjs +0 -511
- package/dist/placeholders-MqW2KO9Z.mjs.map +0 -1
- package/dist/resolve-B7e2uGDa.mjs.map +0 -1
- package/dist/resolve-BUtCDolX.d.mts +0 -65
- package/dist/resolve-hzoKURuJ.mjs.map +0 -1
- package/dist/runtime-la_KkjCS.mjs +0 -1
- package/dist/schema-C_damFGy.mjs.map +0 -1
- package/dist/shared-BuRtKsWB.mjs +0 -16
- package/dist/shared-BuRtKsWB.mjs.map +0 -1
- package/dist/unplugin-DXVarwkX.mjs.map +0 -1
- package/dist/unplugin-ce5g3K3a.d.mts +0 -2
package/README.md
CHANGED
package/dist/bun.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as
|
|
1
|
+
import { n as formatProblems } from "./problems-BNAqmOzL.mjs";
|
|
2
|
+
import { t as configSuffixes } from "./formats-D_dKXoPf.mjs";
|
|
3
|
+
import { t as load } from "./load-DxIjRpX6.mjs";
|
|
3
4
|
import { extname } from "node:path";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
5
6
|
import { plugin } from "bun";
|
package/dist/bun.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bun.mjs","names":[],"sources":["../src/bun.ts"],"sourcesContent":["import { extname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { plugin } from 'bun';\n\nimport { configSuffixes, formatProblems } from './core/index.ts';\nimport { load } from './runtime/index.ts';\n\nimport type { BunPlugin } from 'bun';\n\n// The runtime next to this module, so it resolves from config files outside the dependency tree: `.ts` in this repo, `.mjs` once built.\nconst runtime = fileURLToPath(new URL(`runtime/index${extname(import.meta.url)}`, import.meta.url));\n\nconst filter = new RegExp(`[^/\\\\\\\\](?:${configSuffixes.map((suffix) => suffix.replaceAll('.', '\\\\.')).join('|')})$`);\n\n/**\n * The tyfigo Bun plugin. Importing `tyfigo/bun` (a `bunfig.toml` `preload`) registers it for the runtime and `bun test`; pass\n * `tyfigo()` in `plugins` to use it with `Bun.build`, where a `browser` target inlines the config and a server target inlines the config files and reads `.env` files when it runs.\n */\nexport const tyfigo = (): BunPlugin => ({\n\tname: 'tyfigo',\n\tsetup(build) {\n\t\tconst config = build.config as typeof build.config | undefined;\n\t\tconst target = config?.target === 'browser' ? 'browser' : 'server';\n\t\tbuild.onLoad({ filter }, ({ path }) => {\n\t\t\tconst result = load(path, { target, runtime, bundle: config !== undefined });\n\t\t\tif (result.problems.length > 0) {\n\t\t\t\tthrow new Error(`Invalid config ${path}\\n${formatProblems(result.problems)}`);\n\t\t\t}\n\t\t\treturn { contents: result.code, loader: 'js' };\n\t\t});\n\t},\n});\n\nvoid plugin(tyfigo());\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"bun.mjs","names":[],"sources":["../src/bun.ts"],"sourcesContent":["import { extname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { plugin } from 'bun';\n\nimport { configSuffixes, formatProblems } from './core/index.ts';\nimport { load } from './runtime/index.ts';\n\nimport type { BunPlugin } from 'bun';\n\n// The runtime next to this module, so it resolves from config files outside the dependency tree: `.ts` in this repo, `.mjs` once built.\nconst runtime = fileURLToPath(new URL(`runtime/index${extname(import.meta.url)}`, import.meta.url));\n\nconst filter = new RegExp(`[^/\\\\\\\\](?:${configSuffixes.map((suffix) => suffix.replaceAll('.', '\\\\.')).join('|')})$`);\n\n/**\n * The tyfigo Bun plugin. Importing `tyfigo/bun` (a `bunfig.toml` `preload`) registers it for the runtime and `bun test`; pass\n * `tyfigo()` in `plugins` to use it with `Bun.build`, where a `browser` target inlines the config and a server target inlines the config files and reads `.env` files when it runs.\n */\nexport const tyfigo = (): BunPlugin => ({\n\tname: 'tyfigo',\n\tsetup(build) {\n\t\tconst config = build.config as typeof build.config | undefined;\n\t\tconst target = config?.target === 'browser' ? 'browser' : 'server';\n\t\tbuild.onLoad({ filter }, ({ path }) => {\n\t\t\tconst result = load(path, { target, runtime, bundle: config !== undefined });\n\t\t\tif (result.problems.length > 0) {\n\t\t\t\tthrow new Error(`Invalid config ${path}\\n${formatProblems(result.problems)}`);\n\t\t\t}\n\t\t\treturn { contents: result.code, loader: 'js' };\n\t\t});\n\t},\n});\n\nvoid plugin(tyfigo());\n"],"mappings":";;;;;;;AAWA,MAAM,UAAU,cAAc,IAAI,IAAI,gBAAgB,QAAQ,YAAY,GAAG,KAAK,YAAY,GAAG,CAAC;AAElG,MAAM,SAAS,IAAI,OAAO,cAAc,eAAe,KAAK,WAAW,OAAO,WAAW,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,GAAG;;;;;AAMnH,MAAa,gBAA2B;CACvC,MAAM;CACN,MAAM,OAAO;EACZ,MAAM,SAAS,MAAM;EACrB,MAAM,SAAS,QAAQ,WAAW,YAAY,YAAY;EAC1D,MAAM,OAAO,EAAE,OAAO,IAAI,EAAE,WAAW;GACtC,MAAM,SAAS,KAAK,MAAM;IAAE;IAAQ;IAAS,QAAQ,WAAW,KAAA;GAAU,CAAC;GAC3E,IAAI,OAAO,SAAS,SAAS,GAC5B,MAAM,IAAI,MAAM,kBAAkB,KAAK,IAAI,eAAe,OAAO,QAAQ,GAAG;GAE7E,OAAO;IAAE,UAAU,OAAO;IAAM,QAAQ;GAAK;EAC9C,CAAC;CACF;AACD;AAEK,OAAO,OAAO,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import "./index-jUM0zKD5.mjs";
|
|
2
|
+
import { a as LooseInput, o as SchemaInput, r as ConfigValidationError, s as SchemaOutput } from "./schema-BsuU_Hup.mjs";
|
|
3
|
+
import { ConfigProvider, Context, Effect, Layer, Schema } from "effect";
|
|
4
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
5
|
+
/**
|
|
6
|
+
* A Standard Schema or any Effect Schema, including one that needs services to decode.
|
|
7
|
+
*/
|
|
8
|
+
type EffectConfigSchema = StandardSchemaV1 | Schema.Top;
|
|
9
|
+
/**
|
|
10
|
+
* The services an Effect Schema needs to decode, or `never` for a Standard Schema.
|
|
11
|
+
*/
|
|
12
|
+
type SchemaServices<S> = S extends StandardSchemaV1 ? never : S extends Schema.Top ? S['DecodingServices'] : never;
|
|
13
|
+
/**
|
|
14
|
+
* The error of every tyfigo Effect: a config or the environment does not match its schema, or a config file could not
|
|
15
|
+
* be resolved. It is the same class the Promise API throws, tagged `ConfigValidationError`.
|
|
16
|
+
*/
|
|
17
|
+
declare const ConfigError: typeof ConfigValidationError;
|
|
18
|
+
type ConfigError = ConfigValidationError;
|
|
19
|
+
/**
|
|
20
|
+
* Validates a config import (or any value) with a Standard Schema or an Effect Schema. Effect Schemas are decoded by
|
|
21
|
+
* Effect itself, so schemas that need services or decode asynchronously work, and so do async Standard Schemas.
|
|
22
|
+
*/
|
|
23
|
+
declare const loadConfig: <S extends EffectConfigSchema>(config: LooseInput<SchemaInput<S>>, schema: S) => Effect.Effect<SchemaOutput<S>, ConfigError, SchemaServices<S>>;
|
|
24
|
+
/**
|
|
25
|
+
* A layer that provides `service` with the validated config.
|
|
26
|
+
*/
|
|
27
|
+
declare const layerConfig: <I, S extends EffectConfigSchema>(service: Context.Key<I, SchemaOutput<S>>, config: LooseInput<SchemaInput<S>>, schema: S) => Layer.Layer<I, ConfigError, SchemaServices<S>>;
|
|
28
|
+
/**
|
|
29
|
+
* Defines a service class for a validated config, with a `layer` that provides it.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* class AppConfig extends ConfigService<AppConfig>()('app/AppConfig', config, schema) {}
|
|
34
|
+
*
|
|
35
|
+
* const program = Effect.gen(function* () {
|
|
36
|
+
* const { port } = yield* AppConfig;
|
|
37
|
+
* }).pipe(Effect.provide(AppConfig.layer));
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
declare const ConfigService: <Self>() => <const Identifier extends string, S extends EffectConfigSchema>(id: Identifier, config: LooseInput<SchemaInput<S>>, schema: S) => Context.ServiceClass<Self, Identifier, SchemaOutput<S>> & {
|
|
41
|
+
layer: Layer.Layer<Self, ConfigValidationError, Exclude<SchemaServices<S>, import("effect/Scope").Scope>>;
|
|
42
|
+
};
|
|
43
|
+
interface ConfigProviderLayerOptions {
|
|
44
|
+
/**
|
|
45
|
+
* Whether the config files win over the provider already installed (by default the environment variables). Defaults to
|
|
46
|
+
* `true`; with `false` the config files only fill in paths the current provider does not have.
|
|
47
|
+
*/
|
|
48
|
+
readonly asPrimary?: boolean | undefined;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* A `ConfigProvider` that reads a config import (or any object): nested keys are path segments and array items are
|
|
52
|
+
* numeric segments, so `Config.Number('port').pipe(Config.nested('server'))` reads `server.port`. Empty strings are kept.
|
|
53
|
+
*/
|
|
54
|
+
declare const configProvider: (config: unknown) => ConfigProvider.ConfigProvider;
|
|
55
|
+
/**
|
|
56
|
+
* Installs {@link configProvider} for a config import on top of the current `ConfigProvider`, which falls back to the
|
|
57
|
+
* environment variables for paths the config does not have.
|
|
58
|
+
*/
|
|
59
|
+
declare const layerConfigProvider: (config: unknown, options?: ConfigProviderLayerOptions) => Layer.Layer<never>;
|
|
60
|
+
export { ConfigService as a, layerConfig as c, ConfigError as i, loadConfig as l, configProvider as n, EffectConfigSchema as o, layerConfigProvider as r, SchemaServices as s, ConfigProviderLayerOptions as t };
|
|
61
|
+
//# sourceMappingURL=effect.browser-Bhr-Yr7t.d.mts.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { n as decodeConfig, t as ConfigValidationError } from "./schema-DcD4N9N-.mjs";
|
|
2
|
+
import { ConfigProvider, Context, Layer } from "effect";
|
|
3
|
+
// src/effect/load.ts
|
|
4
|
+
/**
|
|
5
|
+
* The error of every tyfigo Effect: a config or the environment does not match its schema, or a config file could not
|
|
6
|
+
* be resolved. It is the same class the Promise API throws, tagged `ConfigValidationError`.
|
|
7
|
+
*/
|
|
8
|
+
const ConfigError = ConfigValidationError;
|
|
9
|
+
/**
|
|
10
|
+
* Validates a config import (or any value) with a Standard Schema or an Effect Schema. Effect Schemas are decoded by
|
|
11
|
+
* Effect itself, so schemas that need services or decode asynchronously work, and so do async Standard Schemas.
|
|
12
|
+
*/
|
|
13
|
+
const loadConfig = (config, schema) => decodeConfig(config, schema, {
|
|
14
|
+
async: true,
|
|
15
|
+
native: true
|
|
16
|
+
});
|
|
17
|
+
/**
|
|
18
|
+
* A layer that provides `service` with the validated config.
|
|
19
|
+
*/
|
|
20
|
+
const layerConfig = (service, config, schema) => Layer.effect(service, loadConfig(config, schema));
|
|
21
|
+
/**
|
|
22
|
+
* Defines a service class for a validated config, with a `layer` that provides it.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* class AppConfig extends ConfigService<AppConfig>()('app/AppConfig', config, schema) {}
|
|
27
|
+
*
|
|
28
|
+
* const program = Effect.gen(function* () {
|
|
29
|
+
* const { port } = yield* AppConfig;
|
|
30
|
+
* }).pipe(Effect.provide(AppConfig.layer));
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
const ConfigService = () => (id, config, schema) => {
|
|
34
|
+
const service = Context.Service()(id);
|
|
35
|
+
return Object.assign(service, { layer: Layer.effect(service, loadConfig(config, schema)) });
|
|
36
|
+
};
|
|
37
|
+
// src/effect/provider.ts
|
|
38
|
+
/**
|
|
39
|
+
* A `ConfigProvider` that reads a config import (or any object): nested keys are path segments and array items are
|
|
40
|
+
* numeric segments, so `Config.Number('port').pipe(Config.nested('server'))` reads `server.port`. Empty strings are kept.
|
|
41
|
+
*/
|
|
42
|
+
const configProvider = (config) => ConfigProvider.fromUnknown(config, { preserveEmptyStrings: true });
|
|
43
|
+
/**
|
|
44
|
+
* Installs {@link configProvider} for a config import on top of the current `ConfigProvider`, which falls back to the
|
|
45
|
+
* environment variables for paths the config does not have.
|
|
46
|
+
*/
|
|
47
|
+
const layerConfigProvider = (config, options = {}) => ConfigProvider.layerAdd(configProvider(config), { asPrimary: options.asPrimary ?? true });
|
|
48
|
+
export { layerConfig as a, ConfigService as i, layerConfigProvider as n, loadConfig as o, ConfigError as r, configProvider as t };
|
|
49
|
+
|
|
50
|
+
//# sourceMappingURL=effect.browser-CO87TEE_.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effect.browser-CO87TEE_.mjs","names":[],"sources":["../src/effect/load.ts","../src/effect/provider.ts"],"sourcesContent":["import { Context, Layer } from 'effect';\n\nimport { ConfigValidationError, decodeConfig } from '../schema.ts';\n\nimport type { ConfigSchema, LooseInput, SchemaInput, SchemaOutput } from '../schema.ts';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { Effect, Schema } from 'effect';\n\n/**\n * A Standard Schema or any Effect Schema, including one that needs services to decode.\n */\nexport type EffectConfigSchema = StandardSchemaV1 | Schema.Top;\n\n/**\n * The services an Effect Schema needs to decode, or `never` for a Standard Schema.\n */\nexport type SchemaServices<S> = S extends StandardSchemaV1\n\t? never\n\t: S extends Schema.Top\n\t\t? S['DecodingServices']\n\t\t: never;\n\n/**\n * The error of every tyfigo Effect: a config or the environment does not match its schema, or a config file could not\n * be resolved. It is the same class the Promise API throws, tagged `ConfigValidationError`.\n */\nexport const ConfigError = ConfigValidationError;\nexport type ConfigError = ConfigValidationError;\n\n/**\n * Validates a config import (or any value) with a Standard Schema or an Effect Schema. Effect Schemas are decoded by\n * Effect itself, so schemas that need services or decode asynchronously work, and so do async Standard Schemas.\n */\nexport const loadConfig = <S extends EffectConfigSchema>(\n\tconfig: LooseInput<SchemaInput<S>>,\n\tschema: S,\n): Effect.Effect<SchemaOutput<S>, ConfigError, SchemaServices<S>> =>\n\tdecodeConfig(config, schema as ConfigSchema, { async: true, native: true }) as Effect.Effect<\n\t\tSchemaOutput<S>,\n\t\tConfigError,\n\t\tSchemaServices<S>\n\t>;\n\n/**\n * A layer that provides `service` with the validated config.\n */\nexport const layerConfig = <I, S extends EffectConfigSchema>(\n\tservice: Context.Key<I, SchemaOutput<S>>,\n\tconfig: LooseInput<SchemaInput<S>>,\n\tschema: S,\n): Layer.Layer<I, ConfigError, SchemaServices<S>> => Layer.effect(service, loadConfig(config, schema));\n\n/**\n * Defines a service class for a validated config, with a `layer` that provides it.\n *\n * @example\n * ```ts\n * class AppConfig extends ConfigService<AppConfig>()('app/AppConfig', config, schema) {}\n *\n * const program = Effect.gen(function* () {\n * \tconst { port } = yield* AppConfig;\n * }).pipe(Effect.provide(AppConfig.layer));\n * ```\n */\nexport const ConfigService =\n\t<Self>() =>\n\t<const Identifier extends string, S extends EffectConfigSchema>(\n\t\tid: Identifier,\n\t\tconfig: LooseInput<SchemaInput<S>>,\n\t\tschema: S,\n\t) => {\n\t\tconst service = Context.Service<Self, SchemaOutput<S>>()(id);\n\t\treturn Object.assign(service, {\n\t\t\tlayer: Layer.effect(service, loadConfig(config, schema)),\n\t\t});\n\t};\n","import { ConfigProvider } from 'effect';\n\nimport type { Layer } from 'effect';\n\nexport interface ConfigProviderLayerOptions {\n\t/**\n\t * Whether the config files win over the provider already installed (by default the environment variables). Defaults to\n\t * `true`; with `false` the config files only fill in paths the current provider does not have.\n\t */\n\treadonly asPrimary?: boolean | undefined;\n}\n\n/**\n * A `ConfigProvider` that reads a config import (or any object): nested keys are path segments and array items are\n * numeric segments, so `Config.Number('port').pipe(Config.nested('server'))` reads `server.port`. Empty strings are kept.\n */\nexport const configProvider = (config: unknown): ConfigProvider.ConfigProvider =>\n\tConfigProvider.fromUnknown(config, { preserveEmptyStrings: true });\n\n/**\n * Installs {@link configProvider} for a config import on top of the current `ConfigProvider`, which falls back to the\n * environment variables for paths the config does not have.\n */\nexport const layerConfigProvider = (config: unknown, options: ConfigProviderLayerOptions = {}): Layer.Layer<never> =>\n\tConfigProvider.layerAdd(configProvider(config), { asPrimary: options.asPrimary ?? true });\n"],"mappings":";;;;;;;AA0BA,MAAa,cAAc;;;;;AAO3B,MAAa,cACZ,QACA,WAEA,aAAa,QAAQ,QAAwB;CAAE,OAAO;CAAM,QAAQ;AAAK,CAAC;;;;AAS3E,MAAa,eACZ,SACA,QACA,WACoD,MAAM,OAAO,SAAS,WAAW,QAAQ,MAAM,CAAC;;;;;;;;;;;;;AAcrG,MAAa,uBAGX,IACA,QACA,WACI;CACJ,MAAM,UAAU,QAAQ,QAA+B,CAAC,CAAC,EAAE;CAC3D,OAAO,OAAO,OAAO,SAAS,EAC7B,OAAO,MAAM,OAAO,SAAS,WAAW,QAAQ,MAAM,CAAC,EACxD,CAAC;AACF;;;;;;AC3DD,MAAa,kBAAkB,WAC9B,eAAe,YAAY,QAAQ,EAAE,sBAAsB,KAAK,CAAC;;;;;AAMlE,MAAa,uBAAuB,QAAiB,UAAsC,CAAC,MAC3F,eAAe,SAAS,eAAe,MAAM,GAAG,EAAE,WAAW,QAAQ,aAAa,KAAK,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { a as LocatedSpan, c as Path, i as ResolvedLayer, l as Span, n as ResolveOptions, o as Problem, r as ResolvedConfig, s as ProblemCode } from "./index-jUM0zKD5.mjs";
|
|
2
|
+
import { t as ConfigSource } from "./source-BWf_Y0YZ.mjs";
|
|
3
|
+
import { a as LooseInput, i as LoadEnvOptions, n as ConfigSchema, o as SchemaInput, r as ConfigValidationError, s as SchemaOutput, t as ConfigIssue } from "./schema-BsuU_Hup.mjs";
|
|
4
|
+
import { a as ConfigService, c as layerConfig, i as ConfigError, l as loadConfig, n as configProvider, o as EffectConfigSchema, r as layerConfigProvider, s as SchemaServices, t as ConfigProviderLayerOptions } from "./effect.browser-Bhr-Yr7t.mjs";
|
|
5
|
+
export { ConfigError, type ConfigIssue, ConfigProviderLayerOptions, type ConfigSchema, ConfigService, type ConfigSource, ConfigValidationError, EffectConfigSchema, type LoadEnvOptions, type LocatedSpan, type LooseInput, type Path, type Problem, type ProblemCode, type ResolveOptions, type ResolvedConfig, type ResolvedLayer, type SchemaInput, type SchemaOutput, SchemaServices, type Span, configProvider, layerConfig, layerConfigProvider, loadConfig };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { t as ConfigValidationError } from "./schema-DcD4N9N-.mjs";
|
|
2
|
+
import { a as layerConfig, i as ConfigService, n as layerConfigProvider, o as loadConfig, r as ConfigError, t as configProvider } from "./effect.browser-CO87TEE_.mjs";
|
|
3
|
+
export { ConfigError, ConfigService, ConfigValidationError, configProvider, layerConfig, layerConfigProvider, loadConfig };
|
package/dist/effect.d.mts
CHANGED
|
@@ -1,80 +1,25 @@
|
|
|
1
|
-
import { a as LocatedSpan, c as Path, i as ResolvedLayer, l as Span, n as ResolveOptions, o as Problem, r as ResolvedConfig, s as ProblemCode } from "./index-
|
|
2
|
-
import {
|
|
3
|
-
import { a as LooseInput, i as LoadEnvOptions, n as ConfigSchema, o as SchemaInput, r as ConfigValidationError, s as SchemaOutput, t as ConfigIssue } from "./schema-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
/**
|
|
7
|
-
* A Standard Schema or any Effect Schema, including one that needs services to decode.
|
|
8
|
-
*/
|
|
9
|
-
export type EffectConfigSchema = StandardSchemaV1 | Schema.Top;
|
|
10
|
-
/**
|
|
11
|
-
* The services an Effect Schema needs to decode, or `never` for a Standard Schema.
|
|
12
|
-
*/
|
|
13
|
-
export type SchemaServices<S> = S extends StandardSchemaV1 ? never : S extends Schema.Top ? S['DecodingServices'] : never;
|
|
14
|
-
/**
|
|
15
|
-
* The error of every tyfigo Effect: a config or the environment does not match its schema, or a config file could not
|
|
16
|
-
* be resolved. It is the same class the Promise API throws, tagged `ConfigValidationError`.
|
|
17
|
-
*/
|
|
18
|
-
export declare const ConfigError: typeof ConfigValidationError;
|
|
19
|
-
export type ConfigError = ConfigValidationError;
|
|
20
|
-
/**
|
|
21
|
-
* Validates a config import (or any value) with a Standard Schema or an Effect Schema. Effect Schemas are decoded by
|
|
22
|
-
* Effect itself, so schemas that need services or decode asynchronously work, and so do async Standard Schemas.
|
|
23
|
-
*/
|
|
24
|
-
export declare const loadConfig: <S extends EffectConfigSchema>(config: LooseInput<SchemaInput<S>>, schema: S) => Effect.Effect<SchemaOutput<S>, ConfigError, SchemaServices<S>>;
|
|
1
|
+
import { a as LocatedSpan, c as Path, i as ResolvedLayer, l as Span, n as ResolveOptions, o as Problem, r as ResolvedConfig, s as ProblemCode } from "./index-jUM0zKD5.mjs";
|
|
2
|
+
import { t as ConfigSource } from "./source-BWf_Y0YZ.mjs";
|
|
3
|
+
import { a as LooseInput, i as LoadEnvOptions, n as ConfigSchema, o as SchemaInput, r as ConfigValidationError, s as SchemaOutput, t as ConfigIssue } from "./schema-BsuU_Hup.mjs";
|
|
4
|
+
import { a as ConfigService, c as layerConfig, i as ConfigError, l as loadConfig, n as configProvider, o as EffectConfigSchema, r as layerConfigProvider, s as SchemaServices, t as ConfigProviderLayerOptions } from "./effect.browser-Bhr-Yr7t.mjs";
|
|
5
|
+
import { ConfigProvider, Context, Effect, Layer } from "effect";
|
|
25
6
|
/**
|
|
26
7
|
* Validates `.env`, `.env.local`, `.env.<environment>` and `.env.<environment>.local` with the real environment on top.
|
|
27
8
|
* Never writes `process.env`.
|
|
28
9
|
*/
|
|
29
10
|
export declare const loadEnv: <S extends EffectConfigSchema>(schema: S, options?: LoadEnvOptions) => Effect.Effect<SchemaOutput<S>, ConfigError, SchemaServices<S>>;
|
|
30
|
-
/**
|
|
31
|
-
* A layer that provides `service` with the validated config.
|
|
32
|
-
*/
|
|
33
|
-
export declare const layerConfig: <I, S extends EffectConfigSchema>(service: Context.Key<I, SchemaOutput<S>>, config: LooseInput<SchemaInput<S>>, schema: S) => Layer.Layer<I, ConfigError, SchemaServices<S>>;
|
|
34
11
|
/**
|
|
35
12
|
* A layer that provides `service` with the validated environment variables.
|
|
36
13
|
*/
|
|
37
14
|
export declare const layerEnv: <I, S extends EffectConfigSchema>(service: Context.Key<I, SchemaOutput<S>>, schema: S, options?: LoadEnvOptions) => Layer.Layer<I, ConfigError, SchemaServices<S>>;
|
|
38
|
-
/**
|
|
39
|
-
* Defines a service class for a validated config, with a `layer` that provides it.
|
|
40
|
-
*
|
|
41
|
-
* @example
|
|
42
|
-
* ```ts
|
|
43
|
-
* class AppConfig extends ConfigService<AppConfig>()('app/AppConfig', config, schema) {}
|
|
44
|
-
*
|
|
45
|
-
* const program = Effect.gen(function* () {
|
|
46
|
-
* const { port } = yield* AppConfig;
|
|
47
|
-
* }).pipe(Effect.provide(AppConfig.layer));
|
|
48
|
-
* ```
|
|
49
|
-
*/
|
|
50
|
-
export declare const ConfigService: <Self>() => <const Identifier extends string, S extends EffectConfigSchema>(id: Identifier, config: LooseInput<SchemaInput<S>>, schema: S) => Context.ServiceClass<Self, Identifier, SchemaOutput<S>> & {
|
|
51
|
-
layer: Layer.Layer<Self, ConfigValidationError, Exclude<SchemaServices<S>, import("effect/Scope").Scope>>;
|
|
52
|
-
};
|
|
53
|
-
export interface ConfigProviderLayerOptions {
|
|
54
|
-
/**
|
|
55
|
-
* Whether the config files win over the provider already installed (by default the environment variables). Defaults to
|
|
56
|
-
* `true`; with `false` the config files only fill in paths the current provider does not have.
|
|
57
|
-
*/
|
|
58
|
-
readonly asPrimary?: boolean | undefined;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* A `ConfigProvider` that reads a config import (or any object): nested keys are path segments and array items are
|
|
62
|
-
* numeric segments, so `Config.Number('port').pipe(Config.nested('server'))` reads `server.port`. Empty strings are kept.
|
|
63
|
-
*/
|
|
64
|
-
export declare const configProvider: (config: unknown) => ConfigProvider.ConfigProvider;
|
|
65
15
|
/**
|
|
66
16
|
* Resolves a config file with its layers, `.env` files and placeholders, like a config import does, and returns a
|
|
67
17
|
* `ConfigProvider` over the merged value.
|
|
68
18
|
*/
|
|
69
19
|
export declare const configProviderFromFile: (file: string, options?: ResolveOptions | undefined) => Effect.Effect<ConfigProvider.ConfigProvider, ConfigValidationError, never>;
|
|
70
|
-
/**
|
|
71
|
-
* Installs {@link configProvider} for a config import on top of the current `ConfigProvider`, which falls back to the
|
|
72
|
-
* environment variables for paths the config does not have.
|
|
73
|
-
*/
|
|
74
|
-
export declare const layerConfigProvider: (config: unknown, options?: ConfigProviderLayerOptions) => Layer.Layer<never>;
|
|
75
20
|
/**
|
|
76
21
|
* Installs {@link configProviderFromFile} on top of the current `ConfigProvider`.
|
|
77
22
|
*/
|
|
78
23
|
export declare const layerConfigProviderFromFile: (file: string, options?: ResolveOptions & ConfigProviderLayerOptions) => Layer.Layer<never, ConfigError>;
|
|
79
|
-
export { type ConfigIssue, type ConfigSchema, type ConfigSource, ConfigValidationError, type LoadEnvOptions, type LocatedSpan, type LooseInput, type Path, type Problem, type ProblemCode, type ResolveOptions, type ResolvedConfig, type ResolvedLayer, type SchemaInput, type SchemaOutput, type Span };
|
|
24
|
+
export { ConfigError, type ConfigIssue, ConfigProviderLayerOptions, type ConfigSchema, ConfigService, type ConfigSource, ConfigValidationError, EffectConfigSchema, type LoadEnvOptions, type LocatedSpan, type LooseInput, type Path, type Problem, type ProblemCode, type ResolveOptions, type ResolvedConfig, type ResolvedLayer, type SchemaInput, type SchemaOutput, SchemaServices, type Span, configProvider, layerConfig, layerConfigProvider, loadConfig };
|
|
80
25
|
//# sourceMappingURL=effect.d.mts.map
|
package/dist/effect.mjs
CHANGED
|
@@ -1,20 +1,9 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* be resolved. It is the same class the Promise API throws, tagged `ConfigValidationError`.
|
|
8
|
-
*/
|
|
9
|
-
const ConfigError = ConfigValidationError;
|
|
10
|
-
/**
|
|
11
|
-
* Validates a config import (or any value) with a Standard Schema or an Effect Schema. Effect Schemas are decoded by
|
|
12
|
-
* Effect itself, so schemas that need services or decode asynchronously work, and so do async Standard Schemas.
|
|
13
|
-
*/
|
|
14
|
-
const loadConfig = (config, schema) => decodeConfig(config, schema, {
|
|
15
|
-
async: true,
|
|
16
|
-
native: true
|
|
17
|
-
});
|
|
1
|
+
import { t as ConfigValidationError } from "./schema-DcD4N9N-.mjs";
|
|
2
|
+
import { t as decodeEnv } from "./env-Bd-1Atoz.mjs";
|
|
3
|
+
import { a as layerConfig, i as ConfigService, n as layerConfigProvider, o as loadConfig, r as ConfigError, t as configProvider } from "./effect.browser-CO87TEE_.mjs";
|
|
4
|
+
import { t as resolveConfig } from "./resolve-D3geHCGs.mjs";
|
|
5
|
+
import { ConfigProvider, Effect, Layer } from "effect";
|
|
6
|
+
// src/effect/env.ts
|
|
18
7
|
/**
|
|
19
8
|
* Validates `.env`, `.env.local`, `.env.<environment>` and `.env.<environment>.local` with the real environment on top.
|
|
20
9
|
* Never writes `process.env`.
|
|
@@ -25,35 +14,10 @@ const loadEnv = (schema, options = {}) => decodeEnv(schema, {
|
|
|
25
14
|
native: true
|
|
26
15
|
});
|
|
27
16
|
/**
|
|
28
|
-
* A layer that provides `service` with the validated config.
|
|
29
|
-
*/
|
|
30
|
-
const layerConfig = (service, config, schema) => Layer.effect(service, loadConfig(config, schema));
|
|
31
|
-
/**
|
|
32
17
|
* A layer that provides `service` with the validated environment variables.
|
|
33
18
|
*/
|
|
34
19
|
const layerEnv = (service, schema, options = {}) => Layer.effect(service, loadEnv(schema, options));
|
|
35
|
-
|
|
36
|
-
* Defines a service class for a validated config, with a `layer` that provides it.
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* ```ts
|
|
40
|
-
* class AppConfig extends ConfigService<AppConfig>()('app/AppConfig', config, schema) {}
|
|
41
|
-
*
|
|
42
|
-
* const program = Effect.gen(function* () {
|
|
43
|
-
* const { port } = yield* AppConfig;
|
|
44
|
-
* }).pipe(Effect.provide(AppConfig.layer));
|
|
45
|
-
* ```
|
|
46
|
-
*/
|
|
47
|
-
const ConfigService = () => (id, config, schema) => {
|
|
48
|
-
const service = Context.Service()(id);
|
|
49
|
-
return Object.assign(service, { layer: Layer.effect(service, loadConfig(config, schema)) });
|
|
50
|
-
};
|
|
51
|
-
// src/effect/provider.ts
|
|
52
|
-
/**
|
|
53
|
-
* A `ConfigProvider` that reads a config import (or any object): nested keys are path segments and array items are
|
|
54
|
-
* numeric segments, so `Config.Number('port').pipe(Config.nested('server'))` reads `server.port`. Empty strings are kept.
|
|
55
|
-
*/
|
|
56
|
-
const configProvider = (config) => ConfigProvider.fromUnknown(config, { preserveEmptyStrings: true });
|
|
20
|
+
// src/effect/file-provider.ts
|
|
57
21
|
/**
|
|
58
22
|
* Resolves a config file with its layers, `.env` files and placeholders, like a config import does, and returns a
|
|
59
23
|
* `ConfigProvider` over the merged value.
|
|
@@ -71,11 +35,6 @@ const configProviderFromFile = Effect.fn("configProviderFromFile")(function* (fi
|
|
|
71
35
|
return configProvider(result.value);
|
|
72
36
|
});
|
|
73
37
|
/**
|
|
74
|
-
* Installs {@link configProvider} for a config import on top of the current `ConfigProvider`, which falls back to the
|
|
75
|
-
* environment variables for paths the config does not have.
|
|
76
|
-
*/
|
|
77
|
-
const layerConfigProvider = (config, options = {}) => ConfigProvider.layerAdd(configProvider(config), { asPrimary: options.asPrimary ?? true });
|
|
78
|
-
/**
|
|
79
38
|
* Installs {@link configProviderFromFile} on top of the current `ConfigProvider`.
|
|
80
39
|
*/
|
|
81
40
|
const layerConfigProviderFromFile = (file, options = {}) => ConfigProvider.layerAdd(configProviderFromFile(file, options), { asPrimary: options.asPrimary ?? true });
|
package/dist/effect.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"effect.mjs","names":[],"sources":["../src/effect/
|
|
1
|
+
{"version":3,"file":"effect.mjs","names":[],"sources":["../src/effect/env.ts","../src/effect/file-provider.ts"],"sourcesContent":["import { Layer } from 'effect';\n\nimport { decodeEnv } from '../env.ts';\n\nimport type { ConfigSchema, LoadEnvOptions, SchemaOutput } from '../schema.ts';\nimport type { ConfigError, EffectConfigSchema, SchemaServices } from './load.ts';\nimport type { Context, Effect } from 'effect';\n\n/**\n * Validates `.env`, `.env.local`, `.env.<environment>` and `.env.<environment>.local` with the real environment on top.\n * Never writes `process.env`.\n */\nexport const loadEnv = <S extends EffectConfigSchema>(\n\tschema: S,\n\toptions: LoadEnvOptions = {},\n): Effect.Effect<SchemaOutput<S>, ConfigError, SchemaServices<S>> =>\n\tdecodeEnv(schema as ConfigSchema, { ...options, async: true, native: true }) as Effect.Effect<\n\t\tSchemaOutput<S>,\n\t\tConfigError,\n\t\tSchemaServices<S>\n\t>;\n\n/**\n * A layer that provides `service` with the validated environment variables.\n */\nexport const layerEnv = <I, S extends EffectConfigSchema>(\n\tservice: Context.Key<I, SchemaOutput<S>>,\n\tschema: S,\n\toptions: LoadEnvOptions = {},\n): Layer.Layer<I, ConfigError, SchemaServices<S>> => Layer.effect(service, loadEnv(schema, options));\n","import { ConfigProvider, Effect } from 'effect';\n\nimport { configProvider } from './provider.ts';\n\nimport { resolveConfig } from '../core/resolve.ts';\nimport { ConfigValidationError } from '../schema.ts';\n\nimport type { ResolveOptions } from '../core/resolve.ts';\nimport type { ConfigError } from './load.ts';\nimport type { ConfigProviderLayerOptions } from './provider.ts';\nimport type { Layer } from 'effect';\n\n/**\n * Resolves a config file with its layers, `.env` files and placeholders, like a config import does, and returns a\n * `ConfigProvider` over the merged value.\n */\nexport const configProviderFromFile = Effect.fn('configProviderFromFile')(function* (\n\tfile: string,\n\toptions: ResolveOptions = {},\n): Effect.fn.Return<ConfigProvider.ConfigProvider, ConfigError> {\n\tconst result = yield* resolveConfig(file, options);\n\tif (result.problems.length > 0) {\n\t\treturn yield* new ConfigValidationError({\n\t\t\tsubject: `config ${result.file}`,\n\t\t\tissues: result.problems.map((problem) => ({\n\t\t\t\tpath: [],\n\t\t\t\tmessage: `${problem.message} (${problem.code})`,\n\t\t\t\tlocation: `${problem.file}:${problem.line}:${problem.column}`,\n\t\t\t})),\n\t\t});\n\t}\n\treturn configProvider(result.value);\n});\n\n/**\n * Installs {@link configProviderFromFile} on top of the current `ConfigProvider`.\n */\nexport const layerConfigProviderFromFile = (\n\tfile: string,\n\toptions: ResolveOptions & ConfigProviderLayerOptions = {},\n): Layer.Layer<never, ConfigError> =>\n\tConfigProvider.layerAdd(configProviderFromFile(file, options), { asPrimary: options.asPrimary ?? true });\n"],"mappings":";;;;;;;;;;AAYA,MAAa,WACZ,QACA,UAA0B,CAAC,MAE3B,UAAU,QAAwB;CAAE,GAAG;CAAS,OAAO;CAAM,QAAQ;AAAK,CAAC;;;;AAS5E,MAAa,YACZ,SACA,QACA,UAA0B,CAAC,MACyB,MAAM,OAAO,SAAS,QAAQ,QAAQ,OAAO,CAAC;;;;;;ACbnG,MAAa,yBAAyB,OAAO,GAAG,wBAAwB,CAAC,CAAC,WACzE,MACA,UAA0B,CAAC,GACoC;CAC/D,MAAM,SAAS,OAAO,cAAc,MAAM,OAAO;CACjD,IAAI,OAAO,SAAS,SAAS,GAC5B,OAAO,OAAO,IAAI,sBAAsB;EACvC,SAAS,UAAU,OAAO;EAC1B,QAAQ,OAAO,SAAS,KAAK,aAAa;GACzC,MAAM,CAAC;GACP,SAAS,GAAG,QAAQ,QAAQ,IAAI,QAAQ,KAAK;GAC7C,UAAU,GAAG,QAAQ,KAAK,GAAG,QAAQ,KAAK,GAAG,QAAQ;EACtD,EAAE;CACH,CAAC;CAEF,OAAO,eAAe,OAAO,KAAK;AACnC,CAAC;;;;AAKD,MAAa,+BACZ,MACA,UAAuD,CAAC,MAExD,eAAe,SAAS,uBAAuB,MAAM,OAAO,GAAG,EAAE,WAAW,QAAQ,aAAa,KAAK,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { n as processEnv, r as readEnv } from "./env-R3_XPW_u.mjs";
|
|
2
|
+
import { r as validate } from "./schema-DcD4N9N-.mjs";
|
|
3
|
+
import { Effect } from "effect";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import process from "node:process";
|
|
6
|
+
// src/env.ts
|
|
7
|
+
const decodeEnv = Effect.fn("decodeEnv")(function* (schema, options) {
|
|
8
|
+
const env = options.env ?? processEnv();
|
|
9
|
+
const environment = options.environment ?? (env.NODE_ENV || void 0);
|
|
10
|
+
const result = yield* readEnv(join(options.cwd ?? process.cwd(), ".env"), {
|
|
11
|
+
environment,
|
|
12
|
+
env
|
|
13
|
+
});
|
|
14
|
+
return yield* validate(schema, result.variables, {
|
|
15
|
+
subject: "environment variables",
|
|
16
|
+
async: options.async,
|
|
17
|
+
native: options.native,
|
|
18
|
+
issues: result.problems.map((problem) => ({
|
|
19
|
+
path: [],
|
|
20
|
+
message: problem.message,
|
|
21
|
+
location: `${problem.file}:${problem.line}:${problem.column}`
|
|
22
|
+
}))
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
export { decodeEnv as t };
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=env-Bd-1Atoz.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-Bd-1Atoz.mjs","names":[],"sources":["../src/env.ts"],"sourcesContent":["import { join } from 'node:path';\nimport process from 'node:process';\n\nimport { Effect } from 'effect';\n\nimport { processEnv, readEnv } from './core/env.ts';\nimport { validate } from './schema.ts';\n\nimport type { ConfigSchema, LoadEnvOptions } from './schema.ts';\n\nexport const decodeEnv = Effect.fn('decodeEnv')(function* <S extends ConfigSchema>(\n\tschema: S,\n\toptions: LoadEnvOptions & { readonly async: boolean; readonly native?: boolean | undefined },\n) {\n\tconst env = options.env ?? processEnv();\n\tconst environment = options.environment ?? (env.NODE_ENV || undefined);\n\tconst result = yield* readEnv(join(options.cwd ?? process.cwd(), '.env'), { environment, env });\n\treturn yield* validate(schema, result.variables, {\n\t\tsubject: 'environment variables',\n\t\tasync: options.async,\n\t\tnative: options.native,\n\t\tissues: result.problems.map((problem) => ({\n\t\t\tpath: [],\n\t\t\tmessage: problem.message,\n\t\t\tlocation: `${problem.file}:${problem.line}:${problem.column}`,\n\t\t})),\n\t});\n});\n"],"mappings":";;;;;;AAUA,MAAa,YAAY,OAAO,GAAG,WAAW,CAAC,CAAC,WAC/C,QACA,SACC;CACD,MAAM,MAAM,QAAQ,OAAO,WAAW;CACtC,MAAM,cAAc,QAAQ,gBAAgB,IAAI,YAAY,KAAA;CAC5D,MAAM,SAAS,OAAO,QAAQ,KAAK,QAAQ,OAAO,QAAQ,IAAI,GAAG,MAAM,GAAG;EAAE;EAAa;CAAI,CAAC;CAC9F,OAAO,OAAO,SAAS,QAAQ,OAAO,WAAW;EAChD,SAAS;EACT,OAAO,QAAQ;EACf,QAAQ,QAAQ;EAChB,QAAQ,OAAO,SAAS,KAAK,aAAa;GACzC,MAAM,CAAC;GACP,SAAS,QAAQ;GACjB,UAAU,GAAG,QAAQ,KAAK,GAAG,QAAQ,KAAK,GAAG,QAAQ;EACtD,EAAE;CACH,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { t as fileProblem } from "./problems-BNAqmOzL.mjs";
|
|
2
|
+
import { Effect, Result } from "effect";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import { readFileSync, statSync } from "node:fs";
|
|
6
|
+
import { parseEnv } from "node:util";
|
|
7
|
+
// src/core/files.ts
|
|
8
|
+
const isFile = (path) => Effect.sync(() => statSync(path, { throwIfNoEntry: false })?.isFile() ?? false);
|
|
9
|
+
/**
|
|
10
|
+
* The nearest directory at or above `directory` that has a `package.json`.
|
|
11
|
+
*/
|
|
12
|
+
const findProjectRoot = Effect.fn("findProjectRoot")(function* (directory) {
|
|
13
|
+
for (let current = directory;; current = dirname(current)) {
|
|
14
|
+
if (yield* isFile(join(current, "package.json"))) return current;
|
|
15
|
+
if (dirname(current) === current) return void 0;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* The first existing `name` in `directories`.
|
|
20
|
+
*/
|
|
21
|
+
const findFile = Effect.fn("findFile")(function* (directories, name) {
|
|
22
|
+
for (const directory of directories) {
|
|
23
|
+
const path = join(directory, name);
|
|
24
|
+
if (yield* isFile(path)) return path;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* The base file's directory followed by the project root when it is a different directory.
|
|
29
|
+
*/
|
|
30
|
+
const searchDirectories = Effect.fn("searchDirectories")(function* (baseFile) {
|
|
31
|
+
const directory = dirname(baseFile);
|
|
32
|
+
const root = yield* findProjectRoot(directory);
|
|
33
|
+
return root === void 0 || root === directory ? [directory] : [directory, root];
|
|
34
|
+
});
|
|
35
|
+
// src/core/env.ts
|
|
36
|
+
/**
|
|
37
|
+
* A copy of the real environment. This is the only place tyfigo reads `process.env`.
|
|
38
|
+
*/
|
|
39
|
+
const processEnv = () => ({ ...process.env });
|
|
40
|
+
const envFileNames = (environment) => environment ? [
|
|
41
|
+
".env",
|
|
42
|
+
".env.local",
|
|
43
|
+
`.env.${environment}`,
|
|
44
|
+
`.env.${environment}.local`
|
|
45
|
+
] : [".env", ".env.local"];
|
|
46
|
+
/**
|
|
47
|
+
* Reads `.env`, `.env.local`, `.env.<environment>` and `.env.<environment>.local` (each later one wins) and puts `env` on top.
|
|
48
|
+
* Each file is searched next to `baseFile` first, then in the nearest directory with a `package.json`. Never writes `process.env`.
|
|
49
|
+
*/
|
|
50
|
+
const readEnv = Effect.fn("readEnv")(function* (baseFile, options = {}) {
|
|
51
|
+
const directories = yield* searchDirectories(resolve(baseFile));
|
|
52
|
+
const variables = {};
|
|
53
|
+
const files = [];
|
|
54
|
+
const problems = [];
|
|
55
|
+
for (const name of envFileNames(options.environment)) {
|
|
56
|
+
const file = yield* findFile(directories, name);
|
|
57
|
+
if (!file) continue;
|
|
58
|
+
const parsed = yield* Effect.result(Effect.try({
|
|
59
|
+
try: () => parseEnv(readFileSync(file, "utf8")),
|
|
60
|
+
catch: (error) => fileProblem(file, "read-error", `Cannot read ${file}: ${error.message}`)
|
|
61
|
+
}));
|
|
62
|
+
if (Result.isFailure(parsed)) {
|
|
63
|
+
problems.push(parsed.failure);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
files.push(file);
|
|
67
|
+
Object.assign(variables, parsed.success);
|
|
68
|
+
}
|
|
69
|
+
for (const [key, value] of Object.entries(options.env ?? processEnv())) if (value !== void 0) variables[key] = value;
|
|
70
|
+
return {
|
|
71
|
+
variables,
|
|
72
|
+
files,
|
|
73
|
+
problems
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
export { findProjectRoot as a, findFile as i, processEnv as n, isFile as o, readEnv as r, searchDirectories as s, envFileNames as t };
|
|
77
|
+
|
|
78
|
+
//# sourceMappingURL=env-R3_XPW_u.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-R3_XPW_u.mjs","names":[],"sources":["../src/core/files.ts","../src/core/env.ts"],"sourcesContent":["import { statSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\nimport { Effect } from 'effect';\n\nexport const isFile = (path: string): Effect.Effect<boolean> =>\n\tEffect.sync(() => statSync(path, { throwIfNoEntry: false })?.isFile() ?? false);\n\n/**\n * The nearest directory at or above `directory` that has a `package.json`.\n */\nexport const findProjectRoot = Effect.fn('findProjectRoot')(function* (directory: string) {\n\tfor (let current = directory; ; current = dirname(current)) {\n\t\tif (yield* isFile(join(current, 'package.json'))) return current;\n\t\tif (dirname(current) === current) return undefined;\n\t}\n});\n\n/**\n * The first existing `name` in `directories`.\n */\nexport const findFile = Effect.fn('findFile')(function* (directories: readonly string[], name: string) {\n\tfor (const directory of directories) {\n\t\tconst path = join(directory, name);\n\t\tif (yield* isFile(path)) return path;\n\t}\n\treturn undefined;\n});\n\n/**\n * The base file's directory followed by the project root when it is a different directory.\n */\nexport const searchDirectories = Effect.fn('searchDirectories')(function* (baseFile: string) {\n\tconst directory = dirname(baseFile);\n\tconst root = yield* findProjectRoot(directory);\n\treturn root === undefined || root === directory ? [directory] : [directory, root];\n});\n","import { readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport process from 'node:process';\nimport { parseEnv } from 'node:util';\n\nimport { Effect, Result } from 'effect';\n\nimport { findFile, searchDirectories } from './files.ts';\nimport { fileProblem } from './problems.ts';\n\nimport type { Problem } from './problems.ts';\n\nexport type EnvVariables = Readonly<Record<string, string | undefined>>;\n\nexport interface EnvResult {\n\t/**\n\t * The `.env` values with the real environment on top.\n\t */\n\treadonly variables: EnvVariables;\n\t/**\n\t * The `.env` files that were read, in the order they apply.\n\t */\n\treadonly files: readonly string[];\n\treadonly problems: readonly Problem[];\n}\n\n/**\n * A copy of the real environment. This is the only place tyfigo reads `process.env`.\n */\nexport const processEnv = (): EnvVariables => ({ ...process.env });\n\nexport const envFileNames = (environment?: string): readonly string[] =>\n\tenvironment ? ['.env', '.env.local', `.env.${environment}`, `.env.${environment}.local`] : ['.env', '.env.local'];\n\n/**\n * Reads `.env`, `.env.local`, `.env.<environment>` and `.env.<environment>.local` (each later one wins) and puts `env` on top.\n * Each file is searched next to `baseFile` first, then in the nearest directory with a `package.json`. Never writes `process.env`.\n */\nexport const readEnv = Effect.fn('readEnv')(function* (\n\tbaseFile: string,\n\toptions: { readonly environment?: string | undefined; readonly env?: EnvVariables | undefined } = {},\n) {\n\tconst directories = yield* searchDirectories(resolve(baseFile));\n\tconst variables: Record<string, string | undefined> = {};\n\tconst files: string[] = [];\n\tconst problems: Problem[] = [];\n\tfor (const name of envFileNames(options.environment)) {\n\t\tconst file = yield* findFile(directories, name);\n\t\tif (!file) continue;\n\t\tconst parsed = yield* Effect.result(\n\t\t\tEffect.try({\n\t\t\t\ttry: () => parseEnv(readFileSync(file, 'utf8')),\n\t\t\t\tcatch: (error) => fileProblem(file, 'read-error', `Cannot read ${file}: ${(error as Error).message}`),\n\t\t\t}),\n\t\t);\n\t\tif (Result.isFailure(parsed)) {\n\t\t\tproblems.push(parsed.failure);\n\t\t\tcontinue;\n\t\t}\n\n\t\tfiles.push(file);\n\t\tObject.assign(variables, parsed.success);\n\t}\n\n\tfor (const [key, value] of Object.entries(options.env ?? processEnv())) {\n\t\tif (value !== undefined) variables[key] = value;\n\t}\n\treturn { variables, files, problems } satisfies EnvResult;\n});\n"],"mappings":";;;;;;;AAKA,MAAa,UAAU,SACtB,OAAO,WAAW,SAAS,MAAM,EAAE,gBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,KAAK,KAAK;;;;AAK/E,MAAa,kBAAkB,OAAO,GAAG,iBAAiB,CAAC,CAAC,WAAW,WAAmB;CACzF,KAAK,IAAI,UAAU,YAAa,UAAU,QAAQ,OAAO,GAAG;EAC3D,IAAI,OAAO,OAAO,KAAK,SAAS,cAAc,CAAC,GAAG,OAAO;EACzD,IAAI,QAAQ,OAAO,MAAM,SAAS,OAAO,KAAA;CAC1C;AACD,CAAC;;;;AAKD,MAAa,WAAW,OAAO,GAAG,UAAU,CAAC,CAAC,WAAW,aAAgC,MAAc;CACtG,KAAK,MAAM,aAAa,aAAa;EACpC,MAAM,OAAO,KAAK,WAAW,IAAI;EACjC,IAAI,OAAO,OAAO,IAAI,GAAG,OAAO;CACjC;AAED,CAAC;;;;AAKD,MAAa,oBAAoB,OAAO,GAAG,mBAAmB,CAAC,CAAC,WAAW,UAAkB;CAC5F,MAAM,YAAY,QAAQ,QAAQ;CAClC,MAAM,OAAO,OAAO,gBAAgB,SAAS;CAC7C,OAAO,SAAS,KAAA,KAAa,SAAS,YAAY,CAAC,SAAS,IAAI,CAAC,WAAW,IAAI;AACjF,CAAC;;;;;ACPD,MAAa,oBAAkC,EAAE,GAAG,QAAQ,IAAI;AAEhE,MAAa,gBAAgB,gBAC5B,cAAc;CAAC;CAAQ;CAAc,QAAQ;CAAe,QAAQ,YAAY;AAAO,IAAI,CAAC,QAAQ,YAAY;;;;;AAMjH,MAAa,UAAU,OAAO,GAAG,SAAS,CAAC,CAAC,WAC3C,UACA,UAAkG,CAAC,GAClG;CACD,MAAM,cAAc,OAAO,kBAAkB,QAAQ,QAAQ,CAAC;CAC9D,MAAM,YAAgD,CAAC;CACvD,MAAM,QAAkB,CAAC;CACzB,MAAM,WAAsB,CAAC;CAC7B,KAAK,MAAM,QAAQ,aAAa,QAAQ,WAAW,GAAG;EACrD,MAAM,OAAO,OAAO,SAAS,aAAa,IAAI;EAC9C,IAAI,CAAC,MAAM;EACX,MAAM,SAAS,OAAO,OAAO,OAC5B,OAAO,IAAI;GACV,WAAW,SAAS,aAAa,MAAM,MAAM,CAAC;GAC9C,QAAQ,UAAU,YAAY,MAAM,cAAc,eAAe,KAAK,IAAK,MAAgB,SAAS;EACrG,CAAC,CACF;EACA,IAAI,OAAO,UAAU,MAAM,GAAG;GAC7B,SAAS,KAAK,OAAO,OAAO;GAC5B;EACD;EAEA,MAAM,KAAK,IAAI;EACf,OAAO,OAAO,WAAW,OAAO,OAAO;CACxC;CAEA,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,OAAO,WAAW,CAAC,GACpE,IAAI,UAAU,KAAA,GAAW,UAAU,OAAO;CAE3C,OAAO;EAAE;EAAW;EAAO;CAAS;AACrC,CAAC"}
|