nestjs-zod-config
Advanced tools
Comparing version 1.2.3 to 2.0.0
export * from './types'; | ||
export * from './utilities'; | ||
export * from './zod-config'; | ||
export * from './zod-config-static'; | ||
export * from './zod-config.loader'; | ||
export * from './zod-config.module'; | ||
export * from './zod.config'; | ||
export * from './zod-config-options.inteface'; |
@@ -18,4 +18,7 @@ "use strict"; | ||
__exportStar(require("./types"), exports); | ||
__exportStar(require("./utilities"), exports); | ||
__exportStar(require("./zod-config"), exports); | ||
__exportStar(require("./zod-config-static"), exports); | ||
__exportStar(require("./zod-config.loader"), exports); | ||
__exportStar(require("./zod-config.module"), exports); | ||
__exportStar(require("./zod.config"), exports); | ||
__exportStar(require("./zod-config-options.inteface"), exports); |
@@ -0,3 +1,17 @@ | ||
import { Type } from '@nestjs/common'; | ||
import type { z } from 'zod'; | ||
export type UnknownRecord = Record<any, unknown>; | ||
export type UnknownZodSchema = z.ZodType<UnknownRecord>; | ||
import { ZodConfigStatic } from './zod-config-static'; | ||
/** | ||
* Type representation of an object with unknown keys. | ||
*/ | ||
export type UnknownRecord = Record<string, unknown>; | ||
/** | ||
* Used in generic types to represent a Zod object schema with unknown keys. | ||
*/ | ||
export type UnknownZodObjectSchema = z.ZodType<UnknownRecord>; | ||
/** | ||
* Type representation of the dynamically generated ZodConfig class. | ||
*/ | ||
export type ZodConfigType<Schema extends UnknownZodObjectSchema> = Type<ZodConfigStatic<Schema>> & { | ||
schema: Schema; | ||
}; |
@@ -1,13 +0,9 @@ | ||
import { Type } from '@nestjs/common'; | ||
import { UnknownZodSchema } from './types'; | ||
import { ZodConfigService } from './zod.config'; | ||
import { UnknownZodObjectSchema, ZodConfigType } from './types'; | ||
export interface ZodConfigOptions { | ||
/** | ||
* If "true", the {@link ConfigModule} will be registered as a global module. | ||
* If "true",it will be registered as a global module. | ||
* See: https://docs.nestjs.com/modules#global-modules | ||
*/ | ||
isGlobal?: boolean; | ||
service: Type<ZodConfigService> & { | ||
zodSchema: UnknownZodSchema; | ||
}; | ||
config: ZodConfigType<UnknownZodObjectSchema>; | ||
} |
import type { DynamicModule } from '@nestjs/common'; | ||
import { ZodConfigOptions } from './zod-config-options.inteface'; | ||
/** | ||
* Module to register ZodConfig as a provider in the NestJS DI container. | ||
*/ | ||
export declare class ZodConfigModule { | ||
static forRoot(options: ZodConfigOptions): DynamicModule; | ||
} |
@@ -12,3 +12,5 @@ "use strict"; | ||
const common_1 = require("@nestjs/common"); | ||
const config_1 = require("@nestjs/config"); | ||
/** | ||
* Module to register ZodConfig as a provider in the NestJS DI container. | ||
*/ | ||
let ZodConfigModule = ZodConfigModule_1 = class ZodConfigModule { | ||
@@ -19,9 +21,4 @@ static forRoot(options) { | ||
module: ZodConfigModule_1, | ||
imports: [ | ||
config_1.ConfigModule.forRoot({ | ||
validate: (config) => options.service.zodSchema.parse(config), | ||
}), | ||
], | ||
providers: [options.service], | ||
exports: [options.service], | ||
providers: [options.config], | ||
exports: [options.config], | ||
}; | ||
@@ -28,0 +25,0 @@ } |
{ | ||
"name": "nestjs-zod-config", | ||
"version": "1.2.3", | ||
"version": "2.0.0", | ||
"description": "NestJS module to load, type and validate configuration using Zod", | ||
@@ -31,3 +31,2 @@ "keywords": [ | ||
"@nestjs/common": "^10.3.0", | ||
"@nestjs/config": "^3.1.1", | ||
"zod": "^3.0.0" | ||
@@ -37,6 +36,2 @@ }, | ||
"@nestjs/common": "^10.3.0", | ||
"@nestjs/config": "^3.1.1", | ||
"reflect-metadata": "^0.2.1", | ||
"rxjs": "^7.8.1", | ||
"zod": "^3.0.0", | ||
"@rollup/plugin-typescript": "^11.1.6", | ||
@@ -49,9 +44,15 @@ "@types/node": "^20.11.0", | ||
"prettier": "^3.2.2", | ||
"reflect-metadata": "^0.2.1", | ||
"rollup": "^4.9.5", | ||
"rollup-plugin-dts": "^6.1.0", | ||
"rollup-plugin-terser": "^7.0.2", | ||
"rxjs": "^7.8.1", | ||
"tsx": "^4.7.0", | ||
"typescript": "^5.3.3", | ||
"vitest": "^1.2.0" | ||
"vitest": "^1.2.0", | ||
"zod": "^3.0.0" | ||
}, | ||
"dependencies": { | ||
"dotenv": "^16.4.1" | ||
} | ||
} |
126
README.md
@@ -7,3 +7,3 @@ # NestJS Zod Config | ||
**nestjs-zod-config** - NestJS module to load, type and validate configuration using Zod. | ||
**nestjs-zod-config** - NestJS module to load, type and validate configuration using Zod. Insied and outside the NestJS context. | ||
@@ -15,48 +15,55 @@ ## Installation | ||
``` | ||
> Peer dependencies: `yarn add @nestjs/common @nestjs/core zod` | ||
> Peer dependencies: `yarn add @nestjs/common zod` | ||
## Setup | ||
1. Have a `.env` file in the root of your project. | ||
```dotenv | ||
# .env | ||
PORT=3000 | ||
``` | ||
The first thing that we need to do is to create a config class that extends `ZodConfig` and pass it our Zod schema. | ||
2. Create a config class that extends `ZodConfig` and pass it a Zod schema. | ||
```ts | ||
// app.config.ts | ||
import { ZodConfig } from 'nestjs-zod-config'; | ||
import { z } from 'zod'; | ||
const appConfigSchema = z.object({ | ||
HOSTNAME: z.string().min(1).default('0.0.0.0'), | ||
PORT: z.coerce.number().default(3000), | ||
}); | ||
export class AppConfig extends ZodConfig(appConfigSchema) {} | ||
``` | ||
```ts | ||
// app.config.ts | ||
import { ZodConfig } from 'nestjs-zod-config'; | ||
import { z } from 'zod'; | ||
3. Register the config class in your module. | ||
```ts | ||
// app.module.ts | ||
import { Module } from '@nestjs/common'; | ||
import { ZodConfigModule } from 'nestjs-zod-config'; | ||
import { AppConfig } from './app.config'; | ||
@Module({ | ||
imports: [ | ||
ZodConfigModule.forRoot({ | ||
service: AppConfig, | ||
}), | ||
], | ||
}) | ||
export class AppModule {} | ||
``` | ||
const appConfigSchema = z.object({ | ||
HOSTNAME: z.string().min(1).default('0.0.0.0'), | ||
PORT: z.coerce.number().default(3000), | ||
}); | ||
export class AppConfig extends ZodConfig(appConfigSchema) {} | ||
``` | ||
> This assumes that you have a `.env` file in the root of your project or that you have set the environment variables in `process.env` in some other way. | ||
✨ All done. Let's see how we can use it. | ||
Then we need to register the config class in our module. | ||
## Usage | ||
Use it in your service like this: | ||
### Inside NestJS context | ||
We will have to register the config class in a module: | ||
```ts | ||
// app.module.ts | ||
import { Module } from '@nestjs/common'; | ||
import { ZodConfigModule } from 'nestjs-zod-config'; | ||
import { AppConfig } from './app.config'; | ||
@Module({ | ||
imports: [ | ||
ZodConfigModule.forRoot({ | ||
isGlobal: true, // optional, defaults to true | ||
config: AppConfig, | ||
}), | ||
], | ||
}) | ||
export class AppModule {} | ||
``` | ||
> It is recommended to register the config class in the root module of your application. | ||
Now we can inject `AppConfig` in your services like this: | ||
```ts | ||
// app.service.ts | ||
@@ -68,11 +75,11 @@ import { Injectable } from '@nestjs/common'; | ||
export class AppService { | ||
constructor(private readonly appConfig: AppConfig) {} | ||
getPort(): number { | ||
return this.appConfig.get('PORT'); | ||
} | ||
constructor(private readonly appConfig: AppConfig) {} | ||
getPort(): number { | ||
return this.appConfig.get('PORT'); | ||
} | ||
} | ||
``` | ||
or in your `main.ts` like this: | ||
or in our `main.ts`, like this: | ||
@@ -99,2 +106,21 @@ ```ts | ||
### Outside NestJS context | ||
There are cases where we need to access the config outside the NestJS context. For example, we might want to use the config in a seeder script: | ||
```ts | ||
// seed.ts | ||
import { loadZodConfig } from 'nestjs-zod-config'; | ||
const seedDb = async () => { | ||
const appConfig = loadZodConfig(AppConfig); | ||
const databaseurl = appConfig.get('DATABASE_URL'); | ||
// use the `databaseurl` to connect to the database and seed it | ||
}; | ||
``` | ||
> In this case we cannot inject the `AppConfig` and we don't have access to the `app` instance. The file is executed outside the NestJS context. | ||
## Testing | ||
@@ -105,1 +131,15 @@ | ||
``` | ||
## Roadmap | ||
- [ ] Provide a way to customize the env loader. Useful when different name, format or location of the env file is needed. | ||
- [ ] Provide async methods to load the config. | ||
- [ ] Write tests 🧪 | ||
## Tips and Tricks | ||
### Use `safeBooleanCoerce` to coerce strings to booleans safely | ||
This is a utility function that can be used to coerce a string value to a boolean in a strict manner. | ||
Normally you will do: `z.coerce.boolean()` but this will also coerce the string `'false'` to `true`. | ||
So instead we use this function to only allow the string `'false'` to be coerced to `false` and everything else will throw an error. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
14485
17
18
229
141
2
1
+ Addeddotenv@^16.4.1
- Removed@nestjs/config@3.2.3(transitive)
- Removeddotenv-expand@10.0.0(transitive)
- Removedlodash@4.17.21(transitive)