@travetto/config 7.0.0-rc.0 → 7.0.0-rc.2

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
@@ -13,7 +13,7 @@ npm install @travetto/config
13
13
  yarn add @travetto/config
14
14
  ```
15
15
 
16
- The config module provides support for loading application config on startup. Configuration values support the common [YAML](https://en.wikipedia.org/wiki/YAML) constructs as defined in [yaml](https://github.com/eemeli/yaml). Additionally, the configuration is built upon the [Schema](https://github.com/travetto/travetto/tree/main/module/schema#readme "Data type registry for runtime validation, reflection and binding.") module, to enforce type correctness, and allow for validation of configuration as an entrypoint into the application. Given that all [@Config](https://github.com/travetto/travetto/tree/main/module/config/src/decorator.ts#L13) classes are [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L19)-based classes, all the standard [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L19) and [@Field](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L21) functionality applies.
16
+ The config module provides support for loading application config on startup. Configuration values support the common [YAML](https://en.wikipedia.org/wiki/YAML) constructs as defined in [yaml](https://github.com/eemeli/yaml). Additionally, the configuration is built upon the [Schema](https://github.com/travetto/travetto/tree/main/module/schema#readme "Data type registry for runtime validation, reflection and binding.") module, to enforce type correctness, and allow for validation of configuration as an entrypoint into the application. Given that all [@Config](https://github.com/travetto/travetto/tree/main/module/config/src/decorator.ts#L13) classes are [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L19)-based classes, all the standard [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L19) and [@Field](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L23) functionality applies.
17
17
 
18
18
  ## Resolution
19
19
  The configuration information is comprised of:
@@ -104,27 +104,27 @@ The framework provides two simple base classes that assist with existing pattern
104
104
  **Code: Memory Provider**
105
105
  ```typescript
106
106
  import { ConfigData } from '../parser/types.ts';
107
- import { ConfigSource, ConfigSpec } from './types.ts';
107
+ import { ConfigSource, ConfigPayload } from './types.ts';
108
108
 
109
109
  /**
110
110
  * Meant to be instantiated and provided as a unique config source
111
111
  */
