28 KiB
28 KiB
@suaveplan/env - Type-safe environment variable loading: schema-first validation, field types, dotenv loader, presets, structured errors.
Summary
Type-safe, schema-first environment variable loading for Node.js and edge runtimes. Define a schema of typed field builders, point it at your sources, and receive a frozen record with TypeScript types inferred at compile time — no manual type annotations required.
Documentation tree
- create-env — (no submodules)
- create-env — (no submodules)
- field — (no submodules)
- field — (no submodules)
- validator — (no submodules)
- validator — (no submodules)
- env-error — Provides the complete error class hierarchy and a value-object factory for
@suaveplan/env. All classes extend `Suavep… - error-codes — Defines and registers all stable error codes for the
@suaveplan/envpackage using thedefineCodesfactory from `@su… - array-field — (no submodules)
- array-field — (no submodules)
- boolean-field — (no submodules)
- boolean-field — (no submodules)
- email-field — (no submodules)
- email-field — (no submodules)
- enum-field — (no submodules)
- enum-field — (no submodules)
- json-field — (no submodules)
- json-field — (no submodules)
- number-field — (no submodules)
- number-field — (no submodules)
- port-field — (no submodules)
- port-field — (no submodules)
- string-field — (no submodules)
- string-field — (no submodules)
- url-field — (no submodules)
- url-field — (no submodules)
- dotenv — (no submodules)
- dotenv — (no submodules)
- object — (no submodules)
- object — (no submodules)
- common — (no submodules)
- common — (no submodules)
- server — (no submodules)
- server — (no submodules)
- schemas — (no submodules)
- env.schemas — (no submodules)
- coerce — (no submodules)
- coerce — (no submodules)
- types — (no submodules)
- common — (no submodules)
- utils — (no submodules)
- interpolation — (no submodules)
- error-codes — Defines and registers all stable error codes for the
@suaveplan/envpackage using thedefineCodesfactory from `@su… - array-field — (no submodules)- array-field — (no submodules)- boolean-field — (no submodules)- boolean-field — (no submodules)- email-field — (no submodules)- email-field — (no submodules)- enum-field — (no submodules)- enum-field — (no submodules)- json-field — (no submodules)- json-field — (no submodules)- number-field — (no submodules)- number-field — (no submodules)- port-field — (no submodules)- port-field — (no submodules)- string-field — (no submodules)- string-field — (no submodules)- url-field — (no submodules)- url-field — (no submodules)- dotenv — (no submodules)- dotenv — (no submodules)- object — (no submodules)- object — (no submodules)- common — (no submodules)- common — (no submodules)- server — (no submodules)- server — (no submodules)- schemas — (no submodules)- env.schemas — (no submodules)- coerce — (no submodules)- coerce — (no submodules)- types — (no submodules)- common — (no submodules)- utils — (no submodules)- interpolation — (no submodules)- create-env — (no submodules)- field — (no submodules)- field — (no submodules)- validator — (no submodules)- validator — (no submodules)- env-error — Provides the complete error class hierarchy and a value-object factory for
@suaveplan/env. All classes extend `Suavep… - error-codes — Defines and registers all stable error codes for the
@suaveplan/envpackage using thedefineCodesfactory from `@su… - array-field — (no submodules)- array-field — (no submodules)- boolean-field — (no submodules)- boolean-field — (no submodules)- email-field — (no submodules)- email-field — (no submodules)- enum-field — (no submodules)- enum-field — (no submodules)- json-field — (no submodules)- json-field — (no submodules)- number-field — (no submodules)- number-field — (no submodules)- port-field — (no submodules)- port-field — (no submodules)- string-field — (no submodules)- string-field — (no submodules)- url-field — (no submodules)- url-field — (no submodules)- dotenv — (no submodules)- dotenv — (no submodules)- object — (no submodules)- object — (no submodules)- common — (no submodules)- common — (no submodules)- server — (no submodules)- server — (no submodules)- schemas — (no submodules)- env.schemas — (no submodules)- coerce — (no submodules)- coerce — (no submodules)- types — (no submodules)- common — (no submodules)- utils — (no submodules)- interpolation — (no submodules)- create-env — (no submodules)- field — (no submodules)- field — (no submodules)- validator — (no submodules)- validator — (no submodules)- env-error — Provides the complete error class hierarchy and a value-object factory for
@suaveplan/env. All classes extend `Suavep… - error-codes — Defines and registers all stable error codes for the
@suaveplan/envpackage using thedefineCodesfactory from `@su… - array-field — (no submodules)- array-field — (no submodules)- boolean-field — (no submodules)- boolean-field — (no submodules)- email-field — (no submodules)- email-field — (no submodules)- enum-field — (no submodules)- enum-field — (no submodules)- json-field — (no submodules)- json-field — (no submodules)- number-field — (no submodules)- number-field — (no submodules)- port-field — (no submodules)- port-field — (no submodules)- string-field — (no submodules)- string-field — (no submodules)- url-field — (no submodules)- url-field — (no submodules)- dotenv — (no submodules)- dotenv — (no submodules)- object — (no submodules)- object — (no submodules)- common — (no submodules)- common — (no submodules)- server — (no submodules)- server — (no submodules)- schemas — (no submodules)- env.schemas — (no submodules)- coerce — (no submodules)- coerce — (no submodules)- types — (no submodules)- common — (no submodules)- utils — (no submodules)- interpolation — (no submodules)- create-env — (no submodules)- field — (no submodules) - field — (no submodules)- validator — (no submodules) - validator — (no submodules)- env-error — Provides the complete error class hierarchy and a value-object factory for
@suaveplan/env. All classes extend `Suavep… - error-codes — Defines and registers all stable error codes for the
@suaveplan/envpackage using thedefineCodesfactory from `@su… - array-field — (no submodules) - array-field — (no submodules)- boolean-field — (no submodules) - boolean-field — (no submodules)- email-field — (no submodules) - email-field — (no submodules)- enum-field — (no submodules) - enum-field — (no submodules)- json-field — (no submodules) - json-field — (no submodules)- number-field — (no submodules) - number-field — (no submodules)- port-field — (no submodules) - port-field — (no submodules)- string-field — (no submodules) - string-field — (no submodules)- url-field — (no submodules) - url-field — (no submodules)- dotenv — (no submodules) - dotenv — (no submodules)- object — (no submodules) - object — (no submodules)- common — (no submodules) - common — (no submodules)- server — (no submodules) - server — (no submodules)- schemas — (no submodules) - env.schemas — (no submodules)- coerce — (no submodules) - coerce — (no submodules)- types — (no submodules) - common — (no submodules)- utils — (no submodules) - interpolation — (no submodules)
Features
- Nine field builders:
str,num,bool,enums,url,email,port,json,array - Fluent builder chains: constraints, defaults, sensitive marking, and descriptions per field
- Pluggable loaders: dotenv file, object (
process.env), or custom loaders with priority ordering - Three error modes:
throw(default),collect(partial data),warn(log and continue) - Full-error accumulation: reports every broken field in a single run, not just the first
- Sensitive value redaction:
maskSensitivereplaces secret values with****before logging - Preset libraries:
commonFieldsandserverFieldsfor the most frequent env variables - Zod runtime schemas: for validation at serialisation boundaries
- 100% Istanbul coverage: foundation-grade reliability
Installation
bun add @suaveplan/env
Quick Start
import { createEnv, str, num, bool } from '@suaveplan/env';
const env = createEnv({
schema: {
HOST: str().default('localhost'),
PORT: num().default(3000),
DEBUG: bool().default(false),
API_KEY: str().nonempty().sensitive(),
},
source: process.env,
});
// Full TypeScript types — no manual annotation needed
console.log(env.HOST); // string
console.log(env.PORT); // number
console.log(env.DEBUG); // boolean
console.log(env.API_KEY); // string
Field Builders
| Factory | Output type | Key methods |
|---|---|---|
str() |
string |
trim, lowercase, uppercase, minLength, maxLength, pattern, nonempty, startsWith, endsWith, includes |
num() |
number |
min, max, integer, positive, nonNegative |
bool() |
boolean |
truthy(values), falsy(values) |
enums(values) |
"a" | "b" | … |
caseInsensitive, getAllowedValues |
url() |
string |
protocols(list), noTrailingSlash |
email() |
string |
normalise, pattern(regex) |
port() |
number |
min(n), max(n) |
json<T>() |
T (default unknown) |
validator(fn) |
array(itemField) |
T[] |
separator, noTrim, keepEmpty, minItems, maxItems |
All builders share: optional(), default(value), sensitive(), describe(text), addRule(options).
Loaders
import { createEnv, str } from '@suaveplan/env';
import { dotenvLoader, objectLoader } from '@suaveplan/env/loaders';
const env = createEnv({
schema: { DB_URL: str().sensitive() },
loaders: [
dotenvLoader({ path: '.env' }), // from file
objectLoader({ source: process.env }), // from process.env (wins)
],
});
Later loaders override earlier ones for the same key. source (if provided) overrides all loaders.
Error Modes
// Default: throws EnvValidationError with all failures listed
const env = createEnv({ schema, source: process.env });
// Collect: returns partial data silently
const env = createEnv({ schema, source: process.env, onError: 'collect' });
// Warn: logs each failure via console.warn, returns partial data
const env = createEnv({ schema, source: process.env, onError: 'warn' });
Prefix Support
// Reads APP_HOST, APP_PORT from process.env; output keys are HOST, PORT
const env = createEnv({
schema: { HOST: str().default('localhost'), PORT: num().default(3000) },
source: process.env,
prefix: 'APP_',
});
Presets
import { commonFields } from '@suaveplan/env/presets/common/common';
import { serverFields, databaseUrlField, sessionSecretField } from '@suaveplan/env/presets/server/server';
import { createEnv, str } from '@suaveplan/env';
const env = createEnv({
schema: {
...commonFields, // NODE_ENV, PORT, HOST, DEBUG, LOG_LEVEL
DATABASE_URL: databaseUrlField(),
SESSION_SECRET: sessionSecretField(),
CUSTOM: str().optional(),
},
source: process.env,
});
Sensitive Values
import { validate, maskSensitive } from '@suaveplan/env/core/validator/validator';
import { str } from '@suaveplan/env';
const schema = { SECRET: str().sensitive(), PUBLIC: str() };
const result = validate({ schema, values: { SECRET: 'my-secret', PUBLIC: 'ok' } });
const safe = maskSensitive(schema, result.data);
console.log(safe.SECRET); // "****"
console.log(safe.PUBLIC); // "ok"
Errors
import { EnvValidationError, CoercionError } from '@suaveplan/env/errors';
import { ENV_CODES } from '@suaveplan/env/errors';
try {
createEnv({ schema, source: {} });
} catch (err) {
if (err instanceof EnvValidationError) {
console.log(err.code); // "ENV.VALIDATION_FAILED"
console.log(err.errors); // [{ key, message }]
}
}
Zod Schemas
Runtime schemas for validation at API or persistence boundaries:
import { FieldConfigSchema, ValidationResultSchema } from '@suaveplan/env/schemas';
const result = FieldConfigSchema.safeParse(unknownPayload);