runtime-config-loader 6.0.1 → 6.1.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
@@ -6,24 +6,102 @@ Most applications require certain configuration values that can be changed at ru
6
6
 
7
7
  This library provides an easy way to load one or more JSON files with configuration values or make one or more HTTP GET calls to an API endpoint that returns those values. The config objects that are returned from the call(s) will be combined into a single configuration object. You can then use that configuration throughout the application. The default location of the JSON file is in the `assets` folder, at `./assets/config.json`. When the service loads the file, it stores that configuration object in a local variable which can be accessed via the `getConfig()` and `getConfigObjectKey(key: string)` methods. `getConfig` returns the entire configuration object; `getConfigObjectKey(key: string)` returns part of the configuration object, namely the part defined by the key passed in. In some cases, the `config.json` is not finished loading before other modules/services are, so the above methods will return null. If that is the case, subscribe to the `configSubject` and access the configuration object that way.
8
8
 
9
- ## How to Implement
9
+ ### How to Implement
10
10
 
11
- In your `app.config.ts` file, add the following to the `providers` array:
11
+ In your Angular application's `app.config.ts` (or wherever you provide your environment providers), use `provideRuntimeConfig`:
12
12
 
13
13
  ```ts
14
14
  import { provideRuntimeConfig } from 'runtime-config-loader';
15
15
 
16
16
  export const appConfig: ApplicationConfig = {
17
- providers: [
18
- ...,
19
- provideRuntimeConfig({ configUrl: './assets/config.json' }),
20
- ...
21
- ]
17
+ providers: [
18
+ // ...,
19
+ provideRuntimeConfig({ configUrl: './assets/config.json' }),
20
+ // ...
21
+ ],
22
22
  };
23
23
  ```
24
24
 
25
25
  That's it; it's that simple. The `provideRuntimeConfig` function sets up the `APP_INITIALIZER` token to load the configuration from a file or an API endpoint before the application starts.
26
26
 
27
+ ### Type Safety with Generics
28
+
29
+ There are two main ways to use generics for type safety in your application.
30
+
31
+ #### Option 1: Using the `RUNTIME_CONFIG` Token (Recommended)
32
+
33
+ You can provide the type directly in `provideRuntimeConfig`. This also sets up the `RUNTIME_CONFIG` injection token, which you can use to inject the typed configuration object directly into your components or services.
34
+
35
+ ```ts
36
+ // app.config.ts
37
+ provideRuntimeConfig<MyConfig>({ configUrl: './assets/config.json' })
38
+
39
+ // component.ts
40
+ import { RUNTIME_CONFIG } from 'runtime-config-loader';
41
+
42
+ constructor(@Inject(RUNTIME_CONFIG) private config: MyConfig) {
43
+ console.log(this.config.apiUrl); // Fully typed!
44
+ }
45
+ ```
46
+
47
+ #### Option 2: Using the Service with a Type Alias
48
+
49
+ If you prefer to use the `RuntimeConfigLoaderService` methods (like `getConfigObjectKey`), you can define a type alias to avoid repeating the generic type everywhere.
50
+
51
+ ```ts
52
+ // config.service.ts
53
+ export type MyConfigService = RuntimeConfigLoaderService<MyConfig>;
54
+
55
+ // component.ts
56
+ constructor(private configSvc: MyConfigService) {
57
+ const apiUrl = this.configSvc.getConfigObjectKey('apiUrl'); // Typed as string | null
58
+ }
59
+ ```
60
+
61
+ #### Option 3: Specific Configuration Tokens
62
+
63
+ If you prefer your components to depend only on specific configuration values rather than the entire configuration object, you can use the `provideConfigToken` helper. This allows you to inject individual configuration properties cleanly and maintain strict boundaries.
64
+
65
+ ```ts
66
+ import { InjectionToken } from '@angular/core';
67
+ import { provideRuntimeConfig, provideConfigToken } from 'runtime-config-loader';
68
+
69
+ // 1. Define tokens for your specific configuration values
70
+ export const API_URL = new InjectionToken<string>('API_URL');
71
+
72
+ // 2. Provide them using the helper
73
+ export const appConfig: ApplicationConfig = {
74
+ providers: [
75
+ provideRuntimeConfig<MyConfig>({ configUrl: './assets/config.json' }),
76
+
77
+ // Provide the specific token mapping it to a key in your config
78
+ provideConfigToken(API_URL, 'apiUrl'),
79
+
80
+ // It also supports dot-notation for nested keys
81
+ // provideConfigToken(NESTED_TOKEN, 'api.baseUrl')
82
+ ],
83
+ };
84
+
85
+ // 3. Inject them directly
86
+ // component.ts
87
+ constructor(@Inject(API_URL) private apiUrl: string) {
88
+ console.log(this.apiUrl); // Typed as string | null
89
+ }
90
+ ```
91
+
92
+ ### Nested Key Access (Dot-Notation)
93
+
94
+ The `getConfigObjectKey` method supports dot-notation for accessing deeply nested configuration values.
95
+
96
+ ```ts
97
+ // For a config like: { api: { baseUrl: 'https://api.com' } }
98
+ const baseUrl = this.configSvc.getConfigObjectKey('api.baseUrl'); // Returns 'https://api.com'
99
+ ```
100
+
101
+ > [!NOTE]
102
+ > When using dot-notation for nested keys, the return type will be `any` unless you provide an explicit generic type to the call:
103
+ > `this.configSvc.getConfigObjectKey<string>('api.baseUrl')`
104
+
27
105
  ### Configuration
