@daiso-tech/core
Version:
The library offers flexible, framework-agnostic solutions for modern web applications, built on adaptable components that integrate seamlessly with popular frameworks like Next Js.
96 lines • 3.2 kB
JavaScript
/**
* @module EnvAccessor
*/
import {} from "@standard-schema/spec";
import { UninitializedEnvAccessorError, } from "../../env-accessor/contracts/_module.js";
import { resolveOneOrMore, isInvokable, callInvokable, validate, } from "../../utilities/_module.js";
/**
* `EnvAccessor` provides type-safe access to environment variables, with optional schema validation.
*
* It supports multiple sources (sync/async/lazy), schema validation, and convenient access patterns.
*
* @template TEnvConfig The environment config type.
* @group Implementations
*/
export class EnvAccessor {
envConfig = null;
schema;
sources;
/**
* @example
* ```ts
* import { EnvAccessor } from "@daiso-tech/core/env-accessor";
* import { z } from "zod";
* import { SecretsManagerClient, GetSecretValueCommand } from "@aws-sdk/client-secrets-manager";
*
*
* // Combine AWS Secrets Manager and process.env as sources
* // Note: The order matters—later sources override previous ones for overlapping keys.
* const secretsManager = new SecretsManagerClient({ region: "us-east-1" });
* const sources = [
* process.env,
* async () => {
* const secret = await secretsManager.send(
* new GetSecretValueCommand({ SecretId: "my-app/env" })
* );
* return JSON.parse(secret.SecretString ?? "{}");
* },
* ];
*
* // Define a schema for your environment variables
* const schema = z.object({
* NODE_ENV: z.string(),
* PORT: z.string().default("3000").pipe(z.coerce.number()),
* });
*
* // Initialize the accessor
* const accessor = new EnvAccessor({ schema, sources });
* await accessor.init();
*
* // Retrieve a value
* const port = accessor.get("PORT");
* ```
*/
constructor(settings) {
const { schema, sources } = settings;
this.schema = schema;
this.sources = sources;
}
/**
* Initialize the EnvAccessor by resolving all sources and validating the merged config.
*
* @returns Promise that resolves when initialization is complete.
*/
async init() {
const resolvedSource = resolveOneOrMore(this.sources).map((source) => {
if (isInvokable(source)) {
return source;
}
return () => source;
});
let mergedRawConfig = {};
for (const source of resolvedSource) {
mergedRawConfig = {
...mergedRawConfig,
...(await callInvokable(source)),
};
}
this.envConfig = await validate(this.schema, mergedRawConfig);
}
get(field) {
if (this.envConfig === null) {
throw UninitializedEnvAccessorError.create();
}
const value = this.envConfig[field] ?? null;
return value;
}
getOr(field, defaultValue) {
const value = this.get(field);
if (value === null) {
return defaultValue;
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return value;
}
}
//# sourceMappingURL=env-accessor.js.map