@fanboynz/network-scanner 1.0.67 → 1.0.69

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/nwss.js CHANGED
@@ -1,4 +1,4 @@
1
- // === Network scanner script (nwss.js) v1.0.67 ===
1
+ // === Network scanner script (nwss.js) v1.0.69 ===
2
2
 
3
3
  // puppeteer for browser automation, fs for file system operations, psl for domain parsing.
4
4
  // const pLimit = require('p-limit'); // Will be dynamically imported
@@ -27,6 +27,8 @@ const { createNetToolsHandler, createEnhancedDryRunCallback, validateWhoisAvaila
27
27
  const { loadComparisonRules, filterUniqueRules } = require('./lib/compare');
28
28
  // CDP functionality
29
29
  const { createCDPSession } = require('./lib/cdp');
30
+ // Post-processing cleanup
31
+ const { processResults } = require('./lib/post-processing');
30
32
  // Colorize various text when used
31
33
  const { colorize, colors, messageColors, tags, formatLogMessage } = require('./lib/colorize');
32
34
  // Enhanced mouse interaction and page simulation
@@ -42,6 +44,37 @@ function fastTimeout(ms) {
42
44
  return new Promise(resolve => setTimeout(resolve, ms));
43
45
  }
44
46
 
47
+ // --- Configuration Constants ---
48
+ const TIMEOUTS = {
49
+ DEFAULT_PAGE: 30000,
50
+ DEFAULT_NAVIGATION: 25000,
51
+ DEFAULT_NAVIGATION_REDUCED: 20000, // Reduced timeout for faster failures
52
+ DEFAULT_PAGE_REDUCED: 15000, // Reduced page timeout
53
+ FRAME_LOAD_WAIT: 2000,
54
+ NETWORK_IDLE: 2000,
55
+ NETWORK_IDLE_MAX: 10000,
56
+ FAST_SITE_THRESHOLD: 15000,
57
+ EMERGENCY_RESTART_DELAY: 2000,
58
+ BROWSER_STABILIZE_DELAY: 1000,
59
+ CURL_HANDLER_DELAY: 3000,
60
+ PROTOCOL_TIMEOUT: 60000,
61
+ REDIRECT_JS_TIMEOUT: 5000
62
+ };
63
+
64
+ const CACHE_LIMITS = {
65
+ DISK_CACHE_SIZE: 52428800, // 50MB
66
+ MEDIA_CACHE_SIZE: 52428800, // 50MB
67
+ DEFAULT_CACHE_PATH: '.cache',
68
+ DEFAULT_MAX_SIZE: 5000
69
+ };
70
+
71
+ const CONCURRENCY_LIMITS = {
72
+ MIN: 1,
73
+ MAX: 50,
74
+ DEFAULT: 6,
75
+ HIGH_CONCURRENCY_THRESHOLD: 12 // Auto-enable aggressive caching above this
76
+ };
77
+
45
78
  /**
46
79
  * Detects the installed Puppeteer version dynamically
47
80
  * @returns {Object} Version info and compatibility settings
@@ -85,7 +118,7 @@ const { navigateWithRedirectHandling, handleRedirectTimeout } = require('./lib/r
85
118
  const { monitorBrowserHealth, isBrowserHealthy } = require('./lib/browserhealth');
86
119
 
87
120
  // --- Script Configuration & Constants ---
88
- const VERSION = '1.0.67'; // Script version
121
+ const VERSION = '1.0.69'; // Script version
89
122
 
90
123
  // get startTime
91
124
  const startTime = Date.now();
@@ -276,7 +309,7 @@ if (clearCache && !dryRunMode) {
276
309
  clearPersistentCache({
277
310
  silent: silentMode,
278
311
  forceDebug,
279
- cachePath: '.cache' // Default path, will be updated after config loads if needed
312
+ cachePath: CACHE_LIMITS.DEFAULT_CACHE_PATH // Default path, will be updated after config loads if needed
280
313
  });
281
314
  }
282
315
 
@@ -566,24 +599,24 @@ const {
566
599
  const MAX_CONCURRENT_SITES = (() => {
567
600
  // Check command line argument first
568
601
  if (maxConcurrentSites !== null) {
569
- if (maxConcurrentSites > 0 && maxConcurrentSites <= 50) {
602
+ if (maxConcurrentSites >= CONCURRENCY_LIMITS.MIN && maxConcurrentSites <= CONCURRENCY_LIMITS.MAX) {
570
603
  if (forceDebug) console.log(formatLogMessage('debug', `Using command line max_concurrent_sites: ${maxConcurrentSites}`));
571
604
  return maxConcurrentSites;
572
605
  } else {
573
- console.warn(`⚠ Invalid --max-concurrent value: ${maxConcurrentSites}. Must be 1-50. Using config/default value.`);
606
+ console.warn(`⚠ Invalid --max-concurrent value: ${maxConcurrentSites}. Must be ${CONCURRENCY_LIMITS.MIN}-${CONCURRENCY_LIMITS.MAX}. Using config/default value.`);
574
607
  }
575
608
  }
576
609
 
577
610
  // Check config.json value
578
- if (typeof max_concurrent_sites === 'number' && max_concurrent_sites > 0 && max_concurrent_sites <= 50) {
611
+ if (typeof max_concurrent_sites === 'number' && max_concurrent_sites >= CONCURRENCY_LIMITS.MIN && max_concurrent_sites <= CONCURRENCY_LIMITS.MAX) {
579
612
  if (forceDebug) console.log(formatLogMessage('debug', `Using config max_concurrent_sites: ${max_concurrent_sites}`));
580
613
  return max_concurrent_sites;
581
- } else if (max_concurrent_sites !== 6) {
582
- console.warn(`⚠ Invalid config max_concurrent_sites value: ${max_concurrent_sites}. Using default: 6`);
614
+ } else if (max_concurrent_sites !== CONCURRENCY_LIMITS.DEFAULT) {
615
+ console.warn(`⚠ Invalid config max_concurrent_sites value: ${max_concurrent_sites}. Using default: ${CONCURRENCY_LIMITS.DEFAULT}`);
583
616
  }
584
617
 
585
618
  // Use default
586
- return 6;
619
+ return CONCURRENCY_LIMITS.DEFAULT;
587
620
  })();
588
621
 
589
622
  const RESOURCE_CLEANUP_INTERVAL = (() => {
@@ -619,7 +652,7 @@ if (clearCache && dryRunMode) {
619
652
  }
620
653
 
621
654
  // Also clear for custom cache paths in normal mode if not already cleared
622
- if (clearCache && !dryRunMode && config.cache_path && config.cache_path !== '.cache') {
655
+ if (clearCache && !dryRunMode && config.cache_path && config.cache_path !== CACHE_LIMITS.DEFAULT_CACHE_PATH) {
623
656
  clearPersistentCache({
624
657
  silent: silentMode,
625
658
  forceDebug,
@@ -636,11 +669,11 @@ smartCache = createSmartCache({
636
669
  ...config,
637
670
  forceDebug,
638
671
  max_concurrent_sites: MAX_CONCURRENT_SITES, // Pass concurrency info
639
- cache_aggressive_mode: MAX_CONCURRENT_SITES > 12, // Auto-enable for high concurrency
672
+ cache_aggressive_mode: MAX_CONCURRENT_SITES > CONCURRENCY_LIMITS.HIGH_CONCURRENCY_THRESHOLD, // Auto-enable for high concurrency
640
673
  cache_persistence: false, // Disable persistence completely
641
674
  cache_autosave: false, // Disable auto-save completely
642
675
  cache_autosave_minutes: config.cache_autosave_minutes || 1,
643
- cache_max_size: config.cache_max_size || 5000
676
+ cache_max_size: config.cache_max_size || CACHE_LIMITS.DEFAULT_MAX_SIZE
644
677
  });
645
678
  }
646
679
 
@@ -936,6 +969,22 @@ function outputDryRunResults(url, matchedItems, netToolsResults, pageTitle) {
936
969
  }
937
970
  }
938
971
 
972
+ /**
973
+ * Helper function to check if a URL should be processed (valid HTTP/HTTPS)
974
+ * @param {string} url - URL to validate
975
+ * @param {boolean} forceDebug - Debug logging flag
976
+ * @returns {boolean} True if URL is valid for processing
977
+ */
978
+ function shouldProcessUrl(url, forceDebug) {
979
+ try {
980
+ const parsed = new URL(url);
981
+ return parsed.protocol === 'http:' || parsed.protocol === 'https:';
982
+ } catch (err) {
983
+ if (forceDebug) console.log(formatLogMessage('debug', `Invalid URL for processing: ${url}`));
984
+ return false;
985
+ }
986
+ }
987
+
939
988
  // ability to use widcards in ignoreDomains
940
989
  function matchesIgnoreDomain(domain, ignorePatterns) {
941
990
  return ignorePatterns.some(pattern => {
@@ -1124,8 +1173,8 @@ function setupFrameHandling(page, forceDebug) {
1124
1173
  args: [
1125
1174
  // Disk space controls - 50MB cache limits
1126
1175
  '--disable-features=VizDisplayCompositor',
1127
- '--disk-cache-size=52428800', // 50MB disk cache (50 * 1024 * 1024)
1128
- '--media-cache-size=52428800', // 50MB media cache
1176
+ `--disk-cache-size=${CACHE_LIMITS.DISK_CACHE_SIZE}`, // 50MB disk cache
1177
+ `--media-cache-size=${CACHE_LIMITS.MEDIA_CACHE_SIZE}`, // 50MB media cache
1129
1178
  '--disable-application-cache',
1130
1179
  '--disable-offline-load-stale-cache',
1131
1180
  '--disable-background-downloads',
@@ -1170,7 +1219,7 @@ function setupFrameHandling(page, forceDebug) {
1170
1219
  '--no-zygote', // Better process isolation
1171
1220
  ],
1172
1221
  // Optimized timeouts for Puppeteer 23.x performance
1173
- protocolTimeout: 60000, // Reduced from 60s to 45s for faster failure detection
1222
+ protocolTimeout: TIMEOUTS.PROTOCOL_TIMEOUT,
1174
1223
  slowMo: 0, // No artificial delays
1175
1224
  defaultViewport: null, // Use system default viewport
1176
1225
  ignoreDefaultArgs: ['--enable-automation'] // Avoid automation detection
@@ -1318,15 +1367,23 @@ function setupFrameHandling(page, forceDebug) {
1318
1367
  matchedDomains.set('dryRunNetTools', []);
1319
1368
  matchedDomains.set('dryRunSearchString', new Map()); // Map URL to search results
1320
1369
  }
1321
- const timeout = siteConfig.timeout || 30000;
1370
+ const timeout = siteConfig.timeout || TIMEOUTS.DEFAULT_PAGE;
1322
1371
 
1323
1372
  if (!silentMode) console.log(`\n${messageColors.scanning('Scanning:')} ${currentUrl}`);
1324
1373
 
1374
+ // Track ALL domains that should be considered first-party (original + redirects)
1375
+ const firstPartyDomains = new Set();
1376
+ const originalRootDomain = safeGetDomain(currentUrl, false);
1377
+ if (originalRootDomain) {
1378
+ firstPartyDomains.add(originalRootDomain);
1379
+ }
1380
+
1325
1381
  // Track redirect domains to exclude from matching
1326
1382
  let redirectDomainsToExclude = [];
1327
1383
 
1328
- // Track the effective current URL for first-party detection (updates after redirects)
1384
+ // Track the effective current URL and final URL for first-party detection (updates after redirects)
1329
1385
  let effectiveCurrentUrl = currentUrl;
1386
+ let finalUrlAfterRedirect = null;
1330
1387
 
1331
1388
  // Enhanced error types for Puppeteer 23.x compatibility
1332
1389
  const CRITICAL_BROWSER_ERRORS = [
@@ -1367,8 +1424,8 @@ function setupFrameHandling(page, forceDebug) {
1367
1424
 
1368
1425
  // Set aggressive timeouts for problematic operations
1369
1426
  // Optimized timeouts for Puppeteer 23.x responsiveness
1370
- page.setDefaultTimeout(Math.min(timeout, 20000)); // Reduced from 15000 for faster failures
1371
- page.setDefaultNavigationTimeout(Math.min(timeout, 25000)); // Reduced from 18000
1427
+ page.setDefaultTimeout(Math.min(timeout, TIMEOUTS.DEFAULT_PAGE_REDUCED));
1428
+ page.setDefaultNavigationTimeout(Math.min(timeout, TIMEOUTS.DEFAULT_NAVIGATION));
1372
1429
  // Aggressive timeouts prevent hanging in Puppeteer 23.x while maintaining speed
1373
1430
 
1374
1431
  page.on('console', (msg) => {
@@ -1435,8 +1492,8 @@ function setupFrameHandling(page, forceDebug) {
1435
1492
  // Apply flowProxy timeouts if detection is enabled
1436
1493
  if (flowproxyDetection) {
1437
1494
  const flowproxyTimeouts = getFlowProxyTimeouts(siteConfig);
1438
- page.setDefaultTimeout(Math.min(flowproxyTimeouts.pageTimeout, 25000));
1439
- page.setDefaultNavigationTimeout(Math.min(flowproxyTimeouts.navigationTimeout, 30000));
1495
+ page.setDefaultTimeout(Math.min(flowproxyTimeouts.pageTimeout, TIMEOUTS.DEFAULT_NAVIGATION));
1496
+ page.setDefaultNavigationTimeout(Math.min(flowproxyTimeouts.navigationTimeout, TIMEOUTS.DEFAULT_PAGE));
1440
1497
  if (forceDebug) {
1441
1498
  console.log(formatLogMessage('debug', `Applied flowProxy timeouts - page: ${flowproxyTimeouts.pageTimeout}ms, nav: ${flowproxyTimeouts.navigationTimeout}ms`));
1442
1499
  }
@@ -1838,13 +1895,9 @@ function setupFrameHandling(page, forceDebug) {
1838
1895
  const checkedUrl = request.url();
1839
1896
  const checkedHostname = safeGetDomain(checkedUrl, true);
1840
1897
  const checkedRootDomain = safeGetDomain(checkedUrl, false); // Root domain for first-party detection
1841
- // Use effectiveCurrentUrl which gets updated after redirects
1842
- // This ensures first-party detection uses the final redirected domain
1843
- const effectiveCurrentHostname = safeGetDomain(effectiveCurrentUrl, true);
1844
- const effectiveCurrentRootDomain = safeGetDomain(effectiveCurrentUrl, false); // Root domain for comparison
1845
-
1846
- // FIXED: Compare root domains instead of full hostnames for first-party detection
1847
- const isFirstParty = checkedRootDomain && effectiveCurrentRootDomain && checkedRootDomain === effectiveCurrentRootDomain;
1898
+ // Check against ALL first-party domains (original + all redirects)
1899
+ // This prevents redirect destinations from being marked as third-party
1900
+ const isFirstParty = checkedRootDomain && firstPartyDomains.has(checkedRootDomain);
1848
1901
 
1849
1902
  // Block infinite iframe loops
1850
1903
  const frameUrl = request.frame() ? request.frame().url() : '';
@@ -2000,14 +2053,6 @@ function setupFrameHandling(page, forceDebug) {
2000
2053
  }
2001
2054
  break; // Skip this URL - it's third-party but thirdParty is disabled
2002
2055
  }
2003
-
2004
- // Check ignoreDomains AFTER regex match but BEFORE domain processing
2005
- if (matchesIgnoreDomain(fullSubdomain, ignoreDomains)) {
2006
- if (forceDebug) {
2007
- console.log(formatLogMessage('debug', `Ignoring domain ${fullSubdomain} (matches ignoreDomains pattern)`));
2008
- }
2009
- break; // Skip this URL - domain is in ignore list
2010
- }
2011
2056
 
2012
2057
  // REMOVED: Check if this URL matches any blocked patterns - if so, skip detection but still continue browser blocking
2013
2058
  // This check is no longer needed here since even_blocked handles it above
@@ -2279,13 +2324,13 @@ function setupFrameHandling(page, forceDebug) {
2279
2324
  // Use explicit Promise-based timeouts instead of page.waitForTimeout()
2280
2325
 
2281
2326
  // Use faster defaults for sites with long timeouts to improve responsiveness
2282
- const isFastSite = timeout <= 15000;
2327
+ const isFastSite = timeout <= TIMEOUTS.FAST_SITE_THRESHOLD;
2283
2328
  const defaultWaitUntil = 'domcontentloaded'; // Always use faster option in Puppeteer 23.x
2284
2329
 
2285
2330
  // Enhanced navigation options for Puppeteer 23.x
2286
2331
  const defaultGotoOptions = {
2287
2332
  waitUntil: defaultWaitUntil,
2288
- timeout: Math.min(timeout, 30000), // Reduced from 20000 for faster failures
2333
+ timeout: Math.min(timeout, TIMEOUTS.DEFAULT_PAGE), // Cap at default page timeout
2289
2334
  // Puppeteer 23.x: Fixed referrer header handling
2290
2335
  ...(siteConfig.referrer_headers && (() => {
2291
2336
  const referrerUrl = Array.isArray(siteConfig.referrer_headers)
@@ -2309,6 +2354,19 @@ function setupFrameHandling(page, forceDebug) {
2309
2354
  if (redirected) {
2310
2355
  const originalDomain = safeGetDomain(originalUrl);
2311
2356
  const finalDomain = safeGetDomain(finalUrl);
2357
+
2358
+ // Add redirect destination to first-party domains immediately
2359
+ if (finalDomain) {
2360
+ firstPartyDomains.add(finalDomain);
2361
+ }
2362
+
2363
+ // Also add any intermediate redirect domains as first-party
2364
+ if (redirectDomains && redirectDomains.length > 0) {
2365
+ redirectDomains.forEach(domain => {
2366
+ const rootDomain = safeGetDomain(`http://${domain}`, false);
2367
+ if (rootDomain) firstPartyDomains.add(rootDomain);
2368
+ });
2369
+ }
2312
2370
 
2313
2371
  if (originalDomain !== finalDomain) {
2314
2372
  if (!silentMode) {
@@ -2317,6 +2375,7 @@ function setupFrameHandling(page, forceDebug) {
2317
2375
 
2318
2376
  if (forceDebug) {
2319
2377
  console.log(formatLogMessage('debug', `Full redirect chain: ${redirectChain.join(' → ')}`));
2378
+ console.log(formatLogMessage('debug', `All first-party domains: ${Array.from(firstPartyDomains).join(', ')}`));
2320
2379
  }
2321
2380
 
2322
2381
  // VALIDATION: Only update currentUrl if finalUrl is a valid HTTP/HTTPS URL
@@ -2326,6 +2385,7 @@ function setupFrameHandling(page, forceDebug) {
2326
2385
 
2327
2386
  // IMPORTANT: Also update effectiveCurrentUrl for first-party detection
2328
2387
  effectiveCurrentUrl = finalUrl;
2388
+ finalUrlAfterRedirect = finalUrl;
2329
2389
 
2330
2390
  // Update the redirect domains to exclude from matching
2331
2391
  if (redirectDomains && redirectDomains.length > 0) {
@@ -2389,7 +2449,7 @@ function setupFrameHandling(page, forceDebug) {
2389
2449
  if (forceDebug) {
2390
2450
  try {
2391
2451
  // Use fast timeout helper for compatibility
2392
- await fastTimeout(2000); // Give iframes time to load
2452
+ await fastTimeout(TIMEOUTS.FRAME_LOAD_WAIT); // Give iframes time to load
2393
2453
  const frames = page.frames();
2394
2454
  console.log(formatLogMessage('debug', `Total frames found: ${frames.length}`));
2395
2455
  frames.forEach((frame, index) => {
@@ -2433,10 +2493,10 @@ function setupFrameHandling(page, forceDebug) {
2433
2493
  const delayMs = siteConfig.delay || 4000;
2434
2494
 
2435
2495
  // Optimized delays for Puppeteer 23.x performance
2436
- const isFastSite = timeout <= 15000;
2437
- const networkIdleTime = 2000; // Balanced: 2s for reliable network detection
2438
- const networkIdleTimeout = Math.min(timeout / 2, 10000); // Balanced: 10s timeout
2439
- const actualDelay = Math.min(delayMs, 2000); // Balanced: 2s delay for stability
2496
+ const isFastSite = timeout <= TIMEOUTS.FAST_SITE_THRESHOLD;
2497
+ const networkIdleTime = TIMEOUTS.NETWORK_IDLE; // Balanced: 2s for reliable network detection
2498
+ const networkIdleTimeout = Math.min(timeout / 2, TIMEOUTS.NETWORK_IDLE_MAX); // Balanced: 10s timeout
2499
+ const actualDelay = Math.min(delayMs, TIMEOUTS.NETWORK_IDLE); // Balanced: 2s delay for stability
2440
2500
 
2441
2501
  await page.waitForNetworkIdle({
2442
2502
  idleTime: networkIdleTime,
@@ -2521,7 +2581,7 @@ function setupFrameHandling(page, forceDebug) {
2521
2581
 
2522
2582
  // Wait a moment for async nettools/searchstring operations to complete
2523
2583
  // Use fast timeout helper for Puppeteer 22.x compatibility
2524
- await fastTimeout(3000); // Increased for nettools operations
2584
+ await fastTimeout(TIMEOUTS.CURL_HANDLER_DELAY); // Wait for async operations
2525
2585
 
2526
2586
  outputDryRunResults(currentUrl, enhancedMatches, dryRunNetTools, pageTitle);
2527
2587
 
@@ -2541,7 +2601,13 @@ function setupFrameHandling(page, forceDebug) {
2541
2601
  };
2542
2602
  const formattedRules = formatRules(matchedDomains, siteConfig, globalOptions);
2543
2603
 
2544
- return { url: currentUrl, rules: formattedRules, success: true };
2604
+ return {
2605
+ url: currentUrl,
2606
+ rules: formattedRules,
2607
+ success: true,
2608
+ finalUrl: finalUrlAfterRedirect || currentUrl,
2609
+ redirectDomains: redirectDomainsToExclude
2610
+ };
2545
2611
  }
2546
2612
 
2547
2613
  } catch (err) {
@@ -2577,7 +2643,14 @@ function setupFrameHandling(page, forceDebug) {
2577
2643
  };
2578
2644
  const formattedRules = formatRules(matchedDomains, siteConfig, globalOptions);
2579
2645
  if (forceDebug) console.log(formatLogMessage('debug', `Saving ${formattedRules.length} rules despite page load failure`));
2580
- return { url: currentUrl, rules: formattedRules, success: false, hasMatches: true };
2646
+ return {
2647
+ url: currentUrl,
2648
+ rules: formattedRules,
2649
+ success: false,
2650
+ hasMatches: true,
2651
+ finalUrl: finalUrlAfterRedirect || currentUrl,
2652
+ redirectDomains: redirectDomainsToExclude
2653
+ };
2581
2654
  }
2582
2655
 
2583
2656
  if (siteConfig.screenshot === true && page) {
@@ -2591,7 +2664,13 @@ function setupFrameHandling(page, forceDebug) {
2591
2664
  console.warn(messageColors.warn(`[screenshot failed] ${currentUrl}: ${screenshotErr.message}`));
2592
2665
  }
2593
2666
  }
2594
- return { url: currentUrl, rules: [], success: false };
2667
+ return {
2668
+ url: currentUrl,
2669
+ rules: [],
2670
+ success: false,
2671
+ finalUrl: finalUrlAfterRedirect || currentUrl,
2672
+ redirectDomains: redirectDomainsToExclude
2673
+ };
2595
2674
  } finally {
2596
2675
  // Guaranteed resource cleanup - this runs regardless of success or failure
2597
2676
 
@@ -2640,7 +2719,7 @@ function setupFrameHandling(page, forceDebug) {
2640
2719
  }
2641
2720
  }
2642
2721
 
2643
- const results = [];
2722
+ let results = [];
2644
2723
  let processedUrlCount = 0;
2645
2724
  let urlsSinceLastCleanup = 0;
2646
2725
 
@@ -2719,7 +2798,7 @@ function setupFrameHandling(page, forceDebug) {
2719
2798
 
2720
2799
  // Reset cleanup counter and add delay
2721
2800
  urlsSinceLastCleanup = 0;
2722
- await fastTimeout(1000);
2801
+ await fastTimeout(TIMEOUTS.BROWSER_STABILIZE_DELAY);
2723
2802
  }
2724
2803
 
2725
2804
  if (forceDebug) {
@@ -2787,13 +2866,27 @@ function setupFrameHandling(page, forceDebug) {
2787
2866
  }
2788
2867
  browser = await createBrowser();
2789
2868
  urlsSinceLastCleanup = 0; // Reset counter
2790
- await fastTimeout(2000); // Give browser time to stabilize
2869
+ await fastTimeout(TIMEOUTS.EMERGENCY_RESTART_DELAY); // Give browser time to stabilize
2791
2870
  } catch (emergencyRestartErr) {
2792
2871
  if (forceDebug) console.log(formatLogMessage('debug', `Emergency restart failed: ${emergencyRestartErr.message}`));
2793
2872
  }
2794
2873
  }
2795
2874
  }
2796
2875
 
2876
+ // === POST-SCAN PROCESSING ===
2877
+ // Clean up first-party domains and validate results
2878
+ if (!dryRunMode) {
2879
+ // Always run post-processing for both firstParty cleanup and ignoreDomains safety net
2880
+ const sitesWithFirstPartyDisabled = sites.filter(site => site.firstParty === false);
2881
+ if (sitesWithFirstPartyDisabled.length > 0) {
2882
+ if (forceDebug) {
2883
+ console.log(formatLogMessage('debug', `Running post-scan processing for ${sitesWithFirstPartyDisabled.length} sites with firstParty: false`));
2884
+ }
2885
+ // Always run post-processing for ignoreDomains safety net
2886
+ results = processResults(results, sites, { forceDebug, silentMode, ignoreDomains });
2887
+ }
2888
+ }
2889
+
2797
2890
  // Handle dry run output file writing
2798
2891
  if (dryRunMode && outputFile && dryRunOutput.length > 0) {
2799
2892
  try {
@@ -2951,7 +3044,7 @@ function setupFrameHandling(page, forceDebug) {
2951
3044
  forceDebug,
2952
3045
  comprehensive: true
2953
3046
  });
2954
- await fastTimeout(1000); // Give filesystem time to sync
3047
+ await fastTimeout(TIMEOUTS.BROWSER_STABILIZE_DELAY); // Give filesystem time to sync
2955
3048
 
2956
3049
  // Calculate timing, success rates, and provide summary information
2957
3050
  if (forceDebug) console.log(formatLogMessage('debug', `Calculating timing statistics...`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fanboynz/network-scanner",
3
- "version": "1.0.67",
3
+ "version": "1.0.69",
4
4
  "description": "A Puppeteer-based network scanner for analyzing web traffic, generating adblock filter rules, and identifying third-party requests. Features include fingerprint spoofing, Cloudflare bypass, content analysis with curl/grep, and multiple output formats.",
5
5
  "main": "nwss.js",
6
6
  "scripts": {