@tsed/config 8.9.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/lib/esm/constants/constants.js +2 -0
  2. package/lib/esm/constants/constants.js.map +1 -0
  3. package/lib/esm/hooks/afterResolveConfiguration.js +55 -0
  4. package/lib/esm/hooks/afterResolveConfiguration.js.map +1 -0
  5. package/lib/esm/index.js +20 -0
  6. package/lib/esm/index.js.map +1 -0
  7. package/lib/esm/interfaces/ConfigSource.js +2 -0
  8. package/lib/esm/interfaces/ConfigSource.js.map +1 -0
  9. package/lib/esm/interfaces/index.js +2 -0
  10. package/lib/esm/interfaces/index.js.map +1 -0
  11. package/lib/esm/providers/dotenv/DotEnvsConfigSource.js +30 -0
  12. package/lib/esm/providers/dotenv/DotEnvsConfigSource.js.map +1 -0
  13. package/lib/esm/providers/dotenv/index.js +3 -0
  14. package/lib/esm/providers/dotenv/index.js.map +1 -0
  15. package/lib/esm/providers/envs/EnvsConfigSource.js +14 -0
  16. package/lib/esm/providers/envs/EnvsConfigSource.js.map +1 -0
  17. package/lib/esm/providers/envs/index.js +3 -0
  18. package/lib/esm/providers/envs/index.js.map +1 -0
  19. package/lib/esm/providers/json/JsonConfigSource.js +23 -0
  20. package/lib/esm/providers/json/JsonConfigSource.js.map +1 -0
  21. package/lib/esm/providers/json/index.js +3 -0
  22. package/lib/esm/providers/json/index.js.map +1 -0
  23. package/lib/esm/providers/yaml/YamlConfigSource.js +23 -0
  24. package/lib/esm/providers/yaml/YamlConfigSource.js.map +1 -0
  25. package/lib/esm/providers/yaml/index.js +3 -0
  26. package/lib/esm/providers/yaml/index.js.map +1 -0
  27. package/lib/esm/utils/getConfigSources.js +43 -0
  28. package/lib/esm/utils/getConfigSources.js.map +1 -0
  29. package/lib/esm/utils/jsonParse.js +9 -0
  30. package/lib/esm/utils/jsonParse.js.map +1 -0
  31. package/lib/esm/utils/validate.js +16 -0
  32. package/lib/esm/utils/validate.js.map +1 -0
  33. package/lib/esm/utils/withOptions.js +13 -0
  34. package/lib/esm/utils/withOptions.js.map +1 -0
  35. package/lib/tsconfig.esm.tsbuildinfo +1 -0
  36. package/lib/types/constants/constants.d.ts +3 -0
  37. package/lib/types/hooks/afterResolveConfiguration.d.ts +2 -0
  38. package/lib/types/index.d.ts +19 -0
  39. package/lib/types/interfaces/ConfigSource.d.ts +57 -0
  40. package/lib/types/interfaces/index.d.ts +11 -0
  41. package/lib/types/providers/dotenv/DotEnvsConfigSource.d.ts +8 -0
  42. package/lib/types/providers/dotenv/index.d.ts +2 -0
  43. package/lib/types/providers/envs/EnvsConfigSource.d.ts +8 -0
  44. package/lib/types/providers/envs/index.d.ts +2 -0
  45. package/lib/types/providers/json/JsonConfigSource.d.ts +18 -0
  46. package/lib/types/providers/json/index.d.ts +2 -0
  47. package/lib/types/providers/yaml/YamlConfigSource.d.ts +13 -0
  48. package/lib/types/providers/yaml/index.d.ts +2 -0
  49. package/lib/types/utils/getConfigSources.d.ts +6 -0
  50. package/lib/types/utils/jsonParse.d.ts +1 -0
  51. package/lib/types/utils/validate.d.ts +2 -0
  52. package/lib/types/utils/withOptions.d.ts +12 -0
  53. package/package.json +105 -0
  54. package/readme.md +354 -0
  55. package/src/constants/constants.ts +4 -0
  56. package/src/hooks/afterResolveConfiguration.ts +77 -0
  57. package/src/index.ts +19 -0
  58. package/src/interfaces/ConfigSource.ts +65 -0
  59. package/src/interfaces/index.ts +12 -0
  60. package/src/providers/dotenv/DotEnvsConfigSource.ts +40 -0
  61. package/src/providers/dotenv/index.ts +3 -0
  62. package/src/providers/envs/EnvsConfigSource.spec.ts +51 -0
  63. package/src/providers/envs/EnvsConfigSource.ts +23 -0
  64. package/src/providers/envs/index.ts +3 -0
  65. package/src/providers/json/JsonConfigSource.spec.ts +60 -0
  66. package/src/providers/json/JsonConfigSource.ts +45 -0
  67. package/src/providers/json/index.ts +3 -0
  68. package/src/providers/yaml/YamlConfigSource.spec.ts +64 -0
  69. package/src/providers/yaml/YamlConfigSource.ts +39 -0
  70. package/src/providers/yaml/index.ts +3 -0
  71. package/src/utils/getConfigSources.ts +52 -0
  72. package/src/utils/jsonParse.ts +7 -0
  73. package/src/utils/validate.ts +18 -0
  74. package/src/utils/withOptions.ts +19 -0
  75. package/tsconfig.esm.json +26 -0
  76. package/vitest.config.mts +21 -0
