@onlineapps/service-wrapper 2.0.12 → 2.0.13

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
@@ -101,6 +101,22 @@ NO infrastructure code needed in your service!
101
101
 
102
102
  ## Configuration
103
103
 
104
+ ### Environment Variable Parsing
105
+
106
+ **ServiceWrapper handles environment variable parsing directly** rather than delegating to a separate connector. This design decision is based on:
107
+
108
+ 1. **Core Responsibility** - Configuration loading is fundamental to the wrapper's initialization, not a specialized concern
109
+ 2. **Simplicity** - Avoids creating a separate connector for ~20 lines of parsing logic
110
+ 3. **Performance** - Eliminates unnecessary abstraction layers for a trivial operation
111
+ 4. **Universal Need** - All connectors (MQ, Registry, Cache) require parsed configuration
112
+
113
+ The wrapper parses `${VAR:default}` syntax in configuration files:
114
+ - `${RABBITMQ_URL}` - Uses environment variable, fails if not set
115
+ - `${PORT:3000}` - Uses environment variable, defaults to 3000 if not set
116
+ - `${ENABLED:true}` - Uses environment variable, defaults to true
117
+
118
+ This follows Docker/Kubernetes best practices for configuration management while keeping the wrapper architecture clean and focused.
119
+
104
120
  ### operations.json
105
121
  ```json
106
122
  {
@@ -121,13 +137,23 @@ NO infrastructure code needed in your service!
121
137
  {
122
138
  "service": {
123
139
  "name": "my-service",
124
- "port": 3000
140
+ "port": "${PORT:3000}"
125
141
  },
126
142
  "wrapper": {
127
- "mq": { "url": "${RABBITMQ_URL}" },
128
- "registry": { "url": "${REGISTRY_URL}" },
129
- "monitoring": { "enabled": true },
130
- "health": { "endpoint": "/health" }
143
+ "mq": {
144
+ "url": "${RABBITMQ_URL:amqp://localhost:5672}",
145
+ "enabled": "${MQ_ENABLED:true}"
146
+ },
147
+ "registry": {
148
+ "url": "${REGISTRY_URL}",
149
+ "enabled": "${REGISTRY_ENABLED:false}"
150
+ },
151
+ "monitoring": {
152
+ "enabled": "${MONITORING_ENABLED:true}"
153
+ },
154
+ "health": {
155
+ "endpoint": "/health"
156
+ }
131
157
  }
132
158
  }
133
159
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onlineapps/service-wrapper",
3
- "version": "2.0.12",
3
+ "version": "2.0.13",
4
4
  "description": "Thin orchestration layer for microservices - delegates all infrastructure concerns to specialized connectors",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -82,10 +82,25 @@ class ServiceWrapper {
82
82
  _processConfig(config) {
83
83
  // Replace environment variables in config
84
84
  const processValue = (value) => {
85
- if (typeof value === 'string' && value.startsWith('${') && value.endsWith('}')) {
86
- const envVar = value.slice(2, -1);
87
- const [varName, defaultValue] = envVar.split(':');
88
- return process.env[varName] || defaultValue || '';
85
+ if (typeof value === 'string') {
86
+ // Support ${VAR:default} format anywhere in string
87
+ return value.replace(/\$\{([^:}]+)(?::([^}]*))?\}/g, (match, varName, defaultValue) => {
88
+ const envValue = process.env[varName];
89
+
90
+ // Use env value if exists (even if empty string)
91
+ if (envValue !== undefined) {
92
+ return envValue;
93
+ }
94
+
95
+ // Use default if provided
96
+ if (defaultValue !== undefined) {
97
+ return defaultValue;
98
+ }
99
+
100
+ // Log warning and return empty string
101
+ console.warn(`[ServiceWrapper] Missing env variable: ${varName}`);
102
+ return '';
103
+ });
89
104
  }
90
105
  return value;
91
106
  };
@@ -96,6 +111,10 @@ class ServiceWrapper {
96
111
  for (const [key, value] of Object.entries(obj)) {
97
112
  if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
98
113
  result[key] = processObject(value);
114
+ } else if (Array.isArray(value)) {
115
+ result[key] = value.map(item =>
116
+ typeof item === 'object' && item !== null ? processObject(item) : processValue(item)
117
+ );
99
118
  } else {
100
119
  result[key] = processValue(value);
101
120
  }