28
106
 
29
107
  The `provideRuntimeConfig` function accepts a configuration object with a `configUrl` property. This can be a single string or an array of strings.
@@ -51,7 +129,114 @@ provideRuntimeConfig({
51
129
 
52
130
  If an attribute is repeated in multiple configuration files, the latest value is kept. For example, if `apiUrl` exists in both files above, the value from `config-2.json` will override the value from `config-1.json`.
53
131
 
54
- > [!TIP]
55
- > This is useful for maintaining local overrides (e.g., `local.config.json` ignored by git) or separating environment-specific values from global ones.
132
+ #### Fallback Configuration
133
+
134
+ If you'd like the application to gracefully fall back to a default configuration in the event that the config file(s) fail to load (e.g., due to network errors or 404s), you can provide a `defaultConfig` object.
135
+
136
+ ```ts
137
+ provideRuntimeConfig({
138
+ configUrl: './assets/config.json',
139
+ defaultConfig: {
140
+ apiUrl: 'https://fallback.api.com',
141
+ theme: 'light',
142
+ },
143
+ });
144
+ ```
145
+
146
+ When a failure occurs and `defaultConfig` is provided, the application will emit a console warning (`Falling back to default configuration`), load the provided object, and proceed with initialization.
147
+
148
+ ### HTTP Options and Headers
149
+
150
+ You can pass standard Angular `HttpClient` options (such as custom `HttpHeaders` or `HttpContext`) to the underlying HTTP request doing the fetching.
151
+
152
+ Pass an `options` object into the `provideRuntimeConfig` function:
153
+
154
+ ```ts
155
+ import { HttpHeaders } from '@angular/common/http';
156
+
157
+ provideRuntimeConfig({
158
+ configUrl: './assets/config.json',
159
+ options: {
160
+ headers: new HttpHeaders({
161
+ Authorization: 'Bearer YOUR_TOKEN_HERE',
162
+ 'X-Custom-Header': 'custom-value',
163
+ }),
164
+ withCredentials: true,
165
+ },
166
+ });
167
+ ```
168
+
169
+ This is useful for APIs that require authentication or tracking headers to return configuration data.
170
+
171
+ ### Runtime Schema Validation
172
+
173
+ You can provide an optional `validator` function to verify the configuration before the application starts. If validation fails (returns `false`, throws an error, or emits an error), the configuration will be set to `null`.
174
+
175
+ The validator supports synchronous results, `Promise<boolean>`, and `Observable<boolean>`.
176
+
177
+ ```ts
178
+ provideRuntimeConfig<MyConfig>({
179
+ configUrl: './assets/config.json',
180
+ validator: (config) => {
181
+ return !!config.apiUrl && !!config.apiKey;
182
+ },
183
+ });
184
+ ```
185
+
186
+ #### Integration with Zod
187
+
188
+ This feature integrates well with schema validation libraries like [Zod](https://zod.dev):
189
+
190
+ ```ts
191
+ import { z } from 'zod';
192
+
193
+ const ConfigSchema = z.object({
194
+ apiUrl: z.string().url(),
195
+ apiKey: z.string().min(10),
196
+ });
197
+
198
+ provideRuntimeConfig({
199
+ configUrl: './assets/config.json',
200
+ validator: (config) => ConfigSchema.safeParse(config).success,
201
+ });
202
+ ```
56
203
 
57
204
  Make sure that the path(s) you provide are accessible by the Angular application. The `assets` folder is generally the easiest place to serve these files.
205
+
206
+ ### Testing
207
+
208
+ When writing unit tests for components or services that depend on `RUNTIME_CONFIG` or `RuntimeConfigLoaderService`, you can easily mock the configuration using the `provideMockRuntimeConfig` utility.
209
+
210
+ This avoids making HTTP requests and allows you to instantly return a mocked configuration object of your choosing.
211
+
212
+ ```ts
213
+ import { TestBed } from '@angular/core/testing';
214
+ import {
215
+ provideMockRuntimeConfig,
216
+ RUNTIME_CONFIG,
217
+ RuntimeConfigLoaderService,
218
+ } from 'runtime-config-loader';
219
+
220
+ describe('MyComponent', () => {
221
+ beforeEach(() => {
222
+ TestBed.configureTestingModule({
223
+ providers: [
224
+ // Provide the mock configuration object
225
+ provideMockRuntimeConfig({
226
+ apiUrl: 'https://mock-api.com',
227
+ theme: 'dark',
228
+ }),
229
+ ],
230
+ });
231
+ });
232
+
233
+ it('should use the mocked config', () => {
234
+ const config = TestBed.inject(RUNTIME_CONFIG);
235
+ expect(config.apiUrl).toBe('https://mock-api.com');
236
+
237
+ // If testing something that uses the service directly:
238
+ const service = TestBed.inject(RuntimeConfigLoaderService);
239
+ expect(service.getConfigObjectKey('theme')).toBe('dark');
240
+ });
241
+ });
242
+ ```
@@ -1,62 +1,102 @@
1
1
  import { HttpClient, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
2
2
  import * as i0 from '@angular/core';
3
- import { inject, Injectable, provideAppInitializer, makeEnvironmentProviders } from '@angular/core';
4
- import { Subject, forkJoin, of } from 'rxjs';
5
- import { tap, catchError, take } from 'rxjs/operators';
3
+ import { inject, Injectable, InjectionToken, provideAppInitializer, makeEnvironmentProviders } from '@angular/core';
4
+ import { ReplaySubject, forkJoin, isObservable, of, from } from 'rxjs';
5
+ import { map, catchError, switchMap, tap, take } from 'rxjs/operators';
6
6
 
7
7
  class RuntimeConfig {
8
8
  constructor(obj = {}) {
9
9
  this.configUrl = obj.configUrl || './assets/config.json';
10
+ this.defaultConfig = obj.defaultConfig;
11
+ this.validator = obj.validator;
12
+ this.options = obj.options;
10
13
  }
11
14
  }
12
15
 
13
16
  class RuntimeConfigLoaderService {
14
17
  constructor() {
15
18
  this.configUrl = './assets/config.json';
16
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
19
  this.configObject = null;
18
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
- this.configSubject = new Subject();
20
+ this.configSubject = new ReplaySubject(1);
20
21
  this._http = inject(HttpClient);
21
22
  this._config = inject(RuntimeConfig, { optional: true });
22
23
  if (this._config) {
23
24
  this.configUrl = this._config.configUrl;
24
25
  }
25
26
  }
26
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
27
  loadConfig() {
28
28
  const urls = Array.isArray(this.configUrl)
29
29
  ? this.configUrl
30
30
  : [this.configUrl];
31
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
31
  const observables = urls.map((url) => this.makeHttpCall(url));
33
- return forkJoin(observables).pipe(
34
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
- tap((configDataArray) => {
36
- this.configObject = configDataArray.reduce(
37
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
- (acc, configData) => {
32
+ return forkJoin(observables).pipe(map((configDataArray) => {
33
+ const combinedConfig = configDataArray.reduce((acc, configData) => {
39
34
  return { ...acc, ...configData };
40
35
  }, {});
36
+ if (this._config && this._config.validator) {
37
+ const validationResult = this._config.validator(combinedConfig);
38
+ if (isObservable(validationResult)) {
39
+ return validationResult.pipe(map((isValid) => this.handleValidationResult(isValid, combinedConfig)), catchError((err) => {
40
+ console.error('Config validation error', err);
41
+ return of(this.handleValidationResult(false));
42
+ }));
43
+ }
44
+ else if (validationResult instanceof Promise) {
45
+ return from(validationResult).pipe(map((isValid) => this.handleValidationResult(isValid, combinedConfig)), catchError((err) => {
46
+ console.error('Config validation error', err);
47
+ return of(this.handleValidationResult(false));
48
+ }));
49
+ }
50
+ else {
51
+ const isValid = validationResult === undefined ||
52
+ validationResult === true;
53
+ return of(this.handleValidationResult(isValid, combinedConfig));
54
+ }
55
+ }
56
+ return of(this.handleValidationResult(true, combinedConfig));
57
+ }), switchMap((obs) => obs), tap((config) => {
58
+ this.configObject = config;
41
59
  this.configSubject.next(this.configObject);
42
- }),
43
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
- catchError((err) => {
45
- console.error('Error loading config: ', err);
46
- this.configObject = null;
60
+ }), catchError((err) => {
61
+ console.error('Error loading config', err);
62
+ if (this._config && this._config.defaultConfig !== undefined) {
63
+ console.warn('Falling back to default configuration');
64
+ this.configObject = this._config.defaultConfig;
65
+ }
66
+ else {
67
+ this.configObject = null;
68
+ }
47
69
  this.configSubject.next(this.configObject);
48
- return of(null);
70
+ return of(this.configObject);
49
71
  }));
50
72
  }
51
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
73
+ handleValidationResult(isValid, config) {
74
+ if (isValid === false) {
75
+ console.error('Config validation failed');
76
+ return null;
77
+ }
78
+ return config || null;
79
+ }
52
80
  makeHttpCall(url) {
53
- return this._http.get(url).pipe(take(1));
81
+ return this._http.get(url, this._config?.options).pipe(take(1));
54
82
  }
55
83
  getConfig() {
56
84
  return this.configObject;
57
85
  }
58
86
  getConfigObjectKey(key) {
59
- return this.configObject ? this.configObject[key] : null;
87
+ if (!this.configObject) {
88
+ return null;
89
+ }
90
+ if (typeof key === 'string' && key.indexOf('.') > -1) {
91
+ return this.getValueByPath(this.configObject, key);
92
+ }
93
+ return this.configObject[key] ?? null;
94
+ }
95
+ getValueByPath(obj, path) {
96
+ const value = path.split('.').reduce((prev, curr) => {
97
+ return prev ? prev[curr] : null;
98
+ }, obj);
99
+ return value ?? null;
60
100
  }
61
101
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: RuntimeConfigLoaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
62
102
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: RuntimeConfigLoaderService }); }
@@ -65,6 +105,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
65
105
  type: Injectable
66
106
  }], ctorParameters: () => [] });
67
107
 
108
+ const RUNTIME_CONFIG = new InjectionToken('RUNTIME_CONFIG');
68
109
  function initConfig(configSvc) {
69
110
  return () => configSvc.loadConfig();
70
111
  }
@@ -75,6 +116,11 @@ function provideRuntimeConfig(config) {
75
116
  useValue: config,
76
117
  },
77
118
  RuntimeConfigLoaderService,
119
+ {
120
+ provide: RUNTIME_CONFIG,
121
+ useFactory: (configSvc) => configSvc.getConfig(),
122
+ deps: [RuntimeConfigLoaderService],
123
+ },
78
124
  provideAppInitializer(() => {
79
125
  const initializerFn = initConfig(inject(RuntimeConfigLoaderService));
80
126
  return initializerFn();
@@ -83,10 +129,75 @@ function provideRuntimeConfig(config) {
83
129
  ];
84
130
  return makeEnvironmentProviders(providers);
85
131
  }
132
+ function provideConfigToken(token, key) {
133
+ return {
134
+ provide: token,
135
+ useFactory: (configSvc) => configSvc.getConfigObjectKey(key),
136
+ deps: [RuntimeConfigLoaderService],
137
+ };
138
+ }
139
+
140
+ class MockRuntimeConfigLoaderService {
141
+ constructor() {
142
+ this.configObject = null;
143
+ this.configSubject = new ReplaySubject(1);
144
+ }
145
+ loadConfig() {
146
+ this.configSubject.next(this.configObject);
147
+ return of(this.configObject);
148
+ }
149
+ getConfig() {
150
+ return this.configObject;
151
+ }
152
+ getConfigObjectKey(key) {
153
+ if (!this.configObject) {
154
+ return null;
155
+ }
156
+ if (typeof key === 'string' && key.indexOf('.') > -1) {
157
+ return this.getValueByPath(this.configObject, key);
158
+ }
159
+ return this.configObject[key] ?? null;
160
+ }
161
+ getValueByPath(obj, path) {
162
+ const value = path.split('.').reduce((prev, curr) => {
163
+ return prev ? prev[curr] : null;
164
+ }, obj);
165
+ return value ?? null;
166
+ }
167
+ setMockConfig(config) {
168
+ this.configObject = config;
169
+ this.configSubject.next(this.configObject);
170
+ }
171
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: MockRuntimeConfigLoaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
172
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: MockRuntimeConfigLoaderService }); }
173
+ }
174
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: MockRuntimeConfigLoaderService, decorators: [{
175
+ type: Injectable
176
+ }] });
177
+
178
+ function provideMockRuntimeConfig(mockConfig) {
179
+ const mockService = new MockRuntimeConfigLoaderService();
180
+ mockService.setMockConfig(mockConfig);
181
+ const providers = [
182
+ {
183
+ provide: RuntimeConfigLoaderService,
184
+ useValue: mockService,
185
+ },
186
+ {
187
+ provide: MockRuntimeConfigLoaderService,
188
+ useValue: mockService,
189
+ },
190
+ {
191
+ provide: RUNTIME_CONFIG,
192
+ useValue: mockConfig,
193
+ },
194
+ ];
195
+ return makeEnvironmentProviders(providers);
196
+ }
86
197
 
