@nexusts/config 0.7.0 → 0.7.2
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 -2
- package/dist/config.module.d.ts +38 -0
- package/dist/config.service.d.ts +46 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +3 -3
- package/dist/index.js.map +3 -3
- package/dist/types.d.ts +77 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ This module is part of the NexusTS monorepo. Each module is published as its own
|
|
|
15
15
|
Most apps start with just the core:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
bun add @nexusts/core
|
|
18
|
+
bun add @nexusts/core
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
Then add this module only if you need it:
|
|
@@ -26,7 +26,7 @@ bun add @nexusts/config
|
|
|
26
26
|
|
|
27
27
|
## Peer dependencies
|
|
28
28
|
|
|
29
|
-
None.
|
|
29
|
+
**None.** No external dependencies. Zod is bundled with `@nexusts/core`.
|
|
30
30
|
|
|
31
31
|
## Usage
|
|
32
32
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ConfigModule` — drop-in module for typed, validated configuration.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* // src/config/schema.ts
|
|
6
|
+
* import { z } from 'zod';
|
|
7
|
+
* export const configSchema = z.object({
|
|
8
|
+
* DATABASE_URL: z.string().url(),
|
|
9
|
+
* PORT: z.coerce.number().default(3000),
|
|
10
|
+
* LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
|
|
11
|
+
* });
|
|
12
|
+
*
|
|
13
|
+
* // src/app/app.module.ts
|
|
14
|
+
* @Module({
|
|
15
|
+
* imports: [
|
|
16
|
+
* ConfigModule.forRoot({
|
|
17
|
+
* schema: configSchema,
|
|
18
|
+
* envFilePaths: ['.env.local', '.env'],
|
|
19
|
+
* }),
|
|
20
|
+
* ],
|
|
21
|
+
* })
|
|
22
|
+
* export class AppModule {}
|
|
23
|
+
*
|
|
24
|
+
* // any service
|
|
25
|
+
* class MyService {
|
|
26
|
+
* constructor(@Inject(ConfigService.TOKEN) private config: ConfigService<typeof configSchema>) {}
|
|
27
|
+
* connect() {
|
|
28
|
+
* return this.config.require('DATABASE_URL');
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
*/
|
|
32
|
+
import "reflect-metadata";
|
|
33
|
+
import type { ConfigOptions } from "./types.js";
|
|
34
|
+
export declare class ConfigModule {
|
|
35
|
+
static forRoot(options?: ConfigOptions): {
|
|
36
|
+
new (): {};
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ConfigService` — type-safe access to validated environment
|
|
3
|
+
* variables and configuration values.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* constructor(@Inject(ConfigService.TOKEN) private config: ConfigService<typeof schema>) {}
|
|
7
|
+
*
|
|
8
|
+
* const dbUrl = this.config.get('DATABASE_URL'); // string
|
|
9
|
+
* const port = this.config.get('PORT', { default: 3000 }); // number
|
|
10
|
+
*
|
|
11
|
+
* For full type inference, parameterize the class with your schema:
|
|
12
|
+
* class MyService {
|
|
13
|
+
* constructor(@Inject(ConfigService.TOKEN) private config: ConfigService<typeof schema>) {}
|
|
14
|
+
* }
|
|
15
|
+
*/
|
|
16
|
+
import type { ConfigSchema, InferConfig, ConfigOptions } from "./types.js";
|
|
17
|
+
export declare class ConfigService<S extends ConfigSchema = ConfigSchema> {
|
|
18
|
+
#private;
|
|
19
|
+
private readonly options;
|
|
20
|
+
/** DI token — use with `@Inject(ConfigService.TOKEN)`. */
|
|
21
|
+
static readonly TOKEN: unique symbol;
|
|
22
|
+
/** The validated, fully-typed config. */
|
|
23
|
+
readonly config: InferConfig<S>;
|
|
24
|
+
constructor(options?: ConfigOptions<S>);
|
|
25
|
+
/**
|
|
26
|
+
* Look up a config value by key. Type-safe when the class is
|
|
27
|
+
* parameterized with the schema (`ConfigService<typeof schema>`).
|
|
28
|
+
*/
|
|
29
|
+
get<K extends keyof InferConfig<S>>(key: K): InferConfig<S>[K];
|
|
30
|
+
get<K extends keyof InferConfig<S>>(key: K, options: {
|
|
31
|
+
default: InferConfig<S>[K];
|
|
32
|
+
}): InferConfig<S>[K];
|
|
33
|
+
get(key: string): unknown;
|
|
34
|
+
/**
|
|
35
|
+
* Look up a config value by key, throwing if it's missing.
|
|
36
|
+
* Convenience for required values.
|
|
37
|
+
*/
|
|
38
|
+
require<K extends keyof InferConfig<S>>(key: K): InferConfig<S>[K];
|
|
39
|
+
/**
|
|
40
|
+
* Read the raw env value (string), regardless of the schema.
|
|
41
|
+
* Useful for debugging.
|
|
42
|
+
*/
|
|
43
|
+
env(key: string): string | undefined;
|
|
44
|
+
/** Reload from env. Drops the cache. */
|
|
45
|
+
reload(): void;
|
|
46
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API for `nexusjs/config`.
|
|
3
|
+
*
|
|
4
|
+
* Quick start:
|
|
5
|
+
*
|
|
6
|
+
* // src/config/schema.ts
|
|
7
|
+
* import { z } from 'zod';
|
|
8
|
+
* export const configSchema = z.object({
|
|
9
|
+
* DATABASE_URL: z.string().url(),
|
|
10
|
+
* PORT: z.coerce.number().default(3000),
|
|
11
|
+
* });
|
|
12
|
+
*
|
|
13
|
+
* // src/app/app.module.ts
|
|
14
|
+
* import { Module } from 'nexusjs';
|
|
15
|
+
* import { ConfigModule } from 'nexusjs/config';
|
|
16
|
+
*
|
|
17
|
+
* @Module({
|
|
18
|
+
* imports: [
|
|
19
|
+
* ConfigModule.forRoot({
|
|
20
|
+
* schema: configSchema,
|
|
21
|
+
* }),
|
|
22
|
+
* ],
|
|
23
|
+
* })
|
|
24
|
+
* export class AppModule {}
|
|
25
|
+
*
|
|
26
|
+
* // any service
|
|
27
|
+
* import { ConfigService } from 'nexusjs/config';
|
|
28
|
+
*
|
|
29
|
+
* class MyService {
|
|
30
|
+
* constructor(
|
|
31
|
+
* @Inject(ConfigService.TOKEN)
|
|
32
|
+
* private config: ConfigService<typeof configSchema>,
|
|
33
|
+
* ) {}
|
|
34
|
+
* }
|
|
35
|
+
*/
|
|
36
|
+
export * from "./types.js";
|
|
37
|
+
export { ConfigService } from "./config.service.js";
|
|
38
|
+
export { ConfigModule } from "./config.module.js";
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ var __legacyMetadataTS = (k, v) => {
|
|
|
16
16
|
};
|
|
17
17
|
var __require = import.meta.require;
|
|
18
18
|
// packages/config/src/config.service.ts
|
|
19
|
-
import { Inject, Injectable } from "@nexusts/core
|
|
19
|
+
import { Inject, Injectable } from "@nexusts/core";
|
|
20
20
|
class ConfigService {
|
|
21
21
|
options;
|
|
22
22
|
static TOKEN = Symbol.for("nexus:ConfigService");
|
|
@@ -160,7 +160,7 @@ function readDotEnv(path) {
|
|
|
160
160
|
}
|
|
161
161
|
// packages/config/src/config.module.ts
|
|
162
162
|
import"reflect-metadata";
|
|
163
|
-
import { Module } from "@nexusts/core
|
|
163
|
+
import { Module } from "@nexusts/core";
|
|
164
164
|
class ConfigModule {
|
|
165
165
|
static forRoot(options = {}) {
|
|
166
166
|
class ConfiguredConfigModule {
|
|
@@ -195,5 +195,5 @@ export {
|
|
|
195
195
|
ConfigModule
|
|
196
196
|
};
|
|
197
197
|
|
|
198
|
-
//# debugId=
|
|
198
|
+
//# debugId=3A156CD1115D4F4B64756E2164756E21
|
|
199
199
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/config.service.ts", "../src/config.module.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * `ConfigService` — type-safe access to validated environment\n * variables and configuration values.\n *\n * Usage:\n * constructor(@Inject(ConfigService.TOKEN) private config: ConfigService<typeof schema>) {}\n *\n * const dbUrl = this.config.get('DATABASE_URL'); // string\n * const port = this.config.get('PORT', { default: 3000 }); // number\n *\n * For full type inference, parameterize the class with your schema:\n * class MyService {\n * constructor(@Inject(ConfigService.TOKEN) private config: ConfigService<typeof schema>) {}\n * }\n */\n\nimport { Inject, Injectable } from \"@nexusts/core
|
|
6
|
-
"/**\n * `ConfigModule` — drop-in module for typed, validated configuration.\n *\n * Usage:\n * // src/config/schema.ts\n * import { z } from 'zod';\n * export const configSchema = z.object({\n * DATABASE_URL: z.string().url(),\n * PORT: z.coerce.number().default(3000),\n * LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),\n * });\n *\n * // src/app/app.module.ts\n * @Module({\n * imports: [\n * ConfigModule.forRoot({\n * schema: configSchema,\n * envFilePaths: ['.env.local', '.env'],\n * }),\n * ],\n * })\n * export class AppModule {}\n *\n * // any service\n * class MyService {\n * constructor(@Inject(ConfigService.TOKEN) private config: ConfigService<typeof configSchema>) {}\n * connect() {\n * return this.config.require('DATABASE_URL');\n * }\n * }\n */\n\nimport \"reflect-metadata\";\nimport { Module } from \"@nexusts/core
|
|
5
|
+
"/**\n * `ConfigService` — type-safe access to validated environment\n * variables and configuration values.\n *\n * Usage:\n * constructor(@Inject(ConfigService.TOKEN) private config: ConfigService<typeof schema>) {}\n *\n * const dbUrl = this.config.get('DATABASE_URL'); // string\n * const port = this.config.get('PORT', { default: 3000 }); // number\n *\n * For full type inference, parameterize the class with your schema:\n * class MyService {\n * constructor(@Inject(ConfigService.TOKEN) private config: ConfigService<typeof schema>) {}\n * }\n */\n\nimport { Inject, Injectable } from \"@nexusts/core\";\nimport type {\n\tConfigSchema,\n\tInferConfig,\n\tConfigOptions,\n\tLoadedConfig,\n} from \"./types.js\";\n\n@Injectable()\nexport class ConfigService<S extends ConfigSchema = ConfigSchema> {\n\t/** DI token — use with `@Inject(ConfigService.TOKEN)`. */\n\tstatic readonly TOKEN = Symbol.for(\"nexus:ConfigService\");\n\n\t/** The validated, fully-typed config. */\n\treadonly config: InferConfig<S>;\n\n\t#raw: Record<string, string | undefined>;\n\t#cache = new Map<string, unknown>();\n\t#strict: boolean;\n\n\tconstructor(\n\t\t@Inject(\"CONFIG_OPTIONS\") private readonly options: ConfigOptions<S> = {},\n\t) {\n\t\tconst loaded = loadConfig(options);\n\t\tthis.config = loaded.value as InferConfig<S>;\n\t\tthis.#raw = loaded.raw;\n\t\tthis.#strict = options.strict ?? false;\n\n\t\tif (loaded.errors.length > 0) {\n\t\t\tconst msg =\n\t\t\t\t`[nexus/config] Configuration validation failed:\\n` +\n\t\t\t\tloaded.errors.map((e) => ` - ${e}`).join(\"\\n\");\n\t\t\tif (options.exitOnError) {\n\t\t\t\tconsole.error(msg);\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t\tthrow new Error(msg);\n\t\t}\n\t}\n\n\t/**\n\t * Look up a config value by key. Type-safe when the class is\n\t * parameterized with the schema (`ConfigService<typeof schema>`).\n\t */\n\tget<K extends keyof InferConfig<S>>(key: K): InferConfig<S>[K];\n\tget<K extends keyof InferConfig<S>>(\n\t\tkey: K,\n\t\toptions: { default: InferConfig<S>[K] },\n\t): InferConfig<S>[K];\n\tget(key: string): unknown;\n\tget(key: string, options?: { default?: unknown }): unknown {\n\t\tif (this.options.cache !== false && this.#cache.has(key)) {\n\t\t\treturn this.#cache.get(key);\n\t\t}\n\t\tconst fromConfig = (this.config as Record<string, unknown>)[key];\n\t\tif (fromConfig !== undefined) {\n\t\t\tif (this.options.cache !== false) this.#cache.set(key, fromConfig);\n\t\t\treturn fromConfig;\n\t\t}\n\t\tif (options && \"default\" in options) {\n\t\t\treturn options.default;\n\t\t}\n\t\tif (this.#strict) {\n\t\t\tthrow new Error(`[nexus/config] Unknown config key \"${key}\"`);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Look up a config value by key, throwing if it's missing.\n\t * Convenience for required values.\n\t */\n\trequire<K extends keyof InferConfig<S>>(key: K): InferConfig<S>[K] {\n\t\tconst v = this.get(key);\n\t\tif (v === undefined || v === null || v === \"\") {\n\t\t\tthrow new Error(`[nexus/config] Required config key \"${String(key)}\" is missing`);\n\t\t}\n\t\treturn v as InferConfig<S>[K];\n\t}\n\n\t/**\n\t * Read the raw env value (string), regardless of the schema.\n\t * Useful for debugging.\n\t */\n\tenv(key: string): string | undefined {\n\t\treturn this.#raw[key];\n\t}\n\n\t/** Reload from env. Drops the cache. */\n\treload(): void {\n\t\tthis.#cache.clear();\n\t\tconst loaded = loadConfig(this.options);\n\t\tObject.assign(this.config as object, loaded.value);\n\t\tthis.#raw = loaded.raw;\n\t}\n}\n\n/**\n * Internal: load + validate config.\n *\n * Order: static `load` overrides → `.env` files → `process.env`.\n * Env wins on conflict (most recent takes precedence).\n */\nfunction loadConfig<S extends ConfigSchema>(\n\toptions: ConfigOptions<S>,\n): LoadedConfig<S> {\n\t// 1) process.env as the base layer\n\tconst env: Record<string, string | undefined> = {};\n\tfor (const [k, v] of Object.entries(process.env)) {\n\t\tenv[k] = v;\n\t}\n\n\t// 2) .env files (overrides env defaults but env still wins)\n\tconst paths = options.envFilePaths ?? [];\n\n\t// When envFile is enabled (default), auto-load environment-specific files.\n\tconst useEnvFile = options.envFile !== false;\n\tif (useEnvFile) {\n\t\tconst nodeEnv = options.nodeEnv ?? process.env[\"NODE_ENV\"] ?? \"development\";\n\t\t// Base .env is always loaded first.\n\t\tif (!paths.includes(\".env\")) paths.unshift(\".env\");\n\t\t// .env.local — local overrides (should be .gitignored).\n\t\tif (!paths.includes(\".env.local\")) paths.push(\".env.local\");\n\t\t// .env.{NODE_ENV} — environment-specific (e.g. .env.production).\n\t\tconst envSpecific = `.env.${nodeEnv}`;\n\t\tif (!paths.includes(envSpecific)) paths.push(envSpecific);\n\t}\n\n\tfor (const p of paths) {\n\t\tconst file = readDotEnv(p);\n\t\tfor (const [k, v] of Object.entries(file)) {\n\t\t\tif (env[k] === undefined) env[k] = v;\n\t\t}\n\t}\n\n\t// 3) Static load() overrides\n\tconst merged: Record<string, unknown> = { ...env };\n\tif (options.load) {\n\t\tfor (const layer of options.load) {\n\t\t\tfor (const [k, v] of Object.entries(layer)) {\n\t\t\t\tif (!(k in env)) merged[k] = v;\n\t\t\t}\n\t\t}\n\t}\n\n\t// 4) Validate through Zod\n\tconst schema = options.schema;\n\tif (!schema) {\n\t\treturn { value: merged as InferConfig<S>, raw: env, errors: [] };\n\t}\n\tconst result = schema.safeParse(merged);\n\tif (result.success) {\n\t\treturn { value: result.data as InferConfig<S>, raw: env, errors: [] };\n\t}\n\tconst errors = result.error.issues.map(\n\t\t(i) => `${i.path.join(\".\") || \"(root)\"}: ${i.message}`,\n\t);\n\treturn { value: merged as InferConfig<S>, raw: env, errors };\n}\n\n/**\n * Minimal .env reader. Avoids a runtime dep on `dotenv`.\n * Supports `KEY=value` lines, comments, and quoted values.\n */\nfunction readDotEnv(path: string): Record<string, string> {\n\ttry {\n\t\t// Bun has Bun.file(); Node has node:fs. Use whichever is available.\n\t\t// eslint-disable-next-line @typescript-eslint/no-require-imports\n\t\tconst fs = require(\"node:fs\") as typeof import(\"node:fs\");\n\t\tif (!fs.existsSync(path)) return {};\n\t\tconst text = fs.readFileSync(path, \"utf8\");\n\t\tconst out: Record<string, string> = {};\n\t\tfor (const rawLine of text.split(/\\r?\\n/)) {\n\t\t\tconst line = rawLine.trim();\n\t\t\tif (!line || line.startsWith(\"#\")) continue;\n\t\t\tconst eq = line.indexOf(\"=\");\n\t\t\tif (eq < 0) continue;\n\t\t\tconst key = line.slice(0, eq).trim();\n\t\t\tlet value = line.slice(eq + 1).trim();\n\t\t\t// Strip inline comments after unquoted values.\n\t\t\tif (!value.startsWith('\"') && !value.startsWith(\"'\")) {\n\t\t\t\tconst hash = value.indexOf(\" #\");\n\t\t\t\tif (hash >= 0) value = value.slice(0, hash).trim();\n\t\t\t}\n\t\t\t// Strip surrounding quotes.\n\t\t\tif (\n\t\t\t\t(value.startsWith('\"') && value.endsWith('\"')) ||\n\t\t\t\t(value.startsWith(\"'\") && value.endsWith(\"'\"))\n\t\t\t) {\n\t\t\t\tvalue = value.slice(1, -1);\n\t\t\t}\n\t\t\tout[key] = value;\n\t\t}\n\t\treturn out;\n\t} catch {\n\t\treturn {};\n\t}\n}",
|
|
6
|
+
"/**\n * `ConfigModule` — drop-in module for typed, validated configuration.\n *\n * Usage:\n * // src/config/schema.ts\n * import { z } from 'zod';\n * export const configSchema = z.object({\n * DATABASE_URL: z.string().url(),\n * PORT: z.coerce.number().default(3000),\n * LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),\n * });\n *\n * // src/app/app.module.ts\n * @Module({\n * imports: [\n * ConfigModule.forRoot({\n * schema: configSchema,\n * envFilePaths: ['.env.local', '.env'],\n * }),\n * ],\n * })\n * export class AppModule {}\n *\n * // any service\n * class MyService {\n * constructor(@Inject(ConfigService.TOKEN) private config: ConfigService<typeof configSchema>) {}\n * connect() {\n * return this.config.require('DATABASE_URL');\n * }\n * }\n */\n\nimport \"reflect-metadata\";\nimport { Module } from \"@nexusts/core\";\nimport { ConfigService } from \"./config.service.js\";\nimport type { ConfigOptions } from \"./types.js\";\n\n@Module({\n\tproviders: [\n\t\tConfigService,\n\t\t{ provide: ConfigService.TOKEN, useExisting: ConfigService },\n\t],\n\texports: [ConfigService, ConfigService.TOKEN],\n})\nexport class ConfigModule {\n\tstatic forRoot(options: ConfigOptions = {}) {\n\t\t@Module({\n\t\t\tproviders: [\n\t\t\t\tConfigService,\n\t\t\t\t{ provide: ConfigService.TOKEN, useExisting: ConfigService },\n\t\t\t\t{ provide: \"CONFIG_OPTIONS\", useValue: options },\n\t\t\t],\n\t\t\texports: [ConfigService, ConfigService.TOKEN],\n\t\t})\n\t\tclass ConfiguredConfigModule {}\n\n\t\tObject.defineProperty(ConfiguredConfigModule, \"name\", {\n\t\t\tvalue: \"ConfiguredConfigModule\",\n\t\t});\n\n\t\treturn ConfiguredConfigModule;\n\t}\n}\n"
|
|
7
7
|
],
|
|
8
8
|
"mappings": "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",
|
|
9
|
-
"debugId": "
|
|
9
|
+
"debugId": "3A156CD1115D4F4B64756E2164756E21",
|
|
10
10
|
"names": []
|
|
11
11
|
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config types — the contract for `nexusjs/config`.
|
|
3
|
+
*
|
|
4
|
+
* Configuration is loaded from environment variables (and optionally
|
|
5
|
+
* `.env` files) and validated against a Zod schema at boot. Typed
|
|
6
|
+
* access via `ConfigService.get('KEY')`.
|
|
7
|
+
*
|
|
8
|
+
* Mirrors `@nestjs/config` + `@adonisjs/config` but adds Zod-driven
|
|
9
|
+
* validation and full type inference.
|
|
10
|
+
*/
|
|
11
|
+
import type { ZodTypeAny, z } from "zod";
|
|
12
|
+
/** A config schema. Use Zod's `z.object({...})`. */
|
|
13
|
+
export type ConfigSchema = ZodTypeAny;
|
|
14
|
+
/** Inferred TypeScript type from a schema. */
|
|
15
|
+
export type InferConfig<S extends ConfigSchema> = z.infer<S>;
|
|
16
|
+
/**
|
|
17
|
+
* Optional `ConfigModule.forRoot` arguments.
|
|
18
|
+
*
|
|
19
|
+
* The schema is the source of truth: every env var the app reads
|
|
20
|
+
* must be declared in the schema, or `config.get()` won't know about it.
|
|
21
|
+
*/
|
|
22
|
+
export interface ConfigOptions<S extends ConfigSchema = ConfigSchema> {
|
|
23
|
+
/** Zod schema describing the expected config. */
|
|
24
|
+
schema?: S;
|
|
25
|
+
/**
|
|
26
|
+
* Additional config to merge in (e.g. from a static file). Values
|
|
27
|
+
* here are merged with env vars; env vars win on conflict.
|
|
28
|
+
*/
|
|
29
|
+
load?: Array<Record<string, unknown>>;
|
|
30
|
+
/**
|
|
31
|
+
* Path(s) to dotenv files to load. Default: `['.env']`. Pass `[]` to
|
|
32
|
+
* disable file loading.
|
|
33
|
+
*/
|
|
34
|
+
envFilePaths?: string[];
|
|
35
|
+
/**
|
|
36
|
+
* Enable environment-aware loading (`.env.development`, `.env.production`,
|
|
37
|
+
* `.env.testing`). When enabled, the service auto-loads:
|
|
38
|
+
* 1. `.env` — shared defaults
|
|
39
|
+
* 2. `.env.local` — local overrides (add to `.gitignore`)
|
|
40
|
+
* 3. `.env.{NODE_ENV}` — environment-specific (e.g. `.env.development`)
|
|
41
|
+
*
|
|
42
|
+
* `process.env` always takes precedence over all file sources.
|
|
43
|
+
* Default: `true`.
|
|
44
|
+
*/
|
|
45
|
+
envFile?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Override the detected `NODE_ENV`. Useful when the env var name
|
|
48
|
+
* differs (e.g. `APP_ENV`, `ENVIRONMENT`). Default: read from
|
|
49
|
+
* `process.env.NODE_ENV` and fall back to `"development"`.
|
|
50
|
+
*/
|
|
51
|
+
nodeEnv?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Whether to cache the parsed config. Default: `true`. Set `false`
|
|
54
|
+
* in tests so each `get()` re-reads the env.
|
|
55
|
+
*/
|
|
56
|
+
cache?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Whether to call `process.exit(1)` on schema validation failure.
|
|
59
|
+
* Default: `false` (throw instead). Production should set `true`
|
|
60
|
+
* so a misconfigured deploy fails fast.
|
|
61
|
+
*/
|
|
62
|
+
exitOnError?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Whether to expand missing keys to `undefined` (default) or throw.
|
|
65
|
+
* Default: `false` (return undefined for unknown keys).
|
|
66
|
+
*/
|
|
67
|
+
strict?: boolean;
|
|
68
|
+
}
|
|
69
|
+
/** Result of loading + validating config. */
|
|
70
|
+
export interface LoadedConfig<S extends ConfigSchema> {
|
|
71
|
+
/** The parsed, fully-typed config object. */
|
|
72
|
+
value: InferConfig<S>;
|
|
73
|
+
/** Raw env object (for debugging). */
|
|
74
|
+
raw: Record<string, string | undefined>;
|
|
75
|
+
/** Validation errors (if any). Empty on success. */
|
|
76
|
+
errors: string[];
|
|
77
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nexusts/config",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Zod-validated configuration with layered loading",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -26,6 +26,6 @@
|
|
|
26
26
|
],
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@nexusts/core": "^0.7.
|
|
29
|
+
"@nexusts/core": "^0.7.2"
|
|
30
30
|
}
|
|
31
31
|
}
|