i18ntk 2.3.8 → 2.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.
@@ -1,9 +1,10 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
- const os = require('os');
4
- const crypto = require('crypto');
5
- const SecurityUtils = require('./security');
6
- const { logger } = require('./logger');
3
+ const os = require('os');
4
+ const crypto = require('crypto');
5
+ const SecurityUtils = require('./security');
6
+ const { logger } = require('./logger');
7
+ const { envManager } = require('./env-manager');
7
8
 
8
9
  // Determine package directory and user project root
9
10
  const packageDir = path.resolve(__dirname, '..');
@@ -20,55 +21,55 @@ const CONFIG_LOCK_PATH = `${PROJECT_CONFIG_PATH}.lock`;
20
21
  const CONFIG_LOCK_TIMEOUT_MS = 5000;
21
22
  const CONFIG_LOCK_STALE_MS = 15000;
22
23
  const CONFIG_LOCK_RETRY_MS = 50;
23
- let autosaveDisabledWarned = false;
24
- let defaultConfigNoticeShown = false;
25
- let configFallbackNoticeShown = false;
26
-
27
- function logInfo(message, details) {
28
- logger.info(message, details);
29
- }
30
-
31
- function logWarn(message, details) {
32
- logger.warn(message, details);
33
- }
34
-
35
- function logError(message, details) {
36
- logger.error(message, details);
37
- }
38
-
39
- function notifyDefaultConfig(reason, error) {
40
- if (defaultConfigNoticeShown) {
41
- return;
42
- }
43
- defaultConfigNoticeShown = true;
44
-
45
- logger.info('Using default configuration (reason: configuration error)', { reason });
46
- if (logger.isDebugMode() && error) {
47
- logger.debug(`Default configuration reason details: ${error.message}`, {
48
- stack: error.stack
49
- });
50
- }
51
- }
52
-
53
- function notifyConfigFallback(error) {
54
- if (!configFallbackNoticeShown) {
55
- configFallbackNoticeShown = true;
56
- logger.info('Using default configuration (reason: configuration error)', {
57
- reason: 'configuration error'
58
- });
59
- }
60
-
61
- logger.recordFirstError('config:load-fallback', {
62
- message: error && error.message ? error.message : 'Unknown configuration error',
63
- stack: error && error.stack ? error.stack : null
64
- });
65
-
66
- if (logger.isDebugMode() && error) {
67
- logger.debug(`Configuration load fallback details: ${error.message}`, {
68
- stack: error.stack
69
- });
70
- }
71
- }
24
+ let autosaveDisabledWarned = false;
25
+ let defaultConfigNoticeShown = false;
26
+ let configFallbackNoticeShown = false;
27
+
28
+ function logInfo(message, details) {
29
+ logger.info(message, details);
30
+ }
31
+
32
+ function logWarn(message, details) {
33
+ logger.warn(message, details);
34
+ }
35
+
36
+ function logError(message, details) {
37
+ logger.error(message, details);
38
+ }
39
+
40
+ function notifyDefaultConfig(reason, error) {
41
+ if (defaultConfigNoticeShown) {
42
+ return;
43
+ }
44
+ defaultConfigNoticeShown = true;
45
+
46
+ logger.info('Using default configuration (reason: configuration error)', { reason });
47
+ if (logger.isDebugMode() && error) {
48
+ logger.debug(`Default configuration reason details: ${error.message}`, {
49
+ stack: error.stack
50
+ });
51
+ }
52
+ }
53
+
54
+ function notifyConfigFallback(error) {
55
+ if (!configFallbackNoticeShown) {
56
+ configFallbackNoticeShown = true;
57
+ logger.info('Using default configuration (reason: configuration error)', {
58
+ reason: 'configuration error'
59
+ });
60
+ }
61
+
62
+ logger.recordFirstError('config:load-fallback', {
63
+ message: error && error.message ? error.message : 'Unknown configuration error',
64
+ stack: error && error.stack ? error.stack : null
65
+ });
66
+
67
+ if (logger.isDebugMode() && error) {
68
+ logger.debug(`Configuration load fallback details: ${error.message}`, {
69
+ stack: error.stack
70
+ });
71
+ }
72
+ }
72
73
 
73
74
  // Setup tracking file