87
198
  /**
88
199
  * Generated bundle index. Do not edit.
89
200
  */
90
201
 
91
- export { RuntimeConfig, RuntimeConfigLoaderService, initConfig, provideRuntimeConfig };
202
+ export { MockRuntimeConfigLoaderService, RUNTIME_CONFIG, RuntimeConfig, RuntimeConfigLoaderService, initConfig, provideConfigToken, provideMockRuntimeConfig, provideRuntimeConfig };
92
203
  //# sourceMappingURL=runtime-config-loader.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-config-loader.mjs","sources":["../../../../libs/runtime-config-loader/src/lib/runtime-config.ts","../../../../libs/runtime-config-loader/src/lib/runtime-config-loader/runtime-config-loader.service.ts","../../../../libs/runtime-config-loader/src/lib/runtime-config-loader.provider.ts","../../../../libs/runtime-config-loader/src/runtime-config-loader.ts"],"sourcesContent":["export class RuntimeConfig {\n\tconfigUrl: string | string[];\n\n\tconstructor(obj: { configUrl?: string | string[] } = {}) {\n\t\tthis.configUrl = obj.configUrl || './assets/config.json';\n\t}\n}\n","import { HttpClient } from '@angular/common/http';\nimport { Injectable, inject } from '@angular/core';\nimport { RuntimeConfig } from '../runtime-config';\nimport { forkJoin, Observable, of, Subject } from 'rxjs';\nimport { catchError, take, tap } from 'rxjs/operators';\n\n@Injectable()\nexport class RuntimeConfigLoaderService {\n\tprivate configUrl: string | string[] = './assets/config.json';\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tprivate configObject: any = null;\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tpublic configSubject: Subject<any> = new Subject<any>();\n\n\tprivate _http = inject(HttpClient);\n\tprivate _config = inject(RuntimeConfig, { optional: true });\n\n\tconstructor() {\n\t\tif (this._config) {\n\t\t\tthis.configUrl = this._config.configUrl;\n\t\t}\n\t}\n\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tloadConfig(): Observable<any> {\n\t\tconst urls: string[] = Array.isArray(this.configUrl)\n\t\t\t? this.configUrl\n\t\t\t: [this.configUrl];\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\tconst observables: Observable<any>[] = urls.map((url) =>\n\t\t\tthis.makeHttpCall(url)\n\t\t);\n\n\t\treturn forkJoin(observables).pipe(\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\ttap((configDataArray: any[]) => {\n\t\t\t\tthis.configObject = configDataArray.reduce(\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t\t\t(acc, configData) => {\n\t\t\t\t\t\treturn { ...acc, ...configData };\n\t\t\t\t\t},\n\t\t\t\t\t{}\n\t\t\t\t);\n\n\t\t\t\tthis.configSubject.next(this.configObject);\n\t\t\t}),\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\tcatchError((err: any) => {\n\t\t\t\tconsole.error('Error loading config: ', err);\n\t\t\t\tthis.configObject = null;\n\t\t\t\tthis.configSubject.next(this.configObject);\n\t\t\t\treturn of(null);\n\t\t\t})\n\t\t);\n\t}\n\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tprivate makeHttpCall(url: string): Observable<any> {\n\t\treturn this._http.get(url).pipe(take(1));\n\t}\n\n\tgetConfig() {\n\t\treturn this.configObject;\n\t}\n\n\tgetConfigObjectKey(key: string) {\n\t\treturn this.configObject ? this.configObject[key] : null;\n\t}\n}\n","import {\n\tEnvironmentProviders,\n\tProvider,\n\tinject,\n\tmakeEnvironmentProviders,\n\tprovideAppInitializer,\n} from '@angular/core';\nimport {\n\tprovideHttpClient,\n\twithInterceptorsFromDi,\n} from '@angular/common/http';\nimport { RuntimeConfig } from './runtime-config';\nimport { RuntimeConfigLoaderService } from './runtime-config-loader/runtime-config-loader.service';\n\nexport function initConfig(configSvc: RuntimeConfigLoaderService) {\n\treturn () => configSvc.loadConfig();\n}\n\nexport function provideRuntimeConfig(\n\tconfig: RuntimeConfig\n): EnvironmentProviders {\n\tconst providers: (Provider | EnvironmentProviders)[] = [\n\t\t{\n\t\t\tprovide: RuntimeConfig,\n\t\t\tuseValue: config,\n\t\t},\n\t\tRuntimeConfigLoaderService,\n\t\tprovideAppInitializer(() => {\n\t\t\tconst initializerFn = initConfig(\n\t\t\t\tinject(RuntimeConfigLoaderService)\n\t\t\t);\n\t\t\treturn initializerFn();\n\t\t}),\n\t\tprovideHttpClient(withInterceptorsFromDi()),\n\t];\n\n\treturn makeEnvironmentProviders(providers);\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtime-config-loader.mjs","sources":["../../../../libs/runtime-config-loader/src/lib/runtime-config.ts","../../../../libs/runtime-config-loader/src/lib/runtime-config-loader/runtime-config-loader.service.ts","../../../../libs/runtime-config-loader/src/lib/runtime-config-loader.provider.ts","../../../../libs/runtime-config-loader/src/lib/testing/mock-runtime-config-loader.service.ts","../../../../libs/runtime-config-loader/src/lib/testing/provide-mock-runtime-config.ts","../../../../libs/runtime-config-loader/src/runtime-config-loader.ts"],"sourcesContent":["import { Observable } from 'rxjs';\nimport { HttpContext, HttpHeaders, HttpParams } from '@angular/common/http';\n\nexport class RuntimeConfig<T = any> {\n\tconfigUrl: string | string[];\n\tdefaultConfig?: T;\n\tvalidator?: (\n\t\tconfig: T\n\t) => boolean | Promise<boolean> | Observable<boolean> | void;\n\toptions?: {\n\t\theaders?: HttpHeaders | { [header: string]: string | string[] };\n\t\tcontext?: HttpContext;\n\t\tobserve?: 'body';\n\t\tparams?:\n\t\t\t| HttpParams\n\t\t\t| {\n\t\t\t\t\t[param: string]:\n\t\t\t\t\t\t| string\n\t\t\t\t\t\t| number\n\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t| ReadonlyArray<string | number | boolean>;\n\t\t\t };\n\t\treportProgress?: boolean;\n\t\tresponseType?: 'json';\n\t\twithCredentials?: boolean;\n\t};\n\n\tconstructor(\n\t\tobj: {\n\t\t\tconfigUrl?: string | string[];\n\t\t\tdefaultConfig?: T;\n\t\t\tvalidator?: (\n\t\t\t\tconfig: T\n\t\t\t) => boolean | Promise<boolean> | Observable<boolean> | void;\n\t\t\toptions?: {\n\t\t\t\theaders?: HttpHeaders | { [header: string]: string | string[] };\n\t\t\t\tcontext?: HttpContext;\n\t\t\t\tobserve?: 'body';\n\t\t\t\tparams?:\n\t\t\t\t\t| HttpParams\n\t\t\t\t\t| {\n\t\t\t\t\t\t\t[param: string]:\n\t\t\t\t\t\t\t\t| string\n\t\t\t\t\t\t\t\t| number\n\t\t\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t\t\t| ReadonlyArray<string | number | boolean>;\n\t\t\t\t\t };\n\t\t\t\treportProgress?: boolean;\n\t\t\t\tresponseType?: 'json';\n\t\t\t\twithCredentials?: boolean;\n\t\t\t};\n\t\t} = {}\n\t) {\n\t\tthis.configUrl = obj.configUrl || './assets/config.json';\n\t\tthis.defaultConfig = obj.defaultConfig;\n\t\tthis.validator = obj.validator;\n\t\tthis.options = obj.options;\n\t}\n}\n","import { HttpClient } from '@angular/common/http';\nimport { Injectable, inject } from '@angular/core';\nimport { RuntimeConfig } from '../runtime-config';\nimport {\n\tforkJoin,\n\tfrom,\n\tisObservable,\n\tObservable,\n\tof,\n\tReplaySubject,\n\tSubject,\n} from 'rxjs';\nimport { catchError, map, take, tap, switchMap } from 'rxjs/operators';\n\n@Injectable()\nexport class RuntimeConfigLoaderService<T = any> {\n\tprivate configUrl: string | string[] = './assets/config.json';\n\tprivate configObject: T | null = null;\n\tpublic configSubject: Subject<T | null> = new ReplaySubject<T | null>(1);\n\n\tprivate _http = inject(HttpClient);\n\tprivate _config = inject(RuntimeConfig, { optional: true });\n\n\tconstructor() {\n\t\tif (this._config) {\n\t\t\tthis.configUrl = this._config.configUrl;\n\t\t}\n\t}\n\n\tloadConfig(): Observable<T | null> {\n\t\tconst urls: string[] = Array.isArray(this.configUrl)\n\t\t\t? this.configUrl\n\t\t\t: [this.configUrl];\n\n\t\tconst observables: Observable<any>[] = urls.map((url) =>\n\t\t\tthis.makeHttpCall(url)\n\t\t);\n\n\t\treturn forkJoin(observables).pipe(\n\t\t\tmap((configDataArray: any[]) => {\n\t\t\t\tconst combinedConfig = configDataArray.reduce(\n\t\t\t\t\t(acc, configData) => {\n\t\t\t\t\t\treturn { ...acc, ...configData };\n\t\t\t\t\t},\n\t\t\t\t\t{} as T\n\t\t\t\t);\n\n\t\t\t\tif (this._config && this._config.validator) {\n\t\t\t\t\tconst validationResult =\n\t\t\t\t\t\tthis._config.validator(combinedConfig);\n\n\t\t\t\t\tif (isObservable(validationResult)) {\n\t\t\t\t\t\treturn validationResult.pipe(\n\t\t\t\t\t\t\tmap((isValid) =>\n\t\t\t\t\t\t\t\tthis.handleValidationResult(\n\t\t\t\t\t\t\t\t\tisValid,\n\t\t\t\t\t\t\t\t\tcombinedConfig\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tcatchError((err) => {\n\t\t\t\t\t\t\t\tconsole.error('Config validation error', err);\n\t\t\t\t\t\t\t\treturn of(this.handleValidationResult(false));\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t);\n\t\t\t\t\t} else if (validationResult instanceof Promise) {\n\t\t\t\t\t\treturn from(validationResult).pipe(\n\t\t\t\t\t\t\tmap((isValid) =>\n\t\t\t\t\t\t\t\tthis.handleValidationResult(\n\t\t\t\t\t\t\t\t\tisValid,\n\t\t\t\t\t\t\t\t\tcombinedConfig\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tcatchError((err) => {\n\t\t\t\t\t\t\t\tconsole.error('Config validation error', err);\n\t\t\t\t\t\t\t\treturn of(this.handleValidationResult(false));\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst isValid =\n\t\t\t\t\t\t\tvalidationResult === undefined ||\n\t\t\t\t\t\t\tvalidationResult === true;\n\t\t\t\t\t\treturn of(\n\t\t\t\t\t\t\tthis.handleValidationResult(isValid, combinedConfig)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn of(this.handleValidationResult(true, combinedConfig));\n\t\t\t}),\n\t\t\tswitchMap((obs) => obs),\n\t\t\ttap((config) => {\n\t\t\t\tthis.configObject = config;\n\t\t\t\tthis.configSubject.next(this.configObject);\n\t\t\t}),\n\t\t\tcatchError((err) => {\n\t\t\t\tconsole.error('Error loading config', err);\n\n\t\t\t\tif (this._config && this._config.defaultConfig !== undefined) {\n\t\t\t\t\tconsole.warn('Falling back to default configuration');\n\t\t\t\t\tthis.configObject = this._config.defaultConfig;\n\t\t\t\t} else {\n\t\t\t\t\tthis.configObject = null;\n\t\t\t\t}\n\n\t\t\t\tthis.configSubject.next(this.configObject);\n\t\t\t\treturn of(this.configObject);\n\t\t\t})\n\t\t) as Observable<T | null>;\n\t}\n\n\tprivate handleValidationResult(\n\t\tisValid: boolean | void,\n\t\tconfig?: T\n\t): T | null {\n\t\tif (isValid === false) {\n\t\t\tconsole.error('Config validation failed');\n\t\t\treturn null;\n\t\t}\n\t\treturn config || null;\n\t}\n\n\tprivate makeHttpCall(url: string): Observable<any> {\n\t\treturn this._http.get(url, this._config?.options).pipe(take(1));\n\t}\n\n\tgetConfig(): T | null {\n\t\treturn this.configObject;\n\t}\n\n\tgetConfigObjectKey<K extends keyof T>(key: K): T[K] | null;\n\tgetConfigObjectKey<R = any>(key: string): R | null;\n\tgetConfigObjectKey(key: any): any {\n\t\tif (!this.configObject) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (typeof key === 'string' && key.indexOf('.') > -1) {\n\t\t\treturn this.getValueByPath(this.configObject, key);\n\t\t}\n\n\t\treturn (this.configObject as any)[key] ?? null;\n\t}\n\n\tprivate getValueByPath(obj: any, path: string): any {\n\t\tconst value = path.split('.').reduce((prev, curr) => {\n\t\t\treturn prev ? prev[curr] : null;\n\t\t}, obj);\n\t\treturn value ?? null;\n\t}\n}\n","import {\n\tEnvironmentProviders,\n\tInjectionToken,\n\tProvider,\n\tinject,\n\tmakeEnvironmentProviders,\n\tprovideAppInitializer,\n} from '@angular/core';\nimport {\n\tprovideHttpClient,\n\twithInterceptorsFromDi,\n} from '@angular/common/http';\nimport { RuntimeConfig } from './runtime-config';\nimport { RuntimeConfigLoaderService } from './runtime-config-loader/runtime-config-loader.service';\n\nexport const RUNTIME_CONFIG = new InjectionToken<any>('RUNTIME_CONFIG');\n\nexport function initConfig(configSvc: RuntimeConfigLoaderService) {\n\treturn () => configSvc.loadConfig();\n}\n\nexport function provideRuntimeConfig<T = any>(\n\tconfig: RuntimeConfig<T>\n): EnvironmentProviders {\n\tconst providers: (Provider | EnvironmentProviders)[] = [\n\t\t{\n\t\t\tprovide: RuntimeConfig,\n\t\t\tuseValue: config,\n\t\t},\n\t\tRuntimeConfigLoaderService,\n\t\t{\n\t\t\tprovide: RUNTIME_CONFIG,\n\t\t\tuseFactory: (configSvc: RuntimeConfigLoaderService<T>) =>\n\t\t\t\tconfigSvc.getConfig(),\n\t\t\tdeps: [RuntimeConfigLoaderService],\n\t\t},\n\t\tprovideAppInitializer(() => {\n\t\t\tconst initializerFn = initConfig(\n\t\t\t\tinject(RuntimeConfigLoaderService)\n\t\t\t);\n\t\t\treturn initializerFn();\n\t\t}),\n\t\tprovideHttpClient(withInterceptorsFromDi()),\n\t];\n\n\treturn makeEnvironmentProviders(providers);\n}\n\nexport function provideConfigToken<T, K extends keyof T>(\n\ttoken: InjectionToken<T[K]>,\n\tkey: K\n): Provider;\nexport function provideConfigToken<R = any>(\n\ttoken: InjectionToken<R>,\n\tpath: string\n): Provider;\nexport function provideConfigToken(\n\ttoken: InjectionToken<any>,\n\tkey: any\n): Provider {\n\treturn {\n\t\tprovide: token,\n\t\tuseFactory: (configSvc: RuntimeConfigLoaderService) =>\n\t\t\tconfigSvc.getConfigObjectKey(key),\n\t\tdeps: [RuntimeConfigLoaderService],\n\t};\n}\n","import { Injectable } from '@angular/core';\nimport { Observable, of, Subject, ReplaySubject } from 'rxjs';\nimport { RuntimeConfigLoaderService } from '../runtime-config-loader/runtime-config-loader.service';\n\n@Injectable()\nexport class MockRuntimeConfigLoaderService<T = any>\n\timplements Partial<RuntimeConfigLoaderService<T>>\n{\n\tprivate configObject: T | null = null;\n\tpublic configSubject: Subject<T | null> = new ReplaySubject<T | null>(1);\n\n\tloadConfig(): Observable<T | null> {\n\t\tthis.configSubject.next(this.configObject);\n\t\treturn of(this.configObject);\n\t}\n\n\tgetConfig(): T | null {\n\t\treturn this.configObject;\n\t}\n\n\tgetConfigObjectKey<K extends keyof T>(key: K): T[K] | null;\n\tgetConfigObjectKey<R = any>(key: string): R | null;\n\tgetConfigObjectKey(key: any): any {\n\t\tif (!this.configObject) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (typeof key === 'string' && key.indexOf('.') > -1) {\n\t\t\treturn this.getValueByPath(this.configObject, key);\n\t\t}\n\n\t\treturn (this.configObject as any)[key] ?? null;\n\t}\n\n\tprivate getValueByPath(obj: any, path: string): any {\n\t\tconst value = path.split('.').reduce((prev, curr) => {\n\t\t\treturn prev ? prev[curr] : null;\n\t\t}, obj);\n\t\treturn value ?? null;\n\t}\n\n\tsetMockConfig(config: T): void {\n\t\tthis.configObject = config;\n\t\tthis.configSubject.next(this.configObject);\n\t}\n}\n","import {\n\tEnvironmentProviders,\n\tProvider,\n\tmakeEnvironmentProviders,\n} from '@angular/core';\nimport { RUNTIME_CONFIG } from '../runtime-config-loader.provider';\nimport { RuntimeConfigLoaderService } from '../runtime-config-loader/runtime-config-loader.service';\nimport { MockRuntimeConfigLoaderService } from './mock-runtime-config-loader.service';\n\nexport function provideMockRuntimeConfig<T = any>(\n\tmockConfig: T\n): EnvironmentProviders {\n\tconst mockService = new MockRuntimeConfigLoaderService<T>();\n\tmockService.setMockConfig(mockConfig);\n\n\tconst providers: Provider[] = [\n\t\t{\n\t\t\tprovide: RuntimeConfigLoaderService,\n\t\t\tuseValue: mockService,\n\t\t},\n\t\t{\n\t\t\tprovide: MockRuntimeConfigLoaderService,\n\t\t\tuseValue: mockService,\n\t\t},\n\t\t{\n\t\t\tprovide: RUNTIME_CONFIG,\n\t\t\tuseValue: mockConfig,\n\t\t},\n\t];\n\n\treturn makeEnvironmentProviders(providers);\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runtime-config-loader",