@@ -0,0 +1,3 @@
1
+ import { ConfigSource } from "../interfaces/ConfigSource.js";
2
+ export declare const CONFIG_SOURCES: unique symbol;
3
+ export type CONFIG_SOURCES = Record<string, ConfigSource>;
@@ -0,0 +1,2 @@
1
+ import "@tsed/ajv";
2
+ export declare function afterResolveConfiguration(): Promise<void>;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @file Automatically generated by @tsed/barrels.
3
+ */
4
+ export * from "./constants/constants.js";
5
+ export * from "./hooks/afterResolveConfiguration.js";
6
+ export * from "./interfaces/ConfigSource.js";
7
+ export * from "./interfaces/index.js";
8
+ export * from "./providers/dotenv/DotEnvsConfigSource.js";
9
+ export * from "./providers/dotenv/index.js";
10
+ export * from "./providers/envs/EnvsConfigSource.js";
11
+ export * from "./providers/envs/index.js";
12
+ export * from "./providers/json/index.js";
13
+ export * from "./providers/json/JsonConfigSource.js";
14
+ export * from "./providers/yaml/index.js";
15
+ export * from "./providers/yaml/YamlConfigSource.js";
16
+ export * from "./utils/getConfigSources.js";
17
+ export * from "./utils/jsonParse.js";
18
+ export * from "./utils/validate.js";
19
+ export * from "./utils/withOptions.js";
@@ -0,0 +1,57 @@
1
+ import type { Type } from "@tsed/core";
2
+ import { JsonSchema } from "@tsed/schema";
3
+ export interface ConfigSourceOptions<Opts = any> {
4
+ /**
5
+ * The name of the configuration provider.
6
+ */
7
+ name?: string;
8
+ /**
9
+ * The priority of the configuration provider. Higher priority providers will override values from lower priority providers.
10
+ * @default 0
11
+ */
12
+ priority?: number;
13
+ /**
14
+ * Whether to enable the configuration provider.
15
+ * @default true
16
+ */
17
+ enabled?: boolean;
18
+ /**
19
+ * The ConfigSource to use for loading configuration values.
20
+ * @param args
21
+ */
22
+ use: Type<ConfigSource<Opts>>;
23
+ /**
24
+ * Options for the configuration provider.
25
+ */
26
+ options: Opts;
27
+ /**
28
+ * The schema to validate the configuration values against.
29
+ */
30
+ validationSchema?: JsonSchema;
31
+ /**
32
+ * Enable FileSystem Watch mode. ConfigSource must implement the `watch()` method.
33
+ */
34
+ watch?: boolean;
35
+ /**
36
+ * Refresh strategy. Ts.ED can refresh ConfigSource during the "$onRequest" or "$onResponse" hook.
37
+ *
38
+ * Note: refresh data during `$onRequest` can degrade performance depending on the ConfigSource type.
39
+ * We recommend to refresh data during the $onResponse hook (action are asynchronous).
40
+ */
41
+ refreshOn?: "request" | "response";
42
+ }
43
+ export type InitialConfigSourceOptions = Omit<ConfigSourceOptions, "options" | "use">;
44
+ export type ConfigSourceWatchCloseCB = () => Promise<void> | void;
45
+ export type ConfigSourceOnChangeCB = () => void;
46
+ /**
47
+ * Interface for a configuration source that can provide configuration values.
48
+ */
49
+ export interface ConfigSource<Opts = any> {
50
+ options: Opts;
51
+ /**
52
+ * Load configuration from the source.
53
+ */
54
+ getAll(): Promise<Record<string, unknown>> | Record<string, unknown>;
55
+ watch?(onChange?: ConfigSourceOnChangeCB): Promise<ConfigSourceWatchCloseCB> | ConfigSourceWatchCloseCB;
56
+ }
57
+ export type ConfigurationExtends = (Type<ConfigSource> | ConfigSourceOptions)[];
@@ -0,0 +1,11 @@
1
+ import type { ConfigurationExtends } from "./ConfigSource.js";
2
+ /**
3
+ * Extend the global TsED namespace to include configuration for this package.
4
+ */
5
+ declare global {
6
+ namespace TsED {
7
+ interface Configuration {
8
+ extends?: ConfigurationExtends;
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,8 @@
1
+ import { type DotenvFlowConfigOptions } from "dotenv-flow";
2
+ import type { ConfigSourceOnChangeCB } from "../../interfaces/ConfigSource.js";
3
+ import { EnvsConfigSource, type EnvsConfigSourceOptions } from "../envs/EnvsConfigSource.js";
4
+ export type DotEnvsConfigSourceOptions = EnvsConfigSourceOptions & DotenvFlowConfigOptions;
5
+ export declare class DotEnvsConfigSource extends EnvsConfigSource<DotEnvsConfigSourceOptions> {
6
+ getAll(): Record<string, unknown>;
7
+ watch(onChange?: ConfigSourceOnChangeCB): Promise<() => void>;
8
+ }
@@ -0,0 +1,2 @@
1
+ import "../../hooks/afterResolveConfiguration.js";
2
+ export * from "./DotEnvsConfigSource.js";
@@ -0,0 +1,8 @@
1
+ import type { ConfigSource } from "../../interfaces/ConfigSource.js";
2
+ export interface EnvsConfigSourceOptions {
3
+ parseJson?: boolean;
4
+ }
5
+ export declare class EnvsConfigSource<Config extends EnvsConfigSourceOptions = EnvsConfigSourceOptions> implements ConfigSource<Config> {
6
+ options: Config;
7
+ getAll(): Record<string, unknown>;
8
+ }
@@ -0,0 +1,2 @@
1
+ import "../../hooks/afterResolveConfiguration.js";
2
+ export * from "./EnvsConfigSource.js";
@@ -0,0 +1,18 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ import type { ConfigSource } from "../../interfaces/ConfigSource.js";
3
+ export interface JsonConfigSourceOptions {
4
+ /**
5
+ * The path to the JSON file.
6
+ */
7
+ path: string;
8
+ /**
9
+ * The encoding to use when reading the file.
10
+ * @default "utf8"
11
+ */
12
+ encoding?: BufferEncoding;
13
+ }
14
+ export declare class JsonConfigSource implements ConfigSource<JsonConfigSourceOptions> {
15
+ options: JsonConfigSourceOptions;
16
+ getAll(): Record<string, unknown>;
17
+ watch(onChange: () => void): () => void;
18
+ }
@@ -0,0 +1,2 @@
1
+ import "../../hooks/afterResolveConfiguration.js";
2
+ export * from "./JsonConfigSource.js";
@@ -0,0 +1,13 @@
1
+ import { type LoadOptions } from "js-yaml";
2
+ import type { ConfigSource } from "../../interfaces/ConfigSource.js";
3
+ export interface YamlConfigSourceOptions extends LoadOptions {
4
+ /**
5
+ * The path to the JSON file.
6
+ */
7
+ path: string;
8
+ }
9
+ export declare class YamlConfigSource implements ConfigSource<YamlConfigSourceOptions> {
10
+ options: YamlConfigSourceOptions;
11
+ getAll(): Promise<Record<string, unknown>>;
12
+ watch(onChange: () => void): () => void;
13
+ }
@@ -0,0 +1,2 @@
1
+ import "../../hooks/afterResolveConfiguration.js";
2
+ export * from "./YamlConfigSource.js";
@@ -0,0 +1,6 @@
1
+ import { type Type } from "@tsed/core";
2
+ import type { ConfigSource, ConfigSourceOptions } from "../interfaces/ConfigSource.js";
3
+ export declare function getConfigSources(configSources: (Type<ConfigSource<any>> | ConfigSourceOptions)[]): Map<string, ConfigSourceOptions<any> & {
4
+ instance: ConfigSource<any>;
5
+ data: Record<string, any>;
6
+ }>;
@@ -0,0 +1 @@
1
+ export declare function jsonParse(value: string): any;
@@ -0,0 +1,2 @@
1
+ import { JsonSchema } from "@tsed/schema";
2
+ export declare function validate(configName: string, config: Record<string, unknown>, validationSchema: JsonSchema): Promise<any>;
@@ -0,0 +1,12 @@
1
+ import type { Type } from "@tsed/core";
2
+ import type { ConfigSource, InitialConfigSourceOptions } from "../interfaces/ConfigSource.js";
3
+ export declare function withOptions<Opts>(use: Type<ConfigSource<Opts>>, { name, priority, validationSchema, enabled, refreshOn, watch, ...opts }: InitialConfigSourceOptions & Opts): {
4
+ name: string | undefined;
5
+ priority: number | undefined;
6
+ validationSchema: import("@tsed/schema").JsonSchema | undefined;
7
+ use: Type<ConfigSource<Opts>>;
8
+ watch: boolean | undefined;
9
+ refreshOn: "request" | "response" | undefined;
10
+ enabled: boolean;
11
+ options: Omit<InitialConfigSourceOptions & Opts, "name" | "priority" | "enabled" | "validationSchema" | "watch" | "refreshOn">;
12
+ };
package/package.json ADDED
@@ -0,0 +1,105 @@
1
+ {
2
+ "name": "@tsed/config",
3
+ "description": "Configuration management for Ts.ED",
4
+ "type": "module",
5
+ "version": "8.9.0-beta.1",
6
+ "keywords": [
7
+ "Ts.ED",
8
+ "Configuration",
9
+ "Config"
10
+ ],
11
+ "source": "./src/index.ts",
12
+ "main": "./lib/esm/index.js",
13
+ "module": "./lib/esm/index.js",
14
+ "typings": "./lib/types/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "tsed-source": "./src/index.ts",
18
+ "types": "./lib/types/index.d.ts",
19
+ "import": "./lib/esm/index.js",
20
+ "default": "./lib/esm/index.js"
21
+ },
22
+ "./dotenv": {
23
+ "tsed-source": "./src/providers/dotenv/index.ts",
24
+ "types": "./lib/types/providers/dotenv/index.d.ts",
25
+ "import": "./lib/esm/providers/dotenv/index.js",
26
+ "default": "./lib/esm/providers/dotenv/index.js"
27
+ },
28
+ "./envs": {
29
+ "tsed-source": "./src/providers/envs/index.ts",
30
+ "types": "./lib/types/providers/envs/index.d.ts",
31
+ "import": "./lib/esm/providers/envs/index.js",
32
+ "default": "./lib/esm/providers/envs/index.js"
33
+ },
34
+ "./json": {
35
+ "tsed-source": "./src/providers/json/index.ts",
36
+ "types": "./lib/types/providers/json/index.d.ts",
37
+ "import": "./lib/esm/providers/json/index.js",
38
+ "default": "./lib/esm/providers/json/index.js"
39
+ }
40
+ },
41
+ "scripts": {
42
+ "build": "yarn barrels && yarn build:ts",
43
+ "barrels": "barrels",
44
+ "test": "vitest run",
45
+ "build:ts": "tsc --build tsconfig.esm.json",
46
+ "test:ci": "vitest run --coverage.thresholds.autoUpdate=true"
47
+ },
48
+ "dependencies": {
49
+ "change-case": "5.4.4",
50
+ "tslib": "2.7.0"
51
+ },
52
+ "devDependencies": {
53
+ "@tsed/ajv": "8.9.0-beta.1",
54
+ "@tsed/barrels": "8.9.0-beta.1",
55
+ "@tsed/core": "8.9.0-beta.1",
56
+ "@tsed/di": "8.9.0-beta.1",
57
+ "@tsed/typescript": "8.9.0-beta.1",
58
+ "@types/js-yaml": "4.0.9",
59
+ "dotenv": "^16.5.0",
60
+ "dotenv-expand": "^12.0.2",
61
+ "dotenv-flow": "^4.1.0",
62
+ "eslint": "9.12.0",
63
+ "typescript": "5.4.5",
64
+ "vitest": "3.1.1"
65
+ },
66
+ "peerDependencies": {
67
+ "@tsed/core": "workspace:*",
68
+ "@tsed/di": "workspace:*",
69
+ "dotenv": "^16.5.0",
70
+ "dotenv-expand": "^12.0.2",
71
+ "dotenv-flow": "^4.1.0",
72
+ "globby": "^14.1.0",
73
+ "js-yaml": "^4.1.0"
74
+ },
75
+ "peerDependenciesMeta": {
76
+ "@tsed/core": {
77
+ "optional": false
78
+ },
79
+ "@tsed/di": {
80
+ "optional": false
81
+ },
82
+ "dotenv": {
83
+ "optional": true
84
+ },
85
+ "dotenv-expand": {
86
+ "optional": true
87
+ },
88
+ "dotenv-flow": {
89
+ "optional": true
90
+ },
91
+ "js-yaml": {
92
+ "optional": true
93
+ }
94
+ },
95
+ "repository": "https://github.com/tsedio/tsed",
96
+ "bugs": {
97
+ "url": "https://github.com/tsedio/tsed/issues"
98
+ },
99
+ "homepage": "https://github.com/tsedio/tsed/tree/production/packages/config",
100
+ "author": "Romain Lenzotti",
101
+ "license": "MIT",
102
+ "publishConfig": {
103
+ "tag": "beta"
104
+ }
105
+ }
package/readme.md ADDED
@@ -0,0 +1,354 @@
1
+ <p style="text-align: center" align="center">
2
+ <a href="https://tsed.dev" target="_blank"><img src="https://tsed.dev/tsed-og.png" width="200" alt="Ts.ED logo"/></a>
3
+ </p>
4
+
5
+ <div align="center">
6
+ <h1>@tsed/config</h1>
7
+
8
+ [![Build & Release](https://github.com/tsedio/tsed/workflows/Build%20&%20Release/badge.svg)](https://github.com/tsedio/tsed/actions?query=workflow%3A%22Build+%26+Release%22)
9
+ [![PR Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/tsedio/tsed/blob/master/CONTRIBUTING.md)
10
+ [![npm version](https://badge.fury.io/js/%40tsed%2Fcommon.svg)](https://badge.fury.io/js/%40tsed%2Fcommon)
11
+ [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
12
+ [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)
13
+ [![github](https://img.shields.io/static/v1?label=Github%20sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/romakita)
14
+ [![opencollective](https://img.shields.io/static/v1?label=OpenCollective%20sponsor&message=%E2%9D%A4&logo=OpenCollective&color=%23fe8e86)](https://opencollective.com/tsed)
15
+
16
+ </div>
17
+
18
+ <div align="center">
19
+ <a href="https://tsed.dev/">Website</a>
20
+ <span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
21
+ <a href="https://tsed.dev/getting-started/">Getting started</a>
22
+ <span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
23
+ <a href="https://slack.tsed.dev">Slack</a>
24
+ <span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
25
+ <a href="https://twitter.com/TsED_io">Twitter</a>
26
+ </div>
27
+
28
+ <hr />
29
+
30
+ > Configuration management for Ts.ED
31
+
32
+ A package of Ts.ED framework. See website: https://tsed.dev/
33
+
34
+ ## Installation
35
+
36
+ ```bash
37
+ npm install --save @tsed/config
38
+ ```
39
+
40
+ ## Supported config sources
41
+
42
+ | Type | Watch mode | Import | Description |
43
+ | ------ | ---------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
44
+ | Envs | No | `@tsed/config/envs` | Load environment variables from the process.env object. |
45
+ | DotEnv | Yes | `@tsed/config/dotenv` | Load environment variables from .env files. Supports [dotenv-flow](https://www.npmjs.com/package/dotenv-flow) and [dotenv-expand](https://www.npmjs.com/package/dotenv-expand). |
46
+ | Json | Yes | `@tsed/config/json` | Load configuration from a JSON file. Supports watch mode to reload the configuration when the file changes. |
47
+ | YAML | Yes | `@tsed/config/yaml` | Load configuration from a YAML file. Supports watch mode to reload the configuration when the file changes. |
48
+
49
+ ## Usage
50
+
51
+ ### Import the module
52
+
53
+ ```typescript
54
+ import {Configuration} from "@tsed/di";
55
+ import "@tsed/config";
56
+ import {EnvsConfigSource} from "@tsed/config/envs";
57
+ import {JsonConfigSource} from "@tsed/config/json";
58
+ import {withOptions} from "@tsed/config";
59
+
60
+ @Configuration({
61
+ extends: [
62
+ withOptions(JsonConfigSource, {
63
+ path: "./config.json"
64
+ }),
65
+ EnvsConfigSource
66
+ ]
67
+ })
68
+ export class Server {}
69
+ ```
70
+
71
+ ### Use the configuration service
72
+
73
+ ```typescript
74
+ import {Injectable} from "@tsed/di";
75
+
76
+ @Injectable()
77
+ export class MyService {
78
+ @Constant("myConfigKey")
79
+ myConfigKey: string; // merge value from all sources
80
+
81
+ @Constant("configs.json.myConfigKey")
82
+ myConfigKeyFromJson: string; // get value from json file only
83
+
84
+ @Constant("configs.env.myConfigKey")
85
+ myConfigKeyFromEnv: string; // get value from env file only
86
+
87
+ constructor() {
88
+ console.log(this.myConfigKey); // "myValue"
89
+ }
90
+ }
91
+ ```
92
+
93
+ ### Naming a configuration source
94
+
95
+ You can name a configuration source by using the `name` option. This is useful when you have multiple sources and want
96
+ to differentiate between them.
97
+
98
+ ```typescript
99
+ import {Configuration} from "@tsed/di";
100
+ import "@tsed/config";
101
+ import {EnvsConfigSource} from "@tsed/config/envs";
102
+ import {JsonConfigSource} from "@tsed/config/json";
103
+ import {withOptions} from "@tsed/config";
104
+
105
+ @Configuration({
106
+ extends: [
107
+ withOptions(JsonConfigSource, {
108
+ name: "database",
109
+ path: "./db.json"
110
+ }),
111
+ withOptions(JsonConfigSource, {
112
+ name: "server",
113
+ path: "./server.json"
114
+ }),
115
+ EnvsConfigSource
116
+ ]
117
+ })
118
+ export class Server {}
119
+ ```
120
+
121
+ Then you can use the `@Constant` decorator to inject the configuration value from a specific source:
122
+
123
+ ```typescript
124
+ import {Injectable} from "@tsed/di";
125
+
126
+ @Injectable()
127
+ export class MyService {
128
+ @Constant("configs.database.host")
129
+ databaseHost: string; // get value from json file only
130
+
131
+ @Constant("configs.server.port")
132
+ port: string; // get value from env file only
133
+ }
134
+ ```
135
+
136
+ ### Validate configuration
137
+
138
+ You can validate your configuration using the `validationSchema` option. This is useful to ensure that your
139
+ configuration values are of the expected type.
140
+
141
+ ```typescript
142
+ import {Configuration} from "@tsed/di";
143
+ import "@tsed/config";
144
+ import {string, object} from "@tsed/schema";
145
+ import {EnvsConfigSource} from "@tsed/config/envs";
146
+
147
+ @Configuration({
148
+ extends: [
149
+ withOptions(EnvsConfigSource, {
150
+ validationSchema: object({
151
+ DATABASE_HOST: string().required()
152
+ })
153
+ })
154
+ ]
155
+ })
156
+ export class Server {}
157
+ ```
158
+
159
+ ### Refresh strategy
160
+
161
+ #### Watch strategy
162
+
163
+ You can use the `watch` strategy to automatically reload your configuration when the file changes.
164
+ This is useful for development environments where you want to see changes immediately.
165
+
166
+ ```typescript
167
+ import {Configuration} from "@tsed/di";
168
+ import {withOptions} from "@tsed/config";
169
+ import {JsonConfigSource} from "@tsed/config/json";
170
+
171
+ @Configuration({
172
+ extends: [
173
+ withOptions(JsonConfigSource, {
174
+ watch: true
175
+ })
176
+ ]
177
+ })
178
+ export class Server {}
179
+ ```
180
+
181
+ #### Refresh on request strategy
182
+
183
+ You can use the `request` strategy to reload your configuration on each request.
184
+ This is useful for dynamic configurations that may change at runtime.
185
+
186
+ ```typescript
187
+ import {Configuration} from "@tsed/di";
188
+ import {withOptions} from "@tsed/config";
189
+ import {MyDbSourceConfig} from "./sources/DbSourceConfig.js";
190
+
191
+ @Configuration({
192
+ extends: [
193
+ withOptions(MyDbSourceConfig, {
194
+ refreshOn: "request"
195
+ })
196
+ ]
197
+ })
198
+ export class Server {}
199
+ ```
200
+
201
+ > Important: Use the `request` strategy with caution, as it can impact performance.
202
+ > It's recommended to use it only for configurations that are expected to change frequently.
203
+
204
+ #### Refresh on response strategy
205
+
206
+ You can use the `response` strategy to reload your configuration on each response.
207
+
208
+ This is useful for dynamic configurations that may change at runtime. This version is more efficient than the `request`
209
+ strategy, as it only reloads the configuration after a response is sent.
210
+
211
+ ```typescript
212
+ import {Configuration} from "@tsed/di";
213
+ import {withOptions} from "@tsed/config";
214
+ import {MyDbSourceConfig} from "./sources/DbSourceConfig.js";
215
+
216
+ @Configuration({
217
+ extends: [
218
+ withOptions(MyDbSourceConfig, {
219
+ refreshOn: "response"
220
+ })
221
+ ]
222
+ })
223
+ export class Server {}
224
+ ```
225
+
226
+ ### Enable config source on demand
227
+
228
+ You can enable a config source on demand by using the `enable` option. This is useful when you want to load a
229
+ configuration source only when needed.
230
+
231
+ ```typescript
232
+ import {Configuration} from "@tsed/di";
233
+ import {withOptions} from "@tsed/config";
234
+ import {MyDbSourceConfig} from "./sources/DbSourceConfig.js";
235
+
236
+ @Configuration({
237
+ extends: [
238
+ withOptions(MyDbSourceConfig, {
239
+ enable: process.env.NODE_ENV === "production"
240
+ })
241
+ ]
242
+ })
243
+ export class Server {}
244
+ ```
245
+
246
+ ### Create a custom configuration provider
247
+
248
+ You can create a custom configuration source by implementing the `ConfigSource` interface:
249
+
250
+ ```typescript
251
+ import type {ConfigSource} from "@tsed/config";
252
+
253
+ export interface MyCustomConfigSourceOptions {
254
+ // Custom options
255
+ }
256
+
257
+ export class MyCustomConfigSource implements ConfigSource<MyCustomConfigSourceOptions> {
258
+ options: MyCustomConfigSourceOptions;
259
+
260
+ async getAll(): Promise<Record<string, unknown>> {
261
+ return {
262
+ key: value
263
+ };
264
+ }
265
+ }
266
+ ```
267
+
268
+ Then use it in your configuration:
269
+
270
+ ```typescript
271
+ import {Configuration} from "@tsed/di";
272
+ import "@tsed/config";
273
+ import {MyCustomConfigSource} from "./MyCustomConfigSource.js";
274
+
275
+ @Configuration({
276
+ extends: [
277
+ MyCustomConfigSource,
278
+ // or with options
279
+ withOptions(MyCustomConfigSource, {
280
+ // options
281
+ })
282
+ ]
283
+ })
284
+ export class Server {}
285
+ ```
286
+
287
+ ### Implement watch method
288
+
289
+ You can implement the `watch` method to listen for changes in your configuration source. This is useful for dynamic
290
+ configurations that may change at runtime.
291
+
292
+ ```typescript
293
+ import {ConfigSource} from "@tsed/config";
294
+ import {watch} from "node:fs";
295
+
296
+ export interface MyCustomProviderOptions {
297
+ path: string;
298
+ }
299
+
300
+ export class MyCustomConfigSource implements ConfigSource<MyCustomConfigSourceOptions> {
301
+ options: MyCustomConfigSourceOptions;
302
+
303
+ async getAll(): Promise<Record<string, unknown>> {
304
+ const {path, encoding = "utf8"} = this.options;
305
+ // Read the file
306
+ const fileContent = readFileSync(path, encoding);
307
+
308
+ return JSON.parse(fileContent);
309
+ }
310
+
311
+ watch(onChange: () => void) {
312
+ const {path} = this.options;
313
+ const watcher = watch(path, onChange);
314
+
315
+ return () => {
316
+ watcher.close();
317
+ };
318
+ }
319
+ }
320
+ ```
321
+
322
+ ## Contributors
323
+
324
+ <a href="https://github.com/tsedio/tsed/graphs/contributors"><img src="https://opencollective.com/tsed/contributors.svg?width=890" /></a>
325
+
326
+ ## Backers
327
+
328
+ Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/tsed#backer)]
329
+
330
+ <a href="https://opencollective.com/tsed#backers" target="_blank"><img src="https://opencollective.com/tsed/tiers/backer.svg?width=890"></a>
331
+
332
+ ## Sponsors
333
+
334
+ Support this project by becoming a sponsor. Your logo will show up here with a link to your
335
+ website. [[Become a sponsor](https://opencollective.com/tsed#sponsor)]
336
+
337
+ ## License
338
+
339
+ The MIT License (MIT)
340
+
341
+ Copyright (c) 2016 - 2022 Romain Lenzotti
342
+
343
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
344
+ documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
345
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
346
+ persons to whom the Software is furnished to do so, subject to the following conditions:
347
+
348
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
349
+ Software.
350
+
351
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
352
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
353
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
354
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,4 @@
1
+ import {ConfigSource} from "../interfaces/ConfigSource.js";
2
+
3
+ export const CONFIG_SOURCES = Symbol.for("CONFIG_SOURCES");
4
+ export type CONFIG_SOURCES = Record<string, ConfigSource>;