@crawlee/puppeteer 3.0.0-alpha.2 → 3.0.0-alpha.3

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 (38) hide show
  1. package/dist/LICENSE.md +201 -0
  2. package/{README.md → dist/README.md} +0 -0
  3. package/dist/index.d.ts +12 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +12 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/index.mjs +76 -0
  8. package/dist/internals/enqueue-links/click-elements.d.ts +188 -0
  9. package/dist/internals/enqueue-links/click-elements.d.ts.map +1 -0
  10. package/dist/internals/enqueue-links/click-elements.js +336 -0
  11. package/dist/internals/enqueue-links/click-elements.js.map +1 -0
  12. package/dist/internals/puppeteer-crawler.d.ts +149 -0
  13. package/dist/internals/puppeteer-crawler.d.ts.map +1 -0
  14. package/dist/internals/puppeteer-crawler.js +117 -0
  15. package/dist/internals/puppeteer-crawler.js.map +1 -0
  16. package/dist/internals/puppeteer-launcher.d.ts +134 -0
  17. package/dist/internals/puppeteer-launcher.d.ts.map +1 -0
  18. package/dist/internals/puppeteer-launcher.js +146 -0
  19. package/dist/internals/puppeteer-launcher.js.map +1 -0
  20. package/dist/internals/stealth/hiding_tricks.d.ts +10 -0
  21. package/dist/internals/stealth/hiding_tricks.d.ts.map +1 -0
  22. package/dist/internals/stealth/hiding_tricks.js +334 -0
  23. package/dist/internals/stealth/hiding_tricks.js.map +1 -0
  24. package/dist/internals/stealth/index.d.ts +40 -0
  25. package/dist/internals/stealth/index.d.ts.map +1 -0
  26. package/dist/internals/stealth/index.js +108 -0
  27. package/dist/internals/stealth/index.js.map +1 -0
  28. package/dist/internals/utils/puppeteer_request_interception.d.ts +60 -0
  29. package/dist/internals/utils/puppeteer_request_interception.d.ts.map +1 -0
  30. package/dist/internals/utils/puppeteer_request_interception.js +225 -0
  31. package/dist/internals/utils/puppeteer_request_interception.js.map +1 -0
  32. package/dist/internals/utils/puppeteer_utils.d.ts +298 -0
  33. package/dist/internals/utils/puppeteer_utils.d.ts.map +1 -0
  34. package/dist/internals/utils/puppeteer_utils.js +468 -0
  35. package/dist/internals/utils/puppeteer_utils.js.map +1 -0
  36. package/dist/package.json +66 -0
  37. package/dist/tsconfig.build.tsbuildinfo +1 -0
  38. package/package.json +8 -7
