Skip to content

Feature/compt 51 config module and service#3

Merged
y-aithnini merged 6 commits intodevelopfrom
feature/COMPT-51-config-module-and-service
Apr 7, 2026
Merged

Feature/compt 51 config module and service#3
y-aithnini merged 6 commits intodevelopfrom
feature/COMPT-51-config-module-and-service

Conversation

@y-aithnini
Copy link
Copy Markdown

Summary

  • What does this PR change?

Why

  • Why is this change needed?

Checklist

  • Added/updated tests (if behavior changed)
  • npm run lint passes
  • npm run typecheck passes
  • npm test passes
  • npm run build passes
  • Added a changeset (npx changeset) if this affects consumers

Notes

  • Anything reviewers should pay attention to?

- Add defineConfig(schema) returning ConfigDefinition<T>
- Add ConfigDefinition.parse() — validates process.env synchronously,
  returns frozen fully-typed config, throws ConfigValidationError on failure
- Add ConfigValidationError extending Error with fields: ZodIssue[]
- Add zod as peerDependency (^3 || ^4)
- Install zod as devDependency for local development
- Update src/index.ts to export defineConfig, ConfigDefinition, ConfigValidationError
- Add node to tsconfig types array for process.env access
- Add ConfigModule with register() sync, registerAsync() async factory,
  and forRoot() global registration
- Add ConfigService<TDef> with typed get<K>(key) — return type inferred
  directly from Zod schema output, no casting needed
- Add CONFIG_VALUES_TOKEN internal DI token in constants.ts
- Validation runs before any provider resolves in all three registration modes
- App fails to boot when validation fails (ConfigValidationError thrown)
- Update src/index.ts to export ConfigModule, ConfigService, ConfigModuleAsyncOptions
@y-aithnini y-aithnini requested a review from a team as a code owner April 7, 2026 08:47
Copilot AI review requested due to automatic review settings April 7, 2026 08:47
@y-aithnini y-aithnini merged commit 243e4f4 into develop Apr 7, 2026
1 of 2 checks passed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds the NestJS integration layer for @ciscode/config-kit, exposing a dynamic ConfigModule and injectable ConfigService so consumers can validate process.env at startup and retrieve strongly-typed config values throughout an app.

Changes:

  • Export ConfigModule, ConfigService, and ConfigModuleAsyncOptions from the public entrypoint.
  • Introduce internal DI token(s) (CONFIG_VALUES_TOKEN) for wiring parsed config into Nest providers.
  • Implement ConfigModule.register/registerAsync/forRoot plus typed ConfigService.get() backed by the validated config object.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
src/index.ts Exposes the new NestJS module/service types as public API exports.
src/constants.ts Defines internal DI token used to provide the parsed config object.
src/config.service.ts Implements typed ConfigService<TDef>.get(key) via injected parsed config.
src/config.module.ts Implements dynamic module registration APIs (sync/async/global) and providers wiring.

Comment thread src/config.module.ts
Comment on lines +116 to +118
@Global() // Applied only when used via forRoot(); register() and registerAsync() are non-global
@Module({})
export class ConfigModule {
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConfigModule is decorated with @Global(), which makes it global for all usages (including register() and registerAsync()), contradicting the doc comment and the returned DynamicModule objects that set global: false. This changes DI scope unexpectedly for consumers. Remove the @Global() decorator and rely solely on returning global: true from forRoot() (or split into separate global/non-global modules).

Copilot uses AI. Check for mistakes.
Comment thread src/config.module.ts
Comment on lines +73 to +88
imports?: DynamicModule["imports"];

/**
* Tokens to inject into `useFactory` as positional arguments.
* Same semantics as `inject` in a standard NestJS `useFactory` provider.
*/
inject?: unknown[];

/**
* Factory function that returns the ConfigDefinition to validate.
* May be synchronous or async.
*/
useFactory: (
...args: unknown[]
) => Promise<ConfigDefinition<T>> | ConfigDefinition<T>;
}
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConfigModuleAsyncOptions types inject and useFactory args as unknown[], which gives consumers little compile-time help and makes it easy to pass invalid injection tokens/argument shapes. Consider typing inject as Nest’s injection token list type (e.g., FactoryProvider['inject'] / InjectionToken[]) and using generics/tuples to type the useFactory parameters accordingly.

Copilot uses AI. Check for mistakes.
Comment thread src/config.module.ts
Comment on lines +199 to +202
return definition.parse(process.env);
},
inject: (options.inject ?? []) as never[],
};
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inject: (options.inject ?? []) as never[] is an unsafe assertion that disables type checking and can hide mistakes in options.inject. Prefer passing inject: options.inject ?? [] with the correct type on ConfigModuleAsyncOptions.inject so this provider stays type-safe without assertions.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants