zod-conf 1.0.2 → 1.1.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/LICENSE +1 -1
- package/README.md +60 -18
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/values/define.d.ts +10 -65
- package/dist/values/define.d.ts.map +1 -1
- package/dist/values/define.js +67 -121
- package/dist/values/define.js.map +1 -1
- package/dist/values/env-metadata.js +1 -2
- package/dist/values/env.d.ts +0 -29
- package/dist/values/env.d.ts.map +1 -1
- package/dist/values/env.js +1 -37
- package/dist/values/object.d.ts +0 -30
- package/dist/values/object.d.ts.map +1 -1
- package/dist/values/object.js +1 -30
- package/package.json +16 -16
- package/dist/index.test.d.ts +0 -2
- package/dist/index.test.d.ts.map +0 -1
- package/dist/index.test.js +0 -372
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@ Not affiliated with the official Zod library.
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
9
|
- **Type-safe** - Full TypeScript support with Zod schema validation
|
|
10
|
+
- **Multi-source** - Load from env vars, config files (e.g. YAML), or any plain object
|
|
10
11
|
- **Env-first** - Bind schema fields directly to environment variables
|
|
11
12
|
- **Simple API** - Intuitive, Zod-native API that feels familiar
|
|
12
13
|
- **Zero compromise** - All Zod features work - transformations, refinements, and more
|
|
@@ -52,13 +53,13 @@ console.log(config);
|
|
|
52
53
|
const schema = zc.define({
|
|
53
54
|
// string
|
|
54
55
|
apiUrl: zc.env('API_URL').string(),
|
|
55
|
-
|
|
56
|
-
// number
|
|
56
|
+
|
|
57
|
+
// number
|
|
57
58
|
port: zc.env('PORT').number(),
|
|
58
|
-
|
|
59
|
+
|
|
59
60
|
// boolean
|
|
60
61
|
isProduction: zc.env('NODE_ENV').boolean(),
|
|
61
|
-
|
|
62
|
+
|
|
62
63
|
// enum
|
|
63
64
|
logLevel: zc.env('LOG_LEVEL').enum(['debug', 'info', 'warn', 'error']),
|
|
64
65
|
});
|
|
@@ -70,10 +71,10 @@ const schema = zc.define({
|
|
|
70
71
|
const schema = zc.define({
|
|
71
72
|
// with default value
|
|
72
73
|
port: zc.env('PORT').number().default(3000),
|
|
73
|
-
|
|
74
|
+
|
|
74
75
|
// optional field
|
|
75
76
|
apiKey: zc.env('API_KEY').string().optional(),
|
|
76
|
-
|
|
77
|
+
|
|
77
78
|
// nullable field
|
|
78
79
|
proxyUrl: zc.env('PROXY_URL').string().nullable(),
|
|
79
80
|
});
|
|
@@ -133,6 +134,45 @@ const config = schema.load({
|
|
|
133
134
|
});
|
|
134
135
|
```
|
|
135
136
|
|
|
137
|
+
### Multiple Configuration Sources
|
|
138
|
+
|
|
139
|
+
You can load from multiple sources. Loaders are processed left-to-right; later loaders override earlier ones.
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
import { parse } from 'yaml';
|
|
143
|
+
import { readFileSync } from 'fs';
|
|
144
|
+
|
|
145
|
+
const yamlConfig = parse(readFileSync('config.yml', 'utf8'));
|
|
146
|
+
|
|
147
|
+
// yaml values are used as base, env vars override
|
|
148
|
+
const config = schema.load({ values: yamlConfig }, { env: process.env });
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
You can also layer multiple objects for defaults:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
const defaults = { port: 3000, host: 'localhost' };
|
|
155
|
+
const yamlConfig = parse(readFileSync('config.yml', 'utf8'));
|
|
156
|
+
|
|
157
|
+
const config = schema.load({ values: defaults }, { values: yamlConfig }, { env: process.env });
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
The `values` loader maps values by property name and passes them directly to Zod — no string coercion is needed since YAML/JSON already preserves types. This also means you can use types that env vars can't represent, like arrays:
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
import { z } from 'zod';
|
|
164
|
+
|
|
165
|
+
const schema = zc.define({
|
|
166
|
+
host: zc.env('HOST').string().default('localhost'),
|
|
167
|
+
port: zc.env('PORT').number().default(3000),
|
|
168
|
+
allowedOrigins: z.array(z.string()),
|
|
169
|
+
servers: z.array(z.object({ host: z.string(), port: z.number() })),
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// arrays come from yaml, scalar fields can be overridden by env
|
|
173
|
+
const config = schema.load({ values: yamlConfig }, { env: process.env });
|
|
174
|
+
```
|
|
175
|
+
|
|
136
176
|
### Error Handling
|
|
137
177
|
|
|
138
178
|
The error-handling is similar to Zod's standard behavior:
|
|
@@ -160,14 +200,16 @@ All Zod transformations work seamlessly:
|
|
|
160
200
|
|
|
161
201
|
```typescript
|
|
162
202
|
const schema = zc.define({
|
|
163
|
-
port: zc
|
|
203
|
+
port: zc
|
|
204
|
+
.env('PORT')
|
|
164
205
|
.number()
|
|
165
206
|
.default(3000)
|
|
166
|
-
.transform(p => Math.max(1024, p)), // Ensure port is at least 1024
|
|
167
|
-
|
|
168
|
-
apiUrl: zc
|
|
207
|
+
.transform((p) => Math.max(1024, p)), // Ensure port is at least 1024
|
|
208
|
+
|
|
209
|
+
apiUrl: zc
|
|
210
|
+
.env('API_URL')
|
|
169
211
|
.string()
|
|
170
|
-
.transform(url => url.replace(/\/$/, '')), // Remove trailing slash
|
|
212
|
+
.transform((url) => url.replace(/\/$/, '')), // Remove trailing slash
|
|
171
213
|
});
|
|
172
214
|
```
|
|
173
215
|
|
|
@@ -198,22 +240,22 @@ Creates a nested object schema.
|
|
|
198
240
|
- **shape**: An object where values are `zc.env()` or nested `zc.object()` calls
|
|
199
241
|
- **returns**: A Zod object schema
|
|
200
242
|
|
|
201
|
-
### `schema.load(
|
|
243
|
+
### `schema.load(...loaders)`
|
|
202
244
|
|
|
203
|
-
Loads and validates configuration.
|
|
245
|
+
Loads and validates configuration from one or more loaders.
|
|
204
246
|
|
|
205
|
-
- **
|
|
247
|
+
- **loaders**: One or more loader objects, processed left-to-right (later overrides earlier)
|
|
248
|
+
- `{ env: Record<string, string | undefined> }` - Load from environment variables
|
|
249
|
+
- `{ values: Record<string, unknown> }` - Load from a plain object (e.g. parsed YAML/JSON)
|
|
206
250
|
- **returns**: Validated configuration object
|
|
207
251
|
- **throws**: ZodError if validation fails
|
|
208
252
|
|
|
209
|
-
### `schema.safeLoad(
|
|
253
|
+
### `schema.safeLoad(...loaders)`
|
|
210
254
|
|
|
211
|
-
Safely loads configuration without throwing.
|
|
255
|
+
Safely loads configuration without throwing. Same loader arguments as `load()`.
|
|
212
256
|
|
|
213
|
-
- **params.env**: Environment variables object
|
|
214
257
|
- **returns**: `{ success: true, data: T }` or `{ success: false, error: ZodError }`
|
|
215
258
|
|
|
216
259
|
## License
|
|
217
260
|
|
|
218
261
|
MIT
|
|
219
|
-
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { boolean, number, string, enum as zenum } from 'zod';
|
|
2
|
-
export { ZodConfSchema } from './values/define.js';
|
|
2
|
+
export { ZodConfSchema, type Loader, type EnvLoader, type ValuesLoader } from './values/define.js';
|
|
3
3
|
export declare const zc: {
|
|
4
4
|
define: <T extends import("zod").ZodRawShape>(shape: T) => import("./values/define.js").ZodConfSchema<T>;
|
|
5
5
|
env: (key: string) => {
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,IAAI,KAAK,EAAE,MAAM,KAAK,CAAC;AAK7D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,IAAI,KAAK,EAAE,MAAM,KAAK,CAAC;AAK7D,OAAO,EAAE,aAAa,EAAE,KAAK,MAAM,EAAE,KAAK,SAAS,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEnG,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;CAWd,CAAC;AAEF,eAAe,EAAE,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,14 +4,13 @@ import { env } from './values/env.js';
|
|
|
4
4
|
import { object } from './values/object.js';
|
|
5
5
|
export { ZodConfSchema } from './values/define.js';
|
|
6
6
|
export const zc = {
|
|
7
|
-
// core values
|
|
8
7
|
define,
|
|
9
8
|
env,
|
|
10
9
|
object,
|
|
11
|
-
// re-export common zod values for convenience
|
|
12
10
|
string,
|
|
13
11
|
boolean,
|
|
14
12
|
number,
|
|
15
13
|
enum: zenum,
|
|
16
14
|
};
|
|
17
15
|
export default zc;
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,IAAI,KAAK,EAAE,MAAM,KAAK,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,IAAI,KAAK,EAAE,MAAM,KAAK,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,EAAE,aAAa,EAAkD,MAAM,oBAAoB,CAAC;AAEnG,MAAM,CAAC,MAAM,EAAE,GAAG;IAEhB,MAAM;IACN,GAAG;IACH,MAAM;IAGN,MAAM;IACN,OAAO;IACP,MAAM;IACN,IAAI,EAAE,KAAK;CACZ,CAAC;AAEF,eAAe,EAAE,CAAC"}
|
package/dist/values/define.d.ts
CHANGED
|
@@ -1,78 +1,23 @@
|
|
|
1
1
|
import { ZodObject, type ZodRawShape, type infer as ZodInfer } from 'zod';
|
|
2
2
|
type Env = Record<string, string | undefined>;
|
|
3
|
-
export type
|
|
3
|
+
export type EnvLoader = {
|
|
4
4
|
env: Env;
|
|
5
|
+
values?: never | undefined;
|
|
5
6
|
};
|
|
7
|
+
export type ValuesLoader = {
|
|
8
|
+
values: Record<string, unknown>;
|
|
9
|
+
env?: never | undefined;
|
|
10
|
+
};
|
|
11
|
+
export type Loader = EnvLoader | ValuesLoader;
|
|
6
12
|
export declare class ZodConfSchema<T extends ZodRawShape> {
|
|
7
13
|
private shape;
|
|
8
14
|
private schema;
|
|
9
15
|
constructor(shape: T, schema: ZodObject<T>);
|
|
16
|
+
private resolveEnvValue;
|
|
10
17
|
private loadValue;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
* Throws a ZodError if validation fails.
|
|
14
|
-
*
|
|
15
|
-
* @param input - Object containing environment variables
|
|
16
|
-
* @param input.env - Environment variables as key-value pairs
|
|
17
|
-
* @returns Validated configuration object
|
|
18
|
-
* @throws {ZodError} If validation fails
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* ```typescript
|
|
22
|
-
* const config = schema.load({ env: process.env });
|
|
23
|
-
* ```
|
|
24
|
-
*/
|
|
25
|
-
load(input: LoadParams): ZodInfer<ZodObject<T>>;
|
|
26
|
-
/**
|
|
27
|
-
* Safely loads and validates configuration without throwing.
|
|
28
|
-
* Returns a result object with either success or error.
|
|
29
|
-
*
|
|
30
|
-
* @param input - Object containing environment variables
|
|
31
|
-
* @param input.env - Environment variables as key-value pairs
|
|
32
|
-
* @returns SafeParseReturnType with either { success: true, data } or { success: false, error }
|
|
33
|
-
*
|
|
34
|
-
* @example
|
|
35
|
-
* ```typescript
|
|
36
|
-
* const result = schema.safeLoad({ env: process.env });
|
|
37
|
-
*
|
|
38
|
-
* if (result.success) {
|
|
39
|
-
* console.log('Config:', result.data);
|
|
40
|
-
* } else {
|
|
41
|
-
* console.error('Errors:', result.error.issues);
|
|
42
|
-
* }
|
|
43
|
-
* ```
|
|
44
|
-
*/
|
|
45
|
-
safeLoad(input: LoadParams): import("zod").ZodSafeParseResult<import("zod/v4/core").$InferObjectOutput<T, {}>>;
|
|
18
|
+
load(...loaders: [Loader, ...Loader[]]): ZodInfer<ZodObject<T>>;
|
|
19
|
+
safeLoad(...loaders: [Loader, ...Loader[]]): import("zod").ZodSafeParseResult<import("zod/v4/core").$InferObjectOutput<T, {}>>;
|
|
46
20
|
}
|
|
47
|
-
/**
|
|
48
|
-
* Creates a configuration schema with environment variable bindings.
|
|
49
|
-
*
|
|
50
|
-
* @param shape - An object defining the configuration structure where each field
|
|
51
|
-
* uses `env()` to bind to environment variables or `object()` for nesting
|
|
52
|
-
* @returns A ZodConfSchema instance with `load()` and `safeLoad()` methods
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
* ```typescript
|
|
56
|
-
* // define a configuration schema
|
|
57
|
-
* const schema = define({
|
|
58
|
-
* port: env('PORT').number().default(3000),
|
|
59
|
-
* host: env('HOST').string().default('localhost'),
|
|
60
|
-
* database: object({
|
|
61
|
-
* url: env('DATABASE_URL').string(),
|
|
62
|
-
* poolSize: env('DB_POOL_SIZE').number().default(10),
|
|
63
|
-
* }),
|
|
64
|
-
* });
|
|
65
|
-
*
|
|
66
|
-
* // load configuration from environment
|
|
67
|
-
* const config = schema.load({ env: process.env });
|
|
68
|
-
*
|
|
69
|
-
* // safe load without throwing
|
|
70
|
-
* const result = schema.safeLoad({ env: process.env });
|
|
71
|
-
* if (result.success) {
|
|
72
|
-
* console.log(result.data);
|
|
73
|
-
* }
|
|
74
|
-
* ```
|
|
75
|
-
*/
|
|
76
21
|
export declare const define: <T extends ZodRawShape>(shape: T) => ZodConfSchema<T>;
|
|
77
22
|
export {};
|
|
78
23
|
//# sourceMappingURL=define.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/values/define.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAU,KAAK,WAAW,EAAgB,KAAK,KAAK,IAAI,QAAQ,EAAE,MAAM,KAAK,CAAC;AAGhG,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE9C,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/values/define.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAU,KAAK,WAAW,EAAgB,KAAK,KAAK,IAAI,QAAQ,EAAE,MAAM,KAAK,CAAC;AAGhG,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE9C,MAAM,MAAM,SAAS,GAAG;IAAE,GAAG,EAAE,GAAG,CAAC;IAAC,MAAM,CAAC,EAAE,KAAK,GAAG,SAAS,CAAA;CAAE,CAAC;AACjE,MAAM,MAAM,YAAY,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,GAAG,CAAC,EAAE,KAAK,GAAG,SAAS,CAAA;CAAE,CAAC;AACxF,MAAM,MAAM,MAAM,GAAG,SAAS,GAAG,YAAY,CAAC;AAE9C,qBAAa,aAAa,CAAC,CAAC,SAAS,WAAW;IAE5C,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,MAAM;gBADN,KAAK,EAAE,CAAC,EACR,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IAG9B,OAAO,CAAC,eAAe;IA2DvB,OAAO,CAAC,SAAS;IA6DjB,IAAI,CAAC,GAAG,OAAO,EAAE,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IA8B/D,QAAQ,CAAC,GAAG,OAAO,EAAE,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;CAK3C;AA4BD,eAAO,MAAM,MAAM,GAAI,CAAC,SAAS,WAAW,EAAE,OAAO,CAAC,KAAG,aAAa,CAAC,CAAC,CAEvE,CAAC"}
|
package/dist/values/define.js
CHANGED
|
@@ -7,150 +7,96 @@ export class ZodConfSchema {
|
|
|
7
7
|
this.shape = shape;
|
|
8
8
|
this.schema = schema;
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
resolveEnvValue(schema, env) {
|
|
11
|
+
let currentSchema = schema;
|
|
12
|
+
let envKey;
|
|
13
|
+
let envType;
|
|
14
|
+
while (currentSchema && !envKey) {
|
|
15
|
+
const metadata = _envMetadata.get(currentSchema);
|
|
16
|
+
if (metadata) {
|
|
17
|
+
envKey = metadata.key;
|
|
18
|
+
envType = metadata.type;
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
const def = currentSchema._def;
|
|
22
|
+
if (def?.innerType) {
|
|
23
|
+
currentSchema = def.innerType;
|
|
24
|
+
}
|
|
25
|
+
else if (def?.schema) {
|
|
26
|
+
currentSchema = def.schema;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (!envKey) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
const value = env[envKey];
|
|
36
|
+
switch (envType) {
|
|
37
|
+
case 'string':
|
|
38
|
+
return value;
|
|
39
|
+
case 'number':
|
|
40
|
+
return value ? Number(value) : undefined;
|
|
41
|
+
case 'boolean':
|
|
42
|
+
return value === 'true' ? true : value === 'false' ? false : undefined;
|
|
43
|
+
case 'enum': {
|
|
44
|
+
const numValue = Number(value);
|
|
45
|
+
if (value && !isNaN(numValue) && Number.isInteger(numValue)) {
|
|
46
|
+
return numValue;
|
|
47
|
+
}
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
default:
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
loadValue(shape, loaders) {
|
|
11
55
|
const input = {};
|
|
12
56
|
for (const key in shape) {
|
|
13
57
|
const schema = shape[key];
|
|
14
58
|
if (schema instanceof ZodObject) {
|
|
15
|
-
|
|
16
|
-
|
|
59
|
+
const subLoaders = loaders.map((loader) => {
|
|
60
|
+
if ('values' in loader && loader.values) {
|
|
61
|
+
const nested = loader.values[key];
|
|
62
|
+
return { values: nested && typeof nested === 'object' ? nested : {} };
|
|
63
|
+
}
|
|
64
|
+
return loader;
|
|
65
|
+
});
|
|
66
|
+
input[key] = this.loadValue(schema.shape, subLoaders);
|
|
17
67
|
}
|
|
18
68
|
else {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if (metadata) {
|
|
26
|
-
// found metadata -> use it
|
|
27
|
-
envKey = metadata.key;
|
|
28
|
-
envType = metadata.type;
|
|
29
|
-
break;
|
|
30
|
-
}
|
|
31
|
-
// check if this is a wrapped schema (default, optional, etc.)
|
|
32
|
-
const def = currentSchema._def;
|
|
33
|
-
if (def?.innerType) {
|
|
34
|
-
// zod wrappers like optional, default, nullable, etc.
|
|
35
|
-
currentSchema = def.innerType;
|
|
36
|
-
}
|
|
37
|
-
else if (def?.schema) {
|
|
38
|
-
// zod effects
|
|
39
|
-
currentSchema = def.schema;
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
// end of the chain, no metadata found
|
|
43
|
-
break;
|
|
69
|
+
for (const loader of loaders) {
|
|
70
|
+
if ('values' in loader && loader.values) {
|
|
71
|
+
const value = loader.values[key];
|
|
72
|
+
if (value !== undefined) {
|
|
73
|
+
input[key] = value;
|
|
74
|
+
}
|
|
44
75
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
switch (envType) {
|
|
49
|
-
case 'string':
|
|
76
|
+
else if ('env' in loader && loader.env) {
|
|
77
|
+
const value = this.resolveEnvValue(schema, loader.env);
|
|
78
|
+
if (value !== undefined) {
|
|
50
79
|
input[key] = value;
|
|
51
|
-
break;
|
|
52
|
-
case 'number':
|
|
53
|
-
input[key] = value ? Number(value) : undefined;
|
|
54
|
-
break;
|
|
55
|
-
case 'boolean':
|
|
56
|
-
input[key] = value === 'true' ? true : value === 'false' ? false : undefined;
|
|
57
|
-
break;
|
|
58
|
-
case 'enum': {
|
|
59
|
-
const numValue = Number(value);
|
|
60
|
-
// guess if enum is number-based
|
|
61
|
-
if (value && !isNaN(numValue) && Number.isInteger(numValue)) {
|
|
62
|
-
input[key] = numValue;
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
input[key] = value;
|
|
66
|
-
}
|
|
67
|
-
break;
|
|
68
80
|
}
|
|
69
|
-
default:
|
|
70
|
-
input[key] = undefined;
|
|
71
81
|
}
|
|
72
82
|
}
|
|
73
|
-
else {
|
|
74
|
-
input[key] = undefined;
|
|
75
|
-
}
|
|
76
83
|
}
|
|
77
84
|
}
|
|
78
85
|
return input;
|
|
79
86
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
* Throws a ZodError if validation fails.
|
|
83
|
-
*
|
|
84
|
-
* @param input - Object containing environment variables
|
|
85
|
-
* @param input.env - Environment variables as key-value pairs
|
|
86
|
-
* @returns Validated configuration object
|
|
87
|
-
* @throws {ZodError} If validation fails
|
|
88
|
-
*
|
|
89
|
-
* @example
|
|
90
|
-
* ```typescript
|
|
91
|
-
* const config = schema.load({ env: process.env });
|
|
92
|
-
* ```
|
|
93
|
-
*/
|
|
94
|
-
load(input) {
|
|
95
|
-
const result = this.safeLoad(input);
|
|
87
|
+
load(...loaders) {
|
|
88
|
+
const result = this.safeLoad(...loaders);
|
|
96
89
|
if (!result.success) {
|
|
97
90
|
throw result.error;
|
|
98
91
|
}
|
|
99
92
|
return result.data;
|
|
100
93
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
* Returns a result object with either success or error.
|
|
104
|
-
*
|
|
105
|
-
* @param input - Object containing environment variables
|
|
106
|
-
* @param input.env - Environment variables as key-value pairs
|
|
107
|
-
* @returns SafeParseReturnType with either { success: true, data } or { success: false, error }
|
|
108
|
-
*
|
|
109
|
-
* @example
|
|
110
|
-
* ```typescript
|
|
111
|
-
* const result = schema.safeLoad({ env: process.env });
|
|
112
|
-
*
|
|
113
|
-
* if (result.success) {
|
|
114
|
-
* console.log('Config:', result.data);
|
|
115
|
-
* } else {
|
|
116
|
-
* console.error('Errors:', result.error.issues);
|
|
117
|
-
* }
|
|
118
|
-
* ```
|
|
119
|
-
*/
|
|
120
|
-
safeLoad(input) {
|
|
121
|
-
const value = this.loadValue(this.shape, input.env);
|
|
94
|
+
safeLoad(...loaders) {
|
|
95
|
+
const value = this.loadValue(this.shape, loaders);
|
|
122
96
|
return this.schema.safeParse(value);
|
|
123
97
|
}
|
|
124
98
|
}
|
|
125
|
-
/**
|
|
126
|
-
* Creates a configuration schema with environment variable bindings.
|
|
127
|
-
*
|
|
128
|
-
* @param shape - An object defining the configuration structure where each field
|
|
129
|
-
* uses `env()` to bind to environment variables or `object()` for nesting
|
|
130
|
-
* @returns A ZodConfSchema instance with `load()` and `safeLoad()` methods
|
|
131
|
-
*
|
|
132
|
-
* @example
|
|
133
|
-
* ```typescript
|
|
134
|
-
* // define a configuration schema
|
|
135
|
-
* const schema = define({
|
|
136
|
-
* port: env('PORT').number().default(3000),
|
|
137
|
-
* host: env('HOST').string().default('localhost'),
|
|
138
|
-
* database: object({
|
|
139
|
-
* url: env('DATABASE_URL').string(),
|
|
140
|
-
* poolSize: env('DB_POOL_SIZE').number().default(10),
|
|
141
|
-
* }),
|
|
142
|
-
* });
|
|
143
|
-
*
|
|
144
|
-
* // load configuration from environment
|
|
145
|
-
* const config = schema.load({ env: process.env });
|
|
146
|
-
*
|
|
147
|
-
* // safe load without throwing
|
|
148
|
-
* const result = schema.safeLoad({ env: process.env });
|
|
149
|
-
* if (result.success) {
|
|
150
|
-
* console.log(result.data);
|
|
151
|
-
* }
|
|
152
|
-
* ```
|
|
153
|
-
*/
|
|
154
99
|
export const define = (shape) => {
|
|
155
100
|
return new ZodConfSchema(shape, object(shape));
|
|
156
101
|
};
|
|
102
|
+
//# sourceMappingURL=define.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define.js","sourceRoot":"","sources":["../../src/values/define.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAA0D,MAAM,KAAK,CAAC;AAChG,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAQjD,MAAM,OAAO,aAAa;IAEd;IACA;IAFV,YACU,KAAQ,EACR,MAAoB;QADpB,UAAK,GAAL,KAAK,CAAG;QACR,WAAM,GAAN,MAAM,CAAc;IAC3B,CAAC;IAEI,
|
|
1
|
+
{"version":3,"file":"define.js","sourceRoot":"","sources":["../../src/values/define.ts"],"names":[],"mappings":"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"}
|
package/dist/values/env.d.ts
CHANGED
|
@@ -1,34 +1,5 @@
|
|
|
1
1
|
import { type util, type ZodEnum } from 'zod';
|
|
2
2
|
import { coerce } from 'zod';
|
|
3
|
-
/**
|
|
4
|
-
* Binds a Zod schema to an environment variable.
|
|
5
|
-
*
|
|
6
|
-
* @param key - The name of the environment variable to bind to
|
|
7
|
-
* @returns An object with methods to create different types of schemas:
|
|
8
|
-
* - `string()` - Creates a string schema
|
|
9
|
-
* - `number()` - Creates a number schema (auto-coerced from string)
|
|
10
|
-
* - `boolean()` - Creates a boolean schema (accepts 'true'/'false')
|
|
11
|
-
* - `enum(values)` - Creates an enum schema (string array or TypeScript enum)
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```typescript
|
|
15
|
-
* // string environment variable
|
|
16
|
-
* const apiUrl = env('API_URL').string();
|
|
17
|
-
*
|
|
18
|
-
* // number with default
|
|
19
|
-
* const port = env('PORT').number().default(3000);
|
|
20
|
-
*
|
|
21
|
-
* // boolean
|
|
22
|
-
* const debug = env('DEBUG').boolean().default(false);
|
|
23
|
-
*
|
|
24
|
-
* // enum with string array
|
|
25
|
-
* const logLevel = env('LOG_LEVEL').enum(['info', 'debug', 'error']);
|
|
26
|
-
*
|
|
27
|
-
* // enum with TypeScript enum
|
|
28
|
-
* enum Level { INFO = 'info', DEBUG = 'debug' }
|
|
29
|
-
* const level = env('LOG_LEVEL').enum(Level);
|
|
30
|
-
* ```
|
|
31
|
-
*/
|
|
32
3
|
export declare const env: (key: string) => {
|
|
33
4
|
string: () => import("zod").ZodString;
|
|
34
5
|
number: () => coerce.ZodCoercedNumber<unknown>;
|
package/dist/values/env.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/values/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,OAAO,EAAgB,MAAM,KAAK,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAyB,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/values/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,OAAO,EAAgB,MAAM,KAAK,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAyB,MAAM,KAAK,CAAC;AAgCpD,eAAO,MAAM,GAAG,GAAI,KAAK,MAAM;;;;;eA2CC,CAAC,SAAS,SAAS,MAAM,EAAE,UAAU,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;eAExE,CAAC,6DAA4B,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;;CAS1E,CAAC"}
|
package/dist/values/env.js
CHANGED
|
@@ -1,58 +1,22 @@
|
|
|
1
1
|
import { coerce, string, enum as zenum } from 'zod';
|
|
2
2
|
import { _envMetadata } from './env-metadata.js';
|
|
3
|
-
/**
|
|
4
|
-
* Binds a Zod schema to an environment variable.
|
|
5
|
-
*
|
|
6
|
-
* @param key - The name of the environment variable to bind to
|
|
7
|
-
* @returns An object with methods to create different types of schemas:
|
|
8
|
-
* - `string()` - Creates a string schema
|
|
9
|
-
* - `number()` - Creates a number schema (auto-coerced from string)
|
|
10
|
-
* - `boolean()` - Creates a boolean schema (accepts 'true'/'false')
|
|
11
|
-
* - `enum(values)` - Creates an enum schema (string array or TypeScript enum)
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```typescript
|
|
15
|
-
* // string environment variable
|
|
16
|
-
* const apiUrl = env('API_URL').string();
|
|
17
|
-
*
|
|
18
|
-
* // number with default
|
|
19
|
-
* const port = env('PORT').number().default(3000);
|
|
20
|
-
*
|
|
21
|
-
* // boolean
|
|
22
|
-
* const debug = env('DEBUG').boolean().default(false);
|
|
23
|
-
*
|
|
24
|
-
* // enum with string array
|
|
25
|
-
* const logLevel = env('LOG_LEVEL').enum(['info', 'debug', 'error']);
|
|
26
|
-
*
|
|
27
|
-
* // enum with TypeScript enum
|
|
28
|
-
* enum Level { INFO = 'info', DEBUG = 'debug' }
|
|
29
|
-
* const level = env('LOG_LEVEL').enum(Level);
|
|
30
|
-
* ```
|
|
31
|
-
*/
|
|
32
3
|
export const env = (key) => {
|
|
33
4
|
const wrap = (schema, envKey, envType) => {
|
|
34
|
-
// create a proxy to preserve metadata through method chaining
|
|
35
5
|
const proxied = new Proxy(schema, {
|
|
36
6
|
get(target, prop) {
|
|
37
7
|
const value = target[prop];
|
|
38
|
-
// if it's a method, wrap the result to preserve metadata
|
|
39
|
-
// e.g. .default(), .optional(), etc.
|
|
40
8
|
if (typeof value === 'function') {
|
|
41
9
|
return (...args) => {
|
|
42
|
-
// call original method
|
|
43
10
|
const result = value.apply(target, args);
|
|
44
11
|
if (result && typeof result === 'object' && result._def) {
|
|
45
|
-
// if result is a new chained Zod schema, wrap it in a new proxy
|
|
46
12
|
return wrap(result, envKey, envType);
|
|
47
13
|
}
|
|
48
14
|
return result;
|
|
49
15
|
};
|
|
50
16
|
}
|
|
51
|
-
// regular property, just return it
|
|
52
17
|
return value;
|
|
53
18
|
},
|
|
54
19
|
});
|
|
55
|
-
// remember metadata for the proxied object
|
|
56
20
|
_envMetadata.set(proxied, { key: envKey, type: envType });
|
|
57
21
|
return proxied;
|
|
58
22
|
};
|
|
@@ -61,7 +25,6 @@ export const env = (key) => {
|
|
|
61
25
|
number: () => wrap(coerce.number(), key, 'number'),
|
|
62
26
|
boolean: () => wrap(coerce.boolean(), key, 'boolean'),
|
|
63
27
|
enum: (() => {
|
|
64
|
-
// implementation
|
|
65
28
|
function enumMethod(values) {
|
|
66
29
|
return wrap(zenum(values), key, 'enum');
|
|
67
30
|
}
|
|
@@ -69,3 +32,4 @@ export const env = (key) => {
|
|
|
69
32
|
})(),
|
|
70
33
|
};
|
|
71
34
|
};
|
|
35
|
+
//# sourceMappingURL=env.js.map
|
package/dist/values/object.d.ts
CHANGED
|
@@ -1,34 +1,4 @@
|
|
|
1
1
|
import { type ZodObject } from 'zod';
|
|
2
2
|
import { type ZodRawShape } from 'zod';
|
|
3
|
-
/**
|
|
4
|
-
* Creates a nested object schema for grouping related configuration.
|
|
5
|
-
* This is a convenience wrapper around Zod's object() for consistency.
|
|
6
|
-
*
|
|
7
|
-
* @param shape - An object where values are environment bindings or nested objects
|
|
8
|
-
* @returns A Zod object schema
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```typescript
|
|
12
|
-
* const schema = define({
|
|
13
|
-
* // group related configuration
|
|
14
|
-
* server: object({
|
|
15
|
-
* host: env('SERVER_HOST').string().default('localhost'),
|
|
16
|
-
* port: env('SERVER_PORT').number().default(3000),
|
|
17
|
-
* }),
|
|
18
|
-
*
|
|
19
|
-
* // nested objects
|
|
20
|
-
* database: object({
|
|
21
|
-
* connection: object({
|
|
22
|
-
* url: env('DATABASE_URL').string(),
|
|
23
|
-
* timeout: env('DB_TIMEOUT').number().default(5000),
|
|
24
|
-
* }),
|
|
25
|
-
* pool: object({
|
|
26
|
-
* min: env('DB_POOL_MIN').number().default(1),
|
|
27
|
-
* max: env('DB_POOL_MAX').number().default(10),
|
|
28
|
-
* }),
|
|
29
|
-
* }),
|
|
30
|
-
* });
|
|
31
|
-
* ```
|
|
32
|
-
*/
|
|
33
3
|
export declare const object: <T extends ZodRawShape>(shape: T) => ZodObject<T>;
|
|
34
4
|
//# sourceMappingURL=object.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../../src/values/object.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,CAAC;AACrC,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../../src/values/object.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,CAAC;AACrC,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,KAAK,CAAC;AAiCvC,eAAO,MAAM,MAAM,GAAI,CAAC,SAAS,WAAW,EAAE,OAAO,CAAC,KAAG,SAAS,CAAC,CAAC,CAEnE,CAAC"}
|
package/dist/values/object.js
CHANGED
|
@@ -1,34 +1,5 @@
|
|
|
1
1
|
import { object as zobject } from 'zod';
|
|
2
|
-
/**
|
|
3
|
-
* Creates a nested object schema for grouping related configuration.
|
|
4
|
-
* This is a convenience wrapper around Zod's object() for consistency.
|
|
5
|
-
*
|
|
6
|
-
* @param shape - An object where values are environment bindings or nested objects
|
|
7
|
-
* @returns A Zod object schema
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```typescript
|
|
11
|
-
* const schema = define({
|
|
12
|
-
* // group related configuration
|
|
13
|
-
* server: object({
|
|
14
|
-
* host: env('SERVER_HOST').string().default('localhost'),
|
|
15
|
-
* port: env('SERVER_PORT').number().default(3000),
|
|
16
|
-
* }),
|
|
17
|
-
*
|
|
18
|
-
* // nested objects
|
|
19
|
-
* database: object({
|
|
20
|
-
* connection: object({
|
|
21
|
-
* url: env('DATABASE_URL').string(),
|
|
22
|
-
* timeout: env('DB_TIMEOUT').number().default(5000),
|
|
23
|
-
* }),
|
|
24
|
-
* pool: object({
|
|
25
|
-
* min: env('DB_POOL_MIN').number().default(1),
|
|
26
|
-
* max: env('DB_POOL_MAX').number().default(10),
|
|
27
|
-
* }),
|
|
28
|
-
* }),
|
|
29
|
-
* });
|
|
30
|
-
* ```
|
|
31
|
-
*/
|
|
32
2
|
export const object = (shape) => {
|
|
33
3
|
return zobject(shape);
|
|
34
4
|
};
|
|
5
|
+
//# sourceMappingURL=object.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zod-conf",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Type-safe configuration management with Zod schemas and environment variables",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "smnbbrv",
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
"clean": "rm -rf dist",
|
|
43
43
|
"prebuild": "npm run clean",
|
|
44
44
|
"prepublishOnly": "npm run build && npm run test && npm run lint",
|
|
45
|
-
"
|
|
46
|
-
"lint
|
|
47
|
-
"
|
|
45
|
+
"validate": "run-s lint typecheck test",
|
|
46
|
+
"lint": "eslint . --report-unused-disable-directives --max-warnings 0",
|
|
47
|
+
"typecheck": "tsc",
|
|
48
48
|
"test": "npx tsx --test --experimental-test-coverage src/index.test.ts",
|
|
49
49
|
"prepare": "husky",
|
|
50
50
|
"semantic-release": "semantic-release"
|
|
@@ -57,24 +57,24 @@
|
|
|
57
57
|
"zod": "^4.0.0"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
|
-
"@commitlint/cli": "^
|
|
61
|
-
"@commitlint/config-conventional": "^
|
|
60
|
+
"@commitlint/cli": "^20.4.1",
|
|
61
|
+
"@commitlint/config-conventional": "^20.4.1",
|
|
62
62
|
"@semantic-release/changelog": "^6.0.3",
|
|
63
63
|
"@semantic-release/git": "^10.0.1",
|
|
64
|
-
"@types/node": "^
|
|
65
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
66
|
-
"dotenv": "^17.2.
|
|
67
|
-
"eslint": "^9.
|
|
64
|
+
"@types/node": "^25.2.0",
|
|
65
|
+
"@typescript-eslint/eslint-plugin": "^8.54.0",
|
|
66
|
+
"dotenv": "^17.2.3",
|
|
67
|
+
"eslint": "^9.39.2",
|
|
68
68
|
"eslint-config-prettier": "^10.1.8",
|
|
69
69
|
"eslint-import-resolver-typescript": "^4.4.4",
|
|
70
70
|
"eslint-plugin-import": "^2.32.0",
|
|
71
|
-
"eslint-plugin-prettier": "^5.5.
|
|
71
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
72
72
|
"husky": "^9.1.7",
|
|
73
73
|
"npm-run-all": "^4.1.5",
|
|
74
|
-
"semantic-release": "^
|
|
75
|
-
"tsx": "^4.
|
|
76
|
-
"typescript": "^5.9.
|
|
77
|
-
"typescript-eslint": "^8.
|
|
78
|
-
"zod": "^4.
|
|
74
|
+
"semantic-release": "^25.0.3",
|
|
75
|
+
"tsx": "^4.21.0",
|
|
76
|
+
"typescript": "^5.9.3",
|
|
77
|
+
"typescript-eslint": "^8.54.0",
|
|
78
|
+
"zod": "^4.3.6"
|
|
79
79
|
}
|
|
80
80
|
}
|
package/dist/index.test.d.ts
DELETED
package/dist/index.test.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
|
package/dist/index.test.js
DELETED
|
@@ -1,372 +0,0 @@
|
|
|
1
|
-
import { strictEqual, deepStrictEqual } from 'node:assert';
|
|
2
|
-
import { test } from 'node:test';
|
|
3
|
-
import zc from './index.js';
|
|
4
|
-
test('zod-conf configuration parsing', async (t) => {
|
|
5
|
-
await t.test('parses string environment variables', () => {
|
|
6
|
-
const schema = zc.define({
|
|
7
|
-
apiUrl: zc.env('API_URL').string(),
|
|
8
|
-
});
|
|
9
|
-
const config = schema.load({
|
|
10
|
-
env: { API_URL: 'https://api.example.com' },
|
|
11
|
-
});
|
|
12
|
-
strictEqual(config.apiUrl, 'https://api.example.com');
|
|
13
|
-
});
|
|
14
|
-
await t.test('parses number environment variables', () => {
|
|
15
|
-
const schema = zc.define({
|
|
16
|
-
port: zc.env('PORT').number(),
|
|
17
|
-
});
|
|
18
|
-
const config = schema.load({
|
|
19
|
-
env: { PORT: '3000' },
|
|
20
|
-
});
|
|
21
|
-
strictEqual(config.port, 3000);
|
|
22
|
-
});
|
|
23
|
-
await t.test('parses boolean environment variables', () => {
|
|
24
|
-
const schema = zc.define({
|
|
25
|
-
debug: zc.env('DEBUG').boolean(),
|
|
26
|
-
verbose: zc.env('VERBOSE').boolean(),
|
|
27
|
-
});
|
|
28
|
-
const config = schema.load({
|
|
29
|
-
env: { DEBUG: 'true', VERBOSE: 'false' },
|
|
30
|
-
});
|
|
31
|
-
strictEqual(config.debug, true);
|
|
32
|
-
strictEqual(config.verbose, false);
|
|
33
|
-
});
|
|
34
|
-
await t.test('parses enum environment variables with string array', () => {
|
|
35
|
-
const schema = zc.define({
|
|
36
|
-
logLevel: zc.env('LOG_LEVEL').enum(['info', 'debug', 'error']),
|
|
37
|
-
});
|
|
38
|
-
const config = schema.load({
|
|
39
|
-
env: { LOG_LEVEL: 'debug' },
|
|
40
|
-
});
|
|
41
|
-
strictEqual(config.logLevel, 'debug');
|
|
42
|
-
});
|
|
43
|
-
await t.test('parses enum environment variables with string enum', () => {
|
|
44
|
-
let LogLevel;
|
|
45
|
-
(function (LogLevel) {
|
|
46
|
-
LogLevel["INFO"] = "info";
|
|
47
|
-
LogLevel["DEBUG"] = "debug";
|
|
48
|
-
LogLevel["ERROR"] = "error";
|
|
49
|
-
})(LogLevel || (LogLevel = {}));
|
|
50
|
-
const schema = zc.define({
|
|
51
|
-
logLevel: zc.env('LOG_LEVEL').enum(LogLevel),
|
|
52
|
-
});
|
|
53
|
-
const config = schema.load({
|
|
54
|
-
env: { LOG_LEVEL: 'info' },
|
|
55
|
-
});
|
|
56
|
-
strictEqual(config.logLevel, 'info');
|
|
57
|
-
});
|
|
58
|
-
await t.test('parses enum environment variables with numeric enum', () => {
|
|
59
|
-
let Priority;
|
|
60
|
-
(function (Priority) {
|
|
61
|
-
Priority[Priority["LOW"] = 1] = "LOW";
|
|
62
|
-
Priority[Priority["MEDIUM"] = 2] = "MEDIUM";
|
|
63
|
-
Priority[Priority["HIGH"] = 3] = "HIGH";
|
|
64
|
-
Priority[Priority["URGENT"] = 4] = "URGENT";
|
|
65
|
-
})(Priority || (Priority = {}));
|
|
66
|
-
const schema = zc.define({
|
|
67
|
-
priority: zc.env('PRIORITY').enum(Priority),
|
|
68
|
-
});
|
|
69
|
-
const config = schema.load({
|
|
70
|
-
env: { PRIORITY: '3' },
|
|
71
|
-
});
|
|
72
|
-
strictEqual(config.priority, 3);
|
|
73
|
-
});
|
|
74
|
-
await t.test('parses enum environment variables with mixed enum', () => {
|
|
75
|
-
let Status;
|
|
76
|
-
(function (Status) {
|
|
77
|
-
Status[Status["INACTIVE"] = 0] = "INACTIVE";
|
|
78
|
-
Status[Status["ACTIVE"] = 1] = "ACTIVE";
|
|
79
|
-
Status["PENDING"] = "pending";
|
|
80
|
-
Status["ARCHIVED"] = "archived";
|
|
81
|
-
})(Status || (Status = {}));
|
|
82
|
-
const schema = zc.define({
|
|
83
|
-
statusNum: zc.env('STATUS_NUM').enum(Status),
|
|
84
|
-
statusStr: zc.env('STATUS_STR').enum(Status),
|
|
85
|
-
});
|
|
86
|
-
const config = schema.load({
|
|
87
|
-
env: {
|
|
88
|
-
STATUS_NUM: '1',
|
|
89
|
-
STATUS_STR: 'pending',
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
strictEqual(config.statusNum, 1);
|
|
93
|
-
strictEqual(config.statusStr, 'pending');
|
|
94
|
-
});
|
|
95
|
-
await t.test('handles default values', () => {
|
|
96
|
-
const schema = zc.define({
|
|
97
|
-
host: zc.env('HOST').string().default('localhost'),
|
|
98
|
-
port: zc.env('PORT').number().default(8080),
|
|
99
|
-
secure: zc.env('SECURE').boolean().default(false),
|
|
100
|
-
});
|
|
101
|
-
const config = schema.load({
|
|
102
|
-
env: {},
|
|
103
|
-
});
|
|
104
|
-
strictEqual(config.host, 'localhost');
|
|
105
|
-
strictEqual(config.port, 8080);
|
|
106
|
-
strictEqual(config.secure, false);
|
|
107
|
-
});
|
|
108
|
-
await t.test('handles optional values', () => {
|
|
109
|
-
const schema = zc.define({
|
|
110
|
-
optionalKey: zc.env('OPTIONAL_KEY').string().optional(),
|
|
111
|
-
});
|
|
112
|
-
const config = schema.load({
|
|
113
|
-
env: {},
|
|
114
|
-
});
|
|
115
|
-
strictEqual(config.optionalKey, undefined);
|
|
116
|
-
});
|
|
117
|
-
await t.test('handles nested objects', () => {
|
|
118
|
-
const schema = zc.define({
|
|
119
|
-
server: zc.object({
|
|
120
|
-
host: zc.env('SERVER_HOST').string().default('localhost'),
|
|
121
|
-
port: zc.env('SERVER_PORT').number().default(3000),
|
|
122
|
-
}),
|
|
123
|
-
database: zc.object({
|
|
124
|
-
url: zc.env('DB_URL').string(),
|
|
125
|
-
pool: zc.object({
|
|
126
|
-
min: zc.env('DB_POOL_MIN').number().default(1),
|
|
127
|
-
max: zc.env('DB_POOL_MAX').number().default(10),
|
|
128
|
-
}),
|
|
129
|
-
}),
|
|
130
|
-
});
|
|
131
|
-
const config = schema.load({
|
|
132
|
-
env: {
|
|
133
|
-
SERVER_HOST: '0.0.0.0',
|
|
134
|
-
SERVER_PORT: '4000',
|
|
135
|
-
DB_URL: 'postgres://localhost/mydb',
|
|
136
|
-
DB_POOL_MAX: '20',
|
|
137
|
-
},
|
|
138
|
-
});
|
|
139
|
-
deepStrictEqual(config, {
|
|
140
|
-
server: {
|
|
141
|
-
host: '0.0.0.0',
|
|
142
|
-
port: 4000,
|
|
143
|
-
},
|
|
144
|
-
database: {
|
|
145
|
-
url: 'postgres://localhost/mydb',
|
|
146
|
-
pool: {
|
|
147
|
-
min: 1,
|
|
148
|
-
max: 20,
|
|
149
|
-
},
|
|
150
|
-
},
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
await t.test('handles complex configuration', () => {
|
|
154
|
-
const schema = zc.define({
|
|
155
|
-
app: zc.object({
|
|
156
|
-
name: zc.env('APP_NAME').string().default('MyApp'),
|
|
157
|
-
version: zc.env('APP_VERSION').string().default('1.0.0'),
|
|
158
|
-
debug: zc.env('DEBUG').boolean().default(false),
|
|
159
|
-
}),
|
|
160
|
-
server: zc.object({
|
|
161
|
-
host: zc.env('HOST').string().default('localhost'),
|
|
162
|
-
port: zc.env('PORT').number().default(3000),
|
|
163
|
-
ssl: zc.object({
|
|
164
|
-
enabled: zc.env('SSL_ENABLED').boolean().default(false),
|
|
165
|
-
cert: zc.env('SSL_CERT').string().optional(),
|
|
166
|
-
key: zc.env('SSL_KEY').string().optional(),
|
|
167
|
-
}),
|
|
168
|
-
}),
|
|
169
|
-
features: zc.object({
|
|
170
|
-
auth: zc.env('FEATURE_AUTH').boolean().default(true),
|
|
171
|
-
analytics: zc.env('FEATURE_ANALYTICS').boolean().default(false),
|
|
172
|
-
}),
|
|
173
|
-
});
|
|
174
|
-
const config = schema.load({
|
|
175
|
-
env: {
|
|
176
|
-
APP_NAME: 'TestApp',
|
|
177
|
-
DEBUG: 'true',
|
|
178
|
-
PORT: '5000',
|
|
179
|
-
SSL_ENABLED: 'true',
|
|
180
|
-
SSL_CERT: '/path/to/cert.pem',
|
|
181
|
-
SSL_KEY: '/path/to/key.pem',
|
|
182
|
-
FEATURE_ANALYTICS: 'true',
|
|
183
|
-
},
|
|
184
|
-
});
|
|
185
|
-
deepStrictEqual(config, {
|
|
186
|
-
app: {
|
|
187
|
-
name: 'TestApp',
|
|
188
|
-
version: '1.0.0',
|
|
189
|
-
debug: true,
|
|
190
|
-
},
|
|
191
|
-
server: {
|
|
192
|
-
host: 'localhost',
|
|
193
|
-
port: 5000,
|
|
194
|
-
ssl: {
|
|
195
|
-
enabled: true,
|
|
196
|
-
cert: '/path/to/cert.pem',
|
|
197
|
-
key: '/path/to/key.pem',
|
|
198
|
-
},
|
|
199
|
-
},
|
|
200
|
-
features: {
|
|
201
|
-
auth: true,
|
|
202
|
-
analytics: true,
|
|
203
|
-
},
|
|
204
|
-
});
|
|
205
|
-
});
|
|
206
|
-
await t.test('safeLoad returns success for valid config', () => {
|
|
207
|
-
const schema = zc.define({
|
|
208
|
-
apiKey: zc.env('API_KEY').string(),
|
|
209
|
-
});
|
|
210
|
-
const result = schema.safeLoad({
|
|
211
|
-
env: { API_KEY: 'secret-key' },
|
|
212
|
-
});
|
|
213
|
-
strictEqual(result.success, true);
|
|
214
|
-
if (result.success) {
|
|
215
|
-
strictEqual(result.data.apiKey, 'secret-key');
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
await t.test('safeLoad returns error for invalid config', () => {
|
|
219
|
-
const schema = zc.define({
|
|
220
|
-
port: zc.env('PORT').number(),
|
|
221
|
-
});
|
|
222
|
-
const result = schema.safeLoad({
|
|
223
|
-
env: { PORT: 'not-a-number' },
|
|
224
|
-
});
|
|
225
|
-
strictEqual(result.success, false);
|
|
226
|
-
if (!result.success) {
|
|
227
|
-
strictEqual(result.error.issues.length > 0, true);
|
|
228
|
-
}
|
|
229
|
-
});
|
|
230
|
-
await t.test('handles fields without env metadata', () => {
|
|
231
|
-
const schema = zc.define({
|
|
232
|
-
// this field has no env binding, just a plain zod schema
|
|
233
|
-
plainField: zc.object({
|
|
234
|
-
nestedPlain: zc.env('SHOULD_WORK').string().default('default'),
|
|
235
|
-
}),
|
|
236
|
-
});
|
|
237
|
-
const config = schema.load({
|
|
238
|
-
env: {},
|
|
239
|
-
});
|
|
240
|
-
deepStrictEqual(config, {
|
|
241
|
-
plainField: {
|
|
242
|
-
nestedPlain: 'default',
|
|
243
|
-
},
|
|
244
|
-
});
|
|
245
|
-
});
|
|
246
|
-
await t.test('load throws error for invalid config', () => {
|
|
247
|
-
const schema = zc.define({
|
|
248
|
-
requiredField: zc.env('REQUIRED').string(),
|
|
249
|
-
});
|
|
250
|
-
let error;
|
|
251
|
-
try {
|
|
252
|
-
schema.load({
|
|
253
|
-
env: {},
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
catch (e) {
|
|
257
|
-
error = e;
|
|
258
|
-
}
|
|
259
|
-
strictEqual(error !== undefined, true);
|
|
260
|
-
strictEqual(error.issues !== undefined, true);
|
|
261
|
-
});
|
|
262
|
-
await t.test('handles enum with non-integer number strings', () => {
|
|
263
|
-
const schema = zc.define({
|
|
264
|
-
value: zc.env('VALUE').enum(['a', 'b', 'c']),
|
|
265
|
-
});
|
|
266
|
-
const config = schema.load({
|
|
267
|
-
env: { VALUE: 'a' },
|
|
268
|
-
});
|
|
269
|
-
strictEqual(config.value, 'a');
|
|
270
|
-
});
|
|
271
|
-
await t.test('handles enum with decimal number string', () => {
|
|
272
|
-
const schema = zc.define({
|
|
273
|
-
value: zc.env('DECIMAL_VALUE').enum(['3.14', 'pi', 'e']),
|
|
274
|
-
});
|
|
275
|
-
// this should pass the string through since "3.14" is not an integer
|
|
276
|
-
const config = schema.load({
|
|
277
|
-
env: { DECIMAL_VALUE: '3.14' },
|
|
278
|
-
});
|
|
279
|
-
strictEqual(config.value, '3.14');
|
|
280
|
-
});
|
|
281
|
-
await t.test('handles undefined env values for enum', () => {
|
|
282
|
-
const schema = zc.define({
|
|
283
|
-
optionalEnum: zc.env('OPT_ENUM').enum(['a', 'b']).optional(),
|
|
284
|
-
});
|
|
285
|
-
const config = schema.load({
|
|
286
|
-
env: {},
|
|
287
|
-
});
|
|
288
|
-
strictEqual(config.optionalEnum, undefined);
|
|
289
|
-
});
|
|
290
|
-
await t.test('handles schema without innerType or schema properties', () => {
|
|
291
|
-
// this tests the branch where we break out of the while loop
|
|
292
|
-
const schema = zc.define({
|
|
293
|
-
value: zc.env('VALUE').string(),
|
|
294
|
-
});
|
|
295
|
-
const config = schema.load({
|
|
296
|
-
env: { VALUE: 'test' },
|
|
297
|
-
});
|
|
298
|
-
strictEqual(config.value, 'test');
|
|
299
|
-
});
|
|
300
|
-
await t.test('handles deeply wrapped schemas with transformations', () => {
|
|
301
|
-
const schema = zc.define({
|
|
302
|
-
transformed: zc
|
|
303
|
-
.env('TRANSFORMED')
|
|
304
|
-
.string()
|
|
305
|
-
.optional()
|
|
306
|
-
.default('default')
|
|
307
|
-
.transform((v) => v.toUpperCase()),
|
|
308
|
-
});
|
|
309
|
-
const config = schema.load({
|
|
310
|
-
env: {},
|
|
311
|
-
});
|
|
312
|
-
strictEqual(config.transformed, 'DEFAULT');
|
|
313
|
-
});
|
|
314
|
-
await t.test('handles schema with no env metadata at all', async () => {
|
|
315
|
-
// create a plain zod schema without env bindings
|
|
316
|
-
const z = await import('zod');
|
|
317
|
-
const plainSchema = z.object({
|
|
318
|
-
plainField: z.string().default('plain'),
|
|
319
|
-
});
|
|
320
|
-
// mix it with env-bound fields
|
|
321
|
-
const schema = zc.define({
|
|
322
|
-
envField: zc.env('ENV_FIELD').string().default('env'),
|
|
323
|
-
plainNested: plainSchema.shape.plainField,
|
|
324
|
-
});
|
|
325
|
-
const config = schema.load({
|
|
326
|
-
env: {},
|
|
327
|
-
});
|
|
328
|
-
strictEqual(config.envField, 'env');
|
|
329
|
-
// plain fields without env binding will still use their Zod defaults
|
|
330
|
-
strictEqual(config.plainNested, 'plain');
|
|
331
|
-
});
|
|
332
|
-
await t.test('env proxy preserves non-schema properties and methods', async () => {
|
|
333
|
-
const envSchema = zc.env('TEST').string();
|
|
334
|
-
// test that metadata is stored in WeakMap (we can't directly access it from here)
|
|
335
|
-
// but we can verify the schema works correctly
|
|
336
|
-
const schema = zc.define({
|
|
337
|
-
test: envSchema,
|
|
338
|
-
});
|
|
339
|
-
const config = schema.load({ env: { TEST: 'value' } });
|
|
340
|
-
strictEqual(config.test, 'value');
|
|
341
|
-
// call methods that don't return schemas
|
|
342
|
-
const parsed = envSchema.parse('test');
|
|
343
|
-
strictEqual(parsed, 'test');
|
|
344
|
-
// access description property
|
|
345
|
-
const withDesc = zc.env('DESC').string().describe('A test field');
|
|
346
|
-
strictEqual(withDesc.description, 'A test field');
|
|
347
|
-
// test safeParse which returns a result object, not a schema
|
|
348
|
-
const result = zc.env('SAFE').number().safeParse('123');
|
|
349
|
-
strictEqual(result.success, true);
|
|
350
|
-
if (result.success) {
|
|
351
|
-
strictEqual(result.data, 123);
|
|
352
|
-
}
|
|
353
|
-
});
|
|
354
|
-
await t.test('env proxy handles methods returning non-objects', () => {
|
|
355
|
-
const schema = zc.env('TEST').string();
|
|
356
|
-
// test parse method returns the parsed value (not a schema)
|
|
357
|
-
const parsed = schema.parse('test');
|
|
358
|
-
strictEqual(parsed, 'test');
|
|
359
|
-
// test safeParse returns a result object (not a schema)
|
|
360
|
-
const result = schema.safeParse('value');
|
|
361
|
-
strictEqual(result.success, true);
|
|
362
|
-
if (result.success) {
|
|
363
|
-
strictEqual(result.data, 'value');
|
|
364
|
-
}
|
|
365
|
-
// test that optional() and nullable() still work (these are NOT deprecated)
|
|
366
|
-
const optionalSchema = schema.optional();
|
|
367
|
-
const nullableSchema = schema.nullable();
|
|
368
|
-
// verify they can parse undefined/null respectively
|
|
369
|
-
strictEqual(optionalSchema.parse(undefined), undefined);
|
|
370
|
-
strictEqual(nullableSchema.parse(null), null);
|
|
371
|
-
});
|
|
372
|
-
});
|