@@ -0,0 +1,40 @@
1
+ import { Page, Browser } from 'puppeteer';
2
+ /**
3
+ * Configuration of stealth tricks for a proper hiding effect all of them should be set to true.
4
+ * These tricks are applied only when the `stealth` option is set to `true`.
5
+ */
6
+ export interface StealthOptions {
7
+ /** If plugins should be added to the navigator. */
8
+ addPlugins?: boolean;
9
+ /** Emulates window Iframe. */
10
+ emulateWindowFrame?: boolean;
11
+ /** Emulates graphic card. */
12
+ emulateWebGL?: boolean;
13
+ /** Emulates console.debug to return null. */
14
+ emulateConsoleDebug?: boolean;
15
+ /** Adds languages to the navigator. */
16
+ addLanguage?: boolean;
17
+ /** Hides the webdriver by changing the navigator proto. */
18
+ hideWebDriver?: boolean;
19
+ /** Fakes interaction with permissions. */
20
+ hackPermissions?: boolean;
21
+ /** Adds the chrome runtime properties. */
22
+ mockChrome?: boolean;
23
+ /** Adds the chrome runtime properties inside the every newly created iframe. */
24
+ mockChromeInIframe?: boolean;
25
+ /** Sets device memory to other value than 0. */
26
+ mockDeviceMemory?: boolean;
27
+ }
28
+ /**
29
+ * The main purpose of this function is to override newPage function and attach selected tricks.
30
+ * @param browser puppeteer browser instance
31
+ * @param options
32
+ * @returns Instance of Browser from puppeteer package
33
+ */
34
+ export declare function applyStealthToBrowser(browser: Browser, options: StealthOptions): Browser;
35
+ /**
36
+ * Applies stealth tricks to the puppeteer page
37
+ * @internal
38
+ */
39
+ export declare function applyStealthTricks(page: Page, evaluationDebugMessage: string, options: StealthOptions): Promise<void>;
40
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/internals/stealth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQ1C;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC3B,mDAAmD;IACnD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8BAA8B;IAC9B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,6BAA6B;IAC7B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,6CAA6C;IAC7C,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,uCAAuC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,2DAA2D;IAC3D,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,0CAA0C;IAC1C,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,0CAA0C;IAC1C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gFAAgF;IAChF,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,gDAAgD;IAChD,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAkBD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAwBxF;AAoCD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,EAAE,sBAAsB,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBrH"}
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.applyStealthTricks = exports.applyStealthToBrowser = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const utilities_1 = require("@apify/utilities");
6
+ const log_1 = tslib_1.__importDefault(require("@apify/log"));
7
+ const utils_1 = require("@crawlee/utils");
8
+ const hidingTricks = tslib_1.__importStar(require("./hiding_tricks"));
9
+ const log = log_1.default.child({ prefix: 'Stealth' });
10
+ const DEFAULT_STEALTH_OPTIONS = {
11
+ addPlugins: true,
12
+ emulateWindowFrame: true,
13
+ emulateWebGL: true,
14
+ emulateConsoleDebug: true,
15
+ addLanguage: true,
16
+ hackPermissions: true,
17
+ mockChrome: true,
18
+ mockChromeInIframe: true,
19
+ mockDeviceMemory: true,
20
+ };
21
+ const STEALTH_ERROR_MESSAGE_PREFIX = 'StealthError';
22
+ const MAX_IFRAMES = 10;
23
+ const alreadyWrapped = Symbol('alreadyWrapped');
24
+ /**
25
+ * The main purpose of this function is to override newPage function and attach selected tricks.
26
+ * @param browser puppeteer browser instance
27
+ * @param options
28
+ * @returns Instance of Browser from puppeteer package
29
+ */
30
+ function applyStealthToBrowser(browser, options) {
31
+ const modifiedBrowser = browser;
32
+ const opts = { ...DEFAULT_STEALTH_OPTIONS, ...options };
33
+ const defaultContext = browser.defaultBrowserContext();
34
+ const contextPrototype = Object.getPrototypeOf(defaultContext);
35
+ const prevNewPage = contextPrototype.newPage;
36
+ if (!contextPrototype.newPage[alreadyWrapped]) {
37
+ contextPrototype.newPage = async function (...args) {
38
+ const page = await prevNewPage.bind(this)(...args);
39
+ const evaluationDebugMessage = generateEvaluationDebugMessage();
40
+ addStealthDebugToPage(page, evaluationDebugMessage);
41
+ await applyStealthTricks(page, evaluationDebugMessage, opts);
42
+ return page;
43
+ };
44
+ contextPrototype.newPage[alreadyWrapped] = true;
45
+ }
46
+ return modifiedBrowser;
47
+ }
48
+ exports.applyStealthToBrowser = applyStealthToBrowser;
49
+ function generateEvaluationDebugMessage() {
50
+ const minLength = 6;
51
+ const maxLength = 10;
52
+ const randomLength = Math.random() * (maxLength - minLength) + minLength;
53
+ return (0, utilities_1.cryptoRandomObjectId)(randomLength);
54
+ }
55
+ /**
56
+ * Logs the stealth errors in browser to the node stdout.
57
+ * @param page puppeteer page instance
58
+ * @param evaluationDebugMessage debug message
59
+ */
60
+ function addStealthDebugToPage(page, evaluationDebugMessage) {
61
+ let warningLogged = false;
62
+ let counter = 1;
63
+ page.on('console', (msg) => {
64
+ const text = msg.text();
65
+ if (text.includes(STEALTH_ERROR_MESSAGE_PREFIX)) {
66
+ log.error(text);
67
+ }
68
+ else if (text.includes(evaluationDebugMessage)) {
69
+ if (counter > MAX_IFRAMES && !warningLogged) {
70
+ log.warning(`Evaluating hiding tricks in too many iframes (limit: ${MAX_IFRAMES}).`
71
+ + 'You might experience some performance issues. Try setting \'stealth\' false');
72
+ warningLogged = true;
73
+ }
74
+ counter++;
75
+ log.debug('Tricks evaluated', { counter });
76
+ }
77
+ });
78
+ }
79
+ /**
80
+ * Applies stealth tricks to the puppeteer page
81
+ * @internal
82
+ */
83
+ function applyStealthTricks(page, evaluationDebugMessage, options) {
84
+ const functions = (0, utils_1.keys)(options)
85
+ .filter((key) => {
86
+ return options[key];
87
+ })
88
+ .map((key) => hidingTricks[key].toString());
89
+ /* istanbul ignore next */
90
+ const addFunctions = (functionsArr, errorMessagePrefix, debugMessage) => {
91
+ // eslint-disable-next-line no-console
92
+ console.log(debugMessage);
93
+ // add functions
94
+ for (const func of functionsArr) {
95
+ try {
96
+ eval(func)(); // eslint-disable-line
97
+ }
98
+ catch (e) {
99
+ const err = e;
100
+ // eslint-disable-next-line no-console
101
+ console.error(`${errorMessagePrefix}: Failed to apply stealth trick reason: ${err.message}`);
102
+ }
103
+ }
104
+ };
105
+ return page.evaluateOnNewDocument(addFunctions, functions, STEALTH_ERROR_MESSAGE_PREFIX, evaluationDebugMessage);
106
+ }
107
+ exports.applyStealthTricks = applyStealthTricks;
108
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/internals/stealth/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import { HTTPRequest as PuppeteerRequest, Page } from 'puppeteer';
2
+ export declare type InterceptHandler = (request: PuppeteerRequest) => unknown;
3
+ /**
4
+ * Adds request interception handler in similar to `page.on('request', handler);` but in addition to that
5
+ * supports multiple parallel handlers.
6
+ *
7
+ * All the handlers are executed sequentially in the order as they were added.
8
+ * Each of the handlers must call one of `request.continue()`, `request.abort()` and `request.respond()`.
9
+ * In addition to that any of the handlers may modify the request object (method, postData, headers)
10
+ * by passing its overrides to `request.continue()`.
11
+ * If multiple handlers modify same property then the last one wins. Headers are merged separately so you can
12
+ * override only a value of specific header.
13
+ *
14
+ * If one the handlers calls `request.abort()` or `request.respond()` then request is not propagated further
15
+ * to any of the remaining handlers.
16
+ *
17
+ *
18
+ * **Example usage:**
19
+ *
20
+ * ```javascript
21
+ * // Replace images with placeholder.
22
+ * await addInterceptRequestHandler(page, (request) => {
23
+ * if (request.resourceType() === 'image') {
24
+ * return request.respond({
25
+ * statusCode: 200,
26
+ * contentType: 'image/jpeg',
27
+ * body: placeholderImageBuffer,
28
+ * });
29
+ * }
30
+ * return request.continue();
31
+ * });
32
+ *
33
+ * // Abort all the scripts.
34
+ * await addInterceptRequestHandler(page, (request) => {
35
+ * if (request.resourceType() === 'script') return request.abort();
36
+ * return request.continue();
37
+ * });
38
+ *
39
+ * // Change requests to post.
40
+ * await addInterceptRequestHandler(page, (request) => {
41
+ * return request.continue({
42
+ * method: 'POST',
43
+ * });
44
+ * });
45
+ *
46
+ * await page.goto('http://example.com');
47
+ * ```
48
+ *
49
+ * @param page Puppeteer [`Page`](https://pptr.dev/#?product=Puppeteer&show=api-class-page) object.
50
+ * @param handler Request interception handler.
51
+ */
52
+ export declare function addInterceptRequestHandler(page: Page, handler: InterceptHandler): Promise<void>;
53
+ /**
54
+ * Removes request interception handler for given page.
55
+ *
56
+ * @param page Puppeteer [`Page`](https://pptr.dev/#?product=Puppeteer&show=api-class-page) object.
57
+ * @param handler Request interception handler.
58
+ */
59
+ export declare function removeInterceptRequestHandler(page: Page, handler: InterceptHandler): Promise<void>;
60
+ //# sourceMappingURL=puppeteer_request_interception.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"puppeteer_request_interception.d.ts","sourceRoot":"","sources":["../../../src/internals/utils/puppeteer_request_interception.ts"],"names":[],"mappings":"AAEA,OAAO,EAAe,WAAW,IAAI,gBAAgB,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAiC/E,oBAAY,gBAAgB,GAAG,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC;AAwEtE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,wBAAsB,0BAA0B,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmCrG;AAED;;;;;GAKG;AACH,wBAAsB,6BAA6B,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BxG"}
@@ -0,0 +1,225 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.removeInterceptRequestHandler = exports.addInterceptRequestHandler = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const events_1 = require("events");
6
+ const ow_1 = tslib_1.__importDefault(require("ow"));
7
+ const log_1 = tslib_1.__importDefault(require("@apify/log"));
8
+ // We use weak maps here so that the content gets discarded after page gets closed.
9
+ const pageInterceptRequestHandlersMap = new WeakMap(); // Maps page to an array of request interception handlers.
10
+ const pageInterceptRequestMasterHandlerMap = new WeakMap(); // Maps page to master request interception handler.
11
+ const pageInterceptedRequestsMap = new WeakMap(); // Maps page to a set of its pending intercepted requests.
12
+ /**
13
+ * Enables observation of changes of internal state to be able to queue other actions based on it.
14
+ * @ignore
15
+ */
16
+ class ObservableSet extends events_1.EventEmitter {
17
+ constructor() {
18
+ super(...arguments);
19
+ Object.defineProperty(this, "set", {
20
+ enumerable: true,
21
+ configurable: true,
22
+ writable: true,
23
+ value: new Set()
24
+ });
25
+ }
26
+ add(value) {
27
+ this.set.add(value);
28
+ this.emit('add', value);
29
+ return this.set;
30
+ }
31
+ delete(value) {
32
+ const success = this.set.delete(value);
33
+ this.emit('delete', value);
34
+ return success;
35
+ }
36
+ get size() {
37
+ return this.set.size;
38
+ }
39
+ }
40
+ /**
41
+ * Makes all request headers capitalized to more look like in browser
42
+ */
43
+ function browserifyHeaders(headers) {
44
+ const finalHeaders = {};
45
+ // eslint-disable-next-line prefer-const
46
+ for (let [key, value] of Object.entries(headers)) {
47
+ key = key.toLowerCase()
48
+ .split('-')
49
+ .map((str) => str.charAt(0).toUpperCase() + str.slice(1))
50
+ .join('-');
51
+ finalHeaders[key] = value;
52
+ }
53
+ return finalHeaders;
54
+ }
55
+ /**
56
+ * Executes an array for given intercept request handlers for a given request object.
57
+ *
58
+ * @param request Puppeteer's Request object.
59
+ * @param interceptRequestHandlers An array of intercept request handlers.
60
+ * @ignore
61
+ */
62
+ async function handleRequest(request, interceptRequestHandlers) {
63
+ // If there are no intercept handlers, it means that request interception is not enabled (anymore)
64
+ // and therefore .abort() .respond() and .continue() would throw and crash the process.
65
+ if (!interceptRequestHandlers?.length)
66
+ return;
67
+ let wasAborted = false;
68
+ let wasResponded = false;
69
+ let wasContinued = false;
70
+ const accumulatedOverrides = {
71
+ headers: browserifyHeaders(request.headers()),
72
+ };
73
+ const originalContinue = request.continue.bind(request);
74
+ request.continue = async (overrides = {}) => {
75
+ wasContinued = true;
76
+ const headers = browserifyHeaders({ ...accumulatedOverrides.headers, ...overrides.headers });
77
+ Object.assign(accumulatedOverrides, overrides, { headers });
78
+ };
79
+ const { abort, respond } = request;
80
+ request.abort = async (...args) => {
81
+ wasAborted = true;
82
+ return abort.call(request, ...args);
83
+ };
84
+ request.respond = async (...args) => {
85
+ wasResponded = true;
86
+ return respond.call(request, ...args);
87
+ };
88
+ for (const handler of interceptRequestHandlers) {
89
+ wasContinued = false;
90
+ await handler(request);
91
+ // Check that one of the functions was called.
92
+ if (!wasAborted && !wasResponded && !wasContinued) {
93
+ throw new Error('Intercept request handler must call one of request.continue|respond|abort() methods!');
94
+ }
95
+ // If request was aborted or responded then we can finish immediately.
96
+ if (wasAborted || wasResponded)
97
+ return;
98
+ }
99
+ return originalContinue(accumulatedOverrides);
100
+ }
101
+ /**
102
+ * Adds request interception handler in similar to `page.on('request', handler);` but in addition to that
103
+ * supports multiple parallel handlers.
104
+ *
105
+ * All the handlers are executed sequentially in the order as they were added.
106
+ * Each of the handlers must call one of `request.continue()`, `request.abort()` and `request.respond()`.
107
+ * In addition to that any of the handlers may modify the request object (method, postData, headers)
108
+ * by passing its overrides to `request.continue()`.
109
+ * If multiple handlers modify same property then the last one wins. Headers are merged separately so you can
110
+ * override only a value of specific header.
111
+ *
112
+ * If one the handlers calls `request.abort()` or `request.respond()` then request is not propagated further
113
+ * to any of the remaining handlers.
114
+ *
115
+ *
116
+ * **Example usage:**
117
+ *
118
+ * ```javascript
119
+ * // Replace images with placeholder.
120
+ * await addInterceptRequestHandler(page, (request) => {
121
+ * if (request.resourceType() === 'image') {
122
+ * return request.respond({
123
+ * statusCode: 200,
124
+ * contentType: 'image/jpeg',
125
+ * body: placeholderImageBuffer,
126
+ * });
127
+ * }
128
+ * return request.continue();
129
+ * });
130
+ *
131
+ * // Abort all the scripts.
132
+ * await addInterceptRequestHandler(page, (request) => {
133
+ * if (request.resourceType() === 'script') return request.abort();
134
+ * return request.continue();
135
+ * });
136
+ *
137
+ * // Change requests to post.
138
+ * await addInterceptRequestHandler(page, (request) => {
139
+ * return request.continue({
140
+ * method: 'POST',
141
+ * });
142
+ * });
143
+ *
144
+ * await page.goto('http://example.com');
145
+ * ```
146
+ *
147
+ * @param page Puppeteer [`Page`](https://pptr.dev/#?product=Puppeteer&show=api-class-page) object.
148
+ * @param handler Request interception handler.
149
+ */
150
+ async function addInterceptRequestHandler(page, handler) {
151
+ (0, ow_1.default)(page, ow_1.default.object.hasKeys('goto', 'evaluate'));
152
+ (0, ow_1.default)(handler, ow_1.default.function);
153
+ if (!pageInterceptRequestHandlersMap.has(page)) {
154
+ pageInterceptRequestHandlersMap.set(page, []);
155
+ }
156
+ if (!pageInterceptedRequestsMap.has(page)) {
157
+ pageInterceptedRequestsMap.set(page, new ObservableSet());
158
+ }
159
+ const handlersArray = pageInterceptRequestHandlersMap.get(page);
160
+ handlersArray.push(handler);
161
+ // First handler was just added at this point so we need to set up request interception.
162
+ if (handlersArray.length === 1) {
163
+ await page.setRequestInterception(true);
164
+ // This is a handler that gets set in page.on('request', ...) and that executes all the user
165
+ // added custom handlers.
166
+ const masterHandler = async (request) => {
167
+ const interceptedRequests = pageInterceptedRequestsMap.get(page);
168
+ interceptedRequests.add(request);
169
+ const interceptHandlers = pageInterceptRequestHandlersMap.get(page);
170
+ try {
171
+ await handleRequest(request, interceptHandlers);
172
+ }
173
+ finally {
174
+ interceptedRequests.delete(request);
175
+ }
176
+ };
177
+ pageInterceptRequestMasterHandlerMap.set(page, masterHandler);
178
+ page.on('request', masterHandler);
179
+ }
180
+ }
181
+ exports.addInterceptRequestHandler = addInterceptRequestHandler;
182
+ /**
183
+ * Removes request interception handler for given page.
184
+ *
185
+ * @param page Puppeteer [`Page`](https://pptr.dev/#?product=Puppeteer&show=api-class-page) object.
186
+ * @param handler Request interception handler.
187
+ */
188
+ async function removeInterceptRequestHandler(page, handler) {
189
+ (0, ow_1.default)(page, ow_1.default.object.hasKeys('goto', 'evaluate'));
190
+ (0, ow_1.default)(handler, ow_1.default.function);
191
+ const handlersArray = pageInterceptRequestHandlersMap
192
+ .get(page)
193
+ .filter((item) => item !== handler);
194
+ pageInterceptRequestHandlersMap.set(page, handlersArray);
195
+ if (handlersArray.length === 0) {
196
+ const interceptedRequestsInProgress = pageInterceptedRequestsMap.get(page);
197
+ // Since handlers can be async, we can't simply turn off request interception
198
+ // when there are no handlers, because some handlers could still
199
+ // be in progress and request.abort|respond|continue() would throw.
200
+ if (interceptedRequestsInProgress.size === 0) {
201
+ await disableRequestInterception(page);
202
+ }
203
+ else {
204
+ const onDelete = async () => {
205
+ if (interceptedRequestsInProgress.size === 0) {
206
+ try {
207
+ await disableRequestInterception(page);
208
+ interceptedRequestsInProgress.removeListener('delete', onDelete);
209
+ }
210
+ catch (error) {
211
+ log_1.default.debug('Error while disabling request interception', { error });
212
+ }
213
+ }
214
+ };
215
+ interceptedRequestsInProgress.on('delete', onDelete);
216
+ }
217
+ }
218
+ }
219
+ exports.removeInterceptRequestHandler = removeInterceptRequestHandler;
220
+ async function disableRequestInterception(page) {
221
+ await page.setRequestInterception(false);
222
+ const requestHandler = pageInterceptRequestMasterHandlerMap.get(page);
223
+ page.off('request', requestHandler);
224
+ }
225
+ //# sourceMappingURL=puppeteer_request_interception.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"puppeteer_request_interception.js","sourceRoot":"","sources":["../../../src/internals/utils/puppeteer_request_interception.ts"],"names":[],"mappings":";;;;AAAA,mCAAsC;AACtC,oDAAoB;AAGpB,6DAA6B;AAE7B,mFAAmF;AACnF,MAAM,+BAA+B,GAAsC,IAAI,OAAO,EAAE,CAAC,CAAC,0DAA0D;AACpJ,MAAM,oCAAoC,GAAG,IAAI,OAAO,EAAE,CAAC,CAAC,oDAAoD;AAChH,MAAM,0BAA0B,GAAG,IAAI,OAAO,EAAE,CAAC,CAAC,0DAA0D;AAE5G;;;GAGG;AACH,MAAM,aAAiB,SAAQ,qBAAY;IAA3C;;QACI;;;;mBAAM,IAAI,GAAG,EAAK;WAAC;IAiBvB,CAAC;IAfG,GAAG,CAAC,KAAQ;QACR,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACpB,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC,GAAG,CAAC;IACpB,CAAC;IAED,MAAM,CAAC,KAAQ;QACX,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC3B,OAAO,OAAO,CAAC;IACnB,CAAC;IAED,IAAI,IAAI;QACJ,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;IACzB,CAAC;CACJ;AAID;;GAEG;AACH,SAAS,iBAAiB,CAAC,OAA+B;IACtD,MAAM,YAAY,GAAuB,EAAE,CAAC;IAC5C,wCAAwC;IACxC,KAAK,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;QAC9C,GAAG,GAAG,GAAG,CAAC,WAAW,EAAE;aAClB,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;aACxD,IAAI,CAAC,GAAG,CAAC,CAAC;QAEf,YAAY,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;KAC7B;IAED,OAAO,YAAY,CAAC;AACxB,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,aAAa,CAAC,OAAyB,EAAE,wBAA6C;IACjG,kGAAkG;IAClG,uFAAuF;IACvF,IAAI,CAAC,wBAAwB,EAAE,MAAM;QAAE,OAAO;IAE9C,IAAI,UAAU,GAAG,KAAK,CAAC;IACvB,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,MAAM,oBAAoB,GAAG;QACzB,OAAO,EAAE,iBAAiB,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;KAChD,CAAC;IAEF,MAAM,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxD,OAAO,CAAC,QAAQ,GAAG,KAAK,EAAE,SAAS,GAAG,EAAE,EAAE,EAAE;QACxC,YAAY,GAAG,IAAI,CAAC;QACpB,MAAM,OAAO,GAAG,iBAAiB,CAAC,EAAE,GAAG,oBAAoB,CAAC,OAAO,EAAE,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC;QAC7F,MAAM,CAAC,MAAM,CAAC,oBAAoB,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IAChE,CAAC,CAAC;IAEF,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IACnC,OAAO,CAAC,KAAK,GAAG,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE;QAC9B,UAAU,GAAG,IAAI,CAAC;QAClB,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;IACxC,CAAC,CAAC;IACF,OAAO,CAAC,OAAO,GAAG,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE;QAChC,YAAY,GAAG,IAAI,CAAC;QACpB,OAAO,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;IAC1C,CAAC,CAAC;IAEF,KAAK,MAAM,OAAO,IAAI,wBAAwB,EAAE;QAC5C,YAAY,GAAG,KAAK,CAAC;QAErB,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;QACvB,8CAA8C;QAC9C,IAAI,CAAC,UAAU,IAAI,CAAC,YAAY,IAAI,CAAC,YAAY,EAAE;YAC/C,MAAM,IAAI,KAAK,CAAC,sFAAsF,CAAC,CAAC;SAC3G;QAED,sEAAsE;QACtE,IAAI,UAAU,IAAI,YAAY;YAAE,OAAO;KAC1C;IAED,OAAO,gBAAgB,CAAC,oBAAoB,CAAC,CAAC;AAClD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACI,KAAK,UAAU,0BAA0B,CAAC,IAAU,EAAE,OAAyB;IAClF,IAAA,YAAE,EAAC,IAAI,EAAE,YAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IAChD,IAAA,YAAE,EAAC,OAAO,EAAE,YAAE,CAAC,QAAQ,CAAC,CAAC;IAEzB,IAAI,CAAC,+BAA+B,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;QAC5C,+BAA+B,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;KACjD;IAED,IAAI,CAAC,0BAA0B,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;QACvC,0BAA0B,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,aAAa,EAAE,CAAC,CAAC;KAC7D;IAED,MAAM,aAAa,GAAG,+BAA+B,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;IACjE,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAE5B,wFAAwF;IACxF,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE;QAC5B,MAAM,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC;QAExC,4FAA4F;QAC5F,yBAAyB;QACzB,MAAM,aAAa,GAAG,KAAK,EAAE,OAAoB,EAAE,EAAE;YACjD,MAAM,mBAAmB,GAAG,0BAA0B,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACjE,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACjC,MAAM,iBAAiB,GAAG,+BAA+B,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACpE,IAAI;gBACA,MAAM,aAAa,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;aACnD;oBAAS;gBACN,mBAAmB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;aACvC;QACL,CAAC,CAAC;QAEF,oCAAoC,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;QAC9D,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;KACrC;AACL,CAAC;AAnCD,gEAmCC;AAED;;;;;GAKG;AACI,KAAK,UAAU,6BAA6B,CAAC,IAAU,EAAE,OAAyB;IACrF,IAAA,YAAE,EAAC,IAAI,EAAE,YAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IAChD,IAAA,YAAE,EAAC,OAAO,EAAE,YAAE,CAAC,QAAQ,CAAC,CAAC;IAEzB,MAAM,aAAa,GAAG,+BAA+B;SAChD,GAAG,CAAC,IAAI,CAAE;SACV,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;IAExC,+BAA+B,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IAEzD,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE;QAC5B,MAAM,6BAA6B,GAAG,0BAA0B,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC3E,6EAA6E;QAC7E,gEAAgE;QAChE,mEAAmE;QACnE,IAAI,6BAA6B,CAAC,IAAI,KAAK,CAAC,EAAE;YAC1C,MAAM,0BAA0B,CAAC,IAAI,CAAC,CAAC;SAC1C;aAAM;YACH,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;gBACxB,IAAI,6BAA6B,CAAC,IAAI,KAAK,CAAC,EAAE;oBAC1C,IAAI;wBACA,MAAM,0BAA0B,CAAC,IAAI,CAAC,CAAC;wBACvC,6BAA6B,CAAC,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;qBACpE;oBAAC,OAAO,KAAK,EAAE;wBACZ,aAAG,CAAC,KAAK,CAAC,4CAA4C,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;qBACtE;iBACJ;YACL,CAAC,CAAC;YACF,6BAA6B,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;SACxD;KACJ;AACL,CAAC;AA/BD,sEA+BC;AAED,KAAK,UAAU,0BAA0B,CAAC,IAAU;IAChD,MAAM,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC;IACzC,MAAM,cAAc,GAAG,oCAAoC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACtE,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;AACxC,CAAC"}