@onlineapps/service-wrapper 2.1.55 → 2.1.56
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 +1 -1
- package/src/ConfigLoader.js +49 -51
- package/src/ServiceWrapper.js +5 -1
- package/src/index.js +2 -4
package/package.json
CHANGED
package/src/ConfigLoader.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Usage:
|
|
13
13
|
* const { ConfigLoader } = require('@onlineapps/service-wrapper');
|
|
14
|
-
* const config = ConfigLoader.loadAll();
|
|
14
|
+
* const config = ConfigLoader.loadAll({ env: process.env });
|
|
15
15
|
*
|
|
16
16
|
* Design principle: ONE place to define, validate, and load ALL configs.
|
|
17
17
|
*
|
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
const fs = require('fs');
|
|
23
23
|
const path = require('path');
|
|
24
24
|
|
|
25
|
-
const RUNTIME_DEFAULTS = require('../config/runtime-defaults.json');
|
|
26
25
|
const runtimeCfg = require('./config');
|
|
27
26
|
|
|
28
27
|
/**
|
|
@@ -49,63 +48,47 @@ const CONFIG_REGISTRY = {
|
|
|
49
48
|
|
|
50
49
|
class ConfigLoader {
|
|
51
50
|
/**
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* @
|
|
55
|
-
* @
|
|
51
|
+
* Ensure env is provided for placeholder resolution.
|
|
52
|
+
* @param {any} env
|
|
53
|
+
* @returns {Object} env object
|
|
54
|
+
* @private
|
|
56
55
|
*/
|
|
57
|
-
static
|
|
58
|
-
if (typeof
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Match ${VAR_NAME:default} or ${VAR_NAME}
|
|
63
|
-
const match = value.match(/^\$\{([^:}]+)(?::([^}]+))?\}$/);
|
|
64
|
-
if (!match) {
|
|
65
|
-
return value;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const varName = match[1];
|
|
69
|
-
const defaultValue = match[2];
|
|
70
|
-
|
|
71
|
-
const envValue = process.env[varName];
|
|
72
|
-
if (envValue !== undefined) {
|
|
73
|
-
return envValue;
|
|
56
|
+
static _requireEnv(env) {
|
|
57
|
+
if (!env || typeof env !== 'object') {
|
|
58
|
+
throw new Error('[ConfigLoader] Missing dependency - env is required (pass { env: process.env } from the service entrypoint)');
|
|
74
59
|
}
|
|
75
|
-
|
|
76
|
-
return defaultValue;
|
|
77
|
-
}
|
|
78
|
-
throw new Error(`[ConfigLoader] Missing environment variable - ${varName} is required (config placeholder ${match[0]})`);
|
|
60
|
+
return env;
|
|
79
61
|
}
|
|
80
62
|
|
|
81
63
|
/**
|
|
82
|
-
* Apply ${VAR}
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* NOTE: This does NOT enforce strict missing-env behavior (that is addressed later).
|
|
64
|
+
* Apply ${VAR} substitutions anywhere within a string.
|
|
65
|
+
* NOTE: ${VAR:default} is NOT allowed (no fallbacks). Use explicit config or set ENV.
|
|
86
66
|
*
|
|
87
67
|
* @param {string} value
|
|
68
|
+
* @param {Object} options
|
|
69
|
+
* @param {Object} options.env
|
|
88
70
|
* @returns {string}
|
|
89
71
|
*/
|
|
90
|
-
static resolveEnvPlaceholdersInString(value) {
|
|
72
|
+
static resolveEnvPlaceholdersInString(value, options = {}) {
|
|
91
73
|
if (typeof value !== 'string') {
|
|
92
74
|
return value;
|
|
93
75
|
}
|
|
94
76
|
|
|
77
|
+
const env = this._requireEnv(options.env);
|
|
78
|
+
|
|
95
79
|
return value.replace(/\$\{([^:}]+)(?::([^}]*))?\}/g, (match, varName, defaultValue) => {
|
|
96
|
-
|
|
80
|
+
if (defaultValue !== undefined) {
|
|
81
|
+
throw new Error(`[ConfigLoader] Unsupported placeholder default - "${match}" is not allowed. Fix: set ENV "${varName}" or set an explicit value in config.json`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const envValue = env[varName];
|
|
97
85
|
|
|
98
86
|
// Use env value if exists (even if empty string)
|
|
99
87
|
if (envValue !== undefined) {
|
|
100
88
|
return envValue;
|
|
101
89
|
}
|
|
102
90
|
|
|
103
|
-
//
|
|
104
|
-
if (defaultValue !== undefined) {
|
|
105
|
-
return defaultValue;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Fail-fast: placeholder without default requires ENV to be set
|
|
91
|
+
// Fail-fast: placeholder requires ENV to be set
|
|
109
92
|
throw new Error(`[ConfigLoader] Missing environment variable - ${varName} is required (config placeholder ${match})`);
|
|
110
93
|
});
|
|
111
94
|
}
|
|
@@ -118,23 +101,23 @@ class ConfigLoader {
|
|
|
118
101
|
* @returns {any}
|
|
119
102
|
*/
|
|
120
103
|
static resolveEnvPlaceholdersDeep(input, options = {}) {
|
|
121
|
-
const { jsonPath = '$' } = options;
|
|
104
|
+
const { jsonPath = '$', env } = options;
|
|
122
105
|
|
|
123
106
|
if (Array.isArray(input)) {
|
|
124
|
-
return input.map((item, idx) => this.resolveEnvPlaceholdersDeep(item, { jsonPath: `${jsonPath}[${idx}]
|
|
107
|
+
return input.map((item, idx) => this.resolveEnvPlaceholdersDeep(item, { jsonPath: `${jsonPath}[${idx}]`, env }));
|
|
125
108
|
}
|
|
126
109
|
|
|
127
110
|
if (input && typeof input === 'object') {
|
|
128
111
|
const out = {};
|
|
129
112
|
for (const [k, v] of Object.entries(input)) {
|
|
130
|
-
out[k] = this.resolveEnvPlaceholdersDeep(v, { jsonPath: `${jsonPath}.${k}
|
|
113
|
+
out[k] = this.resolveEnvPlaceholdersDeep(v, { jsonPath: `${jsonPath}.${k}`, env });
|
|
131
114
|
}
|
|
132
115
|
return out;
|
|
133
116
|
}
|
|
134
117
|
|
|
135
118
|
if (typeof input === 'string') {
|
|
136
119
|
try {
|
|
137
|
-
return this.resolveEnvPlaceholdersInString(input);
|
|
120
|
+
return this.resolveEnvPlaceholdersInString(input, { env });
|
|
138
121
|
} catch (err) {
|
|
139
122
|
throw new Error(`${err.message} at ${jsonPath}`);
|
|
140
123
|
}
|
|
@@ -200,7 +183,17 @@ class ConfigLoader {
|
|
|
200
183
|
* @returns {Object} Service configuration
|
|
201
184
|
* @throws {Error} If config file not found or invalid JSON
|
|
202
185
|
*/
|
|
203
|
-
|
|
186
|
+
/**
|
|
187
|
+
* Load service configuration from conn-config/config.json
|
|
188
|
+
* Version is always taken from package.json (Single Source of Truth)
|
|
189
|
+
* @param {Object} options
|
|
190
|
+
* @param {string} [options.basePath] - Base path (defaults to process.cwd())
|
|
191
|
+
* @param {Object} options.env - Environment variables for ${VAR} placeholders
|
|
192
|
+
* @returns {Object} Service configuration
|
|
193
|
+
* @throws {Error} If config file not found or invalid JSON
|
|
194
|
+
*/
|
|
195
|
+
static loadServiceConfig(options = {}) {
|
|
196
|
+
const { basePath = process.cwd(), env } = options;
|
|
204
197
|
const configPath = path.join(basePath, 'conn-config', 'config.json');
|
|
205
198
|
|
|
206
199
|
try {
|
|
@@ -215,13 +208,9 @@ class ConfigLoader {
|
|
|
215
208
|
// Always use version from package.json (Single Source of Truth)
|
|
216
209
|
config.service.version = this.loadPackageVersion(basePath);
|
|
217
210
|
|
|
218
|
-
// Apply repo defaults (non-critical) then allow service config to override
|
|
219
|
-
const defaults = RUNTIME_DEFAULTS?.defaults || {};
|
|
220
|
-
const merged = this.deepMerge(defaults, config);
|
|
221
|
-
|
|
222
211
|
// Resolve env placeholders across the whole config (service + wrapper + custom sections)
|
|
223
212
|
try {
|
|
224
|
-
return this.resolveEnvPlaceholdersDeep(
|
|
213
|
+
return this.resolveEnvPlaceholdersDeep(config, { jsonPath: '$', env });
|
|
225
214
|
} catch (err) {
|
|
226
215
|
throw new Error(`[ConfigLoader] Failed to resolve placeholders in ${configPath}. ${err.message}`);
|
|
227
216
|
}
|
|
@@ -299,8 +288,17 @@ class ConfigLoader {
|
|
|
299
288
|
* @param {string} basePath - Base path (defaults to process.cwd())
|
|
300
289
|
* @returns {Object} Combined configuration object
|
|
301
290
|
*/
|
|
302
|
-
|
|
303
|
-
|
|
291
|
+
/**
|
|
292
|
+
* Load all service configurations at once
|
|
293
|
+
* @param {Object} options
|
|
294
|
+
* @param {string} [options.basePath] - Base path (defaults to process.cwd())
|
|
295
|
+
* @param {Object} options.env - Environment variables for ${VAR} placeholders
|
|
296
|
+
* @returns {Object} Combined configuration object
|
|
297
|
+
*/
|
|
298
|
+
static loadAll(options = {}) {
|
|
299
|
+
const { basePath = process.cwd(), env } = options;
|
|
300
|
+
|
|
301
|
+
const serviceConfig = this.loadServiceConfig({ basePath, env });
|
|
304
302
|
const operations = this.loadOperations(basePath);
|
|
305
303
|
const validationProof = this.loadValidationProof(basePath);
|
|
306
304
|
const nodeEnv = runtimeCfg.get('nodeEnv');
|
package/src/ServiceWrapper.js
CHANGED
|
@@ -1582,7 +1582,11 @@ class ServiceWrapper {
|
|
|
1582
1582
|
}
|
|
1583
1583
|
|
|
1584
1584
|
// Build service URL for validation (HTTP calls to running server)
|
|
1585
|
-
|
|
1585
|
+
// Fail-fast: do not guess hostnames (no localhost defaults). Service URL must be explicit in ServiceConfig.
|
|
1586
|
+
const serviceUrl = this.config.service?.url;
|
|
1587
|
+
if (!serviceUrl) {
|
|
1588
|
+
throw new Error('[ServiceWrapper] Missing configuration - config.service.url is required for validation (set SERVICE_URL in conn-config/config.json placeholder)');
|
|
1589
|
+
}
|
|
1586
1590
|
|
|
1587
1591
|
this.logger?.info('[ServiceWrapper] Checking validation proof...');
|
|
1588
1592
|
|
package/src/index.js
CHANGED
|
@@ -15,6 +15,7 @@ const path = require('path');
|
|
|
15
15
|
const ServiceWrapper = require('./ServiceWrapper');
|
|
16
16
|
const { ConfigLoader } = require('./ConfigLoader');
|
|
17
17
|
const runtimeCfg = require('./config');
|
|
18
|
+
const pkg = require('../package.json');
|
|
18
19
|
|
|
19
20
|
// Note: WorkflowProcessor and ApiCaller functionality has been moved to connectors:
|
|
20
21
|
// - WorkflowProcessor -> @onlineapps/conn-orch-orchestrator
|
|
@@ -39,9 +40,6 @@ const runtimeCfg = require('./config');
|
|
|
39
40
|
* require('@onlineapps/service-wrapper').bootstrap(__dirname);
|
|
40
41
|
*/
|
|
41
42
|
async function bootstrap(serviceRoot, options = {}) {
|
|
42
|
-
// Load dotenv first
|
|
43
|
-
require('dotenv').config({ path: path.join(serviceRoot, '.env') });
|
|
44
|
-
|
|
45
43
|
// Load app, config, and logger from service
|
|
46
44
|
const app = options.app || require(path.join(serviceRoot, 'src', 'app'));
|
|
47
45
|
const config = options.config || require(path.join(serviceRoot, 'src', 'config'));
|
|
@@ -118,4 +116,4 @@ module.exports.ServiceWrapper = ServiceWrapper;
|
|
|
118
116
|
module.exports.ConfigLoader = ConfigLoader;
|
|
119
117
|
module.exports.bootstrap = bootstrap;
|
|
120
118
|
module.exports.default = ServiceWrapper;
|
|
121
|
-
module.exports.VERSION =
|
|
119
|
+
module.exports.VERSION = pkg.version;
|