@owox/internal-helpers 0.5.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 ADDED
@@ -0,0 +1,3 @@
1
+ # @owox/internal-helpers
2
+
3
+ These are internal helpers used by core OWOX packages. This package should not be used externally
@@ -0,0 +1,256 @@
1
+ /**
2
+ * Log levels for environment setup operations
3
+ */
4
+ export declare enum LogLevel {
5
+ LOG = "log",
6
+ WARN = "warn",
7
+ ERROR = "error"
8
+ }
9
+ /**
10
+ * Log message interface for environment setup operations
11
+ */
12
+ export interface LogMessage {
13
+ /** Log level (log, warn, error) */
14
+ logLevel: LogLevel;
15
+ /** Log message content */
16
+ message: string;
17
+ }
18
+ /**
19
+ * Configuration interface for environment setup operations
20
+ */
21
+ export interface EnvSetupConfig {
22
+ /** Path to environment file (optional, uses fallback logic if empty) */
23
+ envFile?: string;
24
+ /** Whether to override existing variables when loading from file (default: false) */
25
+ envFileOverride?: boolean;
26
+ /** Whether to process environment file before flag variables (default: false) */
27
+ envFileFirst?: boolean;
28
+ /** Object containing flag variables to set */
29
+ flagVars?: Record<string, unknown>;
30
+ /** Whether to override existing variables when setting flag variables (default: false) */
31
+ flagVarsOverride?: boolean;
32
+ /** Object containing default variables to set (never override existing) */
33
+ defaultVars?: Record<string, unknown>;
34
+ }
35
+ /**
36
+ * Result object returned by environment setup operations
37
+ */
38
+ export interface EnvSetupResult {
39
+ /** Log messages from the setting process with levels */
40
+ messages: LogMessage[];
41
+ /** Whether the operation was successful */
42
+ success: boolean;
43
+ }
44
+ /**
45
+ * Environment manager for loading and setting environment variables
46
+ *
47
+ * Features:
48
+ * - Load from .env files with priority system
49
+ * - Set variables from objects with validation
50
+ * - Prevent override of existing variables
51
+ * - Comprehensive logging with levels (log, warn, error) and error handling
52
+ * - Returns structured log messages with appropriate emojis
53
+ */
54
+ export declare class EnvManager {
55
+ /**
56
+ * Environment variable name for custom .env file path
57
+ */
58
+ private static readonly DEFAULT_ENV_FILE_PATH;
59
+ /**
60
+ * Template messages for logging with placeholder support
61
+ *
62
+ * Templates use %placeholder% syntax for dynamic content:
63
+ * - %file% - File path
64
+ * - %type% - Environment object type (flags/default)
65
+ * - %error% - Error message
66
+ * - %qty% - Quantity/count
67
+ * - %list% - Comma-separated list
68
+ */
69
+ private static readonly MESSAGES;
70
+ /**
71
+ * Internal log buffer for the current setup operation
72
+ * Reset at the start of each setupEnvironment() call
73
+ */
74
+ private static operationLog;
75
+ /**
76
+ * Setup environment variables from multiple sources with priority system
77
+ *
78
+ * @param config - Configuration object specifying sources and priorities (optional, uses defaults if not provided)
79
+ * @returns Result with operation messages and success status
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * // With full configuration
84
+ * const result = EnvManager.setupEnvironment({
85
+ * envFile: '.env.production',
86
+ * envFileOverride: false,
87
+ * envFileFirst: true,
88
+ * flagVars: { DEBUG: true, PORT: 3000 },
89
+ * flagVarsOverride: true,
90
+ * defaultVars: { NODE_ENV: 'development' }
91
+ * });
92
+ *
93
+ * // With default configuration (loads default .env file only)
94
+ * const result = EnvManager.setupEnvironment();
95
+ *
96
+ * if (result.success) {
97
+ * console.log('Environment setup completed');
98
+ * result.messages.forEach(msg => {
99
+ * console[msg.logLevel](msg.message);
100
+ * });
101
+ * }
102
+ * ```
103
+ */
104
+ static setupEnvironment(config?: EnvSetupConfig): EnvSetupResult;
105
+ /**
106
+ * Build array of operations based on configuration priority settings
107
+ *
108
+ * @private
109
+ * @param config - Environment setup configuration
110
+ * @returns Array of operation functions to execute in order
111
+ */
112
+ private static buildOperations;
113
+ /**
114
+ * Execute all operations sequentially and return combined success status
115
+ *
116
+ * @private
117
+ * @param operations - Array of operation functions to execute
118
+ * @returns True if all operations succeeded, false otherwise
119
+ */
120
+ private static executeOperations;
121
+ /**
122
+ * Process environment file loading with validation and error handling
123
+ *
124
+ * @private
125
+ * @param config - Environment setup configuration containing file settings
126
+ * @returns True if file processing succeeded, false otherwise
127
+ */
128
+ private static processEnvFile;
129
+ /**
130
+ * Process environment variables from object (flags or defaults) with type validation
131
+ *
132
+ * @private
133
+ * @param config - Environment setup configuration containing variable objects
134
+ * @param type - Type of variables being processed (flags or default)
135
+ * @returns True if object processing succeeded, false otherwise
136
+ */
137
+ private static processEnvObject;
138
+ /**
139
+ * Load environment variables from a file with error handling and validation
140
+ *
141
+ * Features:
142
+ * - Reads file content safely with try-catch
143
+ * - Parses .env format using dotenv library
144
+ * - Validates non-empty content
145
+ * - Returns detailed operation results
146
+ *
147
+ * @private
148
+ * @param resolvedPath - Absolute path to environment file
149
+ * @param override - Whether to override existing environment variables
150
+ * @returns Operation result with success status and variable details
151
+ *
152
+ * @example
153
+ * ```typescript
154
+ * const result = this.loadFromFile('/path/to/.env', false);
155
+ * if (result.success) {
156
+ * console.log(`Loaded ${result.setVars?.length} variables`);
157
+ * }
158
+ * ```
159
+ */
160
+ private static loadFromFile;
161
+ /**
162
+ * Set environment variables from an object with comprehensive validation
163
+ *
164
+ * Features:
165
+ * - Converts values to strings automatically (number, boolean → string)
166
+ * - Validates keys (no empty/whitespace-only keys)
167
+ * - Validates values (no undefined/null/empty values after trimming)
168
+ * - Respects existing variables unless override is true
169
+ * - Returns detailed results for logging and debugging
170
+ * - Sanitizes keys by trimming whitespace
171
+ *
172
+ * @private
173
+ * @param envVars - Object with environment variable key-value pairs
174
+ * @param override - Whether to override existing environment variables (default: false)
175
+ * @returns Operation result with set/ignored/skipped variables and success status
176
+ *
177
+ * @example
178
+ * ```typescript
179
+ * const result = this.setFromObject({
180
+ * PORT: 8080, // number → '8080'
181
+ * LOG_FORMAT: 'json', // string → 'json'
182
+ * DEBUG: true, // boolean → 'true'
183
+ * API_KEY: undefined, // ignored (undefined)
184
+ * EMPTY: '', // ignored (empty string)
185
+ * ' ': 'value' // ignored (invalid key)
186
+ * });
187
+ *
188
+ * console.log(`✅ Set ${result.setVars?.length} variables`);
189
+ * console.log(`⚠️ Ignored ${result.ignoredVars?.length} variables`);
190
+ * console.log(`⏭️ Skipped ${result.skippedVars?.length} existing variables`);
191
+ * ```
192
+ */
193
+ private static setFromObject;
194
+ /**
195
+ * Resolve file path using fallback logic with comprehensive path resolution
196
+ *
197
+ * Priority order:
198
+ * 1. Specified filePath parameter (if not empty after trimming)
199
+ * 2. OWOX_ENV_FILE_PATH environment variable (if set and not empty)
200
+ * 3. Default .env file in current working directory
201
+ *
202
+ * @private
203
+ * @param filePath - User-specified file path (may be empty for fallback logic)
204
+ * @returns Resolved absolute path to environment file
205
+ */
206
+ private static resolveFilePath;
207
+ /**
208
+ * Log detailed results of environment variable operation
209
+ *
210
+ * Logs counts and details for:
211
+ * - Successfully set variables
212
+ * - Ignored variables with reasons
213
+ * - Skipped existing variables
214
+ *
215
+ * @private
216
+ * @param result - Operation result containing variable details
217
+ */
218
+ private static logOperationDetails;
219
+ /**
220
+ * Log informational message
221
+ * @private
222
+ * @param message - Message to log
223
+ */
224
+ private static logInfo;
225
+ /**
226
+ * Log error message
227
+ * @private
228
+ * @param message - Error message to log
229
+ */
230
+ private static logError;
231
+ /**
232
+ * Log warning message
233
+ * @private
234
+ * @param message - Warning message to log
235
+ */
236
+ private static logWarning;
237
+ /**
238
+ * Format message template by replacing placeholders with actual values
239
+ *
240
+ * @private
241
+ * @param template - Message template with %placeholder% markers
242
+ * @param replacements - Object with placeholder-value pairs
243
+ * @returns Formatted message with placeholders replaced
244
+ *
245
+ * @example
246
+ * ```typescript
247
+ * const formatted = this.formatMessage(
248
+ * 'Processing %type% with %count% items',
249
+ * { type: 'flags', count: '5' }
250
+ * );
251
+ * // Result: 'Processing flags with 5 items'
252
+ * ```
253
+ */
254
+ private static formatMessage;
255
+ }
256
+ //# sourceMappingURL=env-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-manager.d.ts","sourceRoot":"","sources":["../../src/environment/env-manager.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,oBAAY,QAAQ;IAClB,GAAG,QAAQ;IACX,IAAI,SAAS;IACb,KAAK,UAAU;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,mCAAmC;IACnC,QAAQ,EAAE,QAAQ,CAAC;IACnB,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qFAAqF;IACrF,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,iFAAiF;IACjF,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,0FAA0F;IAC1F,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,wDAAwD;IACxD,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,2CAA2C;IAC3C,OAAO,EAAE,OAAO,CAAC;CAClB;AA0BD;;;;;;;;;GASG;AACH,qBAAa,UAAU;IACrB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAwB;IAErE;;;;;;;;;OASG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAiB9B;IACF;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,YAAY,CAAoB;IAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,MAAM,CAAC,gBAAgB,CAAC,MAAM,GAAE,cAAmB,GAAG,cAAc;IAiBpE;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,eAAe;IAgB9B;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAOhC;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;IAqB7B;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAgC/B;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,OAAO,CAAC,MAAM,CAAC,YAAY;IAyB3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;IA+C5B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,MAAM,CAAC,eAAe;IAqB9B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAwBlC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,OAAO;IAItB;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ;IAIvB;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,UAAU;IAIzB;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;CAM7B"}
@@ -0,0 +1,426 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import dotenv from 'dotenv';
4
+ /** State variable to track if environment file has been loaded */
5
+ let isEnvSet = false;
6
+ /**
7
+ * Log levels for environment setup operations
8
+ */
9
+ export var LogLevel;
10
+ (function (LogLevel) {
11
+ LogLevel["LOG"] = "log";
12
+ LogLevel["WARN"] = "warn";
13
+ LogLevel["ERROR"] = "error";
14
+ })(LogLevel || (LogLevel = {}));
15
+ /**
16
+ * Enumeration of supported environment object types for processing
17
+ */
18
+ var EnvObjectType;
19
+ (function (EnvObjectType) {
20
+ /** Flag variables (command-line style variables) */
21
+ EnvObjectType["FLAGS"] = "flags";
22
+ /** Default variables (fallback values) */
23
+ EnvObjectType["DEFAULT"] = "default";
24
+ })(EnvObjectType || (EnvObjectType = {}));
25
+ /**
26
+ * Environment manager for loading and setting environment variables
27
+ *
28
+ * Features:
29
+ * - Load from .env files with priority system
30
+ * - Set variables from objects with validation
31
+ * - Prevent override of existing variables
32
+ * - Comprehensive logging with levels (log, warn, error) and error handling
33
+ * - Returns structured log messages with appropriate emojis
34
+ */
35
+ export class EnvManager {
36
+ /**
37
+ * Environment variable name for custom .env file path
38
+ */
39
+ static DEFAULT_ENV_FILE_PATH = 'OWOX_ENV_FILE_PATH';
40
+ /**
41
+ * Template messages for logging with placeholder support
42
+ *
43
+ * Templates use %placeholder% syntax for dynamic content:
44
+ * - %file% - File path
45
+ * - %type% - Environment object type (flags/default)
46
+ * - %error% - Error message
47
+ * - %qty% - Quantity/count
48
+ * - %list% - Comma-separated list
49
+ */
50
+ static MESSAGES = {
51
+ FILE_PATH_SPECIFIED: '📂 Using specified environment file: %file%',
52
+ FILE_PATH_ENVIRONMENT: '🌍 Using environment-defined file: %file%',
53
+ FILE_PATH_DEFAULT: '⚙️ Using default environment file: %file%',
54
+ FILE_NOT_FOUND: '🔍 Environment file not found: %file%',
55
+ FILE_PROCESSING: '🔄 Starting to process environment file: %file%',
56
+ FILE_PARSE_FAILED: '💥 Empty content or failed to parse environment file: %file%',
57
+ FILE_READ_FAILED: '📖 Failed to read file %file%: %error%',
58
+ FILE_SUCCESS: '✨ Environment file processed successfully',
59
+ FILE_FAILED: '🚫 Failed to process environment file',
60
+ OBJECT_UNKNOWN: '❓ Unknown environment object type: %type%',
61
+ OBJECT_INVALID: '🚨 Invalid %type% environment variables object provided',
62
+ OBJECT_START: '🚀 Starting to set up %type% values to environment variables...',
63
+ OBJECT_FAILED: '💔 Failed to set up %type% values to environment variables',
64
+ DETAILS_SET: '✅ Set %qty% variables',
65
+ DETAILS_IGNORED: '🗑️ Ignored %qty% invalid variables: %list%',
66
+ DETAILS_SKIPPED: '⏭️ Skipped %qty% existing variables: %list%',
67
+ };
68
+ /**
69
+ * Internal log buffer for the current setup operation
70
+ * Reset at the start of each setupEnvironment() call
71
+ */
72
+ static operationLog = [];
73
+ /**
74
+ * Setup environment variables from multiple sources with priority system
75
+ *
76
+ * @param config - Configuration object specifying sources and priorities (optional, uses defaults if not provided)
77
+ * @returns Result with operation messages and success status
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * // With full configuration
82
+ * const result = EnvManager.setupEnvironment({
83
+ * envFile: '.env.production',
84
+ * envFileOverride: false,
85
+ * envFileFirst: true,
86
+ * flagVars: { DEBUG: true, PORT: 3000 },
87
+ * flagVarsOverride: true,
88
+ * defaultVars: { NODE_ENV: 'development' }
89
+ * });
90
+ *
91
+ * // With default configuration (loads default .env file only)
92
+ * const result = EnvManager.setupEnvironment();
93
+ *
94
+ * if (result.success) {
95
+ * console.log('Environment setup completed');
96
+ * result.messages.forEach(msg => {
97
+ * console[msg.logLevel](msg.message);
98
+ * });
99
+ * }
100
+ * ```
101
+ */
102
+ static setupEnvironment(config = {}) {
103
+ this.operationLog = [];
104
+ if (isEnvSet) {
105
+ return {
106
+ messages: [...this.operationLog],
107
+ success: true,
108
+ };
109
+ }
110
+ const operations = this.buildOperations(config);
111
+ const success = this.executeOperations(operations);
112
+ isEnvSet = true;
113
+ return { messages: [...this.operationLog], success };
114
+ }
115
+ /**
116
+ * Build array of operations based on configuration priority settings
117
+ *
118
+ * @private
119
+ * @param config - Environment setup configuration
120
+ * @returns Array of operation functions to execute in order
121
+ */
122
+ static buildOperations(config) {
123
+ const { envFileFirst = false } = config;
124
+ const operations = [];
125
+ if (envFileFirst) {
126
+ operations.push(() => this.processEnvFile(config));
127
+ operations.push(() => this.processEnvObject(config, EnvObjectType.FLAGS));
128
+ }
129
+ else {
130
+ operations.push(() => this.processEnvObject(config, EnvObjectType.FLAGS));
131
+ operations.push(() => this.processEnvFile(config));
132
+ }
133
+ operations.push(() => this.processEnvObject(config, EnvObjectType.DEFAULT));
134
+ return operations;
135
+ }
136
+ /**
137
+ * Execute all operations sequentially and return combined success status
138
+ *
139
+ * @private
140
+ * @param operations - Array of operation functions to execute
141
+ * @returns True if all operations succeeded, false otherwise
142
+ */
143
+ static executeOperations(operations) {
144
+ return operations.reduce((allSuccessful, operation) => {
145
+ const result = operation();
146
+ return allSuccessful && result;
147
+ }, true);
148
+ }
149
+ /**
150
+ * Process environment file loading with validation and error handling
151
+ *
152
+ * @private
153
+ * @param config - Environment setup configuration containing file settings
154
+ * @returns True if file processing succeeded, false otherwise
155
+ */
156
+ static processEnvFile(config) {
157
+ const { envFile = '', envFileOverride = false } = config;
158
+ const resolvedPath = this.resolveFilePath(envFile);
159
+ if (!existsSync(resolvedPath)) {
160
+ this.logWarning(this.formatMessage(this.MESSAGES.FILE_NOT_FOUND, { file: resolvedPath }));
161
+ return false;
162
+ }
163
+ this.logInfo(this.formatMessage(this.MESSAGES.FILE_PROCESSING, { file: resolvedPath }));
164
+ const result = this.loadFromFile(resolvedPath, envFileOverride);
165
+ if (result.success) {
166
+ this.logOperationDetails(result);
167
+ this.logInfo(this.MESSAGES.FILE_SUCCESS);
168
+ }
169
+ else {
170
+ this.logError(this.MESSAGES.FILE_FAILED);
171
+ }
172
+ return result.success;
173
+ }
174
+ /**
175
+ * Process environment variables from object (flags or defaults) with type validation
176
+ *
177
+ * @private
178
+ * @param config - Environment setup configuration containing variable objects
179
+ * @param type - Type of variables being processed (flags or default)
180
+ * @returns True if object processing succeeded, false otherwise
181
+ */
182
+ static processEnvObject(config, type) {
183
+ let vars;
184
+ let override = false;
185
+ if (type === EnvObjectType.FLAGS) {
186
+ vars = config.flagVars;
187
+ override = config.flagVarsOverride || false;
188
+ }
189
+ else if (type === EnvObjectType.DEFAULT) {
190
+ vars = config.defaultVars;
191
+ }
192
+ else {
193
+ this.logError(this.formatMessage(this.MESSAGES.OBJECT_UNKNOWN, { type }));
194
+ return false;
195
+ }
196
+ if (vars) {
197
+ if (typeof vars !== 'object') {
198
+ this.logError(this.formatMessage(this.MESSAGES.OBJECT_INVALID, { type }));
199
+ return false;
200
+ }
201
+ this.logInfo(this.formatMessage(this.MESSAGES.OBJECT_START, { type }));
202
+ const result = this.setFromObject(vars, override);
203
+ if (result.success) {
204
+ this.logOperationDetails(result);
205
+ }
206
+ else {
207
+ this.logError(this.formatMessage(this.MESSAGES.OBJECT_FAILED, { type }));
208
+ }
209
+ return result.success;
210
+ }
211
+ return true;
212
+ }
213
+ /**
214
+ * Load environment variables from a file with error handling and validation
215
+ *
216
+ * Features:
217
+ * - Reads file content safely with try-catch
218
+ * - Parses .env format using dotenv library
219
+ * - Validates non-empty content
220
+ * - Returns detailed operation results
221
+ *
222
+ * @private
223
+ * @param resolvedPath - Absolute path to environment file
224
+ * @param override - Whether to override existing environment variables
225
+ * @returns Operation result with success status and variable details
226
+ *
227
+ * @example
228
+ * ```typescript
229
+ * const result = this.loadFromFile('/path/to/.env', false);
230
+ * if (result.success) {
231
+ * console.log(`Loaded ${result.setVars?.length} variables`);
232
+ * }
233
+ * ```
234
+ */
235
+ static loadFromFile(resolvedPath = '', override = false) {
236
+ let fileContent = '';
237
+ try {
238
+ // Read file content as UTF-8 string
239
+ fileContent = readFileSync(resolvedPath, 'utf8');
240
+ }
241
+ catch (error) {
242
+ this.logError(this.formatMessage(this.MESSAGES.FILE_READ_FAILED, {
243
+ file: resolvedPath,
244
+ error: error instanceof Error ? error.message : 'Unknown error',
245
+ }));
246
+ return { success: false };
247
+ }
248
+ const parsed = dotenv.parse(fileContent);
249
+ if (Object.keys(parsed).length === 0) {
250
+ this.logError(this.formatMessage(this.MESSAGES.FILE_PARSE_FAILED, { file: resolvedPath }));
251
+ return { success: false };
252
+ }
253
+ return this.setFromObject(parsed, override);
254
+ }
255
+ /**
256
+ * Set environment variables from an object with comprehensive validation
257
+ *
258
+ * Features:
259
+ * - Converts values to strings automatically (number, boolean → string)
260
+ * - Validates keys (no empty/whitespace-only keys)
261
+ * - Validates values (no undefined/null/empty values after trimming)
262
+ * - Respects existing variables unless override is true
263
+ * - Returns detailed results for logging and debugging
264
+ * - Sanitizes keys by trimming whitespace
265
+ *
266
+ * @private
267
+ * @param envVars - Object with environment variable key-value pairs
268
+ * @param override - Whether to override existing environment variables (default: false)
269
+ * @returns Operation result with set/ignored/skipped variables and success status
270
+ *
271
+ * @example
272
+ * ```typescript
273
+ * const result = this.setFromObject({
274
+ * PORT: 8080, // number → '8080'
275
+ * LOG_FORMAT: 'json', // string → 'json'
276
+ * DEBUG: true, // boolean → 'true'
277
+ * API_KEY: undefined, // ignored (undefined)
278
+ * EMPTY: '', // ignored (empty string)
279
+ * ' ': 'value' // ignored (invalid key)
280
+ * });
281
+ *
282
+ * console.log(`✅ Set ${result.setVars?.length} variables`);
283
+ * console.log(`⚠️ Ignored ${result.ignoredVars?.length} variables`);
284
+ * console.log(`⏭️ Skipped ${result.skippedVars?.length} existing variables`);
285
+ * ```
286
+ */
287
+ static setFromObject(envVars, override = false) {
288
+ const setVars = [];
289
+ const ignoredVars = [];
290
+ const skippedVars = [];
291
+ for (const [key, value] of Object.entries(envVars)) {
292
+ const sanitizedKey = key.trim();
293
+ // Check if provided key is valid (not empty after trimming)
294
+ if (!sanitizedKey) {
295
+ ignoredVars.push(`"${key}" (invalid key)`);
296
+ continue;
297
+ }
298
+ // Check if variable already exists with valid value and handle override logic
299
+ if (!override && process.env[sanitizedKey]?.trim()) {
300
+ skippedVars.push(`${sanitizedKey} (already exists)`);
301
+ continue;
302
+ }
303
+ // Check if value is not empty (undefined, null, or empty string after conversion)
304
+ if (value === undefined || value === null) {
305
+ ignoredVars.push(`${key} (undefined/null value)`);
306
+ continue;
307
+ }
308
+ const stringValue = String(value).trim();
309
+ if (!stringValue) {
310
+ ignoredVars.push(`${key} (empty string value)`);
311
+ continue;
312
+ }
313
+ // Set the environment variable
314
+ process.env[sanitizedKey] = stringValue;
315
+ setVars.push(`${sanitizedKey}=***`);
316
+ }
317
+ return {
318
+ setVars,
319
+ ignoredVars,
320
+ skippedVars,
321
+ success: true,
322
+ };
323
+ }
324
+ /**
325
+ * Resolve file path using fallback logic with comprehensive path resolution
326
+ *
327
+ * Priority order:
328
+ * 1. Specified filePath parameter (if not empty after trimming)
329
+ * 2. OWOX_ENV_FILE_PATH environment variable (if set and not empty)
330
+ * 3. Default .env file in current working directory
331
+ *
332
+ * @private
333
+ * @param filePath - User-specified file path (may be empty for fallback logic)
334
+ * @returns Resolved absolute path to environment file
335
+ */
336
+ static resolveFilePath(filePath) {
337
+ const sanitizedPath = filePath.trim();
338
+ if (sanitizedPath) {
339
+ this.logInfo(this.formatMessage(this.MESSAGES.FILE_PATH_SPECIFIED, { file: sanitizedPath }));
340
+ return sanitizedPath;
341
+ }
342
+ else if (process.env[this.DEFAULT_ENV_FILE_PATH]) {
343
+ const envSanitizedPath = process.env[this.DEFAULT_ENV_FILE_PATH]?.trim();
344
+ if (envSanitizedPath) {
345
+ this.logInfo(this.formatMessage(this.MESSAGES.FILE_PATH_ENVIRONMENT, { file: envSanitizedPath }));
346
+ return envSanitizedPath;
347
+ }
348
+ }
349
+ const defaultPath = path.resolve(process.cwd(), '.env');
350
+ this.logInfo(this.formatMessage(this.MESSAGES.FILE_PATH_DEFAULT, { file: defaultPath }));
351
+ return defaultPath;
352
+ }
353
+ /**
354
+ * Log detailed results of environment variable operation
355
+ *
356
+ * Logs counts and details for:
357
+ * - Successfully set variables
358
+ * - Ignored variables with reasons
359
+ * - Skipped existing variables
360
+ *
361
+ * @private
362
+ * @param result - Operation result containing variable details
363
+ */
364
+ static logOperationDetails(result) {
365
+ const { setVars, ignoredVars, skippedVars } = result;
366
+ if (setVars && setVars.length) {
367
+ this.logInfo(this.formatMessage(this.MESSAGES.DETAILS_SET, { qty: String(setVars.length) }));
368
+ }
369
+ if (ignoredVars && ignoredVars.length) {
370
+ this.logWarning(this.formatMessage(this.MESSAGES.DETAILS_IGNORED, {
371
+ qty: String(ignoredVars.length),
372
+ list: ignoredVars.join(', '),
373
+ }));
374
+ }
375
+ if (skippedVars && skippedVars.length) {
376
+ this.logInfo(this.formatMessage(this.MESSAGES.DETAILS_SKIPPED, {
377
+ qty: String(skippedVars.length),
378
+ list: skippedVars.join(', '),
379
+ }));
380
+ }
381
+ }
382
+ /**
383
+ * Log informational message
384
+ * @private
385
+ * @param message - Message to log
386
+ */
387
+ static logInfo(message) {
388
+ this.operationLog.push({ logLevel: LogLevel.LOG, message });
389
+ }
390
+ /**
391
+ * Log error message
392
+ * @private
393
+ * @param message - Error message to log
394
+ */
395
+ static logError(message) {
396
+ this.operationLog.push({ logLevel: LogLevel.ERROR, message });
397
+ }
398
+ /**
399
+ * Log warning message
400
+ * @private
401
+ * @param message - Warning message to log
402
+ */
403
+ static logWarning(message) {
404
+ this.operationLog.push({ logLevel: LogLevel.WARN, message });
405
+ }
406
+ /**
407
+ * Format message template by replacing placeholders with actual values
408
+ *
409
+ * @private
410
+ * @param template - Message template with %placeholder% markers
411
+ * @param replacements - Object with placeholder-value pairs
412
+ * @returns Formatted message with placeholders replaced
413
+ *
414
+ * @example
415
+ * ```typescript
416
+ * const formatted = this.formatMessage(
417
+ * 'Processing %type% with %count% items',
418
+ * { type: 'flags', count: '5' }
419
+ * );
420
+ * // Result: 'Processing flags with 5 items'
421
+ * ```
422
+ */
423
+ static formatMessage(template, replacements) {
424
+ return Object.entries(replacements).reduce((msg, [key, value]) => msg.replace(`%${key}%`, value), template);
425
+ }
426
+ }
@@ -0,0 +1,2 @@
1
+ export * from './environment/env-manager.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export * from './environment/env-manager.js';
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@owox/internal-helpers",
3
+ "version": "0.5.0",
4
+ "description": "Internal helpers used by core OWOX packages",
5
+ "type": "module",
6
+ "author": "OWOX",
7
+ "license": "ELv2",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "engines": {
12
+ "node": ">=22.16.0"
13
+ },
14
+ "homepage": "https://github.com/OWOX/owox-data-marts",
15
+ "bugs": "https://github.com/OWOX/owox-data-marts/issues",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/OWOX/owox-data-marts.git"
19
+ },
20
+ "scripts": {
21
+ "build": "tsc",
22
+ "build:clean": "shx rm -rf dist tsconfig.tsbuildinfo",
23
+ "format": "prettier --write \"**/*.{ts,js,json}\" --ignore-path ../../.prettierignore",
24
+ "format:check": "prettier --check \"**/*.{ts,js,json}\" --ignore-path ../../.prettierignore",
25
+ "lint": "eslint . --config ./eslint.config.js",
26
+ "lint:fix": "eslint . --fix --config ./eslint.config.js",
27
+ "lint:md": "markdownlint-cli2 --config ../../.markdownlint-cli2.mjs",
28
+ "lint:md:fix": "markdownlint-cli2 --config ../../.markdownlint-cli2.mjs --fix",
29
+ "prebuild": "npm run build:clean",
30
+ "prepack": "npm run build",
31
+ "prepublishOnly": "npm run lint && npm run typecheck",
32
+ "typecheck": "tsc --noEmit"
33
+ },
34
+ "keywords": [
35
+ "owox-internal-helpers",
36
+ "owox-package",
37
+ "owox"
38
+ ],
39
+ "dependencies": {
40
+ "dotenv": "^16.4.7"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^22.10.7",
44
+ "typescript": "^5.7.3"
45
+ },
46
+ "files": [
47
+ "dist"
48
+ ],
49
+ "exports": {
50
+ ".": {
51
+ "import": "./dist/index.js",
52
+ "require": "./dist/index.js",
53
+ "types": "./dist/index.d.ts"
54
+ }
55
+ },
56
+ "main": "./dist/index.js",
57
+ "types": "./dist/index.d.ts"
58
+ }