74
75
  const SETUP_COMPLETED_FILE = path.join(PROJECT_SETTINGS_DIR, 'setup.json');
@@ -362,8 +363,7 @@ async function acquireConfigLock(timeoutMs = CONFIG_LOCK_TIMEOUT_MS) {
362
363
  }
363
364
 
364
365
  function isAutosaveDisabled() {
365
- const flag = String(process.env.I18NTK_DISABLE_AUTOSAVE || '').trim().toLowerCase();
366
- return flag === '1' || flag === 'true' || flag === 'yes';
366
+ return envManager.getBoolean('I18NTK_DISABLE_AUTOSAVE');
367
367
  }
368
368
 
369
369
  function clone(obj) {
@@ -530,8 +530,8 @@ function loadConfig() {
530
530
  currentConfig = cfg;
531
531
  return currentConfig;
532
532
  } catch (error) {
533
- logError('[i18ntk] Error in loadConfig', { error: error.message });
534
- notifyConfigFallback(error);
533
+ logError('[i18ntk] Error in loadConfig', { error: error.message });
534
+ notifyConfigFallback(error);
535
535
  currentConfig = clone(DEFAULT_CONFIG);
536
536
  return currentConfig;
537
537
  } finally {
@@ -590,7 +590,7 @@ async function saveConfig(cfg = currentConfig) {
590
590
  currentConfig = cfg;
591
591
  return true;
592
592
  } catch (error) {
593
- logError('[i18ntk] Error saving configuration', { error: error.message });
593
+ logError('[i18ntk] Error saving configuration', { error: error.message });
594
594
  return false;
595
595
  } finally {
596
596
  if (releaseLock) {
@@ -643,7 +643,7 @@ function getConfig() {
643
643
 
644
644
  // Check for legacy config for migration
645
645
  if (SecurityUtils.safeExistsSync(LEGACY_CONFIG_PATH)) {
646
- logInfo('Migrating legacy configuration');
646
+ logInfo('Migrating legacy configuration');
647
647
  const legacyRaw = SecurityUtils.safeReadFileSync(LEGACY_CONFIG_PATH, path.dirname(LEGACY_CONFIG_PATH), 'utf8');
648
648
  const legacyConfig = SecurityUtils.safeParseJSON(legacyRaw);
649
649
  if (!legacyConfig || typeof legacyConfig !== 'object') {
@@ -651,7 +651,7 @@ function getConfig() {
651
651
  }
652
652
  const migratedConfig = { ...DEFAULT_CONFIG, ...legacyConfig };
653
653
  saveConfig(migratedConfig).catch((err) => {
654
- logWarn('[i18ntk] Warning: failed to persist migrated configuration', { error: err.message });
654
+ logWarn('[i18ntk] Warning: failed to persist migrated configuration', { error: err.message });
655
655
  });
656
656
  currentConfig = migratedConfig;
657
657
 
@@ -669,18 +669,18 @@ function getConfig() {
669
669
  }
670
670
 
671
671
  // Use package defaults for new installation
672
- notifyDefaultConfig('default initialization');
673
- saveConfig(DEFAULT_CONFIG).catch((err) => {
674
- logWarn('[i18ntk] Warning: failed to persist default configuration', { error: err.message });
675
- });
676
- currentConfig = DEFAULT_CONFIG;
677
- return resolvePaths(DEFAULT_CONFIG);
678
-
679
- } catch (error) {
680
- notifyConfigFallback(error);
681
- currentConfig = DEFAULT_CONFIG;
682
- return resolvePaths(DEFAULT_CONFIG);
683
- }
672
+ notifyDefaultConfig('default initialization');
673
+ saveConfig(DEFAULT_CONFIG).catch((err) => {
674
+ logWarn('[i18ntk] Warning: failed to persist default configuration', { error: err.message });
675
+ });
676
+ currentConfig = DEFAULT_CONFIG;
677
+ return resolvePaths(DEFAULT_CONFIG);
678
+
679
+ } catch (error) {
680
+ notifyConfigFallback(error);
681
+ currentConfig = DEFAULT_CONFIG;
682
+ return resolvePaths(DEFAULT_CONFIG);
683
+ }
684
684
  }
685
685
 
686
686
  async function setConfig(cfg) {
@@ -13,6 +13,54 @@ const ALLOWED_ENV_VARS = {
13
13
  validate: (value) => ['error', 'warn', 'info', 'debug', 'silent'].includes(value.toLowerCase()),
14
14
  transform: (value) => value.toLowerCase()
15
15
  },
16
+
17
+ 'DEBUG_MODE': {
18
+ default: 'false',
19
+ validate: (value) => ['true', 'false', '1', '0', 'yes', 'no'].includes(value.toLowerCase()),
20
+ transform: normalizeBooleanString
21
+ },
22
+
23
+ 'JSON_LOG': {
24
+ default: 'false',
25
+ validate: (value) => ['true', 'false', '1', '0', 'yes', 'no'].includes(value.toLowerCase()),
26
+ transform: normalizeBooleanString
27
+ },
28
+
29
+ 'NODE_ENV': {
30
+ default: 'development',
31
+ validate: (value) => ['development', 'production', 'test'].includes(value.toLowerCase()),
32
+ transform: (value) => value.toLowerCase()
33
+ },
34
+
35
+ 'CI': {
36
+ default: 'false',
37
+ validate: (value) => ['true', 'false', '1', '0', 'yes', 'no'].includes(value.toLowerCase()),
38
+ transform: normalizeBooleanString
39
+ },
40
+
41
+ 'CONTINUOUS_INTEGRATION': {
42
+ default: 'false',
43
+ validate: (value) => ['true', 'false', '1', '0', 'yes', 'no'].includes(value.toLowerCase()),
44
+ transform: normalizeBooleanString
45
+ },
46
+
47
+ 'NO_INTERACTIVE': {
48
+ default: 'false',
49
+ validate: (value) => ['true', 'false', '1', '0', 'yes', 'no'].includes(value.toLowerCase()),
50
+ transform: normalizeBooleanString
51
+ },
52
+
53
+ 'npm_lifecycle_event': {
54
+ default: '',
55
+ validate: (value) => typeof value === 'string',
56
+ transform: (value) => value.trim()
57
+ },
58
+
59
+ 'npm_config_loglevel': {
60
+ default: '',
61
+ validate: (value) => typeof value === 'string',
62
+ transform: (value) => value.trim().toLowerCase()
63
+ },
16
64
 
17
65
  'I18NTK_OUTDIR': {
18
66
  default: './i18ntk-reports',
@@ -21,29 +69,23 @@ const ALLOWED_ENV_VARS = {
21
69
  },
22
70
 
23
71
  // UI and interaction
24
- 'I18NTK_UI_LANGUAGE': {
25
- default: 'en',
26
- validate: (value) => ['en', 'de', 'es', 'fr', 'ru', 'ja', 'zh'].includes(value.toLowerCase()),
27
- transform: (value) => value.toLowerCase()
28
- },
72
+ 'I18NTK_UI_LANGUAGE': {
73
+ default: 'en',
74
+ validate: (value) => ['en', 'de', 'es', 'fr', 'ru', 'ja', 'zh'].includes(value.toLowerCase()),
75
+ transform: (value) => value.toLowerCase()
76
+ },
29
77
 
30
78
  'I18NTK_SILENT': {
31
79
  default: 'false',
32
80
  validate: (value) => ['true', 'false', '1', '0', 'yes', 'no'].includes(value.toLowerCase()),
33
- transform: (value) => {
34
- const lower = value.toLowerCase();
35
- return lower === 'true' || lower === '1' || lower === 'yes' ? 'true' : 'false';
36
- }
81
+ transform: normalizeBooleanString
37
82
  },
38
83
 
39
84
  // Debug and development
40
85
  'I18NTK_DEBUG_LOCALES': {
41
- default: '0',
86
+ default: 'false',
42
87
  validate: (value) => ['0', '1', 'true', 'false'].includes(value.toLowerCase()),
43
- transform: (value) => {
44
- const lower = value.toLowerCase();
45
- return lower === '1' || lower === 'true' ? '1' : '0';
46
- }
88
+ transform: normalizeBooleanString
47
89
  },
48
90
 
49
91
  // Runtime configuration
@@ -54,19 +96,19 @@ const ALLOWED_ENV_VARS = {
54
96
  },
55
97
 
56
98
  'I18NTK_I18N_DIR': {
57
- default: './locales',
99
+ default: null,
58
100
  validate: (value) => typeof value === 'string' && value.length > 0,
59
101
  transform: (value) => value.trim()
60
102
  },
61
103
 
62
104
  'I18NTK_SOURCE_DIR': {
63
- default: './locales',
105
+ default: null,
64
106
  validate: (value) => typeof value === 'string' && value.length > 0,
65
107
  transform: (value) => value.trim()
66
108
  },
67
109
 
68
110
  'I18NTK_PROJECT_ROOT': {
69
- default: '.',
111
+ default: null,
70
112
  validate: (value) => typeof value === 'string' && value.length > 0,
71
113
  transform: (value) => value.trim()
72
114
  },
@@ -87,13 +129,57 @@ const ALLOWED_ENV_VARS = {
87
129
  'I18NTK_FRAMEWORK_DETECT': {
88
130
  default: 'true',
89
131
  validate: (value) => ['true', 'false', '1', '0', 'yes', 'no'].includes(value.toLowerCase()),
90
- transform: (value) => {
91
- const lower = value.toLowerCase();
92
- return lower === 'true' || lower === '1' || lower === 'yes' ? 'true' : 'false';
93
- }
132
+ transform: normalizeBooleanString
133
+ },
134
+
135
+ 'I18NTK_DISABLE_AUTOSAVE': {
136
+ default: 'false',
137
+ validate: (value) => ['true', 'false', '1', '0', 'yes', 'no'].includes(value.toLowerCase()),
138
+ transform: normalizeBooleanString
139
+ },
140
+
141
+ 'I18NTK_INTERNAL_PATH_PREFIXES': {
142
+ default: '',
143
+ validate: (value) => typeof value === 'string',
144
+ transform: (value) => value.trim()
145
+ },
146
+
147
+ 'I18NTK_ENABLE_SECURITY_LOGS': {
148
+ default: 'false',
149
+ validate: (value) => ['true', 'false', '1', '0', 'yes', 'no'].includes(value.toLowerCase()),
150
+ transform: normalizeBooleanString
151
+ },
152
+
153
+ 'TERM_PROGRAM': {
154
+ default: '',
155
+ validate: (value) => typeof value === 'string',
156
+ transform: (value) => value.trim()
157
+ },
158
+
159
+ 'WT_SESSION': {
160
+ default: '',
161
+ validate: (value) => typeof value === 'string',
162
+ transform: (value) => value.trim()
163
+ },
164
+
165
+ 'PSModulePath': {
166
+ default: '',
167
+ validate: (value) => typeof value === 'string',
168
+ transform: (value) => value.trim()
169
+ },
170
+
171
+ 'POWERSHELL_EDITION': {
172
+ default: '',
173
+ validate: (value) => typeof value === 'string',
174
+ transform: (value) => value.trim()
94
175
  }
95
176
  };
96
177
 
178
+ function normalizeBooleanString(value) {
179
+ const lower = String(value || '').toLowerCase();
180
+ return lower === 'true' || lower === '1' || lower === 'yes' ? 'true' : 'false';
181
+ }
182
+
97
183
  // Security: Block access to sensitive environment variables
98
184
  const BLOCKED_PATTERNS = [
99
185
  /^SECRET/i,
@@ -170,6 +256,11 @@ class EnvironmentManager {
170
256
  }
171
257
  }
172
258
 
259
+ getBoolean(name) {
260
+ const value = this.get(name);
261
+ return value === true || value === 'true' || value === '1';
262
+ }
263
+
173
264
  /**
174
265
  * Check if an environment variable is allowed
175
266
  * @param {string} name - Environment variable name
@@ -229,7 +320,7 @@ class EnvironmentManager {
229
320
  const descriptions = {
230
321
  'I18NTK_LOG_LEVEL': 'Logging level (error, warn, info, debug, silent)',
231
322
  'I18NTK_OUTDIR': 'Output directory for reports and generated files',
232
- 'I18NTK_UI_LANGUAGE': 'UI language (en, de, es, fr, ru, ja, zh)',
323
+ 'I18NTK_UI_LANGUAGE': 'UI language (en, de, es, fr, ru, ja, zh)',
233
324
  'I18NTK_SILENT': 'Run in silent mode without interactive prompts',
234
325
  'I18NTK_DEBUG_LOCALES': 'Enable debug logging for locale loading',
235
326
  'I18NTK_RUNTIME_DIR': 'Custom runtime directory path',
@@ -248,9 +339,9 @@ class EnvironmentManager {
248
339
  // Create singleton instance
249
340
  const envManager = new EnvironmentManager();
250
341
 
251
- module.exports = {
252
- EnvironmentManager,
253
- envManager,
342
+ module.exports = {
343
+ EnvironmentManager,
344
+ envManager,
254
345
  ALLOWED_ENV_VARS,
255
346
  BLOCKED_PATTERNS
256
- };
347
+ };
@@ -1,7 +1,8 @@
1
1
  // utils/i18n-helper.js
2
- const path = require('path');
3
- const fs = require('fs');
4
- const { logger } = require('./logger');
2
+ const path = require('path');
3
+ const fs = require('fs');
4
+ const { logger } = require('./logger');
5
+ const { envManager } = require('./env-manager');
5
6
 
6
7
  // Lazy load SecurityUtils to prevent circular dependencies
7
8
  let securityUtils;
@@ -101,15 +102,15 @@ function pkgUiLocalesDirViaThisFile() {
101
102
  return path.resolve(__dirname, '..', 'ui-locales');
102
103
  }
103
104
 
104
- function pkgUiLocalesDirViaResolve() {
105
- try {
106
- // Resolve using the current exported package path.
107
- const enJson = require.resolve('i18ntk/ui-locales/en.json');
108
- return path.dirname(enJson);
109
- } catch {
110
- return null;
111
- }
112
- }
105
+ function pkgUiLocalesDirViaResolve() {
106
+ try {
107
+ // Resolve using the current exported package path.
108
+ const enJson = require.resolve('i18ntk/ui-locales/en.json');
109
+ return path.dirname(enJson);
110
+ } catch {
111
+ return null;
112
+ }
113
+ }
113
114
 
114
115
  // Removed legacyResourcesUiLocalesDir as resources/i18n/ui-locales is deprecated
115
116
 
@@ -162,7 +163,7 @@ function findLocaleFilesAllDirs(lang, preferredDir) {
162
163
  const SecurityUtils = getSecurityUtils();
163
164
  const dirs = resolveLocalesDirs(preferredDir);
164
165
 
165
- if (process.env.I18NTK_DEBUG_LOCALES === '1') {
166
+ if (envManager.getBoolean('I18NTK_DEBUG_LOCALES')) {
166
167
  console.log('🔎 i18ntk locale search dirs:', dirs);
167
168
  }
168
169
 
@@ -194,28 +195,28 @@ function findLocaleFilesAllDirs(lang, preferredDir) {
194
195
  }
195
196
  }
196
197
 
197
- if (process.env.I18NTK_DEBUG_LOCALES === '1' && errors.length > 0) {
198
+ if (envManager.getBoolean('I18NTK_DEBUG_LOCALES') && errors.length > 0) {
198
199
  console.warn(`⚠️ Locale resolution errors for ${lang}:`, errors);
199
200
  }
200
201
 
201
202
  return files;
202
203
  }
203
204
 
204
- let translations = {};
205
- let currentLanguage = 'en';
206
- let isInitialized = false;
207
- const missingKeyCache = new Map();
208
- const missingKeyTtlMs = 5 * 60 * 1000;
209
-
210
- function shouldReportMissingKey(key) {
211
- const now = Date.now();
212
- const expiresAt = missingKeyCache.get(key) || 0;
213
- if (expiresAt > now) {
214
- return false;
215
- }
216
- missingKeyCache.set(key, now + missingKeyTtlMs);
217
- return true;
218
- }
205
+ let translations = {};
206
+ let currentLanguage = 'en';
207
+ let isInitialized = false;
208
+ const missingKeyCache = new Map();
209
+ const missingKeyTtlMs = 5 * 60 * 1000;
210
+
211
+ function shouldReportMissingKey(key) {
212
+ const now = Date.now();
213
+ const expiresAt = missingKeyCache.get(key) || 0;
214
+ if (expiresAt > now) {
215
+ return false;
216
+ }
217
+ missingKeyCache.set(key, now + missingKeyTtlMs);
218
+ return true;
219
+ }
219
220
 
220
221
  function loadTranslations(language) {
221
222
  const cfg = safeRequireConfig();
@@ -243,7 +244,7 @@ function loadTranslations(language) {
243
244
  currentLanguage = lang;
244
245
  isInitialized = true;
245
246
 
246
- if (process.env.I18NTK_DEBUG_LOCALES === '1') {
247
+ if (envManager.getBoolean('I18NTK_DEBUG_LOCALES')) {
247
248
  console.log(`🗂 Loaded UI locale → ${file} (${lang})`);
248
249
  }
249
250
 
@@ -255,7 +256,7 @@ function loadTranslations(language) {
255
256
  }
256
257
  } catch (e) {
257
258
  loadErrors.push({ file, error: e.message });
258
- if (process.env.I18NTK_DEBUG_LOCALES === '1') {
259
+ if (envManager.getBoolean('I18NTK_DEBUG_LOCALES')) {
259
260
  console.warn(`⚠️ Failed to parse ${file}: ${e.message}`);
260
261
  }
261
262
  }
@@ -263,7 +264,7 @@ function loadTranslations(language) {
263
264
  }
264
265
 
265
266
  // Log comprehensive error summary if debugging
266
- if (process.env.I18NTK_DEBUG_LOCALES === '1' && loadErrors.length > 0) {
267
+ if (envManager.getBoolean('I18NTK_DEBUG_LOCALES') && loadErrors.length > 0) {
267
268
  console.warn(`📊 Locale loading errors summary:`, {
268
269
  requested: requested,
269
270
  triedLanguages: tryOrder,
@@ -298,11 +299,11 @@ function loadTranslations(language) {
298
299
  currentLanguage = 'en';
299
300
  isInitialized = true;
300
301
 
301
- if (loadErrors.length > 0) {
302
- logger.warn('No valid UI locale files found. Using built-in English strings.', {
303
- errorCount: loadErrors.length
304
- });
305
- }
302
+ if (loadErrors.length > 0) {
303
+ logger.warn('No valid UI locale files found. Using built-in English strings.', {
304
+ errorCount: loadErrors.length
305
+ });
306
+ }
306
307
 
307
308
  return translations;
308
309
  }
@@ -351,24 +352,24 @@ function t(key, params = {}) {
351
352
  }
352
353
  }
353
354
 
354
- if (typeof value === 'undefined') {
355
- if (shouldReportMissingKey(key)) {
356
- logger.logMissingTranslationKey(key, 'Configuration error');
357
- }
358
- return key;
359
- }
355
+ if (typeof value === 'undefined') {
356
+ if (shouldReportMissingKey(key)) {
357
+ logger.logMissingTranslationKey(key, 'Configuration error');
358
+ }
359
+ return key;
360
+ }
360
361
 
361
362
  // If we found a string, interpolate parameters
362
363
  if (typeof value === 'string') {
363
364
  return interpolateParams(value, params);
364
365
  }
365
366
 
366
- // Return the key if the final value is not a string
367
- if (shouldReportMissingKey(`${key}:non-string`)) {
368
- logger.warn(`Translation key does not resolve to a string: ${key}`);
369
- }
370
- return key;
371
- }
367
+ // Return the key if the final value is not a string
368
+ if (shouldReportMissingKey(`${key}:non-string`)) {
369
+ logger.warn(`Translation key does not resolve to a string: ${key}`);
370
+ }
371
+ return key;
372
+ }
372
373
 
373
374
  /**
374
375
  * Interpolate parameters into a translation string
@@ -1,8 +1,9 @@
1
- const packageJson = require('../package.json');
2
-
3
- /**
4
- * JSON Output Utility for i18ntk commands
5
- * Provides consistent machine-readable output format for CI/CD integration
1
+ const packageJson = require('../package.json');
2
+ const { envManager } = require('./env-manager');
3
+
4
+ /**
5
+ * JSON Output Utility for i18ntk commands
6
+ * Provides consistent machine-readable output format for CI/CD integration
6
7
  */
7
8
 
8
9
  class JsonOutput {
@@ -23,11 +24,11 @@ class JsonOutput {
23
24
  };
24
25
  }
25
26
 
26
- getPackageVersion() {
27
- try {
28
- return packageJson.version;
29
- } catch (error) {
30
- return '1.8.3';
27
+ getPackageVersion() {
28
+ try {
29
+ return packageJson.version;
30
+ } catch (error) {
31
+ return '1.8.3';
31
32
  }
32
33
  }
33
34
 
@@ -75,7 +76,7 @@ class JsonOutput {
75
76
  output() {
76
77
  this.data.metadata.duration = Date.now() - this.startTime;
77
78
 
78
- if (process.env.NODE_ENV !== 'test') {
79
+ if (envManager.get('NODE_ENV') !== 'test') {
79
80
  console.log(JSON.stringify(this.data, null, 2));
80
81
  }
81
82
 
@@ -97,4 +98,4 @@ class JsonOutput {
97
98
  }
98
99
  }
99
100
 
100
- module.exports = JsonOutput;
101
+ module.exports = JsonOutput;
package/utils/logger.js CHANGED
@@ -1,4 +1,5 @@
1
1
  const colors = require('./colors-new');
2
+ const { envManager } = require('./env-manager');
2
3
 
3
4
  const LEVELS = { error: 0, warn: 1, info: 2, debug: 3 };
4
5
  const DEFAULT_INTERNAL_PREFIXES = ['[BUILD]', '[WORKERS]', '[I18N]', '[SECURITY]', '[SUCCESS]', '[WARN]', '[ERROR]', '[INFO]', '[DEBUG]'];
@@ -9,8 +10,8 @@ function asBoolean(value) {
9
10
  }
10
11
 
11
12
  function resolveLevel() {
12
- const debugMode = asBoolean(process.env.DEBUG_MODE);
13
- const configured = String(process.env.I18NTK_LOG_LEVEL || '').trim().toLowerCase();
13
+ const debugMode = envManager.getBoolean('DEBUG_MODE');
14
+ const configured = String(envManager.get('I18NTK_LOG_LEVEL') || '').trim().toLowerCase();
14
15
  if (configured && Object.prototype.hasOwnProperty.call(LEVELS, configured)) {
15
16
  return configured;
16
17
  }
@@ -20,7 +21,7 @@ function resolveLevel() {
20
21
  }
21
22
 
22
23
  // Silent-by-default in production-like builds.
23
- if (process.env.NODE_ENV === 'production' || asBoolean(process.env.CI)) {
24
+ if (envManager.get('NODE_ENV') === 'production' || envManager.getBoolean('CI')) {
24
25
  return 'error';
25
26
  }
26
27
 
@@ -43,7 +44,7 @@ function normalizePrefix(prefix, fallback) {
43
44
  function write(level, message, options = {}) {
44
45
  if (!shouldLog(level)) return;
45
46
 
46
- const jsonMode = asBoolean(process.env.JSON_LOG);
47
+ const jsonMode = envManager.getBoolean('JSON_LOG');
47
48
  const prefix = normalizePrefix(options.prefix, `[${level.toUpperCase()}]`);
48
49
  const details = options.details && typeof options.details === 'object' ? options.details : undefined;
49
50
  const text = String(message || '').trim();
@@ -116,7 +117,7 @@ function flushErrorContexts() {
116
117
  function emitErrorContextSummary({ force = false } = {}) {
117
118
  const contexts = Array.from(FIRST_ERROR_CONTEXT.entries());
118
119
  if (!contexts.length) return;
119
- if (!force && !asBoolean(process.env.DEBUG_MODE)) return;
120
+ if (!force && !envManager.getBoolean('DEBUG_MODE')) return;
120
121
 
121
122
  for (const [key, context] of contexts) {
122
123
  write('debug', `First error context (${key})`, { prefix: '[ERROR]', details: context });
@@ -204,7 +205,7 @@ const logger = {
204
205
  write('info', String(message), { prefix: '[BUILD]', details });
205
206
  },
206
207
  isDebugMode() {
207
- return asBoolean(process.env.DEBUG_MODE) || resolveLevel() === 'debug';
208
+ return envManager.getBoolean('DEBUG_MODE') || resolveLevel() === 'debug';
208
209
  },
209
210
  shouldLog,
210
211
  formatDuration,