@onlineapps/service-wrapper 2.1.116 → 2.1.117
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/package.json +2 -2
- package/src/ConfigLoader.js +61 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onlineapps/service-wrapper",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.117",
|
|
4
4
|
"description": "Thin orchestration layer for microservices - delegates all infrastructure concerns to specialized connectors",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"@onlineapps/conn-orch-cookbook": "2.0.35",
|
|
33
33
|
"@onlineapps/conn-orch-orchestrator": "1.0.103",
|
|
34
34
|
"@onlineapps/conn-orch-registry": "1.1.52",
|
|
35
|
-
"@onlineapps/conn-orch-validator": "2.0.
|
|
35
|
+
"@onlineapps/conn-orch-validator": "2.0.30",
|
|
36
36
|
"@onlineapps/monitoring-core": "1.0.21",
|
|
37
37
|
"@onlineapps/service-common": "1.0.17",
|
|
38
38
|
"@onlineapps/runtime-config": "1.0.2"
|
package/src/ConfigLoader.js
CHANGED
|
@@ -27,26 +27,48 @@ const runtimeCfg = require('./config');
|
|
|
27
27
|
/**
|
|
28
28
|
* CENTRAL REGISTRY: All configuration files used by business services
|
|
29
29
|
* If you add a new config file, add it here!
|
|
30
|
+
*
|
|
31
|
+
* Path resolution order (first found wins):
|
|
32
|
+
* 1. config/service/ (new standard)
|
|
33
|
+
* 2. conn-config/ (legacy, backward compat)
|
|
30
34
|
*/
|
|
31
35
|
const CONFIG_REGISTRY = {
|
|
32
36
|
SERVICE_CONFIG: {
|
|
33
|
-
|
|
37
|
+
paths: ['config/service/config.json', 'conn-config/config.json'],
|
|
34
38
|
required: true,
|
|
35
39
|
description: 'Service metadata and wrapper configuration'
|
|
36
40
|
},
|
|
37
41
|
OPERATIONS: {
|
|
38
|
-
|
|
42
|
+
paths: ['config/service/operations.json', 'conn-config/operations.json'],
|
|
39
43
|
required: true,
|
|
40
44
|
description: 'Operations specification (API contract)'
|
|
41
45
|
},
|
|
42
46
|
VALIDATION_PROOF: {
|
|
43
|
-
|
|
47
|
+
paths: ['config/runtime/validation-proof.json', 'conn-runtime/validation-proof.json'],
|
|
44
48
|
required: false,
|
|
45
49
|
description: 'Pre-validation proof from cookbook tests'
|
|
46
50
|
}
|
|
47
51
|
};
|
|
48
52
|
|
|
49
53
|
class ConfigLoader {
|
|
54
|
+
/**
|
|
55
|
+
* Resolve a config file from an ordered list of candidate paths.
|
|
56
|
+
* Returns the first path that exists, or null if none found.
|
|
57
|
+
* @param {string[]} candidatePaths - Relative paths to try (first found wins)
|
|
58
|
+
* @param {string} basePath - Service root directory
|
|
59
|
+
* @returns {string|null} Absolute path to the first existing file, or null
|
|
60
|
+
* @private
|
|
61
|
+
*/
|
|
62
|
+
static _resolveConfigPath(candidatePaths, basePath) {
|
|
63
|
+
for (const relPath of candidatePaths) {
|
|
64
|
+
const abs = path.join(basePath, relPath);
|
|
65
|
+
if (fs.existsSync(abs)) {
|
|
66
|
+
return abs;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
|
|
50
72
|
/**
|
|
51
73
|
* Ensure env is provided for placeholder resolution.
|
|
52
74
|
* @param {any} env
|
|
@@ -194,21 +216,25 @@ class ConfigLoader {
|
|
|
194
216
|
*/
|
|
195
217
|
static loadServiceConfig(options = {}) {
|
|
196
218
|
const { basePath = process.cwd(), env } = options;
|
|
197
|
-
const
|
|
219
|
+
const reg = CONFIG_REGISTRY.SERVICE_CONFIG;
|
|
220
|
+
const configPath = this._resolveConfigPath(reg.paths, basePath);
|
|
221
|
+
|
|
222
|
+
if (!configPath) {
|
|
223
|
+
throw new Error(
|
|
224
|
+
`[ConfigLoader] Service config not found - tried: ${reg.paths.map(p => path.join(basePath, p)).join(', ')}`
|
|
225
|
+
);
|
|
226
|
+
}
|
|
198
227
|
|
|
199
228
|
try {
|
|
200
229
|
const content = fs.readFileSync(configPath, 'utf8');
|
|
201
230
|
const config = JSON.parse(content);
|
|
202
231
|
|
|
203
|
-
// Validate required fields (version not required - comes from package.json)
|
|
204
232
|
if (!config.service || !config.service.name) {
|
|
205
233
|
throw new Error('Invalid config.json: Missing required field (service.name)');
|
|
206
234
|
}
|
|
207
235
|
|
|
208
|
-
// Always use version from package.json (Single Source of Truth)
|
|
209
236
|
config.service.version = this.loadPackageVersion(basePath);
|
|
210
237
|
|
|
211
|
-
// Resolve env placeholders across the whole config (service + wrapper + custom sections)
|
|
212
238
|
try {
|
|
213
239
|
return this.resolveEnvPlaceholdersDeep(config, { jsonPath: '$', env });
|
|
214
240
|
} catch (err) {
|
|
@@ -216,7 +242,7 @@ class ConfigLoader {
|
|
|
216
242
|
}
|
|
217
243
|
} catch (error) {
|
|
218
244
|
if (error.code === 'ENOENT') {
|
|
219
|
-
throw new Error(`Service config not found: ${configPath}`);
|
|
245
|
+
throw new Error(`[ConfigLoader] Service config not found: ${configPath}`);
|
|
220
246
|
}
|
|
221
247
|
throw error;
|
|
222
248
|
}
|
|
@@ -229,13 +255,19 @@ class ConfigLoader {
|
|
|
229
255
|
* @throws {Error} If operations file not found or invalid
|
|
230
256
|
*/
|
|
231
257
|
static loadOperations(basePath = process.cwd()) {
|
|
232
|
-
const
|
|
258
|
+
const reg = CONFIG_REGISTRY.OPERATIONS;
|
|
259
|
+
const operationsPath = this._resolveConfigPath(reg.paths, basePath);
|
|
260
|
+
|
|
261
|
+
if (!operationsPath) {
|
|
262
|
+
throw new Error(
|
|
263
|
+
`[ConfigLoader] Operations specification not found - tried: ${reg.paths.map(p => path.join(basePath, p)).join(', ')}`
|
|
264
|
+
);
|
|
265
|
+
}
|
|
233
266
|
|
|
234
267
|
try {
|
|
235
268
|
const content = fs.readFileSync(operationsPath, 'utf8');
|
|
236
269
|
const operations = JSON.parse(content);
|
|
237
270
|
|
|
238
|
-
// Validate structure
|
|
239
271
|
if (!operations.operations || typeof operations.operations !== 'object') {
|
|
240
272
|
throw new Error('Invalid operations.json: Missing or invalid "operations" field');
|
|
241
273
|
}
|
|
@@ -243,7 +275,7 @@ class ConfigLoader {
|
|
|
243
275
|
return operations;
|
|
244
276
|
} catch (error) {
|
|
245
277
|
if (error.code === 'ENOENT') {
|
|
246
|
-
throw new Error(`Operations specification not found: ${operationsPath}`);
|
|
278
|
+
throw new Error(`[ConfigLoader] Operations specification not found: ${operationsPath}`);
|
|
247
279
|
}
|
|
248
280
|
throw error;
|
|
249
281
|
}
|
|
@@ -255,18 +287,17 @@ class ConfigLoader {
|
|
|
255
287
|
* @returns {Object|null} Validation proof or null if not found
|
|
256
288
|
*/
|
|
257
289
|
static loadValidationProof(basePath = process.cwd()) {
|
|
258
|
-
const
|
|
290
|
+
const reg = CONFIG_REGISTRY.VALIDATION_PROOF;
|
|
291
|
+
const proofPath = this._resolveConfigPath(reg.paths, basePath);
|
|
259
292
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
return null;
|
|
264
|
-
}
|
|
293
|
+
if (!proofPath) {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
265
296
|
|
|
297
|
+
try {
|
|
266
298
|
const content = fs.readFileSync(proofPath, 'utf8');
|
|
267
299
|
const proof = JSON.parse(content);
|
|
268
300
|
|
|
269
|
-
// Validate structure
|
|
270
301
|
if (!proof.validationProof && !proof.hash) {
|
|
271
302
|
console.warn('[ConfigLoader] Invalid validation-proof.json structure - ignoring');
|
|
272
303
|
return null;
|
|
@@ -277,7 +308,6 @@ class ConfigLoader {
|
|
|
277
308
|
data: proof.validationData || proof.data
|
|
278
309
|
};
|
|
279
310
|
} catch (error) {
|
|
280
|
-
// Non-critical - just log warning
|
|
281
311
|
console.warn(`[ConfigLoader] Failed to load validation proof: ${error.message}`);
|
|
282
312
|
return null;
|
|
283
313
|
}
|
|
@@ -327,10 +357,9 @@ class ConfigLoader {
|
|
|
327
357
|
customSections[k] = v;
|
|
328
358
|
}
|
|
329
359
|
|
|
330
|
-
// FAIL-FAST: specificationEndpoint is REQUIRED (no fallbacks)
|
|
331
360
|
if (!serviceConfig.service.specificationEndpoint) {
|
|
332
361
|
throw new Error(
|
|
333
|
-
`[ConfigLoader] Missing required field - "specificationEndpoint" is required in conn-config/config.json under "service" section. ` +
|
|
362
|
+
`[ConfigLoader] Missing required field - "specificationEndpoint" is required in config/service/config.json (or conn-config/config.json) under "service" section. ` +
|
|
334
363
|
`Fix: Add "specificationEndpoint": "/api/v1/specification" to config.json`
|
|
335
364
|
);
|
|
336
365
|
}
|
|
@@ -353,21 +382,29 @@ class ConfigLoader {
|
|
|
353
382
|
}
|
|
354
383
|
|
|
355
384
|
/**
|
|
356
|
-
* Get path to config directory
|
|
385
|
+
* Get path to config directory (prefers config/service/, falls back to conn-config/)
|
|
357
386
|
* @param {string} basePath - Base path (defaults to process.cwd())
|
|
358
|
-
* @returns {string} Absolute path to
|
|
387
|
+
* @returns {string} Absolute path to config directory
|
|
359
388
|
*/
|
|
360
389
|
static getConfigDir(basePath = process.cwd()) {
|
|
390
|
+
const newPath = path.join(basePath, 'config', 'service');
|
|
391
|
+
if (fs.existsSync(newPath)) {
|
|
392
|
+
return newPath;
|
|
393
|
+
}
|
|
361
394
|
return path.join(basePath, 'conn-config');
|
|
362
395
|
}
|
|
363
396
|
|
|
364
397
|
/**
|
|
365
|
-
* Get path to specific config file
|
|
398
|
+
* Get path to specific config file (prefers config/service/, falls back to conn-config/)
|
|
366
399
|
* @param {string} filename - Config filename
|
|
367
400
|
* @param {string} basePath - Base path (defaults to process.cwd())
|
|
368
401
|
* @returns {string} Absolute path to config file
|
|
369
402
|
*/
|
|
370
403
|
static getConfigPath(filename, basePath = process.cwd()) {
|
|
404
|
+
const newPath = path.join(basePath, 'config', 'service', filename);
|
|
405
|
+
if (fs.existsSync(newPath)) {
|
|
406
|
+
return newPath;
|
|
407
|
+
}
|
|
371
408
|
return path.join(basePath, 'conn-config', filename);
|
|
372
409
|
}
|
|
373
410
|
}
|