3
- "version": "6.0.1",
3
+ "version": "6.1.0",
4
4
  "author": {
5
5
  "email": "preston.j.lamb@gmail.com",
6
6
  "name": "Preston Lamb",
Binary file
@@ -1,31 +1,83 @@
1
1
  import * as rxjs from 'rxjs';
2
- import { Subject, Observable } from 'rxjs';
2
+ import { Observable, Subject } from 'rxjs';
3
+ import { HttpHeaders, HttpContext, HttpParams } from '@angular/common/http';
3
4
  import * as i0 from '@angular/core';
4
- import { EnvironmentProviders } from '@angular/core';
5
+ import { InjectionToken, Provider, EnvironmentProviders } from '@angular/core';
5
6
 
6
- declare class RuntimeConfig {
7
+ declare class RuntimeConfig<T = any> {
7
8
  configUrl: string | string[];
9
+ defaultConfig?: T;
10
+ validator?: (config: T) => boolean | Promise<boolean> | Observable<boolean> | void;
11
+ options?: {
12
+ headers?: HttpHeaders | {
13
+ [header: string]: string | string[];
14
+ };
15
+ context?: HttpContext;
16
+ observe?: 'body';
17
+ params?: HttpParams | {
18
+ [param: string]: string | number | boolean | ReadonlyArray<string | number | boolean>;
19
+ };
20
+ reportProgress?: boolean;
21
+ responseType?: 'json';
22
+ withCredentials?: boolean;
23
+ };
8
24
  constructor(obj?: {
9
25
  configUrl?: string | string[];
26
+ defaultConfig?: T;
27
+ validator?: (config: T) => boolean | Promise<boolean> | Observable<boolean> | void;
28
+ options?: {
29
+ headers?: HttpHeaders | {
30
+ [header: string]: string | string[];
31
+ };
32
+ context?: HttpContext;
33
+ observe?: 'body';
34
+ params?: HttpParams | {
35
+ [param: string]: string | number | boolean | ReadonlyArray<string | number | boolean>;
36
+ };
37
+ reportProgress?: boolean;
38
+ responseType?: 'json';
39
+ withCredentials?: boolean;
40
+ };
10
41
  });
11
42
  }
12
43
 
13
- declare class RuntimeConfigLoaderService {
44
+ declare class RuntimeConfigLoaderService<T = any> {
14
45
  private configUrl;
15
46
  private configObject;
16
- configSubject: Subject<any>;
47
+ configSubject: Subject<T | null>;
17
48
  private _http;
18
49
  private _config;
19
50
  constructor();
20
- loadConfig(): Observable<any>;
51
+ loadConfig(): Observable<T | null>;
52
+ private handleValidationResult;
21
53
  private makeHttpCall;
22
- getConfig(): any;
23
- getConfigObjectKey(key: string): any;
24
- static ɵfac: i0.ɵɵFactoryDeclaration<RuntimeConfigLoaderService, never>;
25
- static ɵprov: i0.ɵɵInjectableDeclaration<RuntimeConfigLoaderService>;
54
+ getConfig(): T | null;
55
+ getConfigObjectKey<K extends keyof T>(key: K): T[K] | null;
56
+ getConfigObjectKey<R = any>(key: string): R | null;
57
+ private getValueByPath;
58
+ static ɵfac: i0.ɵɵFactoryDeclaration<RuntimeConfigLoaderService<any>, never>;
59
+ static ɵprov: i0.ɵɵInjectableDeclaration<RuntimeConfigLoaderService<any>>;
26
60
  }
27
61
 
62
+ declare const RUNTIME_CONFIG: InjectionToken<any>;
28
63
  declare function initConfig(configSvc: RuntimeConfigLoaderService): () => rxjs.Observable<any>;
29
- declare function provideRuntimeConfig(config: RuntimeConfig): EnvironmentProviders;
64
+ declare function provideRuntimeConfig<T = any>(config: RuntimeConfig<T>): EnvironmentProviders;
65
+ declare function provideConfigToken<T, K extends keyof T>(token: InjectionToken<T[K]>, key: K): Provider;
66
+ declare function provideConfigToken<R = any>(token: InjectionToken<R>, path: string): Provider;
30
67
 
31
- export { RuntimeConfig, RuntimeConfigLoaderService, initConfig, provideRuntimeConfig };
68
+ declare class MockRuntimeConfigLoaderService<T = any> implements Partial<RuntimeConfigLoaderService<T>> {
69
+ private configObject;
70
+ configSubject: Subject<T | null>;
71
+ loadConfig(): Observable<T | null>;
72
+ getConfig(): T | null;
73
+ getConfigObjectKey<K extends keyof T>(key: K): T[K] | null;
74
+ getConfigObjectKey<R = any>(key: string): R | null;
75
+ private getValueByPath;
76
+ setMockConfig(config: T): void;
77
+ static ɵfac: i0.ɵɵFactoryDeclaration<MockRuntimeConfigLoaderService<any>, never>;
78
+ static ɵprov: i0.ɵɵInjectableDeclaration<MockRuntimeConfigLoaderService<any>>;
79
+ }
80
+
81
+ declare function provideMockRuntimeConfig<T = any>(mockConfig: T): EnvironmentProviders;
82
+
83
+ export { MockRuntimeConfigLoaderService, RUNTIME_CONFIG, RuntimeConfig, RuntimeConfigLoaderService, initConfig, provideConfigToken, provideMockRuntimeConfig, provideRuntimeConfig };
Binary file