@travetto/config 2.1.5 → 2.2.0

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.
package/README.md CHANGED
@@ -116,9 +116,10 @@ $ node @travetto/boot/bin/main ./doc/dbconfig-run.ts
116
116
  errors: [
117
117
  {
118
118
  kind: 'required',
119
- active: true,
119
+ value: undefined,
120
+ message: 'port is required',
120
121
  path: 'port',
121
- message: 'port is required'
122
+ type: undefined
122
123
  }
123
124
  ]
124
125
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@travetto/config",
3
3
  "displayName": "Configuration",
4
- "version": "2.1.5",
4
+ "version": "2.2.0",
5
5
  "description": "Environment-aware config management using yaml files",
6
6
  "keywords": [
7
7
  "yaml",
@@ -28,12 +28,12 @@
28
28
  "directory": "module/config"
29
29
  },
30
30
  "dependencies": {
31
- "@travetto/schema": "^2.1.5",
32
- "@travetto/transformer": "^2.1.4",
33
- "@travetto/yaml": "^2.1.4"
31
+ "@travetto/schema": "^2.2.0",
32
+ "@travetto/transformer": "^2.2.0",
33
+ "@travetto/yaml": "^2.2.0"
34
34
  },
35
35
  "devDependencies": {
36
- "@travetto/di": "^2.1.5"
36
+ "@travetto/di": "^2.2.0"
37
37
  },