112
112
  export class MemoryConfigSource implements ConfigSource {
113
- #spec: ConfigSpec;
113
+ #payload: ConfigPayload;
114
114
 
115
115
  constructor(key: string, data: ConfigData, priority: number = 500) {
116
- this.#spec = { data, priority, source: `memory://${key}` };
116
+ this.#payload = { data, priority, source: `memory://${key}` };
117
117
  }
118
118
 
119
- get(): ConfigSpec {
120
- return this.#spec;
119
+ get(): ConfigPayload {
120
+ return this.#payload;
121
121
  }
122
122
  }
123
123
  ```
124
124
 
125
125
  **Code: Environment JSON Provider**
126
126
  ```typescript
127
- import { ConfigSource, ConfigSpec } from './types.ts';
127
+ import { ConfigSource, ConfigPayload } from './types.ts';
128
128
 
129
129
  /**
130
130
  * Represents the environment mapped data as a JSON blob
@@ -138,7 +138,7 @@ export class EnvConfigSource implements ConfigSource {
138
138
  this.#priority = priority;
139
139
  }
140
140
 
141
- get(): ConfigSpec | undefined {
141
+ get(): ConfigPayload | undefined {
142
142
  try {
143
143
  const data = JSON.parse(process.env[this.#envKey] || '{}');
144
144
  return { data, priority: this.#priority, source: `env://${this.#envKey}` };
@@ -154,12 +154,12 @@ In addition to files and environment variables, configuration sources can also b
154
154
 
155
155
  **Code: Custom Configuration Source**
156
156
  ```typescript
157
- import { ConfigSource, ConfigSpec } from '@travetto/config';
157
+ import { ConfigSource, ConfigPayload } from '@travetto/config';
158
158
  import { Injectable } from '@travetto/di';
159
159
 
160
160
  @Injectable()
161
161
  export class CustomConfigSource implements ConfigSource {
162
- async get(): Promise<ConfigSpec> {
162
+ async get(): Promise<ConfigPayload> {
163
163
  return {
164
164
  data: { user: { name: 'bob' } },
165
165
  source: 'custom://override',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/config",
3
- "version": "7.0.0-rc.0",
3
+ "version": "7.0.0-rc.2",
4
4
  "description": "Configuration support",
5
5
  "keywords": [
6
6
  "yaml",
@@ -26,8 +26,8 @@
26
26
  "directory": "module/config"
27
27
  },
28
28
  "dependencies": {
29
- "@travetto/di": "^7.0.0-rc.0",
30
- "@travetto/schema": "^7.0.0-rc.0",
29
+ "@travetto/di": "^7.0.0-rc.2",
30
+ "@travetto/schema": "^7.0.0-rc.2",
31
31
  "yaml": "^2.8.1"
32
32
  },
33
33
  "travetto": {
package/src/decorator.ts CHANGED
@@ -10,21 +10,21 @@ import { ConfigOverrideUtil } from './util.ts';
10
10
  * @augments `@travetto/schema:Schema`
11
11
  * @kind decorator
12
12
  */
13
- export function Config(ns: string) {
13
+ export function Config(namespace: string) {
14
14
  return <T extends Class>(cls: T): T => {
15
15
  // Declare as part of global config
16
16
  SchemaRegistryIndex.getForRegister(cls).register({ interfaces: [ConfigBaseType] });
17
17
 
18
- ConfigOverrideUtil.setOverrideConfig(cls, ns);
18
+ ConfigOverrideUtil.setOverrideConfig(cls, namespace);
19
19
 
20
20
  DependencyRegistryIndex.getForRegister(cls).registerClass();
21
21
 
22
- const og: Function = cls.prototype.postConstruct;
22
+ const handle: Function = cls.prototype.postConstruct;
23
23
  cls.prototype.postConstruct = async function (): Promise<void> {
24
24
  // Apply config
25
- const cfg = await DependencyRegistryIndex.getInstance(ConfigurationService);
26
- await cfg.bindTo(cls, this, ns);
27
- await og?.call(this);
25
+ const config = await DependencyRegistryIndex.getInstance(ConfigurationService);
26
+ await config.bindTo(cls, this, namespace);
27
+ await handle?.call(this);
28
28
  };
29
29
  return cls;
30
30
  };
@@ -16,7 +16,7 @@ export class ParserManager {
16
16
  const parsers = await DependencyRegistryIndex.getInstances(toConcrete<ConfigParser>());
17
17
 
18
18
  // Register parsers
19
- this.#parsers = Object.fromEntries(parsers.flatMap(p => p.ext.map(e => [e, p])));
19
+ this.#parsers = Object.fromEntries(parsers.flatMap(parser => parser.ext.map(ext => [ext, parser])));
20
20
  this.#extMatch = parsers.length ? new RegExp(`(${Object.keys(this.#parsers).join('|').replaceAll('.', '[.]')})`) : /^$/;
21
21
  }
22
22
 
package/src/service.ts CHANGED
@@ -6,11 +6,11 @@ import { BindUtil, DataUtil, SchemaRegistryIndex, SchemaValidator, ValidationRes
6
6
 
7
7
  import { ParserManager } from './parser/parser.ts';
8
8
  import { ConfigData } from './parser/types.ts';
9
- import { ConfigSource, ConfigSpec } from './source/types.ts';
9
+ import { ConfigSource, ConfigPayload } from './source/types.ts';
10
10
  import { FileConfigSource } from './source/file.ts';
11
11
  import { OverrideConfigSource } from './source/override.ts';
12
12
 
13
- type ConfigSpecSimple = Omit<ConfigSpec, 'data'>;
13
+ type ConfigSpecSimple = Omit<ConfigPayload, 'data'>;
14
14
 
15
15
  /**
16
16
  * Common Type for all configuration classes
@@ -24,15 +24,15 @@ export class ConfigBaseType { }
24
24
  export class ConfigurationService {
25
25
 
26
26
  #storage: Record<string, unknown> = {}; // Lowered, and flattened
27
- #specs: ConfigSpecSimple[] = [];
27
+ #payloads: ConfigSpecSimple[] = [];
28
28
  #secrets: (RegExp | string)[] = [/secure(-|_|[a-z])|password|private|secret|salt|(\bkey|key\b)|serviceAccount|(api(-|_)?key)/i];
29
29
 
30
30
  /**
31
31
  * Get a sub tree of the config, or everything if namespace is not passed
32
- * @param ns The namespace of the config to search for, can be dotted for accessing sub namespaces
32
+ * @param namespace The namespace of the config to search for, can be dotted for accessing sub namespaces
33
33
  */
34
- #get<T extends Record<string, unknown> = Record<string, unknown>>(ns?: string): T {
35
- const parts = (ns ? ns.split('.') : []);
34
+ #get<T extends Record<string, unknown> = Record<string, unknown>>(namespace?: string): T {
35
+ const parts = (namespace ? namespace.split('.') : []);
36
36
  let sub: Record<string, unknown> = this.#storage;
37
37
 
38
38
  while (parts.length && sub) {
@@ -53,7 +53,7 @@ export class ConfigurationService {
53
53
  const providers = await DependencyRegistryIndex.getCandidates(toConcrete<ConfigSource>());
54
54
 
55
55
  const configs = await Promise.all(
56
- providers.map(async (el) => await DependencyRegistryIndex.getInstance(el.candidateType, el.qualifier))
56
+ providers.map(async (candidate) => await DependencyRegistryIndex.getInstance<ConfigSource>(candidate.candidateType, candidate.qualifier))
57
57
  );
58
58
 
59
59
  const parser = await DependencyRegistryIndex.getInstance(ParserManager);
@@ -62,27 +62,27 @@ export class ConfigurationService {
62
62
  new FileConfigSource(parser),
63
63
  ...configs,
64
64
  new OverrideConfigSource()
65
- ].map(src => src.get()));
65
+ ].map(source => source.get()));
66
66
 
67
- const specs = possible
67
+ const payloads = possible
68
68
  .flat()
69
- .filter(x => !!x)
69
+ .filter(data => !!data)
70
70
  .toSorted((a, b) => a.priority - b.priority);
71
71
 
72
- for (const spec of specs) {
73
- DataUtil.deepAssign(this.#storage, BindUtil.expandPaths(spec.data), 'coerce');
72
+ for (const payload of payloads) {
73
+ DataUtil.deepAssign(this.#storage, BindUtil.expandPaths(payload.data), 'coerce');
74
74
  }
75
75
 
76
- this.#specs = specs.map(({ data: _, ...v }) => v);
76
+ this.#payloads = payloads.map(({ data: _, ...payload }) => payload);
77
77
 
78
78
  // Initialize Secrets
79
79
  const { secrets = [] } = this.#get<{ secrets?: string | string[] }>('config') ?? {};
80
- for (const el of [secrets].flat()) {
81
- if (typeof el === 'string') {
82
- if (el.startsWith('/')) {
83
- this.#secrets.push(DataUtil.coerceType(el, RegExp, true));
80
+ for (const value of [secrets].flat()) {
81
+ if (typeof value === 'string') {
82
+ if (value.startsWith('/')) {
83
+ this.#secrets.push(DataUtil.coerceType(value, RegExp, true));
84
84
  } else {
85
- this.#secrets.push(DataUtil.coerceType(el, String, true));
85
+ this.#secrets.push(DataUtil.coerceType(value, String, true));
86
86
  }
87
87
  }
88
88
  }
@@ -96,21 +96,21 @@ export class ConfigurationService {
96
96
  const configTargets = await DependencyRegistryIndex.getCandidates(ConfigBaseType);
97
97
  const configs = await Promise.all(
98
98
  configTargets
99
- .filter(el => el.qualifier === getDefaultQualifier(el.class)) // Is self targeting?
99
+ .filter(candidate => candidate.qualifier === getDefaultQualifier(candidate.class)) // Is self targeting?
100
100
  .toSorted((a, b) => a.class.name.localeCompare(b.class.name))
101
- .map(async el => {
102
- const inst = await DependencyRegistryIndex.getInstance(el.class, el.qualifier);
103
- return [el, inst] as const;
101
+ .map(async candidate => {
102
+ const inst = await DependencyRegistryIndex.getInstance(candidate.class, candidate.qualifier);
103
+ return [candidate, inst] as const;
104
104
  })
105
105
  );
106
106
  const out: Record<string, ConfigData> = {};
107
- for (const [el, inst] of configs) {
107
+ for (const [candidate, inst] of configs) {
108
108
  const data = BindUtil.bindSchemaToObject<ConfigData>(
109
- getClass(inst), {}, inst, { filterInput: f => !('secret' in f) || !f.secret, filterValue: v => v !== undefined }
109
+ getClass(inst), {}, inst, { filterInput: field => !('secret' in field) || !field.secret, filterValue: value => value !== undefined }
110
110
  );
111
- out[el.candidateType.name] = DataUtil.filterByKeys(data, this.#secrets);
111
+ out[candidate.candidateType.name] = DataUtil.filterByKeys(data, this.#secrets);
112
112
  }
113
- return { sources: this.#specs, active: out };
113
+ return { sources: this.#payloads, active: out };
114
114
  }
115
115
 
116
116
  /**
@@ -125,15 +125,15 @@ export class ConfigurationService {
125
125
  if (validate) {
126
126
  try {
127
127
  await SchemaValidator.validate(cls, item);
128
- } catch (err) {
129
- if (err instanceof ValidationResultError) {
130
- const ogMessage = err.message;
131
- err.message = `Failed to construct ${classId} as validation errors have occurred`;
132
- err.stack = err.stack?.replace(ogMessage, err.message);
128
+ } catch (error) {
129
+ if (error instanceof ValidationResultError) {
130
+ const originalMessage = error.message;
131
+ error.message = `Failed to construct ${classId} as validation errors have occurred`;
132
+ error.stack = error.stack?.replace(originalMessage, error.message);
133
133
  const imp = Runtime.getImport(cls);
134
- Object.defineProperty(err, 'details', { value: { class: classId, import: imp, ...(err.details ?? {}) } });
134
+ Object.defineProperty(error, 'details', { value: { class: classId, import: imp, ...(error.details ?? {}) } });
135
135
  }
136
- throw err;
136
+ throw error;
137
137
  }
138
138
  }
139
139
  return item;
package/src/source/env.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ConfigSource, ConfigSpec } from './types.ts';
1
+ import { ConfigSource, ConfigPayload } from './types.ts';
2
2
 
3
3
  /**
4
4
  * Represents the environment mapped data as a JSON blob
@@ -12,7 +12,7 @@ export class EnvConfigSource implements ConfigSource {
12
12
  this.#priority = priority;
13
13
  }
14
14
 
15
- get(): ConfigSpec | undefined {
15
+ get(): ConfigPayload | undefined {
16
16
  try {
17
17
  const data = JSON.parse(process.env[this.#envKey] || '{}');
18
18
  return { data, priority: this.#priority, source: `env://${this.#envKey}` };
@@ -3,7 +3,7 @@ import path from 'node:path';
3
3
 
4
4
  import { Env, Runtime, RuntimeResources } from '@travetto/runtime';
5
5
 
6
- import { ConfigSource, ConfigSpec } from './types.ts';
6
+ import { ConfigSource, ConfigPayload } from './types.ts';
7
7
  import { ParserManager } from '../parser/parser.ts';
8
8
 
9
9
  type Profile = [string, number] | readonly [string, number];
@@ -24,13 +24,13 @@ export class FileConfigSource implements ConfigSource {
24
24
  ['application', 100],
25
25
  [Runtime.env!, 200],
26
26
  ...(Env.TRV_PROFILES.list ?? [])
27
- .map((p, i) => [p, 300 + i * 10] as const)
28
- ] as const).filter(x => !!x[0]);
27
+ .map((profile, i) => [profile, 300 + i * 10] as const)
28
+ ] as const).filter(entry => !!entry[0]);
29
29
  }
30
30
 
31
- async get(): Promise<ConfigSpec[]> {
31
+ async get(): Promise<ConfigPayload[]> {
32
32
  const cache: Record<string, Promise<string[]>> = {};
33
- const configs: Promise<ConfigSpec>[] = [];
33
+ const configs: Promise<ConfigPayload>[] = [];
34
34
 
35
35
  for (const [profile, priority] of this.#profiles) {
36
36
  let i = priority;
@@ -1,17 +1,17 @@
1
1
  import { ConfigData } from '../parser/types.ts';
2
- import { ConfigSource, ConfigSpec } from './types.ts';
2
+ import { ConfigSource, ConfigPayload } from './types.ts';
3
3
 
4
4
  /**
5
5
  * Meant to be instantiated and provided as a unique config source
6
6
  */
7
7
  export class MemoryConfigSource implements ConfigSource {
8
- #spec: ConfigSpec;
8
+ #payload: ConfigPayload;
9
9
 
10
10
  constructor(key: string, data: ConfigData, priority: number = 500) {
11
- this.#spec = { data, priority, source: `memory://${key}` };
11
+ this.#payload = { data, priority, source: `memory://${key}` };
12
12
  }
13
13
 
14
- get(): ConfigSpec {
15
- return this.#spec;
14
+ get(): ConfigPayload {
15
+ return this.#payload;
16
16
  }
17
17
  }
@@ -1,5 +1,5 @@
1
1
  import { ConfigData } from '../parser/types.ts';
2
- import { ConfigSource, ConfigSpec } from './types.ts';
2
+ import { ConfigSource, ConfigPayload } from './types.ts';
3
3
  import { ConfigOverrideUtil } from '../util.ts';
4
4
 
5
5
  /**
@@ -11,16 +11,16 @@ export class OverrideConfigSource implements ConfigSource {
11
11
  const out: ConfigData = {};
12
12
  for (const { namespace, fields } of ConfigOverrideUtil.getAllOverrideConfigs()) {
13
13
  for (const [key, value] of Object.entries(fields)) {
14
- const val = value();
15
- if (val !== undefined && val !== '') {
16
- out[`${namespace}.${key}`] = val;
14
+ const data = value();
15
+ if (data !== undefined && data !== '') {
16
+ out[`${namespace}.${key}`] = data;
17
17
  }
18
18
  }
19
19
  }
20
20
  return out;
21
21
  }
22
22
 
23
- get(): ConfigSpec {
23
+ get(): ConfigPayload {
24
24
  return { data: this.#build(), priority: 999, source: 'memory://override' };
25
25
  }
26
26
  }
@@ -3,11 +3,11 @@ import { ConfigData } from '../parser/types.ts';
3
3
  type OrProm<T> = T | Promise<T>;
4
4
  type OneOf<T> = T[] | T | undefined;
5
5
 
6
- export type ConfigSpec = { data: ConfigData, priority: number, source: string, detail?: string };
6
+ export type ConfigPayload = { data: ConfigData, priority: number, source: string, detail?: string };
7
7
 
8
8
  /**
9
9
  * @concrete
10
10
  */
11
11
  export interface ConfigSource {
12
- get(): OrProm<OneOf<ConfigSpec>>;
12
+ get(): OrProm<OneOf<ConfigPayload>>;
13
13
  }
package/src/util.ts CHANGED
@@ -22,9 +22,9 @@ export class ConfigOverrideUtil {
22
22
  static getAllOverrideConfigs(): Required<OverrideConfig>[] {
23
23
  const out: Required<OverrideConfig>[] = [];
24
24
  for (const cls of SchemaRegistryIndex.getClasses()) {
25
- const cfg = this.getOverrideConfig(cls);
26
- if (cfg && cfg.fields && cfg.namespace) {
27
- out.push(asFull(cfg));
25
+ const config = this.getOverrideConfig(cls);
26
+ if (config && config.fields && config.namespace) {
27
+ out.push(asFull(config));
28
28
  }
29
29
  }
30
30
  return out;
@@ -35,7 +35,7 @@ export class ConfigOverrideUtil {
35
35
  .registerMetadata<OverrideConfig>(OverrideConfigSymbol, {});
36
36
 
37
37
  (env.fields ??= {})[field] = (): string | undefined =>
38
- process.env[names.find(x => !!process.env[x])!];
38
+ process.env[names.find(name => !!process.env[name])!];
39
39
  }
40
40
 
41
41
  static setOverrideConfig(cls: Class<Any>, namespace: string): void {