jumpy-lion 0.1.6-beta.7 → 1.0.0-beta.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/README.md +1 -607
- package/browser/fonts/macos-bundle/40-macos-aliases.conf +515 -0
- package/browser/fonts/macos-bundle/README.md +24 -0
- package/browser/fonts/macos-bundle/install.sh +83 -0
- package/dist/browser-controller.d.ts +47 -4
- package/dist/browser-controller.d.ts.map +1 -1
- package/dist/browser-controller.js +219 -278
- package/dist/browser-controller.js.map +1 -1
- package/dist/browser-plugin.d.ts +82 -110
- package/dist/browser-plugin.d.ts.map +1 -1
- package/dist/browser-plugin.js +376 -379
- package/dist/browser-plugin.js.map +1 -1
- package/dist/browser-process/align-fingerprint-config.d.ts +36 -0
- package/dist/browser-process/align-fingerprint-config.d.ts.map +1 -0
- package/dist/browser-process/align-fingerprint-config.js +74 -0
- package/dist/browser-process/align-fingerprint-config.js.map +1 -0
- package/dist/browser-process/anti-detect-browser.d.ts +2 -2
- package/dist/browser-process/anti-detect-browser.js +7 -7
- package/dist/browser-process/anti-detect-config.d.ts +131 -2
- package/dist/browser-process/anti-detect-config.d.ts.map +1 -1
- package/dist/browser-process/anti-detect-config.js +337 -127
- package/dist/browser-process/anti-detect-config.js.map +1 -1
- package/dist/browser-process/browser.d.ts +25 -92
- package/dist/browser-process/browser.d.ts.map +1 -1
- package/dist/browser-process/browser.js +429 -73
- package/dist/browser-process/browser.js.map +1 -1
- package/dist/browser-process/fingerprint-config.d.ts +146 -0
- package/dist/browser-process/fingerprint-config.d.ts.map +1 -0
- package/dist/browser-process/fingerprint-config.js +308 -0
- package/dist/browser-process/fingerprint-config.js.map +1 -0
- package/dist/browser-process/get-chrome-executable.d.ts +6 -0
- package/dist/browser-process/get-chrome-executable.d.ts.map +1 -1
- package/dist/browser-process/get-chrome-executable.js +79 -4
- package/dist/browser-process/get-chrome-executable.js.map +1 -1
- package/dist/browser-process/gpu-family-profiles.d.ts +58 -0
- package/dist/browser-process/gpu-family-profiles.d.ts.map +1 -0
- package/dist/browser-process/gpu-family-profiles.js +480 -0
- package/dist/browser-process/gpu-family-profiles.js.map +1 -0
- package/dist/browser-process/launch-options.d.ts +301 -0
- package/dist/browser-process/launch-options.d.ts.map +1 -0
- package/dist/browser-process/launch-options.js +2 -0
- package/dist/browser-process/launch-options.js.map +1 -0
- package/dist/browser-process/port-allocator.d.ts +64 -0
- package/dist/browser-process/port-allocator.d.ts.map +1 -0
- package/dist/browser-process/port-allocator.js +198 -0
- package/dist/browser-process/port-allocator.js.map +1 -0
- package/dist/browser-process/process.d.ts +85 -0
- package/dist/browser-process/process.d.ts.map +1 -1
- package/dist/browser-process/process.js +235 -19
- package/dist/browser-process/process.js.map +1 -1
- package/dist/browser-process/signal-cleanup.d.ts +40 -0
- package/dist/browser-process/signal-cleanup.d.ts.map +1 -0
- package/dist/browser-process/signal-cleanup.js +105 -0
- package/dist/browser-process/signal-cleanup.js.map +1 -0
- package/dist/browser-process/widevine-cdm.d.ts +144 -0
- package/dist/browser-process/widevine-cdm.d.ts.map +1 -0
- package/dist/browser-process/widevine-cdm.js +298 -0
- package/dist/browser-process/widevine-cdm.js.map +1 -0
- package/dist/browser-profiles/chrome/populate-profile.d.ts.map +1 -1
- package/dist/browser-profiles/chrome/populate-profile.js +21 -22
- package/dist/browser-profiles/chrome/populate-profile.js.map +1 -1
- package/dist/connection/cdp-reconnection.d.ts +50 -0
- package/dist/connection/cdp-reconnection.d.ts.map +1 -0
- package/dist/connection/cdp-reconnection.js +75 -0
- package/dist/connection/cdp-reconnection.js.map +1 -0
- package/dist/connection/page-session.d.ts +114 -0
- package/dist/connection/page-session.d.ts.map +1 -0
- package/dist/connection/page-session.js +237 -0
- package/dist/connection/page-session.js.map +1 -0
- package/dist/connection/session-client.d.ts +34 -0
- package/dist/connection/session-client.d.ts.map +1 -0
- package/dist/connection/session-client.js +129 -0
- package/dist/connection/session-client.js.map +1 -0
- package/dist/crawler.d.ts +9 -88
- package/dist/crawler.d.ts.map +1 -1
- package/dist/crawler.js +157 -8
- package/dist/crawler.js.map +1 -1
- package/dist/fingerprinting/fingerprint-injector.d.ts +24 -114
- package/dist/fingerprinting/fingerprint-injector.d.ts.map +1 -1
- package/dist/fingerprinting/fingerprint-injector.js +305 -611
- package/dist/fingerprinting/fingerprint-injector.js.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.d.ts +1 -1
- package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.d.ts.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.js +16 -14
- package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.js.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/index.d.ts +6 -2
- package/dist/fingerprinting/fingerprint-overrides/index.d.ts.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/index.js +6 -2
- package/dist/fingerprinting/fingerprint-overrides/index.js.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/keyboard-humanization.d.ts +1 -1
- package/dist/fingerprinting/fingerprint-overrides/keyboard-humanization.js +4 -4
- package/dist/fingerprinting/fingerprint-overrides/keyboard-humanization.js.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/locale-spoofing.js +4 -4
- package/dist/fingerprinting/fingerprint-overrides/navigator-override.d.ts +18 -0
- package/dist/fingerprinting/fingerprint-overrides/navigator-override.d.ts.map +1 -0
- package/dist/fingerprinting/fingerprint-overrides/navigator-override.js +136 -0
- package/dist/fingerprinting/fingerprint-overrides/navigator-override.js.map +1 -0
- package/dist/fingerprinting/fingerprint-overrides/override.d.ts +151 -0
- package/dist/fingerprinting/fingerprint-overrides/override.d.ts.map +1 -0
- package/dist/fingerprinting/fingerprint-overrides/override.js +14 -0
- package/dist/fingerprinting/fingerprint-overrides/override.js.map +1 -0
- package/dist/fingerprinting/fingerprint-overrides/platform-consistency.d.ts.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/platform-consistency.js +46 -15
- package/dist/fingerprinting/fingerprint-overrides/platform-consistency.js.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/registry.d.ts +43 -0
- package/dist/fingerprinting/fingerprint-overrides/registry.d.ts.map +1 -0
- package/dist/fingerprinting/fingerprint-overrides/registry.js +342 -0
- package/dist/fingerprinting/fingerprint-overrides/registry.js.map +1 -0
- package/dist/fingerprinting/fingerprint-overrides/screen-override.d.ts +16 -0
- package/dist/fingerprinting/fingerprint-overrides/screen-override.d.ts.map +1 -0
- package/dist/fingerprinting/fingerprint-overrides/screen-override.js +175 -0
- package/dist/fingerprinting/fingerprint-overrides/screen-override.js.map +1 -0
- package/dist/fingerprinting/fingerprint-overrides/scroll-humanization.d.ts +1 -1
- package/dist/fingerprinting/fingerprint-overrides/scroll-humanization.js +4 -4
- package/dist/fingerprinting/fingerprint-overrides/scroll-humanization.js.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/stealth-script.d.ts.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/stealth-script.js +75 -9
- package/dist/fingerprinting/fingerprint-overrides/stealth-script.js.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/ua-ch.d.ts +1 -1
- package/dist/fingerprinting/fingerprint-overrides/ua-ch.d.ts.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/ua-ch.js +34 -20
- package/dist/fingerprinting/fingerprint-overrides/ua-ch.js.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/webgl-spoofing.d.ts.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/webgl-spoofing.js +25 -6
- package/dist/fingerprinting/fingerprint-overrides/webgl-spoofing.js.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/webrtc-spoofing.js +1 -1
- package/dist/fingerprinting/hardware-realism.d.ts +83 -0
- package/dist/fingerprinting/hardware-realism.d.ts.map +1 -0
- package/dist/fingerprinting/hardware-realism.js +156 -0
- package/dist/fingerprinting/hardware-realism.js.map +1 -0
- package/dist/fingerprinting/injection-planner.d.ts +133 -0
- package/dist/fingerprinting/injection-planner.d.ts.map +1 -0
- package/dist/fingerprinting/injection-planner.js +497 -0
- package/dist/fingerprinting/injection-planner.js.map +1 -0
- package/dist/fingerprinting/locale-resolver.d.ts +8 -1
- package/dist/fingerprinting/locale-resolver.d.ts.map +1 -1
- package/dist/fingerprinting/locale-resolver.js +26 -3
- package/dist/fingerprinting/locale-resolver.js.map +1 -1
- package/dist/fingerprinting/non-apify-fingerprint-generator.d.ts +4 -4
- package/dist/fingerprinting/non-apify-fingerprint-generator.d.ts.map +1 -1
- package/dist/fingerprinting/non-apify-fingerprint-generator.js +24 -58
- package/dist/fingerprinting/non-apify-fingerprint-generator.js.map +1 -1
- package/dist/fingerprinting/non-apify-profiles.json +10515 -8494
- package/dist/fingerprinting/os-consistency.d.ts +28 -0
- package/dist/fingerprinting/os-consistency.d.ts.map +1 -0
- package/dist/fingerprinting/os-consistency.js +45 -0
- package/dist/fingerprinting/os-consistency.js.map +1 -0
- package/dist/fingerprinting/profile-quality.d.ts +25 -0
- package/dist/fingerprinting/profile-quality.d.ts.map +1 -0
- package/dist/fingerprinting/profile-quality.js +310 -0
- package/dist/fingerprinting/profile-quality.js.map +1 -0
- package/dist/fingerprinting/profile-selector.d.ts +102 -0
- package/dist/fingerprinting/profile-selector.d.ts.map +1 -0
- package/dist/fingerprinting/profile-selector.js +168 -0
- package/dist/fingerprinting/profile-selector.js.map +1 -0
- package/dist/fingerprinting/ua-alignment.d.ts +83 -0
- package/dist/fingerprinting/ua-alignment.d.ts.map +1 -0
- package/dist/fingerprinting/ua-alignment.js +197 -0
- package/dist/fingerprinting/ua-alignment.js.map +1 -0
- package/dist/fingerprinting/ua-ch-brands.d.ts +88 -0
- package/dist/fingerprinting/ua-ch-brands.d.ts.map +1 -0
- package/dist/fingerprinting/ua-ch-brands.js +174 -0
- package/dist/fingerprinting/ua-ch-brands.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/input/dropdown-selector.d.ts +90 -0
- package/dist/input/dropdown-selector.d.ts.map +1 -0
- package/dist/input/dropdown-selector.js +394 -0
- package/dist/input/dropdown-selector.js.map +1 -0
- package/dist/input/element-target.d.ts +152 -0
- package/dist/input/element-target.d.ts.map +1 -0
- package/dist/input/element-target.js +461 -0
- package/dist/input/element-target.js.map +1 -0
- package/dist/input/input-emulator.d.ts +85 -0
- package/dist/input/input-emulator.d.ts.map +1 -0
- package/dist/input/input-emulator.js +325 -0
- package/dist/input/input-emulator.js.map +1 -0
- package/dist/input/input-transport.d.ts +60 -0
- package/dist/input/input-transport.d.ts.map +1 -0
- package/dist/input/input-transport.js +28 -0
- package/dist/input/input-transport.js.map +1 -0
- package/dist/input/recording-transport.d.ts +32 -0
- package/dist/input/recording-transport.d.ts.map +1 -0
- package/dist/input/recording-transport.js +43 -0
- package/dist/input/recording-transport.js.map +1 -0
- package/dist/keyboard-layout.d.ts +2 -2
- package/dist/keyboard-layout.js +2 -2
- package/dist/navigation/page-navigation.d.ts +67 -0
- package/dist/navigation/page-navigation.d.ts.map +1 -0
- package/dist/navigation/page-navigation.js +122 -0
- package/dist/navigation/page-navigation.js.map +1 -0
- package/dist/network/network-watch.d.ts +110 -0
- package/dist/network/network-watch.d.ts.map +1 -0
- package/dist/network/network-watch.js +223 -0
- package/dist/network/network-watch.js.map +1 -0
- package/dist/page.d.ts +118 -104
- package/dist/page.d.ts.map +1 -1
- package/dist/page.js +311 -1130
- package/dist/page.js.map +1 -1
- package/dist/session/inject-hook.d.ts +24 -0
- package/dist/session/inject-hook.d.ts.map +1 -0
- package/dist/session/inject-hook.js +80 -0
- package/dist/session/inject-hook.js.map +1 -0
- package/dist/session/save.d.ts +21 -0
- package/dist/session/save.d.ts.map +1 -0
- package/dist/session/save.js +163 -0
- package/dist/session/save.js.map +1 -0
- package/dist/session/tar-data-dir.d.ts +18 -0
- package/dist/session/tar-data-dir.d.ts.map +1 -0
- package/dist/session/tar-data-dir.js +105 -0
- package/dist/session/tar-data-dir.js.map +1 -0
- package/dist/session/types.d.ts +80 -0
- package/dist/session/types.d.ts.map +1 -0
- package/dist/session/types.js +29 -0
- package/dist/session/types.js.map +1 -0
- package/dist/session-profile.d.ts +102 -0
- package/dist/session-profile.d.ts.map +1 -0
- package/dist/session-profile.js +163 -0
- package/dist/session-profile.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +17 -6
- package/scripts/postinstall.cjs +58 -0
- package/dist/fingerprinting/custom-fingerprint-injector.d.ts +0 -87
- package/dist/fingerprinting/custom-fingerprint-injector.d.ts.map +0 -1
- package/dist/fingerprinting/custom-fingerprint-injector.js +0 -342
- package/dist/fingerprinting/custom-fingerprint-injector.js.map +0 -1
- package/dist/launcher-wrap.d.ts +0 -10
- package/dist/launcher-wrap.d.ts.map +0 -1
- package/dist/launcher-wrap.js +0 -11
- package/dist/launcher-wrap.js.map +0 -1
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PageNavigation - the deep module beside NetworkWatch/ElementTarget that owns
|
|
3
|
+
* the navigation + load-wait protocol: enable Page, fire navigate/reload, race
|
|
4
|
+
* `domContentEventFired` / `loadEventFired` against a timeout, then reconcile
|
|
5
|
+
* the landed URL via `getNavigationHistory` (NOT `Runtime.evaluate`, which is a
|
|
6
|
+
* CDP detection vector). It also caches the last reconciled URL so `url()` can
|
|
7
|
+
* answer without re-hitting CDP.
|
|
8
|
+
*
|
|
9
|
+
* Talks to the page only through the narrow `NavigationPort`, so the whole
|
|
10
|
+
* protocol is unit-testable with a scripted port - no `new CdpPage(...)` and no
|
|
11
|
+
* fake CDP client. `CdpPage.goto` / `reload` / `url` are thin delegates and the
|
|
12
|
+
* `loadedUrl` state lives here, not on the god object.
|
|
13
|
+
*
|
|
14
|
+
* The URL reconcile prefers `getNavigationHistory` (Page domain only) and falls
|
|
15
|
+
* back to `evaluateUrl` (Runtime) only when history is unavailable.
|
|
16
|
+
*/
|
|
17
|
+
import { log } from 'crawlee';
|
|
18
|
+
const DEFAULT_TIMEOUT_MS = 30000;
|
|
19
|
+
export class PageNavigation {
|
|
20
|
+
constructor(port) {
|
|
21
|
+
Object.defineProperty(this, "port", {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
configurable: true,
|
|
24
|
+
writable: true,
|
|
25
|
+
value: void 0
|
|
26
|
+
});
|
|
27
|
+
Object.defineProperty(this, "loadedUrl", {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
configurable: true,
|
|
30
|
+
writable: true,
|
|
31
|
+
value: null
|
|
32
|
+
});
|
|
33
|
+
this.port = port;
|
|
34
|
+
}
|
|
35
|
+
/** Last reconciled URL, or - before any navigation - the live URL from CDP. */
|
|
36
|
+
async url() {
|
|
37
|
+
if (!this.loadedUrl) {
|
|
38
|
+
return this.currentUrl();
|
|
39
|
+
}
|
|
40
|
+
return this.loadedUrl;
|
|
41
|
+
}
|
|
42
|
+
/** Navigate to `url`, wait for the requested load milestone, reconcile the landed URL. */
|
|
43
|
+
async goto(url, options) {
|
|
44
|
+
await this.port.enablePage();
|
|
45
|
+
// Arm the load/domcontentloaded listener BEFORE navigating. The
|
|
46
|
+
// milestone events (esp. domcontentloaded) can fire in the microtask
|
|
47
|
+
// gap right after `navigate()` resolves; attaching the listener after
|
|
48
|
+
// navigate would miss them and hang until the timeout. Creating the
|
|
49
|
+
// wait promise first registers the CDP listener synchronously.
|
|
50
|
+
const waitForMilestone = this.waitForLoad(options, 'Navigation timeout');
|
|
51
|
+
waitForMilestone.catch(() => { }); // pre-handle so a navigate() throw can't orphan it
|
|
52
|
+
await this.port.navigate(url);
|
|
53
|
+
await waitForMilestone;
|
|
54
|
+
this.loadedUrl = await this.currentUrl();
|
|
55
|
+
}
|
|
56
|
+
/** Reload the current page, wait for the requested load milestone, reconcile the landed URL. */
|
|
57
|
+
async reload(options) {
|
|
58
|
+
await this.port.enablePage();
|
|
59
|
+
const waitForMilestone = this.waitForLoad(options, 'Reload timeout');
|
|
60
|
+
waitForMilestone.catch(() => { }); // pre-handle so a reload() throw can't orphan it
|
|
61
|
+
await this.port.reload();
|
|
62
|
+
await waitForMilestone;
|
|
63
|
+
this.loadedUrl = await this.currentUrl();
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Race the requested load event against the timeout. Resolves when the
|
|
67
|
+
* event fires; rejects with `timeoutMessage` once the timeout elapses.
|
|
68
|
+
*/
|
|
69
|
+
async waitForLoad(options, timeoutMessage) {
|
|
70
|
+
const timeout = options?.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
71
|
+
const waitUntil = options?.waitUntil ?? 'load';
|
|
72
|
+
if (waitUntil !== 'load' && waitUntil !== 'domcontentloaded') {
|
|
73
|
+
throw new Error(`Unsupported waitUntil event: ${waitUntil}`);
|
|
74
|
+
}
|
|
75
|
+
// The CDP event subscription returns an unsubscribe fn. We MUST call it
|
|
76
|
+
// on every outcome - especially on timeout, where the milestone never
|
|
77
|
+
// fires. Leaving it attached leaks one Page.loadEventFired /
|
|
78
|
+
// domContentEventFired listener on the CDP client per timed-out
|
|
79
|
+
// navigation, which on a stuck crawl piles up into a
|
|
80
|
+
// MaxListenersExceededWarning and unbounded memory growth.
|
|
81
|
+
let unsubscribe;
|
|
82
|
+
const waitEvent = new Promise((resolve) => {
|
|
83
|
+
unsubscribe = waitUntil === 'load'
|
|
84
|
+
? this.port.onLoad(() => resolve())
|
|
85
|
+
: this.port.onDomContent(() => resolve());
|
|
86
|
+
});
|
|
87
|
+
let timer;
|
|
88
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
89
|
+
timer = setTimeout(() => reject(new Error(timeoutMessage)), timeout);
|
|
90
|
+
});
|
|
91
|
+
try {
|
|
92
|
+
await Promise.race([waitEvent, timeoutPromise]);
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
// Clear the timer on whichever outcome wins so the timeout closure
|
|
96
|
+
// does not dangle for ~timeout-length after the event resolves.
|
|
97
|
+
if (timer)
|
|
98
|
+
clearTimeout(timer);
|
|
99
|
+
// Detach the milestone listener so it cannot accumulate.
|
|
100
|
+
unsubscribe?.();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Resolve the current URL without activating the Runtime domain when
|
|
105
|
+
* possible: `getNavigationHistory` needs only the Page domain. Falls back
|
|
106
|
+
* to a Runtime evaluation only when history is empty or unavailable.
|
|
107
|
+
*/
|
|
108
|
+
async currentUrl() {
|
|
109
|
+
try {
|
|
110
|
+
await this.port.enablePage();
|
|
111
|
+
const { currentIndex, entries } = await this.port.navigationHistory();
|
|
112
|
+
if (entries && entries.length > 0 && currentIndex >= 0) {
|
|
113
|
+
return entries[currentIndex].url;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
log.debug('getNavigationHistory failed, falling back to evaluate');
|
|
118
|
+
}
|
|
119
|
+
return this.port.evaluateUrl();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=page-navigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-navigation.js","sourceRoot":"","sources":["../../src/navigation/page-navigation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NetworkWatch - the deep module beside ElementTarget/DropdownSelector that
|
|
3
|
+
* owns the network interception protocol: response waiting (match, timeout,
|
|
4
|
+
* body fetch with backoff, listener cleanup), request blocking, and
|
|
5
|
+
* fetch-metadata header repair.
|
|
6
|
+
*
|
|
7
|
+
* Talks to the page only through the narrow `NetworkWatchPort`, so the whole
|
|
8
|
+
* protocol is unit-testable with a scripted port. `CdpPage.waitForResponse`,
|
|
9
|
+
* `CdpPage.blockRequests`, and `CdpPage.setupFetchMetadataHeaders` are thin
|
|
10
|
+
* delegates.
|
|
11
|
+
*/
|
|
12
|
+
export interface WatchedResponse {
|
|
13
|
+
url: string;
|
|
14
|
+
status: number;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
/** A matched response with its (JSON-parsed, or raw-string) body attached. */
|
|
18
|
+
export type WatchedResponseWithBody = WatchedResponse & {
|
|
19
|
+
body: unknown;
|
|
20
|
+
};
|
|
21
|
+
export interface InterceptedRequest {
|
|
22
|
+
interceptionId: string;
|
|
23
|
+
request: {
|
|
24
|
+
url: string;
|
|
25
|
+
method: string;
|
|
26
|
+
headers: Record<string, string>;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export interface NetworkWatchPort {
|
|
30
|
+
/** Lazily enable the Network domain (a CDP detection-surface concern owned by the page). */
|
|
31
|
+
ensureNetworkEnabled(): Promise<void>;
|
|
32
|
+
/** Subscribe to responseReceived; returns the unsubscribe function. */
|
|
33
|
+
onResponseReceived(handler: (params: {
|
|
34
|
+
requestId: string;
|
|
35
|
+
response: WatchedResponse;
|
|
36
|
+
}) => void): () => void;
|
|
37
|
+
getResponseBody(requestId: string): Promise<{
|
|
38
|
+
body: string;
|
|
39
|
+
}>;
|
|
40
|
+
setRequestInterception(patterns: {
|
|
41
|
+
urlPattern: string;
|
|
42
|
+
}[]): Promise<void>;
|
|
43
|
+
onRequestIntercepted(handler: (params: InterceptedRequest) => Promise<void>): void;
|
|
44
|
+
continueInterceptedRequest(params: {
|
|
45
|
+
interceptionId: string;
|
|
46
|
+
headers?: Record<string, string>;
|
|
47
|
+
errorReason?: string;
|
|
48
|
+
}): Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
export interface NetworkWatchOptions {
|
|
51
|
+
/** Backoff before body-fetch retry `attempt` (1-based). Injectable so tests run instantly. */
|
|
52
|
+
backoffMs?: (attempt: number) => number;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Compile glob-ish patterns (`*` = wildcard) to RegExp once, so the hot matcher
|
|
56
|
+
* never rebuilds them.
|
|
57
|
+
*
|
|
58
|
+
* Every character except `*` is escaped first. URLs are full of regex
|
|
59
|
+
* metacharacters, so treating the pattern as a raw regex was both wrong and
|
|
60
|
+
* crash-prone: a pattern containing `ads(1).js` threw
|
|
61
|
+
* `SyntaxError: Unterminated group`, and a plain `?`/`+`/`.` silently changed
|
|
62
|
+
* what matched - an unescaped `.` matches any character, so a pattern for
|
|
63
|
+
* `.google-analytics.com` also matched `xgoogle-analytics.com`.
|
|
64
|
+
* Same bug class as the injected-script template double-escaping fix.
|
|
65
|
+
*/
|
|
66
|
+
export declare function compilePatterns(urlPatterns: string[]): RegExp[];
|
|
67
|
+
/** True when the URL matches any precompiled pattern. */
|
|
68
|
+
export declare function matchesAnyCompiled(url: string, regexes: RegExp[]): boolean;
|
|
69
|
+
/** True when the URL matches any glob-ish pattern (`*` = wildcard). */
|
|
70
|
+
export declare function matchesAnyPattern(url: string, urlPatterns: string[]): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Repair missing sec-fetch-* headers based on request type and destination.
|
|
73
|
+
* Pure: returns the headers to send.
|
|
74
|
+
*/
|
|
75
|
+
export declare function withFetchMetadataHeaders(request: InterceptedRequest['request']): Record<string, string>;
|
|
76
|
+
export declare class NetworkWatch {
|
|
77
|
+
private readonly port;
|
|
78
|
+
private readonly backoffMs;
|
|
79
|
+
/** Compiled block patterns, or null when `blockRequests` was never called. */
|
|
80
|
+
private blockedPatterns;
|
|
81
|
+
/** Whether `setupFetchMetadataHeaders` asked for sec-fetch-* repair. */
|
|
82
|
+
private repairFetchMetadata;
|
|
83
|
+
/** Guards against installing a second interception handler. */
|
|
84
|
+
private interceptionInstalled;
|
|
85
|
+
constructor(port: NetworkWatchPort, options?: NetworkWatchOptions);
|
|
86
|
+
/**
|
|
87
|
+
* Resolve with the first response whose URL contains `urlPart` and whose
|
|
88
|
+
* status matches, with its JSON body attached. The listener is removed on
|
|
89
|
+
* match AND on timeout - a long-lived page must not accumulate handlers.
|
|
90
|
+
*/
|
|
91
|
+
waitForResponse(urlPart: string, statusCode?: number, timeoutMs?: number): Promise<WatchedResponseWithBody>;
|
|
92
|
+
/** Abort every request whose URL matches one of the glob-ish patterns. */
|
|
93
|
+
blockRequests(urlPatterns: string[]): Promise<void>;
|
|
94
|
+
/** Add proper Fetch Metadata (sec-fetch-*) headers to avoid CDP detection. */
|
|
95
|
+
setupFetchMetadataHeaders(): Promise<void>;
|
|
96
|
+
/**
|
|
97
|
+
* Install the SINGLE request-interception handler, at most once per page.
|
|
98
|
+
*
|
|
99
|
+
* Both interception features (blocking, fetch-metadata repair) route
|
|
100
|
+
* through here because CDP allows exactly one continue per
|
|
101
|
+
* `interceptionId`. Registering a handler per feature meant that calling
|
|
102
|
+
* both `blockRequests` and `setupFetchMetadataHeaders` on one page made two
|
|
103
|
+
* handlers race to continue the same request - the second call fails with
|
|
104
|
+
* `Invalid InterceptionId`, and the second `setRequestInterception` silently
|
|
105
|
+
* replaced the first's patterns. One handler consults both pieces of state
|
|
106
|
+
* instead, so the features compose in either call order.
|
|
107
|
+
*/
|
|
108
|
+
private ensureInterception;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=network-watch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-watch.d.ts","sourceRoot":"","sources":["../../src/network/network-watch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NetworkWatch - the deep module beside ElementTarget/DropdownSelector that
|
|
3
|
+
* owns the network interception protocol: response waiting (match, timeout,
|
|
4
|
+
* body fetch with backoff, listener cleanup), request blocking, and
|
|
5
|
+
* fetch-metadata header repair.
|
|
6
|
+
*
|
|
7
|
+
* Talks to the page only through the narrow `NetworkWatchPort`, so the whole
|
|
8
|
+
* protocol is unit-testable with a scripted port. `CdpPage.waitForResponse`,
|
|
9
|
+
* `CdpPage.blockRequests`, and `CdpPage.setupFetchMetadataHeaders` are thin
|
|
10
|
+
* delegates.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Compile glob-ish patterns (`*` = wildcard) to RegExp once, so the hot matcher
|
|
14
|
+
* never rebuilds them.
|
|
15
|
+
*
|
|
16
|
+
* Every character except `*` is escaped first. URLs are full of regex
|
|
17
|
+
* metacharacters, so treating the pattern as a raw regex was both wrong and
|
|
18
|
+
* crash-prone: a pattern containing `ads(1).js` threw
|
|
19
|
+
* `SyntaxError: Unterminated group`, and a plain `?`/`+`/`.` silently changed
|
|
20
|
+
* what matched - an unescaped `.` matches any character, so a pattern for
|
|
21
|
+
* `.google-analytics.com` also matched `xgoogle-analytics.com`.
|
|
22
|
+
* Same bug class as the injected-script template double-escaping fix.
|
|
23
|
+
*/
|
|
24
|
+
export function compilePatterns(urlPatterns) {
|
|
25
|
+
return urlPatterns.map((pattern) => {
|
|
26
|
+
const source = pattern
|
|
27
|
+
// Escape every regex metacharacter, `*` included...
|
|
28
|
+
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
29
|
+
// ...then re-expand the escaped `\*` back into the wildcard.
|
|
30
|
+
.replace(/\\\*/g, '.*');
|
|
31
|
+
return new RegExp(source);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/** True when the URL matches any precompiled pattern. */
|
|
35
|
+
export function matchesAnyCompiled(url, regexes) {
|
|
36
|
+
return regexes.some((regex) => regex.test(url));
|
|
37
|
+
}
|
|
38
|
+
/** True when the URL matches any glob-ish pattern (`*` = wildcard). */
|
|
39
|
+
export function matchesAnyPattern(url, urlPatterns) {
|
|
40
|
+
return matchesAnyCompiled(url, compilePatterns(urlPatterns));
|
|
41
|
+
}
|
|
42
|
+
/** Parse a response body as JSON, falling back to the raw string when it is not JSON. */
|
|
43
|
+
function parseResponseBody(body) {
|
|
44
|
+
try {
|
|
45
|
+
return JSON.parse(body);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return body;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Repair missing sec-fetch-* headers based on request type and destination.
|
|
53
|
+
* Pure: returns the headers to send.
|
|
54
|
+
*/
|
|
55
|
+
export function withFetchMetadataHeaders(request) {
|
|
56
|
+
const url = new URL(request.url);
|
|
57
|
+
const headers = { ...request.headers };
|
|
58
|
+
if (request.method === 'GET' && !headers['sec-fetch-dest']) {
|
|
59
|
+
if (url.pathname.endsWith('.js')) {
|
|
60
|
+
headers['sec-fetch-dest'] = 'script';
|
|
61
|
+
headers['sec-fetch-mode'] = 'no-cors';
|
|
62
|
+
headers['sec-fetch-site'] = url.origin === headers.origin ? 'same-origin' : 'cross-site';
|
|
63
|
+
}
|
|
64
|
+
else if (url.pathname.endsWith('.css')) {
|
|
65
|
+
headers['sec-fetch-dest'] = 'style';
|
|
66
|
+
headers['sec-fetch-mode'] = 'no-cors';
|
|
67
|
+
headers['sec-fetch-site'] = url.origin === headers.origin ? 'same-origin' : 'cross-site';
|
|
68
|
+
}
|
|
69
|
+
else if (url.pathname.match(/\.(png|jpg|jpeg|gif|webp|svg)$/i)) {
|
|
70
|
+
headers['sec-fetch-dest'] = 'image';
|
|
71
|
+
headers['sec-fetch-mode'] = 'no-cors';
|
|
72
|
+
headers['sec-fetch-site'] = url.origin === headers.origin ? 'same-origin' : 'cross-site';
|
|
73
|
+
}
|
|
74
|
+
else if (url.pathname === '/' || !url.pathname.includes('.')) {
|
|
75
|
+
headers['sec-fetch-dest'] = 'document';
|
|
76
|
+
headers['sec-fetch-mode'] = 'navigate';
|
|
77
|
+
headers['sec-fetch-site'] = 'none';
|
|
78
|
+
headers['sec-fetch-user'] = '?1';
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return headers;
|
|
82
|
+
}
|
|
83
|
+
export class NetworkWatch {
|
|
84
|
+
constructor(port, options = {}) {
|
|
85
|
+
Object.defineProperty(this, "port", {
|
|
86
|
+
enumerable: true,
|
|
87
|
+
configurable: true,
|
|
88
|
+
writable: true,
|
|
89
|
+
value: void 0
|
|
90
|
+
});
|
|
91
|
+
Object.defineProperty(this, "backoffMs", {
|
|
92
|
+
enumerable: true,
|
|
93
|
+
configurable: true,
|
|
94
|
+
writable: true,
|
|
95
|
+
value: void 0
|
|
96
|
+
});
|
|
97
|
+
// ── request-interception state, read by the single shared handler ──
|
|
98
|
+
/** Compiled block patterns, or null when `blockRequests` was never called. */
|
|
99
|
+
Object.defineProperty(this, "blockedPatterns", {
|
|
100
|
+
enumerable: true,
|
|
101
|
+
configurable: true,
|
|
102
|
+
writable: true,
|
|
103
|
+
value: null
|
|
104
|
+
});
|
|
105
|
+
/** Whether `setupFetchMetadataHeaders` asked for sec-fetch-* repair. */
|
|
106
|
+
Object.defineProperty(this, "repairFetchMetadata", {
|
|
107
|
+
enumerable: true,
|
|
108
|
+
configurable: true,
|
|
109
|
+
writable: true,
|
|
110
|
+
value: false
|
|
111
|
+
});
|
|
112
|
+
/** Guards against installing a second interception handler. */
|
|
113
|
+
Object.defineProperty(this, "interceptionInstalled", {
|
|
114
|
+
enumerable: true,
|
|
115
|
+
configurable: true,
|
|
116
|
+
writable: true,
|
|
117
|
+
value: false
|
|
118
|
+
});
|
|
119
|
+
this.port = port;
|
|
120
|
+
this.backoffMs = options.backoffMs ?? ((attempt) => 1000 * 2 ** attempt);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Resolve with the first response whose URL contains `urlPart` and whose
|
|
124
|
+
* status matches, with its JSON body attached. The listener is removed on
|
|
125
|
+
* match AND on timeout - a long-lived page must not accumulate handlers.
|
|
126
|
+
*/
|
|
127
|
+
async waitForResponse(urlPart, statusCode = 200, timeoutMs = 180000) {
|
|
128
|
+
await this.port.ensureNetworkEnabled(); // Lazy enable Network only when needed
|
|
129
|
+
return new Promise((resolve, reject) => {
|
|
130
|
+
let unsubscribe = () => { };
|
|
131
|
+
const timer = setTimeout(() => {
|
|
132
|
+
unsubscribe();
|
|
133
|
+
reject(new Error(`Timeout after ${timeoutMs / 1000} seconds`));
|
|
134
|
+
}, timeoutMs);
|
|
135
|
+
const onResponseReceived = ({ requestId, response }) => {
|
|
136
|
+
if (!(response.url.includes(urlPart) && response.status === statusCode))
|
|
137
|
+
return;
|
|
138
|
+
clearTimeout(timer);
|
|
139
|
+
unsubscribe();
|
|
140
|
+
void (async () => {
|
|
141
|
+
let body;
|
|
142
|
+
try {
|
|
143
|
+
({ body } = await this.port.getResponseBody(requestId));
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
// Retry with exponential backoff only for genuine
|
|
147
|
+
// transport failures: the body may not be ready yet, or
|
|
148
|
+
// the Network domain dropped mid-flight. A non-JSON body
|
|
149
|
+
// is NOT a transient error and never reaches this loop.
|
|
150
|
+
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
151
|
+
try {
|
|
152
|
+
await this.port.ensureNetworkEnabled();
|
|
153
|
+
await new Promise((resolveTimeout) => {
|
|
154
|
+
setTimeout(resolveTimeout, this.backoffMs(attempt));
|
|
155
|
+
});
|
|
156
|
+
const retried = await this.port.getResponseBody(requestId);
|
|
157
|
+
resolve({ ...response, body: parseResponseBody(retried.body) });
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
if (attempt === 3)
|
|
162
|
+
reject(new Error(`Failed to get response body after ${attempt} attempts`));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
// Transport succeeded: parse JSON, or resolve the raw string
|
|
168
|
+
// immediately when the body is not JSON.
|
|
169
|
+
resolve({ ...response, body: parseResponseBody(body) });
|
|
170
|
+
})();
|
|
171
|
+
};
|
|
172
|
+
unsubscribe = this.port.onResponseReceived(onResponseReceived);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
/** Abort every request whose URL matches one of the glob-ish patterns. */
|
|
176
|
+
async blockRequests(urlPatterns) {
|
|
177
|
+
// Compile once; the interception handler reads the compiled array so no
|
|
178
|
+
// RegExp is rebuilt on the hot path.
|
|
179
|
+
this.blockedPatterns = compilePatterns(urlPatterns);
|
|
180
|
+
await this.ensureInterception();
|
|
181
|
+
}
|
|
182
|
+
/** Add proper Fetch Metadata (sec-fetch-*) headers to avoid CDP detection. */
|
|
183
|
+
async setupFetchMetadataHeaders() {
|
|
184
|
+
this.repairFetchMetadata = true;
|
|
185
|
+
await this.ensureInterception();
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Install the SINGLE request-interception handler, at most once per page.
|
|
189
|
+
*
|
|
190
|
+
* Both interception features (blocking, fetch-metadata repair) route
|
|
191
|
+
* through here because CDP allows exactly one continue per
|
|
192
|
+
* `interceptionId`. Registering a handler per feature meant that calling
|
|
193
|
+
* both `blockRequests` and `setupFetchMetadataHeaders` on one page made two
|
|
194
|
+
* handlers race to continue the same request - the second call fails with
|
|
195
|
+
* `Invalid InterceptionId`, and the second `setRequestInterception` silently
|
|
196
|
+
* replaced the first's patterns. One handler consults both pieces of state
|
|
197
|
+
* instead, so the features compose in either call order.
|
|
198
|
+
*/
|
|
199
|
+
async ensureInterception() {
|
|
200
|
+
await this.port.ensureNetworkEnabled(); // Lazy enable Network only when needed
|
|
201
|
+
if (this.interceptionInstalled)
|
|
202
|
+
return;
|
|
203
|
+
this.interceptionInstalled = true;
|
|
204
|
+
await this.port.setRequestInterception([{ urlPattern: '*' }]);
|
|
205
|
+
this.port.onRequestIntercepted(async (params) => {
|
|
206
|
+
// Blocking wins: an aborted request must not also be continued.
|
|
207
|
+
if (this.blockedPatterns && matchesAnyCompiled(params.request.url, this.blockedPatterns)) {
|
|
208
|
+
await this.port.continueInterceptedRequest({
|
|
209
|
+
interceptionId: params.interceptionId,
|
|
210
|
+
errorReason: 'Aborted',
|
|
211
|
+
});
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
await this.port.continueInterceptedRequest({
|
|
215
|
+
interceptionId: params.interceptionId,
|
|
216
|
+
...(this.repairFetchMetadata
|
|
217
|
+
? { headers: withFetchMetadataHeaders(params.request) }
|
|
218
|
+
: {}),
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=network-watch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-watch.js","sourceRoot":"","sources":["../../src/network/network-watch.ts"],"names":[],"mappings":"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"}
|