@fanboynz/network-scanner 2.0.66 → 3.0.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.
@@ -6,11 +6,24 @@
6
6
  const { LRUCache } = require('lru-cache');
7
7
  const fs = require('fs');
8
8
  const path = require('path');
9
- const { formatLogMessage } = require('./colorize');
9
+ const { formatLogMessage, messageColors } = require('./colorize');
10
+
11
+ // Precomputed colored '[SmartCache]' subsystem prefix. formatLogMessage only
12
+ // colors the [severity] tag; the '[SmartCache]' substring was sitting plain
13
+ // inside every debug message. Colored once at module load so we don't
14
+ // re-colorize per log call.
15
+ const SMART_CACHE_TAG = messageColors.processing('[SmartCache]');
10
16
 
11
17
  // Shared frozen empty object -- avoids allocating new {} for every default param
12
18
  const EMPTY = Object.freeze({});
13
19
 
20
+ // Headers we fold into the request cache key. Hoisted (not built per-call)
21
+ // so _generateRequestCacheKey doesn't allocate a fresh array on every cache
22
+ // op. Frozen because the array is treated as read-only at runtime.
23
+ const REQUEST_CACHE_KEY_HEADERS = Object.freeze([
24
+ 'accept', 'accept-encoding', 'accept-language', 'user-agent'
25
+ ]);
26
+
14
27
  /**
15
28
  * SmartCache - Intelligent caching system with multiple cache layers
16
29
  * @class
@@ -48,21 +61,20 @@ class SmartCache {
48
61
  this.saveTimeout = null;
49
62
  this.pendingSave = false;
50
63
 
51
- // Cache hot-path flags BEFORE _initializeCaches uses them
64
+ // Cache hot-path flags BEFORE _initializeCaches uses them.
52
65
  this._debug = this.options.forceDebug;
53
66
  this._highConcurrency = this.options.concurrency > 10;
54
67
  this._criticalThreshold = this._highConcurrency ? 0.85 : 1.0;
55
68
  this._warningThreshold = this._highConcurrency ? 0.70 : 0.85;
56
69
  this._infoThreshold = this._highConcurrency ? 0.60 : 0.75;
57
-
58
- // Initialize cache layers (may disable responseCache for high concurrency)
59
- this._initializeCaches();
60
-
61
- // Cache enable flags AFTER _initializeCaches which may modify options
62
70
  this._enablePattern = this.options.enablePatternCache;
63
71
  this._enableResponse = this.options.enableResponseCache;
64
72
  this._enableWhois = this.options.enableWhoisCache;
65
73
  this._enableRequest = this.options.enableRequestCache;
74
+
75
+ // Initialize cache layers. _initializeCaches may flip this._enableResponse
76
+ // off for very high concurrency / aggressive mode (and null the LRU).
77
+ this._initializeCaches();
66
78
 
67
79
  // Initialize statistics
68
80
  this._initializeStats();
@@ -71,12 +83,6 @@ class SmartCache {
71
83
  this._lastHeapUsed = 0;
72
84
  this._memoryPressure = false;
73
85
 
74
-
75
- // NEW: Clear request cache
76
- if (this._enableRequest) {
77
- this.clearRequestCache();
78
- }
79
-
80
86
  // Load persistent cache if enabled
81
87
  if (this.options.enablePersistence) {
82
88
  this._loadPersistentCache();
@@ -136,15 +142,29 @@ class SmartCache {
136
142
  ttl: this.options.ttl * 2 // Patterns are more stable
137
143
  });
138
144
 
139
- // Response content cache - aggressive limits for high concurrency
140
- const responseCacheSize = this._highConcurrency ? 50 : 200;
141
- const responseCacheMemory = this._highConcurrency ? 20 * 1024 * 1024 : 50 * 1024 * 1024;
142
- this.responseCache = new LRUCache({
143
- max: responseCacheSize,
144
- ttl: 1000 * 60 * 30, // 30 minutes for response content
145
- maxSize: responseCacheMemory,
146
- sizeCalculation: (value) => value.length
147
- });
145
+ // Response content cache - aggressive limits for high concurrency.
146
+ // Skip allocation entirely when very high concurrency / aggressive mode
147
+ // would disable it anyway (avoids a dead LRU sitting in memory).
148
+ const responseCacheDisabled = this.options.concurrency > 15 || this.options.aggressiveMode;
149
+ if (responseCacheDisabled) {
150
+ this.options.enableResponseCache = false;
151
+ this._enableResponse = false;
152
+ this.responseCache = null;
153
+ if (this._debug) {
154
+ console.log(formatLogMessage('debug',
155
+ `${SMART_CACHE_TAG} Response cache disabled for high concurrency (${this.options.concurrency})`
156
+ ));
157
+ }
158
+ } else {
159
+ const responseCacheSize = this._highConcurrency ? 50 : 200;
160
+ const responseCacheMemory = this._highConcurrency ? 20 * 1024 * 1024 : 50 * 1024 * 1024;
161
+ this.responseCache = new LRUCache({
162
+ max: responseCacheSize,
163
+ ttl: 1000 * 60 * 30, // 30 minutes for response content
164
+ maxSize: responseCacheMemory,
165
+ sizeCalculation: (value) => value.length
166
+ });
167
+ }
148
168
 
149
169
  // NEW: Request-level cache for --cache-requests feature
150
170
  if (this._enableRequest) {
@@ -163,19 +183,9 @@ class SmartCache {
163
183
  return size;
164
184
  }
165
185
  });
166
-
167
- if (this._debug) {
168
- console.log(formatLogMessage('debug', `[SmartCache] Request cache initialized: ${this.options.requestCacheMaxSize} entries`));
169
- }
170
- }
171
186
 
172
- // Disable response cache entirely for very high concurrency
173
- if (this.options.concurrency > 15 || this.options.aggressiveMode) {
174
- this.options.enableResponseCache = false;
175
187
  if (this._debug) {
176
- console.log(formatLogMessage('debug',
177
- `[SmartCache] Response cache disabled for high concurrency (${this.options.concurrency})`
178
- ));
188
+ console.log(formatLogMessage('debug', `${SMART_CACHE_TAG} Request cache initialized: ${this.options.requestCacheMaxSize} entries`));
179
189
  }
180
190
  }
181
191
 
@@ -194,9 +204,6 @@ class SmartCache {
194
204
 
195
205
  // Regex compilation cache (bounded to prevent unbounded growth)
196
206
  this.regexCache = new LRUCache({ max: 500 });
197
-
198
- // Precompile the regex-stripping pattern (used in getCompiledRegex)
199
- this._regexStripPattern = /^\/(.*)\/$/;
200
207
  }
201
208
 
202
209
  /**
@@ -245,7 +252,7 @@ class SmartCache {
245
252
  if (this._debug) {
246
253
  const age = Date.now() - cached.timestamp;
247
254
  console.log(formatLogMessage('debug',
248
- `[SmartCache] Cache hit for ${domain} (age: ${Math.round(age/1000)}s)`
255
+ `${SMART_CACHE_TAG} Cache hit for ${domain} (age: ${Math.round(age/1000)}s)`
249
256
  ));
250
257
  }
251
258
  return true;
@@ -273,7 +280,7 @@ class SmartCache {
273
280
 
274
281
  if (this._debug) {
275
282
  console.log(formatLogMessage('debug',
276
- `[SmartCache] Marked ${domain} as processed`
283
+ `${SMART_CACHE_TAG} Marked ${domain} as processed`
277
284
  ));
278
285
  }
279
286
  }
@@ -349,16 +356,16 @@ class SmartCache {
349
356
  _generateRequestCacheKey(url, options = EMPTY, normalizedUrl = null) {
350
357
  const method = options.method || 'GET';
351
358
  const normUrl = normalizedUrl || this._normalizeUrl(url);
352
- const headers = options.headers || {};
353
- const importantHeaders = ['accept', 'accept-encoding', 'accept-language', 'user-agent'];
354
-
359
+ const headers = options.headers || EMPTY;
360
+
355
361
  // Build header portion of key by direct concat (avoids JSON.stringify + intermediate array)
356
362
  let headerKey = '';
357
- for (const header of importantHeaders) {
363
+ for (let i = 0; i < REQUEST_CACHE_KEY_HEADERS.length; i++) {
364
+ const header = REQUEST_CACHE_KEY_HEADERS[i];
358
365
  const val = headers[header];
359
366
  if (val) headerKey += header + '=' + val + '&';
360
367
  }
361
-
368
+
362
369
  return method + '|' + normUrl + '|' + headerKey;
363
370
  }
364
371
 
@@ -382,14 +389,26 @@ class SmartCache {
382
389
  if (cached) {
383
390
  this.stats.requestCacheHits++;
384
391
  if (this._debug) {
385
- console.log(formatLogMessage('debug',
386
- `[SmartCache] Request cache hit for ${url.substring(0, 50)}... (${cached.status || 'unknown status'})`
392
+ console.log(formatLogMessage('debug',
393
+ `${SMART_CACHE_TAG} Request cache hit for ${url.substring(0, 50)}... (${cached.status || 'unknown status'})`
387
394
  ));
388
395
  }
389
- // Set directly on cached object (avoids spread allocation per hit)
390
- cached.fromCache = true;
391
- cached.cacheAge = Date.now() - cached.timestamp;
392
- return cached;
396
+ // Return a shallow copy with hit-time metadata. Mutating the live LRU
397
+ // entry races on cacheAge with concurrent readers and lets a caller
398
+ // accidentally corrupt the shared body/headers. The copy costs an
399
+ // object allocation per hit -- worth it for the safety.
400
+ return {
401
+ timestamp: cached.timestamp,
402
+ status: cached.status,
403
+ statusText: cached.statusText,
404
+ headers: cached.headers,
405
+ body: cached.body,
406
+ url: cached.url,
407
+ originalUrl: cached.originalUrl,
408
+ requestOptions: cached.requestOptions,
409
+ fromCache: true,
410
+ cacheAge: Date.now() - cached.timestamp
411
+ };
393
412
  }
394
413
 
395
414
  this.stats.requestCacheMisses++;
@@ -446,16 +465,16 @@ class SmartCache {
446
465
  body: result.body,
447
466
  url: normalizedUrl,
448
467
  originalUrl: url,
449
- requestOptions: { method: method, headers: options.headers || {} }
468
+ requestOptions: { method: method, headers: options.headers || EMPTY }
450
469
  });
451
470
 
452
471
  if (this._debug) {
453
472
  const bodySize = result.body ? result.body.length : 0;
454
473
  console.log(formatLogMessage('debug',
455
- `[SmartCache] Cached request: ${normalizedUrl.substring(0, 50)}... (${result.status || 'unknown'}, ${Math.round(bodySize / 1024)}KB)`
474
+ `${SMART_CACHE_TAG} Cached request: ${normalizedUrl.substring(0, 50)}... (${result.status || 'unknown'}, ${Math.round(bodySize / 1024)}KB)`
456
475
  ));
457
476
  if (normalizedUrl !== url) {
458
- console.log(formatLogMessage('debug', `[SmartCache] URL normalized: ${url} -> ${normalizedUrl}`));
477
+ console.log(formatLogMessage('debug', `${SMART_CACHE_TAG} URL normalized: ${url} -> ${normalizedUrl}`));
459
478
  }
460
479
  }
461
480
  }
@@ -473,7 +492,7 @@ class SmartCache {
473
492
 
474
493
  if (this._debug) {
475
494
  console.log(formatLogMessage('debug',
476
- `[SmartCache] Cleared request cache: ${clearedCount} entries removed`
495
+ `${SMART_CACHE_TAG} Cleared request cache: ${clearedCount} entries removed`
477
496
  ));
478
497
  }
479
498
 
@@ -552,15 +571,31 @@ class SmartCache {
552
571
 
553
572
  this.stats.regexCompilations++;
554
573
  try {
555
- const regex = new RegExp(pattern.replace(this._regexStripPattern, '$1'));
574
+ // Strip /.../ wrapper only when the pattern actually has it. String.replace
575
+ // allocates a result string even on no-match; the charCode check is free
576
+ // and skips the allocation for the common bare-pattern case. (47 == '/')
577
+ let source = pattern;
578
+ if (
579
+ pattern.length >= 2 &&
580
+ pattern.charCodeAt(0) === 47 &&
581
+ pattern.charCodeAt(pattern.length - 1) === 47
582
+ ) {
583
+ source = pattern.slice(1, -1);
584
+ }
585
+ const regex = new RegExp(source);
556
586
  this.regexCache.set(pattern, regex);
557
587
  return regex;
558
588
  } catch (err) {
559
589
  if (this._debug) {
560
- console.log(formatLogMessage('debug',
561
- `[SmartCache] Failed to compile regex: ${pattern}`
590
+ console.log(formatLogMessage('debug',
591
+ `${SMART_CACHE_TAG} Failed to compile regex: ${pattern}`
562
592
  ));
563
593
  }
594
+ // Cache the failure so repeated lookups of the same bad pattern don't
595
+ // re-enter the try/throw/catch path (a JS throw is ~10x the cost of
596
+ // compiling the regex itself). The reader at line 561 uses `!== undefined`
597
+ // so a stored `null` correctly registers as a cache hit.
598
+ this.regexCache.set(pattern, null);
564
599
  return null;
565
600
  }
566
601
  }
@@ -581,7 +616,7 @@ class SmartCache {
581
616
  this.stats.patternHits++;
582
617
  if (this._debug) {
583
618
  console.log(formatLogMessage('debug',
584
- `[SmartCache] Pattern cache hit for ${url.substring(0, 50)}...`
619
+ `${SMART_CACHE_TAG} Pattern cache hit for ${url.substring(0, 50)}...`
585
620
  ));
586
621
  }
587
622
  return cached;
@@ -621,7 +656,7 @@ class SmartCache {
621
656
  this.stats.responseHits++;
622
657
  if (this._debug) {
623
658
  console.log(formatLogMessage('debug',
624
- `[SmartCache] Response cache hit for ${url.substring(0, 50)}...`
659
+ `${SMART_CACHE_TAG} Response cache hit for ${url.substring(0, 50)}...`
625
660
  ));
626
661
  }
627
662
  return cached;
@@ -675,7 +710,7 @@ class SmartCache {
675
710
  this.stats.netToolsHits++;
676
711
  if (this._debug) {
677
712
  console.log(formatLogMessage('debug',
678
- `[SmartCache] ${tool.toUpperCase()} cache hit for ${domain}`
713
+ `${SMART_CACHE_TAG} ${tool.toUpperCase()} cache hit for ${domain}`
679
714
  ));
680
715
  }
681
716
  return cached;
@@ -763,7 +798,7 @@ class SmartCache {
763
798
  this.stats.memoryWarnings++;
764
799
  if (this._debug) {
765
800
  console.log(formatLogMessage('debug',
766
- `[SmartCache] Memory info: ${heapUsedMB}MB/${maxHeapMB}MB (${usagePercent.toFixed(1)}%)`
801
+ `${SMART_CACHE_TAG} Memory info: ${heapUsedMB}MB/${maxHeapMB}MB (${usagePercent.toFixed(1)}%)`
767
802
  ));
768
803
  }
769
804
  }
@@ -780,13 +815,13 @@ class SmartCache {
780
815
 
781
816
  if (this._debug) {
782
817
  console.log(formatLogMessage('debug',
783
- `[SmartCache] Memory ${level}: ${heapUsedMB}MB/${maxHeapMB}MB, performing cleanup...`
818
+ `${SMART_CACHE_TAG} Memory ${level}: ${heapUsedMB}MB/${maxHeapMB}MB, performing cleanup...`
784
819
  ));
785
820
  }
786
821
 
787
822
  if (level === 'critical' || this._highConcurrency) {
788
823
  // Aggressive cleanup - clear volatile caches
789
- this.responseCache.clear();
824
+ if (this.responseCache) this.responseCache.clear();
790
825
  this.patternCache.clear();
791
826
  this.similarityCache.clear();
792
827
 
@@ -798,12 +833,12 @@ class SmartCache {
798
833
  const currentSize = this.domainCache.size;
799
834
  this.domainCache.clear();
800
835
  if (this._debug) {
801
- console.log(formatLogMessage('debug', `[SmartCache] Cleared ${currentSize} domain cache entries`));
836
+ console.log(formatLogMessage('debug', `${SMART_CACHE_TAG} Cleared ${currentSize} domain cache entries`));
802
837
  }
803
838
  }
804
839
  } else if (level === 'warning') {
805
840
  // Moderate cleanup - clear largest cache
806
- this.responseCache.clear();
841
+ if (this.responseCache) this.responseCache.clear();
807
842
 
808
843
  // NEW: Clear request cache during warning cleanup if it's large
809
844
  if (this._enableRequest && this.requestCache.size > this.options.requestCacheMaxSize * 0.8) {
@@ -863,7 +898,7 @@ class SmartCache {
863
898
  netToolsHitRate: (netToolsHitRate * 100).toFixed(2) + '%',
864
899
  domainCacheSize: this.domainCache.size,
865
900
  patternCacheSize: this.patternCache.size,
866
- responseCacheSize: this.responseCache.size,
901
+ responseCacheSize: this.responseCache ? this.responseCache.size : 0,
867
902
  netToolsCacheSize: this.netToolsCache.size,
868
903
  similarityCacheSize: this.similarityCache.size,
869
904
  regexCacheSize: this.regexCache.size,
@@ -873,12 +908,14 @@ class SmartCache {
873
908
  requestCacheMemoryMB: (this._enableRequest && this.requestCache) ?
874
909
  Math.round((this.requestCache.calculatedSize || 0) / 1048576) : 0,
875
910
  totalCacheEntries: this.domainCache.size + this.patternCache.size +
876
- this.responseCache.size + this.netToolsCache.size +
911
+ (this.responseCache ? this.responseCache.size : 0) + this.netToolsCache.size +
877
912
  this.similarityCache.size + this.regexCache.size + ((this._enableRequest && this.requestCache) ? this.requestCache.size : 0),
878
913
  memoryUsageMB: Math.round(heapUsed / 1048576),
879
914
  memoryMaxMB: Math.round(maxHeap / 1048576),
880
915
  memoryUsagePercent: ((heapUsed / maxHeap) * 100).toFixed(1) + '%',
881
- responseCacheMemoryMB: Math.round((this.responseCache.calculatedSize || 0) / 1048576)
916
+ responseCacheMemoryMB: this.responseCache
917
+ ? Math.round((this.responseCache.calculatedSize || 0) / 1048576)
918
+ : 0
882
919
  };
883
920
  }
884
921
 
@@ -888,7 +925,7 @@ class SmartCache {
888
925
  clear() {
889
926
  this.domainCache.clear();
890
927
  this.patternCache.clear();
891
- this.responseCache.clear();
928
+ if (this.responseCache) this.responseCache.clear();
892
929
  this.netToolsCache.clear();
893
930
  this.similarityCache.clear();
894
931
  this.regexCache.clear();
@@ -898,7 +935,7 @@ class SmartCache {
898
935
  this._initializeStats();
899
936
 
900
937
  if (this._debug) {
901
- console.log(formatLogMessage('debug', '[SmartCache] All caches cleared'));
938
+ console.log(formatLogMessage('debug', `${SMART_CACHE_TAG} All caches cleared`));
902
939
  }
903
940
  }
904
941
 
@@ -909,7 +946,7 @@ class SmartCache {
909
946
  _logMemorySkip(operation) {
910
947
  if (this._debug) {
911
948
  console.log(formatLogMessage('debug',
912
- `[SmartCache] Skipping ${operation} due to memory pressure`
949
+ `${SMART_CACHE_TAG} Skipping ${operation} due to memory pressure`
913
950
  ));
914
951
  }
915
952
  }
@@ -936,28 +973,41 @@ class SmartCache {
936
973
  // Validate cache age
937
974
  if (data.timestamp && now - data.timestamp > 24 * 60 * 60 * 1000) {
938
975
  if (this._debug) {
939
- console.log(formatLogMessage('debug',
940
- '[SmartCache] Persistent cache too old, ignoring'
976
+ console.log(formatLogMessage('debug',
977
+ `${SMART_CACHE_TAG} Persistent cache too old, ignoring`
941
978
  ));
942
979
  }
943
980
  return;
944
981
  }
945
982
 
946
- // Load domain cache
983
+ // Load domain cache. Validate shape per-entry: a corrupted or
984
+ // version-mismatched on-disk file shouldn't be able to inject junk
985
+ // (missing timestamp, future timestamp, non-string keys, etc.).
947
986
  if (data.domainCache && Array.isArray(data.domainCache)) {
948
987
  const entries = data.domainCache;
988
+ const ttl = this.options.ttl;
949
989
  for (let i = 0; i < entries.length; i++) {
950
- if (now - entries[i][1].timestamp < this.options.ttl) {
951
- this.domainCache.set(entries[i][0], entries[i][1]);
952
- }
990
+ const e = entries[i];
991
+ if (!Array.isArray(e) || e.length !== 2) continue;
992
+ const key = e[0];
993
+ const val = e[1];
994
+ if (typeof key !== 'string' || !val || typeof val !== 'object') continue;
995
+ const ts = val.timestamp;
996
+ if (typeof ts !== 'number' || ts > now || now - ts >= ttl) continue;
997
+ this.domainCache.set(key, val);
953
998
  }
954
999
  }
955
-
956
- // Load nettools cache
1000
+
1001
+ // Load nettools cache (same shape validation).
957
1002
  if (data.netToolsCache && Array.isArray(data.netToolsCache)) {
958
1003
  const entries = data.netToolsCache;
959
1004
  for (let i = 0; i < entries.length; i++) {
960
- this.netToolsCache.set(entries[i][0], entries[i][1]);
1005
+ const e = entries[i];
1006
+ if (!Array.isArray(e) || e.length !== 2) continue;
1007
+ const key = e[0];
1008
+ const val = e[1];
1009
+ if (typeof key !== 'string' || val === undefined) continue;
1010
+ this.netToolsCache.set(key, val);
961
1011
  }
962
1012
  }
963
1013
 
@@ -965,13 +1015,13 @@ class SmartCache {
965
1015
 
966
1016
  if (this._debug) {
967
1017
  console.log(formatLogMessage('debug',
968
- `[SmartCache] Loaded persistent cache: ${this.domainCache.size} domains, ${this.netToolsCache.size} nettools`
1018
+ `${SMART_CACHE_TAG} Loaded persistent cache: ${this.domainCache.size} domains, ${this.netToolsCache.size} nettools`
969
1019
  ));
970
1020
  }
971
1021
  } catch (err) {
972
1022
  if (this._debug) {
973
1023
  console.log(formatLogMessage('debug',
974
- `[SmartCache] Failed to load persistent cache: ${err.message}`
1024
+ `${SMART_CACHE_TAG} Failed to load persistent cache: ${err.message}`
975
1025
  ));
976
1026
  }
977
1027
  }
@@ -987,7 +1037,7 @@ class SmartCache {
987
1037
  if (this.saveInProgress) {
988
1038
  this.pendingSave = true;
989
1039
  if (this._debug) {
990
- console.log(formatLogMessage('debug', '[SmartCache] Save in progress, marking pending...'));
1040
+ console.log(formatLogMessage('debug', `${SMART_CACHE_TAG} Save in progress, marking pending...`));
991
1041
  }
992
1042
  return;
993
1043
  }
@@ -1032,7 +1082,7 @@ class SmartCache {
1032
1082
  if (writeErr) {
1033
1083
  if (this._debug) {
1034
1084
  console.log(formatLogMessage('debug',
1035
- `[SmartCache] Failed to write cache temp file: ${writeErr.message}`
1085
+ `${SMART_CACHE_TAG} Failed to write cache temp file: ${writeErr.message}`
1036
1086
  ));
1037
1087
  }
1038
1088
  this.saveInProgress = false;
@@ -1043,14 +1093,14 @@ class SmartCache {
1043
1093
  if (renameErr) {
1044
1094
  if (this._debug) {
1045
1095
  console.log(formatLogMessage('debug',
1046
- `[SmartCache] Failed to rename cache file: ${renameErr.message}`
1096
+ `${SMART_CACHE_TAG} Failed to rename cache file: ${renameErr.message}`
1047
1097
  ));
1048
1098
  }
1049
1099
  } else {
1050
1100
  this.stats.persistenceSaves++;
1051
1101
  if (this._debug) {
1052
1102
  console.log(formatLogMessage('debug',
1053
- `[SmartCache] Saved cache to disk: ${cacheFile}`
1103
+ `${SMART_CACHE_TAG} Saved cache to disk: ${cacheFile}`
1054
1104
  ));
1055
1105
  }
1056
1106
  }
@@ -1069,7 +1119,7 @@ class SmartCache {
1069
1119
  } catch (err) {
1070
1120
  if (this._debug) {
1071
1121
  console.log(formatLogMessage('debug',
1072
- `[SmartCache] Failed to save cache: ${err.message}`
1122
+ `${SMART_CACHE_TAG} Failed to save cache: ${err.message}`
1073
1123
  ));
1074
1124
  }
1075
1125
  this.saveInProgress = false;
@@ -1131,7 +1181,7 @@ class SmartCache {
1131
1181
  const errors = [];
1132
1182
 
1133
1183
  if (!silent) {
1134
- console.log(`\n??? Clearing cache...`);
1184
+ console.log(`\n${messageColors.cleanup('Clearing cache...')}`);
1135
1185
  }
1136
1186
 
1137
1187
  // Try the directory first -- rmSync recursive handles all files inside
@@ -1200,13 +1250,13 @@ class SmartCache {
1200
1250
 
1201
1251
  if (!silent) {
1202
1252
  if (clearedItems > 0) {
1203
- console.log(`? Cache cleared: ${clearedItems} item(s), ${result.sizeMB}MB freed`);
1253
+ console.log(messageColors.cleanup(`Cache cleared: ${clearedItems} item(s), ${result.sizeMB}MB freed`));
1204
1254
  } else {
1205
- console.log(`?? No cache files found to clear`);
1255
+ console.log(messageColors.cleanup(`No cache files found to clear`));
1206
1256
  }
1207
-
1257
+
1208
1258
  if (errors.length > 0) {
1209
- console.warn(`?? ${errors.length} error(s) occurred during cache clearing`);
1259
+ console.warn(messageColors.warn(`${errors.length} error(s) occurred during cache clearing`));
1210
1260
  }
1211
1261
  }
1212
1262
 
@@ -19,7 +19,8 @@
19
19
 
20
20
  const net = require('net');
21
21
  const { SocksClient } = require('socks');
22
- const { formatLogMessage } = require('./colorize');
22
+ const { formatLogMessage, messageColors } = require('./colorize');
23
+ const SOCKS_RELAY_TAG = messageColors.processing('[socks-relay]');
23
24
 
24
25
  // upstreamKey -> { server, port, activeSockets:Set<net.Socket> }
25
26
  const _relays = new Map();
@@ -63,7 +64,7 @@ function handleClient(client, upstream, forceDebug) {
63
64
  handshakeTimer = setTimeout(() => {
64
65
  if (phase !== 'piping') {
65
66
  if (forceDebug) {
66
- console.log(formatLogMessage('proxy', `[socks-relay] handshake timeout (phase=${phase}) — closing`));
67
+ console.log(formatLogMessage('proxy', `${SOCKS_RELAY_TAG} handshake timeout (phase=${phase}) — closing`));
67
68
  }
68
69
  cleanup();
69
70
  }
@@ -152,7 +153,7 @@ function handleClient(client, upstream, forceDebug) {
152
153
  });
153
154
  } catch (e) {
154
155
  if (forceDebug) {
155
- console.log(formatLogMessage('proxy', `[socks-relay] upstream connect failed (${host}:${port}): ${e.message}`));
156
+ console.log(formatLogMessage('proxy', `${SOCKS_RELAY_TAG} upstream connect failed (${host}:${port}): ${e.message}`));
156
157
  }
157
158
  failReply(client, 0x05); // connection refused
158
159
  return cleanup();
@@ -178,7 +179,7 @@ function handleClient(client, upstream, forceDebug) {
178
179
  }
179
180
  } catch (e) {
180
181
  if (forceDebug) {
181
- console.log(formatLogMessage('proxy', `[socks-relay] handler error: ${e.message}`));
182
+ console.log(formatLogMessage('proxy', `${SOCKS_RELAY_TAG} handler error: ${e.message}`));
182
183
  }
183
184
  cleanup();
184
185
  }
@@ -224,7 +225,7 @@ async function ensureRelay(upstream, forceDebug = false) {
224
225
  server.removeListener('error', onErr);
225
226
  // Keep a listener so a late server error doesn't crash the process.
226
227
  server.on('error', (e) => {
227
- if (forceDebug) console.log(formatLogMessage('proxy', `[socks-relay] server error: ${e.message}`));
228
+ if (forceDebug) console.log(formatLogMessage('proxy', `${SOCKS_RELAY_TAG} server error: ${e.message}`));
228
229
  });
229
230
  resolve();
230
231
  });
@@ -233,7 +234,7 @@ async function ensureRelay(upstream, forceDebug = false) {
233
234
  const port = server.address().port;
234
235
  _relays.set(key, { server, port, activeSockets });
235
236
  if (forceDebug) {
236
- console.log(formatLogMessage('proxy', `[socks-relay] 127.0.0.1:${port} -> ${upstream.host}:${upstream.port} (auth user "${upstream.username}")`));
237
+ console.log(formatLogMessage('proxy', `${SOCKS_RELAY_TAG} 127.0.0.1:${port} -> ${upstream.host}:${upstream.port} (auth user "${upstream.username}")`));
237
238
  }
238
239
  return port;
239
240
  }
@@ -258,7 +259,7 @@ async function closeAllRelays(forceDebug = false) {
258
259
  await new Promise((res) => {
259
260
  try { r.server.close(() => res()); } catch (_) { res(); }
260
261
  });
261
- if (forceDebug) console.log(formatLogMessage('proxy', `[socks-relay] closed relay for ${key}`));
262
+ if (forceDebug) console.log(formatLogMessage('proxy', `${SOCKS_RELAY_TAG} closed relay for ${key}`));
262
263
  }
263
264
  _relays.clear();
264
265
  }