38
38
  "publishConfig": {
39
39
  "access": "public"
package/src/decorator.ts CHANGED
@@ -7,10 +7,10 @@ import { ConfigManager } from './manager';
7
7
  * @augments `@trv:di/Injectable`
8
8
  */
9
9
  export function Config(ns: string, params?: { internal?: boolean }) {
10
- return <T extends Class>(target: T) => {
10
+ return <T extends Class>(target: T): T => {
11
11
  const og = target.prototype.postConstruct;
12
12
 
13
- target.prototype.postConstruct = async function () {
13
+ target.prototype.postConstruct = async function (): Promise<void> {
14
14
  // Apply config
15
15
  await ConfigManager.install(target, this, ns, params?.internal);
16
16
  if (og) {
@@ -10,7 +10,7 @@ export class ConfigUtil {
10
10
  /**
11
11
  * Find the key using case insensitive search
12
12
  */
13
- static #getKeyName(key: string, fields: string[]) {
13
+ static #getKeyName(key: string, fields: string[]): string | undefined {
14
14
  key = key.trim();
15
15
  const match = new RegExp(key, 'i');
16
16
  const next = fields.find(x => match.test(x));
@@ -20,7 +20,7 @@ export class ConfigUtil {
20
20
  /**
21
21
  * Takes a env var, and produces a partial object against a schema definition. Does not support arrays, only objects.
22
22
  */
23
- static #expandEnvEntry(cls: Class, key: string, value: unknown) {
23
+ static #expandEnvEntry(cls: Class, key: string, value: unknown): Record<string, unknown> | undefined {
24
24
  const parts = key.split('_');
25
25
 
26
26
  const lastPart = parts.pop()!;
@@ -49,6 +49,7 @@ export class ConfigUtil {
49
49
  break;
50
50
  }
51
51
  }
52
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
52
53
  data = ((data[part!] ??= {}) as Record<string, unknown>); // Recurse
53
54
  }
54
55
 
@@ -65,11 +66,11 @@ export class ConfigUtil {
65
66
  * Bind the environment variables onto an object structure when they match by name.
66
67
  * Will split on _ to handle nesting appropriately
67
68
  */
68
- static getEnvOverlay(cls: Class, ns: string) {
69
+ static getEnvOverlay(cls: Class, ns: string): Record<string, unknown> {
69
70
  // Handle process.env on bind as the structure we need may not
70
71
  // fully exist until the config has been created
71
72
  const nsRe = new RegExp(`^${ns.replace(/[.]/g, '_')}`, 'i'); // Check is case insensitive
72
- const data = {};
73
+ const data: Record<string, unknown> = {};
73
74
  for (const [k, v] of Object.entries(process.env)) { // Find all keys that match ns
74
75
  if (k.includes('_') && nsRe.test(k)) { // Require at least one level (nothing should be at the top level as all configs are namespaced)
75
76
  Util.deepAssign(data, this.#expandEnvEntry(cls, ns ? k.substring(ns.length + 1) : k, v), 'coerce');
@@ -83,7 +84,7 @@ export class ConfigUtil {
83
84
  */
84
85
  static async getConfigFileAsData(file: string, ns: string = ''): Promise<Record<string, unknown>> {
85
86
  const data = await ResourceManager.read(file, 'utf8');
86
- const doc = YamlUtil.parse(data) as Record<string, unknown>;
87
+ const doc = YamlUtil.parse<Record<string, unknown>>(data);
87
88
  return ns ? { [ns]: doc } : doc;
88
89
  }
89
90
 
@@ -93,7 +94,7 @@ export class ConfigUtil {
93
94
  * @param ns
94
95
  * @returns
95
96
  */
96
- static lookupRoot(src: Record<string, unknown>, ns?: string, createIfMissing = false) {
97
+ static lookupRoot(src: Record<string, unknown>, ns?: string, createIfMissing = false): Record<string, unknown> {
97
98
  const parts = (ns ? ns.split('.') : []);
98
99
  let sub: Record<string, unknown> = src;
99
100
 
@@ -102,6 +103,7 @@ export class ConfigUtil {
102
103
  if (createIfMissing && !sub[next]) {
103
104
  sub[next] = {};
104
105
  }
106
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
105
107
  sub = sub[next] as Record<string, unknown>;
106
108
  }
107
109
 
@@ -121,6 +123,7 @@ export class ConfigUtil {
121
123
  full[k] = '*'.repeat(10);
122
124
  }
123
125
  }
126
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
124
127
  return BindUtil.expandPaths(full) as T;
125
128
  }
126
129
  }
package/src/manager.ts CHANGED
@@ -24,14 +24,14 @@ class $ConfigManager {
24
24
  'pw',
25
25
  ];
26
26
 
27
- protected getStorage() {
27
+ protected getStorage(): Record<string, unknown> {
28
28
  return this.#storage;
29
29
  }
30
30
 
31
31
  /**
32
32
  * Load all config files
33
33
  */
34
- async #load() {
34
+ async #load(): Promise<void> {
35
35
  const profileIndex = Object.fromEntries(Object.entries(AppManifest.env.profiles).map(([k, v]) => [v, +k] as const));
36
36
 
37
37
  const files = (await ResourceManager.findAll(/[.]ya?ml$/))
@@ -51,9 +51,9 @@ class $ConfigManager {
51
51
 
52
52
  /**
53
53
  * Get a sub tree of the config, or everything if namespace is not passed
54
- * @param ns The namespace of the config to search for, can be dotted for accesing sub namespaces
54
+ * @param ns The namespace of the config to search for, can be dotted for accessing sub namespaces
55
55
  */
56
- #get(ns?: string) {
56
+ #get(ns?: string): Record<string, unknown> {
57
57
  return ConfigUtil.lookupRoot(this.#storage, ns);
58
58
  }
59
59
 
@@ -64,7 +64,7 @@ class $ConfigManager {
64
64
  * - Resource {env}.yml
65
65
  * - Environment vars -> Overrides everything (happens at bind time)
66
66
  */
67
- async init() {
67
+ async init(): Promise<void> {
68
68
  if (!this.#initialized) {
69
69
  this.#initialized = true;
70
70
  await this.#load();
@@ -76,11 +76,12 @@ class $ConfigManager {
76
76
  * @param namespace If only a portion of the config should be exported
77
77
  * @param secure Determines if secrets should be redacted, defaults to true in prod, false otherwise
78
78
  */
79
- toJSON(secure: boolean = EnvUtil.isProd()) {
79
+ toJSON(secure: boolean = EnvUtil.isProd()): Record<string, unknown> {
80
80
  const copy = JSON.parse(JSON.stringify(this.#active));
81
81
  return secure ?
82
82
  ConfigUtil.sanitizeValuesByKey(copy, [
83
83
  ...this.#redactedKeys,
84
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
84
85
  ...(this.#get('config')?.redacted ?? []) as string[]
85
86
  ]) :
86
87
  copy;
@@ -92,7 +93,7 @@ class $ConfigManager {
92
93
  * @param item
93
94
  * @param namespace
94
95
  */
95
- bindTo<T>(cls: Class<T>, item: T, namespace: string) {
96
+ bindTo<T>(cls: Class<T>, item: T, namespace: string): T {
96
97
  if (!SchemaRegistry.has(cls)) {
97
98
  throw new AppError(`${cls.ᚕid} is not a valid schema class, config is not supported`);
98
99
  }
@@ -103,16 +104,16 @@ class $ConfigManager {
103
104
  return BindUtil.bindSchemaToObject(cls, item, cfg);
104
105
  }
105
106
 
106
- async install<T>(cls: Class<T>, item: T, namespace: string, internal?: boolean) {
107
+ async install<T>(cls: Class<T>, item: T, namespace: string, internal?: boolean): Promise<T> {
107
108
  const out = await this.bindTo(cls, item, namespace);
108
109
  try {
109
110
  await SchemaValidator.validate(cls, out);
110
- } catch (e) {
111
- if (e instanceof ValidationResultError) {
112
- e.message = `Failed to construct ${cls.ᚕid} as validation errors have occurred`;
113
- e.payload = { class: cls.ᚕid, file: cls.ᚕfile, ...(e.payload ?? {}) };
111
+ } catch (err) {
112
+ if (err instanceof ValidationResultError) {
113
+ err.message = `Failed to construct ${cls.ᚕid} as validation errors have occurred`;
114
+ err.payload = { class: cls.ᚕid, file: cls.ᚕfile, ...(err.payload ?? {}) };
114
115
  }
115
- throw e;
116
+ throw err;
116
117
  }
117
118
  if (out && !internal) {
118
119
  Util.deepAssign(ConfigUtil.lookupRoot(this.#active, namespace, true), out, 'coerce');
@@ -123,7 +124,7 @@ class $ConfigManager {
123
124
  /**
124
125
  * Reset
125
126
  */
126
- reset() {
127
+ reset(): void {
127
128
  this.#storage = {};
128
129
  this.#initialized = false;
129
130
  }
@@ -4,7 +4,7 @@
4
4
  export const init = {
5
5
  key: '@trv:config/init',
6
6
  before: ['@trv:registry/init'],
7
- async action() {
7
+ async action(): Promise<void> {
8
8
  const { ConfigManager } = await import('../src/manager');
9
9
  await ConfigManager.init();
10
10
  }