diff --git a/README.md b/README.md index 899d980..9b81fc8 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # [envnest](https://www.npmjs.com/package/envnest) -## This package is in underdevelopment and should not be used in production. - `envnest` is a TypeScript library for NestJS that provides type-safe environment variable validation and access using Zod schemas. ## Installation @@ -75,50 +73,6 @@ export class AppService { } ``` -## Presets - -envnest comes with built-in presets for common environment variables. You can use these presets to quickly set up your environment schema. - -### Using a preset - -```typescript -import { createEnvConfig, presets } from "envnest"; - -const envSchema = presets.node().extend({ - ...presets.databaseUrl, - // Add your custom environment variables here -}); - -export const envService = createEnvConfig(envSchema); -``` - -### Available presets - -- `presets.node()`: Common Node.js environment variables (NODE_ENV, PORT) -- `presets.databaseUrl()`: Database URL validation -- `presets.jwt()`: JWT secret and expiration time -- `presets.cors()`: CORS configuration - -## Custom Presets - -You can create custom presets for your specific needs: - -```typescript -import { z } from "envnest"; - -const myCustomPreset = () => z.object({ - CUSTOM_API_KEY: z.string().min(1), - CUSTOM_API_URL: z.string().url(), -}); - -const envSchema = presets.node().extend({ - ...myCustomPreset().shape, - // Other environment variables -}); - -export const envService = createEnvConfig(envSchema); -``` - ## Features - Type-safe environment variable access @@ -133,7 +87,6 @@ export const envService = createEnvConfig(envSchema); - `createEnvConfig(schema: ZodSchema)`: Creates a configuration service with validation - `envService.config`: Typed ConfigService instance - `envService.validateConfig`: Validation function for use with NestJS ConfigModule -- `presets`: Object containing built-in presets ## License diff --git a/Test.md b/Test.md index 17878af..2d99699 100644 --- a/Test.md +++ b/Test.md @@ -192,3 +192,51 @@ Creates a Zod schema by combining multiple preset schemas. ## License MIT + + + + + +## Presets + +envnest comes with built-in presets for common environment variables. You can use these presets to quickly set up your environment schema. + +### Using a preset + +```typescript +import { createEnvConfig, presets } from "envnest"; + +const envSchema = presets.node().extend({ + ...presets.databaseUrl, + // Add your custom environment variables here +}); + +export const envService = createEnvConfig(envSchema); +``` + +### Available presets + +- `presets.node()`: Common Node.js environment variables (NODE_ENV, PORT) +- `presets.databaseUrl()`: Database URL validation +- `presets.jwt()`: JWT secret and expiration time +- `presets.cors()`: CORS configuration + +## Custom Presets + +You can create custom presets for your specific needs: + +```typescript +import { z } from "envnest"; + +const myCustomPreset = () => z.object({ + CUSTOM_API_KEY: z.string().min(1), + CUSTOM_API_URL: z.string().url(), +}); + +const envSchema = presets.node().extend({ + ...myCustomPreset().shape, + // Other environment variables +}); + +export const envService = createEnvConfig(envSchema); +``` \ No newline at end of file diff --git a/package.json b/package.json index fc68e84..70aa58b 100644 --- a/package.json +++ b/package.json @@ -25,10 +25,10 @@ "typesafe-env" ], "description": "Typesafe environment variables for NestJS using zod.", - "homepage": "https://github.com/nischal-dahal/envnest", + "homepage": "https://github.com/broisnischal/nestenv", "repository": { "type": "git", - "url": "https://github.com/nischal-dahal/envnest" + "url": "https://github.com/broisnischal/nestenv" }, "sponsor": { "url": "https://nischal.pro" diff --git a/src/index.ts b/src/index.ts index 88d7017..3c3c3f6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -25,61 +25,63 @@ function convertToNumber(value: unknown): number | unknown { const zodNumberFromString = z.preprocess(convertToNumber, z.number()); export function createNestEnvValidator( - schema: T, - options: { - logErrors?: boolean; - throwOnError?: boolean; - useDefaults?: boolean; - } = {}, + schema: T, + options: { + logErrors?: boolean; + throwOnError?: boolean; + useDefaults?: boolean; + } = {} ): () => z.infer { - return () => { - const parseOptions: z.ParseParams = { - path: [], - errorMap: (issue, ctx) => { - return { - message: `Invalid value for environment variable ${issue.path.join(".")}`, - }; - }, - async: false, - }; - if (options.useDefaults !== false) { - parseOptions.path = []; - } - - // Preprocess the schema to handle number conversions - const preprocessedSchema = z.preprocess((obj) => { - if (typeof obj === "object" && obj !== null) { - return Object.fromEntries( - Object.entries(obj).map(([key, value]) => { - // @ts-ignore - // biome-ignore lint/suspicious/noExplicitAny: - const fieldSchema = (schema as any).shape?.[key]; - if (fieldSchema instanceof z.ZodNumber) { - return [key, convertToNumber(value)]; - } - return [key, value]; - }), - ); - } - return obj; - }, schema); - - const result = preprocessedSchema.safeParse(process.env, parseOptions); - - if (!result.success) { - if (options.logErrors !== false) { - console.error( - "❌ Invalid environment variables:", - result.error.format(), - ); - } - if (options.throwOnError !== false) { - throw new Error("Invalid environment variables"); - } - } - - return result.success ? result.data : process.env; - }; + return () => { + const parseOptions: z.ParseParams = { + path: [], + errorMap: (issue, ctx) => { + return { + message: `Invalid value for environment variable ${issue.path.join( + "." + )}`, + }; + }, + async: false, + }; + if (options.useDefaults !== false) { + parseOptions.path = []; + } + + // Preprocess the schema to handle number conversions + const preprocessedSchema = z.preprocess((obj) => { + if (typeof obj === "object" && obj !== null) { + return Object.fromEntries( + Object.entries(obj).map(([key, value]) => { + // @ts-ignore + // biome-ignore lint/suspicious/noExplicitAny: + const fieldSchema = (schema as any).shape?.[key]; + if (fieldSchema instanceof z.ZodNumber) { + return [key, convertToNumber(value)]; + } + return [key, value]; + }) + ); + } + return obj; + }, schema); + + const result = preprocessedSchema.safeParse(process.env, parseOptions); + + if (!result.success) { + if (options.logErrors !== false) { + console.error( + "❌ Invalid environment variables:", + result.error.format() + ); + } + if (options.throwOnError !== false) { + throw new Error("Invalid environment variables"); + } + } + + return result.success ? result.data : process.env; + }; } export function createTypedConfigService(schema: T) { diff --git a/src/presets.ts b/src/presets.ts index a167e53..86dcc96 100644 --- a/src/presets.ts +++ b/src/presets.ts @@ -1,29 +1,29 @@ -import { z } from "zod"; +// import { z } from "zod"; -export const commonEnvs = { - NODE_ENV: z - .enum(["development", "production", "test"]) - .default("development"), - PORT: z.coerce.number().positive(), - LOG_LEVEL: z.enum(["error", "warn", "info", "debug"]).default("info"), -}; +// export const commonEnvs = { +// NODE_ENV: z +// .enum(["development", "production", "test"]) +// .default("development"), +// PORT: z.coerce.number().positive(), +// LOG_LEVEL: z.enum(["error", "warn", "info", "debug"]).default("info"), +// }; -export const databaseEnvs = { - DATABASE_URL: z.string().url(), - DATABASE_SSL: z.coerce.boolean().default(false), -}; +// export const databaseEnvs = { +// DATABASE_URL: z.string().url(), +// DATABASE_SSL: z.coerce.boolean().default(false), +// }; -export const awsEnvs = { - AWS_ACCESS_KEY_ID: z.string().min(1), - AWS_SECRET_ACCESS_KEY: z.string().min(1), - AWS_REGION: z.string().min(1), -}; +// export const awsEnvs = { +// AWS_ACCESS_KEY_ID: z.string().min(1), +// AWS_SECRET_ACCESS_KEY: z.string().min(1), +// AWS_REGION: z.string().min(1), +// }; -export const authEnvs = { - JWT_SECRET: z.string().min(32), - JWT_EXPIRATION: z.string().regex(/^\d+[smhd]$/), -}; +// export const authEnvs = { +// JWT_SECRET: z.string().min(32), +// JWT_EXPIRATION: z.string().regex(/^\d+[smhd]$/), +// }; -export function createPresetSchema(...presets: z.ZodRawShape[]) { - return z.object(Object.assign({}, ...presets)); -} +// export function createPresetSchema(...presets: z.ZodRawShape[]) { +// return z.object(Object.assign({}, ...presets)); +// }