@devopsplaybook.io/common-utils 1.2.0-beta.7.3382b46 → 1.2.0-beta.7.fd32a5a
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/dist/src/ConfigBase.js +51 -5
- package/package.json +1 -1
- package/src/ConfigBase.ts +58 -7
package/dist/src/ConfigBase.js
CHANGED
|
@@ -40,6 +40,48 @@ exports.ConfigBase = void 0;
|
|
|
40
40
|
const fse = __importStar(require("fs-extra"));
|
|
41
41
|
const uuid_1 = require("uuid");
|
|
42
42
|
const path_1 = __importDefault(require("path"));
|
|
43
|
+
/**
|
|
44
|
+
* Coerce a string value read from an environment variable to match the
|
|
45
|
+
* type of the default value (number → parseFloat, boolean → "true"/"1",
|
|
46
|
+
* array → JSON.parse, etc.). When the default is already a string or
|
|
47
|
+
* there is no default, the original string is returned as-is.
|
|
48
|
+
*/
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
|
+
function coerceValue(value, defaultValue) {
|
|
51
|
+
if (defaultValue === undefined || defaultValue === null) {
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
switch (typeof defaultValue) {
|
|
55
|
+
case "number": {
|
|
56
|
+
const parsed = Number(value);
|
|
57
|
+
return Number.isNaN(parsed) ? value : parsed;
|
|
58
|
+
}
|
|
59
|
+
case "boolean": {
|
|
60
|
+
return value === "true" || value === "1" || value === "yes";
|
|
61
|
+
}
|
|
62
|
+
case "object": {
|
|
63
|
+
if (Array.isArray(defaultValue)) {
|
|
64
|
+
try {
|
|
65
|
+
return JSON.parse(value);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (defaultValue !== null) {
|
|
72
|
+
try {
|
|
73
|
+
return JSON.parse(value);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
default:
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
43
85
|
/**
|
|
44
86
|
* Abstract base class for project configuration.
|
|
45
87
|
*
|
|
@@ -94,7 +136,6 @@ class ConfigBase {
|
|
|
94
136
|
* Fields registered by subclasses (or the base) that {@link reload}
|
|
95
137
|
* should process. Common / DB / OTel fields are pre-registered.
|
|
96
138
|
*/
|
|
97
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
98
139
|
this._fields = [];
|
|
99
140
|
this.SERVICE_ID = serviceId;
|
|
100
141
|
this.CONFIG_FILE = configFile || process.env.CONFIG_FILE || "config.json";
|
|
@@ -120,7 +161,11 @@ class ConfigBase {
|
|
|
120
161
|
{ field: "DATABASE_POSTGRES_HOST", envAliases: ["POSTGRES_HOST"] },
|
|
121
162
|
{ field: "DATABASE_POSTGRES_PORT", envAliases: ["POSTGRES_PORT"] },
|
|
122
163
|
{ field: "DATABASE_POSTGRES_USER", envAliases: ["POSTGRES_USER"] },
|
|
123
|
-
{
|
|
164
|
+
{
|
|
165
|
+
field: "DATABASE_POSTGRES_PASSWORD",
|
|
166
|
+
sensitive: true,
|
|
167
|
+
envAliases: ["POSTGRES_PASSWORD"],
|
|
168
|
+
},
|
|
124
169
|
{ field: "DATABASE_POSTGRES_DATABASE", envAliases: ["POSTGRES_DB"] },
|
|
125
170
|
{ field: "OPENTELEMETRY_COLLECTOR_HTTP_TRACES" },
|
|
126
171
|
{ field: "OPENTELEMETRY_COLLECTOR_HTTP_METRICS" },
|
|
@@ -176,7 +221,7 @@ class ConfigBase {
|
|
|
176
221
|
log(`Configuration Value: CONFIG_FILE: ${this.CONFIG_FILE}`);
|
|
177
222
|
log(`Configuration Value: SERVICE_ID: ${this.SERVICE_ID}`);
|
|
178
223
|
log(`Configuration Value: VERSION: ${this.VERSION}`);
|
|
179
|
-
for (const { field, sensitive, envAliases } of this._fields) {
|
|
224
|
+
for (const { field, sensitive, envAliases, defaultValue } of this._fields) {
|
|
180
225
|
let from = "defaults";
|
|
181
226
|
let foundValue;
|
|
182
227
|
let usedAlias = false;
|
|
@@ -196,10 +241,11 @@ class ConfigBase {
|
|
|
196
241
|
}
|
|
197
242
|
}
|
|
198
243
|
}
|
|
199
|
-
// 3. Apply environment value (full name or alias) if found
|
|
244
|
+
// 3. Apply environment value (full name or alias) if found,
|
|
245
|
+
// coercing strings to match the default value type
|
|
200
246
|
if (foundValue !== undefined) {
|
|
201
247
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
202
|
-
this[field] = foundValue;
|
|
248
|
+
this[field] = coerceValue(foundValue, defaultValue);
|
|
203
249
|
}
|
|
204
250
|
// 4. Config file override (environment always wins, but if neither
|
|
205
251
|
// environment nor alias matched, check config file)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devopsplaybook.io/common-utils",
|
|
3
|
-
"version": "1.2.0-beta.7.
|
|
3
|
+
"version": "1.2.0-beta.7.fd32a5a",
|
|
4
4
|
"description": "Shared utility modules for devopsplaybook.io projects (DB, Config, OTel context, system helpers)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Open Telemetry",
|
package/src/ConfigBase.ts
CHANGED
|
@@ -53,6 +53,48 @@ export interface ConfigCommonInterface
|
|
|
53
53
|
LOG_LEVEL: string;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Coerce a string value read from an environment variable to match the
|
|
58
|
+
* type of the default value (number → parseFloat, boolean → "true"/"1",
|
|
59
|
+
* array → JSON.parse, etc.). When the default is already a string or
|
|
60
|
+
* there is no default, the original string is returned as-is.
|
|
61
|
+
*/
|
|
62
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
63
|
+
function coerceValue(value: string, defaultValue: any): any {
|
|
64
|
+
if (defaultValue === undefined || defaultValue === null) {
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
switch (typeof defaultValue) {
|
|
69
|
+
case "number": {
|
|
70
|
+
const parsed = Number(value);
|
|
71
|
+
return Number.isNaN(parsed) ? value : parsed;
|
|
72
|
+
}
|
|
73
|
+
case "boolean": {
|
|
74
|
+
return value === "true" || value === "1" || value === "yes";
|
|
75
|
+
}
|
|
76
|
+
case "object": {
|
|
77
|
+
if (Array.isArray(defaultValue)) {
|
|
78
|
+
try {
|
|
79
|
+
return JSON.parse(value);
|
|
80
|
+
} catch {
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (defaultValue !== null) {
|
|
85
|
+
try {
|
|
86
|
+
return JSON.parse(value);
|
|
87
|
+
} catch {
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
default:
|
|
94
|
+
return value;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
56
98
|
/**
|
|
57
99
|
* Abstract base class for project configuration.
|
|
58
100
|
*
|
|
@@ -109,9 +151,13 @@ export abstract class ConfigBase implements ConfigCommonInterface {
|
|
|
109
151
|
* Fields registered by subclasses (or the base) that {@link reload}
|
|
110
152
|
* should process. Common / DB / OTel fields are pre-registered.
|
|
111
153
|
*/
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
154
|
+
private _fields: {
|
|
155
|
+
field: string;
|
|
156
|
+
sensitive: boolean;
|
|
157
|
+
envAliases: string[];
|
|
158
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
159
|
+
defaultValue: any;
|
|
160
|
+
}[] = [];
|
|
115
161
|
|
|
116
162
|
/**
|
|
117
163
|
* @param serviceId Unique service identifier (e.g. `"cryptotrader-server"`).
|
|
@@ -143,7 +189,11 @@ export abstract class ConfigBase implements ConfigCommonInterface {
|
|
|
143
189
|
{ field: "DATABASE_POSTGRES_HOST", envAliases: ["POSTGRES_HOST"] },
|
|
144
190
|
{ field: "DATABASE_POSTGRES_PORT", envAliases: ["POSTGRES_PORT"] },
|
|
145
191
|
{ field: "DATABASE_POSTGRES_USER", envAliases: ["POSTGRES_USER"] },
|
|
146
|
-
{
|
|
192
|
+
{
|
|
193
|
+
field: "DATABASE_POSTGRES_PASSWORD",
|
|
194
|
+
sensitive: true,
|
|
195
|
+
envAliases: ["POSTGRES_PASSWORD"],
|
|
196
|
+
},
|
|
147
197
|
{ field: "DATABASE_POSTGRES_DATABASE", envAliases: ["POSTGRES_DB"] },
|
|
148
198
|
{ field: "OPENTELEMETRY_COLLECTOR_HTTP_TRACES" },
|
|
149
199
|
{ field: "OPENTELEMETRY_COLLECTOR_HTTP_METRICS" },
|
|
@@ -201,7 +251,7 @@ export abstract class ConfigBase implements ConfigCommonInterface {
|
|
|
201
251
|
log(`Configuration Value: SERVICE_ID: ${this.SERVICE_ID}`);
|
|
202
252
|
log(`Configuration Value: VERSION: ${this.VERSION}`);
|
|
203
253
|
|
|
204
|
-
for (const { field, sensitive, envAliases } of this._fields) {
|
|
254
|
+
for (const { field, sensitive, envAliases, defaultValue } of this._fields) {
|
|
205
255
|
let from = "defaults";
|
|
206
256
|
let foundValue: string | undefined;
|
|
207
257
|
let usedAlias = false;
|
|
@@ -224,10 +274,11 @@ export abstract class ConfigBase implements ConfigCommonInterface {
|
|
|
224
274
|
}
|
|
225
275
|
}
|
|
226
276
|
|
|
227
|
-
// 3. Apply environment value (full name or alias) if found
|
|
277
|
+
// 3. Apply environment value (full name or alias) if found,
|
|
278
|
+
// coercing strings to match the default value type
|
|
228
279
|
if (foundValue !== undefined) {
|
|
229
280
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
230
|
-
(this as any)[field] = foundValue;
|
|
281
|
+
(this as any)[field] = coerceValue(foundValue, defaultValue);
|
|
231
282
|
}
|
|
232
283
|
|
|
233
284
|
// 4. Config file override (environment always wins, but if neither
|