@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.
- package/.github/workflows/npm-publish.yml +134 -10
- package/CHANGELOG.md +135 -0
- package/CLAUDE.md +18 -7
- package/README.md +12 -4
- package/lib/adblock-rust.js +23 -18
- package/lib/adblock.js +127 -82
- package/lib/browserexit.js +210 -200
- package/lib/browserhealth.js +84 -60
- package/lib/cdp.js +103 -81
- package/lib/clear_sitedata.js +61 -159
- package/lib/cloudflare.js +579 -409
- package/lib/colorize.js +29 -12
- package/lib/compare.js +16 -8
- package/lib/compress.js +2 -1
- package/lib/curl.js +287 -220
- package/lib/domain-cache.js +87 -40
- package/lib/dry-run.js +137 -194
- package/lib/fingerprint.js +20 -18
- package/lib/flowproxy.js +391 -188
- package/lib/ghost-cursor.js +8 -7
- package/lib/grep.js +248 -171
- package/lib/ignore_similar.js +70 -124
- package/lib/interaction.js +132 -235
- package/lib/nettools.js +309 -87
- package/lib/openvpn_vpn.js +12 -11
- package/lib/output.js +92 -59
- package/lib/post-processing.js +216 -162
- package/lib/redirect.js +46 -30
- package/lib/referrer.js +158 -165
- package/lib/searchstring.js +290 -381
- package/lib/smart-cache.js +141 -91
- package/lib/socks-relay.js +8 -7
- package/lib/spawn-async.js +137 -0
- package/lib/validate_rules.js +188 -176
- package/lib/wireguard_vpn.js +111 -117
- package/nwss.js +740 -156
- package/package.json +4 -4
package/lib/domain-cache.js
CHANGED
|
@@ -12,24 +12,33 @@ class DomainCache {
|
|
|
12
12
|
constructor(options = {}) {
|
|
13
13
|
// V8 Optimization: Initialize all properties in constructor for stable hidden class
|
|
14
14
|
this.cache = new Set();
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
// V8 Optimization: Use consistent object shape (no dynamic property addition)
|
|
17
|
-
this.stats =
|
|
18
|
-
|
|
19
|
-
totalSkipped: 0,
|
|
20
|
-
cacheHits: 0,
|
|
21
|
-
cacheMisses: 0
|
|
22
|
-
};
|
|
23
|
-
|
|
17
|
+
this.stats = this._freshStats();
|
|
18
|
+
|
|
24
19
|
// V8 Optimization: Store options directly instead of nested object for faster property access
|
|
25
20
|
this.enableLogging = options.enableLogging || false;
|
|
26
21
|
this.logPrefix = options.logPrefix || '[domain-cache]';
|
|
27
22
|
this.maxCacheSize = options.maxCacheSize || 10000; // Prevent memory leaks
|
|
28
|
-
|
|
23
|
+
|
|
29
24
|
// V8 Optimization: Pre-calculate 90% target to avoid repeated Math.floor
|
|
30
25
|
this.targetCacheSize = Math.floor(this.maxCacheSize * 0.9);
|
|
31
26
|
}
|
|
32
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Canonical stats shape. Centralized so the constructor and clear() can't
|
|
30
|
+
* drift if a new counter is added later.
|
|
31
|
+
* @private
|
|
32
|
+
*/
|
|
33
|
+
_freshStats() {
|
|
34
|
+
return {
|
|
35
|
+
totalDetected: 0,
|
|
36
|
+
totalSkipped: 0,
|
|
37
|
+
cacheHits: 0,
|
|
38
|
+
cacheMisses: 0
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
33
42
|
/**
|
|
34
43
|
* Check if a domain was already detected in a previous scan
|
|
35
44
|
* @param {string} domain - Domain to check
|
|
@@ -61,8 +70,10 @@ class DomainCache {
|
|
|
61
70
|
}
|
|
62
71
|
|
|
63
72
|
/**
|
|
64
|
-
* Mark a domain as detected for future reference
|
|
73
|
+
* Mark a domain as detected for future reference.
|
|
65
74
|
* @param {string} domain - Domain to mark as detected
|
|
75
|
+
* @returns {boolean} True if the domain was newly added; false if it was
|
|
76
|
+
* already present or the input was invalid (not a non-empty string)
|
|
66
77
|
*/
|
|
67
78
|
markDomainAsDetected(domain) {
|
|
68
79
|
if (!domain || typeof domain !== 'string') {
|
|
@@ -80,22 +91,23 @@ class DomainCache {
|
|
|
80
91
|
}
|
|
81
92
|
}
|
|
82
93
|
|
|
83
|
-
// Check size
|
|
84
|
-
//
|
|
85
|
-
// V8 Optimization: Use pre-calculated targetCacheSize
|
|
94
|
+
// Check size after the add so an overflow only fires eviction once per
|
|
95
|
+
// overflowing call (using targetCacheSize precomputed in the constructor).
|
|
86
96
|
if (this.cache.size > this.maxCacheSize) {
|
|
87
97
|
const toRemove = this.cache.size - this.targetCacheSize;
|
|
88
98
|
if (toRemove > 0) {
|
|
89
99
|
this.clearOldestEntries(toRemove);
|
|
90
100
|
}
|
|
91
101
|
}
|
|
92
|
-
|
|
102
|
+
|
|
93
103
|
return wasNew;
|
|
94
104
|
}
|
|
95
105
|
|
|
96
106
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
107
|
+
* Combined check-and-mark in one pass. Functionally equivalent to
|
|
108
|
+
* isDomainAlreadyDetected() followed by markDomainAsDetected(), but with
|
|
109
|
+
* one Set.has() call instead of two. (JS is single-threaded so all three
|
|
110
|
+
* variants are individually atomic; this one is just cheaper.)
|
|
99
111
|
* @param {string} domain - Domain to check and potentially mark
|
|
100
112
|
* @returns {boolean} True if domain was ALREADY detected (should skip), false if NEW (should process)
|
|
101
113
|
*/
|
|
@@ -127,23 +139,22 @@ class DomainCache {
|
|
|
127
139
|
console.log(formatLogMessage('debug', `${this.logPrefix} Cache MISS: ${domain} (processing and marked, cache size: ${this.cache.size})`));
|
|
128
140
|
}
|
|
129
141
|
|
|
130
|
-
// Check size
|
|
131
|
-
//
|
|
132
|
-
// V8 Optimization: Use pre-calculated targetCacheSize
|
|
142
|
+
// Check size after the add so an overflow only fires eviction once per
|
|
143
|
+
// overflowing call (using targetCacheSize precomputed in the constructor).
|
|
133
144
|
if (this.cache.size > this.maxCacheSize) {
|
|
134
145
|
const toRemove = this.cache.size - this.targetCacheSize;
|
|
135
146
|
if (toRemove > 0) {
|
|
136
147
|
this.clearOldestEntries(toRemove);
|
|
137
148
|
}
|
|
138
149
|
}
|
|
139
|
-
|
|
150
|
+
|
|
140
151
|
return false; // New domain, should process
|
|
141
152
|
}
|
|
142
153
|
|
|
143
154
|
/**
|
|
144
|
-
* Clear oldest entries from cache (
|
|
145
|
-
*
|
|
146
|
-
*
|
|
155
|
+
* Clear oldest entries from cache (FIFO eviction). Set iteration order is
|
|
156
|
+
* guaranteed insertion order per ES2015, so this genuinely evicts oldest-
|
|
157
|
+
* first on every supported Node version.
|
|
147
158
|
* @param {number} count - Number of entries to remove
|
|
148
159
|
*/
|
|
149
160
|
clearOldestEntries(count) {
|
|
@@ -181,13 +192,8 @@ class DomainCache {
|
|
|
181
192
|
clear() {
|
|
182
193
|
const previousSize = this.cache.size;
|
|
183
194
|
this.cache.clear();
|
|
184
|
-
this.stats =
|
|
185
|
-
|
|
186
|
-
totalSkipped: 0,
|
|
187
|
-
cacheHits: 0,
|
|
188
|
-
cacheMisses: 0
|
|
189
|
-
};
|
|
190
|
-
|
|
195
|
+
this.stats = this._freshStats();
|
|
196
|
+
|
|
191
197
|
if (this.enableLogging) {
|
|
192
198
|
console.log(formatLogMessage('debug', `${this.logPrefix} Cache cleared (${previousSize} entries removed)`));
|
|
193
199
|
}
|
|
@@ -226,21 +232,40 @@ class DomainCache {
|
|
|
226
232
|
}
|
|
227
233
|
|
|
228
234
|
/**
|
|
229
|
-
* Add multiple domains to cache at once
|
|
235
|
+
* Add multiple domains to cache at once. Uses a single .size delta to
|
|
236
|
+
* count actually-new entries (skipping per-domain .has() calls), and
|
|
237
|
+
* runs the size-overflow eviction check once after the batch instead of
|
|
238
|
+
* per-domain. For a batch of N domains this is N .has() calls saved and
|
|
239
|
+
* up to N redundant cap checks collapsed to one.
|
|
230
240
|
* @param {Array<string>} domains - Array of domains to add
|
|
231
241
|
* @returns {number} Number of domains actually added (excludes duplicates)
|
|
232
242
|
*/
|
|
233
243
|
markMultipleDomainsAsDetected(domains) {
|
|
234
|
-
if (!Array.isArray(domains)) {
|
|
244
|
+
if (!Array.isArray(domains) || domains.length === 0) {
|
|
235
245
|
return 0;
|
|
236
246
|
}
|
|
237
247
|
|
|
238
|
-
|
|
239
|
-
domains.
|
|
240
|
-
|
|
241
|
-
|
|
248
|
+
const startSize = this.cache.size;
|
|
249
|
+
for (let i = 0; i < domains.length; i++) {
|
|
250
|
+
const d = domains[i];
|
|
251
|
+
if (d && typeof d === 'string') {
|
|
252
|
+
this.cache.add(d);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
const addedCount = this.cache.size - startSize;
|
|
256
|
+
this.stats.totalDetected += addedCount;
|
|
257
|
+
|
|
258
|
+
if (this.enableLogging && addedCount > 0) {
|
|
259
|
+
console.log(formatLogMessage('debug', `${this.logPrefix} Batch added ${addedCount} new domains (cache size: ${this.cache.size})`));
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// One eviction sweep at the end, mirroring the single-add overflow check.
|
|
263
|
+
if (this.cache.size > this.maxCacheSize) {
|
|
264
|
+
const toRemove = this.cache.size - this.targetCacheSize;
|
|
265
|
+
if (toRemove > 0) {
|
|
266
|
+
this.clearOldestEntries(toRemove);
|
|
242
267
|
}
|
|
243
|
-
}
|
|
268
|
+
}
|
|
244
269
|
|
|
245
270
|
return addedCount;
|
|
246
271
|
}
|
|
@@ -267,13 +292,34 @@ class DomainCache {
|
|
|
267
292
|
let globalDomainCache = null;
|
|
268
293
|
|
|
269
294
|
/**
|
|
270
|
-
* Get or create the global domain cache instance
|
|
271
|
-
*
|
|
295
|
+
* Get or create the global domain cache instance.
|
|
296
|
+
*
|
|
297
|
+
* NOTE: `options` is honored ONLY on the first call (the call that actually
|
|
298
|
+
* constructs the singleton). Subsequent calls return the existing instance
|
|
299
|
+
* regardless of what's passed. If you need different settings, call
|
|
300
|
+
* resetGlobalCache() first or use `new DomainCache(options)` directly.
|
|
301
|
+
*
|
|
302
|
+
* Under debug logging, a warning fires if a later caller passes options
|
|
303
|
+
* that don't match the live instance — silent drift is a recurring source
|
|
304
|
+
* of "why isn't my maxCacheSize taking effect?" confusion.
|
|
305
|
+
*
|
|
306
|
+
* @param {object} options - Cache options (first-call-only)
|
|
272
307
|
* @returns {DomainCache} Global cache instance
|
|
273
308
|
*/
|
|
274
309
|
function getGlobalDomainCache(options = {}) {
|
|
275
310
|
if (!globalDomainCache) {
|
|
276
311
|
globalDomainCache = new DomainCache(options);
|
|
312
|
+
return globalDomainCache;
|
|
313
|
+
}
|
|
314
|
+
// Singleton already exists — warn if the caller is trying to reconfigure it.
|
|
315
|
+
if (globalDomainCache.enableLogging) {
|
|
316
|
+
const drifted =
|
|
317
|
+
(options.maxCacheSize !== undefined && options.maxCacheSize !== globalDomainCache.maxCacheSize) ||
|
|
318
|
+
(options.enableLogging !== undefined && options.enableLogging !== globalDomainCache.enableLogging) ||
|
|
319
|
+
(options.logPrefix !== undefined && options.logPrefix !== globalDomainCache.logPrefix);
|
|
320
|
+
if (drifted) {
|
|
321
|
+
console.log(formatLogMessage('debug', `${globalDomainCache.logPrefix} getGlobalDomainCache called with options that differ from the live singleton; ignored (call resetGlobalCache() first to apply new options)`));
|
|
322
|
+
}
|
|
277
323
|
}
|
|
278
324
|
return globalDomainCache;
|
|
279
325
|
}
|
|
@@ -323,7 +369,8 @@ function markDomainAsDetected(domain) {
|
|
|
323
369
|
}
|
|
324
370
|
|
|
325
371
|
/**
|
|
326
|
-
*
|
|
372
|
+
* Combined check-and-mark in one pass — one Set.has() call instead of the
|
|
373
|
+
* two you'd pay for isDomainAlreadyDetected() + markDomainAsDetected().
|
|
327
374
|
* @param {string} domain - Domain to check and mark
|
|
328
375
|
* @returns {boolean} True if already detected (skip), false if new (process)
|
|
329
376
|
*/
|