@cosmocoder/mcp-web-docs 2.0.8 → 2.0.9

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 (40) hide show
  1. package/build/crawler/auth.js +117 -7
  2. package/build/crawler/auth.js.map +1 -1
  3. package/build/crawler/auth.test.js +333 -83
  4. package/build/crawler/auth.test.js.map +1 -1
  5. package/build/crawler/browser-config.d.ts +1 -1
  6. package/build/crawler/browser-config.js +7 -1
  7. package/build/crawler/browser-config.js.map +1 -1
  8. package/build/crawler/browser-config.test.js +21 -25
  9. package/build/crawler/browser-config.test.js.map +1 -1
  10. package/build/crawler/crawlee-crawler.d.ts +3 -0
  11. package/build/crawler/crawlee-crawler.js +155 -12
  12. package/build/crawler/crawlee-crawler.js.map +1 -1
  13. package/build/crawler/crawlee-crawler.test.js +190 -143
  14. package/build/crawler/crawlee-crawler.test.js.map +1 -1
  15. package/build/crawler/github.js +3 -2
  16. package/build/crawler/github.js.map +1 -1
  17. package/build/crawler/llms-txt.js +2 -1
  18. package/build/crawler/llms-txt.js.map +1 -1
  19. package/build/index.js +13 -8
  20. package/build/index.js.map +1 -1
  21. package/build/setupTests.js +44 -0
  22. package/build/setupTests.js.map +1 -1
  23. package/build/util/favicon.js +2 -1
  24. package/build/util/favicon.js.map +1 -1
  25. package/build/util/favicon.test.js +27 -37
  26. package/build/util/favicon.test.js.map +1 -1
  27. package/build/util/outbound-request.d.ts +33 -0
  28. package/build/util/outbound-request.integration.test.d.ts +1 -0
  29. package/build/util/outbound-request.integration.test.js +149 -0
  30. package/build/util/outbound-request.integration.test.js.map +1 -0
  31. package/build/util/outbound-request.js +367 -0
  32. package/build/util/outbound-request.js.map +1 -0
  33. package/build/util/outbound-request.test.d.ts +1 -0
  34. package/build/util/outbound-request.test.js +224 -0
  35. package/build/util/outbound-request.test.js.map +1 -0
  36. package/build/util/security.js +1 -1
  37. package/build/util/security.js.map +1 -1
  38. package/build/util/security.test.js +1 -0
  39. package/build/util/security.test.js.map +1 -1
  40. package/package.json +8 -6
@@ -0,0 +1,149 @@
1
+ import { createServer } from 'node:http';
2
+ import { createServer as createTcpServer } from 'node:net';
3
+ import { chromium } from 'playwright';
4
+ import { fetch as undiciFetch, ProxyAgent } from 'undici';
5
+ import { getBrowserConfig } from '../crawler/browser-config.js';
6
+ import { BlockedOutboundRequestError, classifyOutboundFailure, closeOutboundProxy, createOutboundProxy, getOutboundResponseError, } from './outbound-request.js';
7
+ vi.unmock('node:dns/promises');
8
+ vi.unmock('proxy-chain');
9
+ vi.unmock('undici');
10
+ async function listenOnLoopback(server, host = '127.0.0.1') {
11
+ await new Promise((resolve, reject) => {
12
+ server.once('error', reject);
13
+ server.listen(0, host, resolve);
14
+ });
15
+ return server.address().port;
16
+ }
17
+ async function closeTcpServer(server) {
18
+ if (!server.listening) {
19
+ return;
20
+ }
21
+ await new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve())));
22
+ }
23
+ async function loadImage(page, url) {
24
+ return page.evaluate((source) => new Promise((resolve) => {
25
+ const timeout = setTimeout(() => resolve('timed out'), 5000);
26
+ const image = new Image();
27
+ image.onload = () => {
28
+ clearTimeout(timeout);
29
+ resolve('loaded');
30
+ };
31
+ image.onerror = () => {
32
+ clearTimeout(timeout);
33
+ resolve('blocked');
34
+ };
35
+ image.src = source;
36
+ }), url);
37
+ }
38
+ async function openWebSocket(page, url) {
39
+ return page.evaluate((source) => new Promise((resolve) => {
40
+ const socket = new WebSocket(source);
41
+ const timeout = setTimeout(() => {
42
+ socket.close();
43
+ resolve('timed out');
44
+ }, 5000);
45
+ socket.onopen = () => {
46
+ clearTimeout(timeout);
47
+ resolve('connected');
48
+ };
49
+ socket.onerror = () => {
50
+ clearTimeout(timeout);
51
+ resolve('blocked');
52
+ };
53
+ }), url);
54
+ }
55
+ async function closeServer(server) {
56
+ if (!server.listening) {
57
+ return;
58
+ }
59
+ server.closeAllConnections();
60
+ await new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve())));
61
+ }
62
+ describe('outbound request integration', () => {
63
+ let browser;
64
+ afterEach(async () => {
65
+ await browser?.close();
66
+ browser = undefined;
67
+ await closeOutboundProxy();
68
+ });
69
+ it('blocks a real proxied socket before connecting to its private DNS result', async () => {
70
+ let requests = 0;
71
+ const target = createServer((_request, response) => {
72
+ requests++;
73
+ response.end('private');
74
+ });
75
+ const resolver = vi.fn().mockResolvedValue([{ address: '127.0.0.1', family: 4 }]);
76
+ let proxy;
77
+ let dispatcher;
78
+ try {
79
+ const port = await listenOnLoopback(target);
80
+ proxy = await createOutboundProxy(resolver);
81
+ dispatcher = new ProxyAgent(proxy.url);
82
+ await expect(undiciFetch(`http://public.example:${port}`, { dispatcher, signal: AbortSignal.timeout(5000) })).rejects.toThrow();
83
+ expect(resolver).toHaveBeenCalledWith('public.example', { all: true, order: 'verbatim' });
84
+ expect(requests).toBe(0);
85
+ }
86
+ finally {
87
+ await dispatcher?.destroy();
88
+ await proxy?.close();
89
+ await closeServer(target);
90
+ }
91
+ }, 15_000);
92
+ it.each([
93
+ { host: '127.0.0.1', urlHost: '127.0.0.1' },
94
+ { host: '::1', urlHost: '[::1]' },
95
+ ])('keeps Chromium main-frame, subresource, and WebSocket traffic away from $host', async ({ host, urlHost }) => {
96
+ let requests = 0;
97
+ let upgrades = 0;
98
+ const target = createServer((_request, response) => {
99
+ requests++;
100
+ response.end('private');
101
+ });
102
+ target.on('upgrade', (_request, socket) => {
103
+ upgrades++;
104
+ socket.destroy();
105
+ });
106
+ let tlsConnections = 0;
107
+ const tlsTarget = createTcpServer((socket) => {
108
+ tlsConnections++;
109
+ socket.destroy();
110
+ });
111
+ try {
112
+ const port = await listenOnLoopback(target, host);
113
+ const tlsPort = await listenOnLoopback(tlsTarget, host);
114
+ const config = await getBrowserConfig(undefined);
115
+ const proxy = config.launchContext?.launchOptions?.proxy;
116
+ expect(proxy).toEqual(expect.objectContaining({ bypass: '<-loopback>' }));
117
+ browser = await chromium.launch({ headless: true, proxy });
118
+ const page = await browser.newPage();
119
+ const privateUrl = `http://${urlHost}:${port}`;
120
+ const navigationResponse = await page.goto(`${privateUrl}/main`, { waitUntil: 'commit', timeout: 5000 });
121
+ expect(navigationResponse?.status()).toBe(403);
122
+ await expect(getOutboundResponseError(navigationResponse)).resolves.toBeInstanceOf(BlockedOutboundRequestError);
123
+ await page.goto('about:blank');
124
+ await expect(loadImage(page, `${privateUrl}/image.png`)).resolves.toBe('blocked');
125
+ await expect(openWebSocket(page, `ws://${urlHost}:${port}/socket`)).resolves.toBe('blocked');
126
+ const secureUrl = `https://${urlHost}:${tlsPort}`;
127
+ const secureNavigation = await page
128
+ .goto(`${secureUrl}/main`, { waitUntil: 'commit', timeout: 5000 })
129
+ .then(async (response) => (await getOutboundResponseError(response)) instanceof BlockedOutboundRequestError ? 'blocked' : 'loaded')
130
+ .catch(() => 'blocked');
131
+ expect(secureNavigation).toBe('blocked');
132
+ await expect(classifyOutboundFailure(secureUrl)).resolves.toBeInstanceOf(BlockedOutboundRequestError);
133
+ const securePage = await browser.newPage();
134
+ await securePage.goto('about:blank');
135
+ await expect(loadImage(securePage, `${secureUrl}/image.png`)).resolves.toBe('blocked');
136
+ await expect(openWebSocket(securePage, `wss://${urlHost}:${tlsPort}/socket`)).resolves.toBe('blocked');
137
+ expect(requests).toBe(0);
138
+ expect(upgrades).toBe(0);
139
+ expect(tlsConnections).toBe(0);
140
+ }
141
+ finally {
142
+ await browser?.close();
143
+ browser = undefined;
144
+ await closeServer(target);
145
+ await closeTcpServer(tlsTarget);
146
+ }
147
+ }, 30_000);
148
+ });
149
+ //# sourceMappingURL=outbound-request.integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbound-request.integration.test.js","sourceRoot":"","sources":["../../src/util/outbound-request.integration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,367 @@
1
+ import { lookup } from 'node:dns/promises';
2
+ import { BlockList, isIP } from 'node:net';
3
+ import { setTimeout as delay } from 'node:timers/promises';
4
+ import { RequestError, Server as ProxyServer } from 'proxy-chain';
5
+ import { fetch as undiciFetch, ProxyAgent } from 'undici';
6
+ import { validatePublicUrl } from './security.js';
7
+ const MAX_REDIRECTS = 5;
8
+ const BLOCKED_HEADER = 'x-mcp-web-docs-blocked';
9
+ const FAILED_HEADER = 'x-mcp-web-docs-failed';
10
+ const PROXY_SHUTDOWN_TIMEOUT_MS = 1000;
11
+ const FAILURE_CLASSIFICATION_TIMEOUT_MS = 1000;
12
+ const MAX_PROXY_CONNECTIONS = 64;
13
+ const publicAddresses = new BlockList();
14
+ const blockedAddresses = new BlockList();
15
+ publicAddresses.addSubnet('0.0.0.0', 0, 'ipv4');
16
+ publicAddresses.addSubnet('2000::', 3, 'ipv6');
17
+ for (const [network, prefix] of [
18
+ ['0.0.0.0', 8],
19
+ ['10.0.0.0', 8],
20
+ ['100.64.0.0', 10],
21
+ ['127.0.0.0', 8],
22
+ ['169.254.0.0', 16],
23
+ ['172.16.0.0', 12],
24
+ ['192.0.0.0', 24],
25
+ ['192.0.2.0', 24],
26
+ ['192.88.99.0', 24],
27
+ ['192.168.0.0', 16],
28
+ ['198.18.0.0', 15],
29
+ ['198.51.100.0', 24],
30
+ ['203.0.113.0', 24],
31
+ ['224.0.0.0', 4],
32
+ ['240.0.0.0', 4],
33
+ ]) {
34
+ blockedAddresses.addSubnet(network, prefix, 'ipv4');
35
+ }
36
+ for (const [network, prefix] of [
37
+ ['2001::', 32],
38
+ ['2001:2::', 48],
39
+ ['2001:10::', 28],
40
+ ['2001:20::', 28],
41
+ ['2001:db8::', 32],
42
+ ['2002::', 16],
43
+ ['3fff::', 20],
44
+ ]) {
45
+ blockedAddresses.addSubnet(network, prefix, 'ipv6');
46
+ }
47
+ async function raceWithAbort(promise, signal) {
48
+ if (!signal) {
49
+ return promise;
50
+ }
51
+ signal.throwIfAborted();
52
+ let onAbort;
53
+ const aborted = new Promise((_resolve, reject) => {
54
+ onAbort = () => reject(signal.reason);
55
+ signal.addEventListener('abort', onAbort, { once: true });
56
+ });
57
+ try {
58
+ return await Promise.race([promise, aborted]);
59
+ }
60
+ finally {
61
+ signal.removeEventListener('abort', onAbort);
62
+ }
63
+ }
64
+ function createLimitedResolver(resolver) {
65
+ let active = 0;
66
+ const queue = [];
67
+ const drain = () => {
68
+ while (active < MAX_PROXY_CONNECTIONS && queue.length > 0) {
69
+ const lookupRequest = queue.shift();
70
+ lookupRequest.signal?.removeEventListener('abort', lookupRequest.onAbort);
71
+ if (lookupRequest.signal?.aborted) {
72
+ lookupRequest.reject(lookupRequest.signal.reason);
73
+ continue;
74
+ }
75
+ active++;
76
+ Promise.resolve()
77
+ .then(() => resolver(lookupRequest.hostname, lookupRequest.options))
78
+ .then(lookupRequest.resolve, lookupRequest.reject)
79
+ .finally(() => {
80
+ active--;
81
+ drain();
82
+ });
83
+ }
84
+ };
85
+ return (hostname, options, signal) => {
86
+ signal?.throwIfAborted();
87
+ return new Promise((resolve, reject) => {
88
+ const lookupRequest = { hostname, options, signal, resolve, reject };
89
+ lookupRequest.onAbort = () => {
90
+ const index = queue.indexOf(lookupRequest);
91
+ if (index >= 0) {
92
+ queue.splice(index, 1);
93
+ reject(signal.reason);
94
+ }
95
+ };
96
+ queue.push(lookupRequest);
97
+ signal?.addEventListener('abort', lookupRequest.onAbort, { once: true });
98
+ drain();
99
+ });
100
+ };
101
+ }
102
+ function isPublicAddress(address) {
103
+ const family = isIP(address);
104
+ const addressFamily = family === 4 ? 'ipv4' : 'ipv6';
105
+ return family !== 0 && publicAddresses.check(address, addressFamily) && !blockedAddresses.check(address, addressFamily);
106
+ }
107
+ export class BlockedOutboundRequestError extends Error {
108
+ constructor(message = 'Blocked outbound destination') {
109
+ super(message);
110
+ this.name = 'BlockedOutboundRequestError';
111
+ }
112
+ }
113
+ export class OutboundRequestFailedError extends Error {
114
+ constructor(message = 'Outbound request failed') {
115
+ super(message);
116
+ this.name = 'OutboundRequestFailedError';
117
+ }
118
+ }
119
+ export async function getOutboundResponseError(response) {
120
+ if (!response || (response.status() !== 403 && response.status() !== 502)) {
121
+ return undefined;
122
+ }
123
+ try {
124
+ const [blocked, failed] = await Promise.all([response.headerValue(BLOCKED_HEADER), response.headerValue(FAILED_HEADER)]);
125
+ if (response.status() === 403 && blocked === '1') {
126
+ return new BlockedOutboundRequestError();
127
+ }
128
+ if (response.status() === 502 && failed === '1') {
129
+ return new OutboundRequestFailedError('Outbound destination unavailable');
130
+ }
131
+ return undefined;
132
+ }
133
+ catch (error) {
134
+ const message = error instanceof Error ? error.message : String(error);
135
+ throw new OutboundRequestFailedError(`Failed to inspect outbound response: ${message}`);
136
+ }
137
+ }
138
+ export function isNavigationCancellationError(errorText) {
139
+ return /ERR_ABORTED|NS_BINDING_ABORTED|cancel(?:l)?ed.*load|load.*cancel(?:l)?ed/i.test(errorText);
140
+ }
141
+ function validateHostname(hostname) {
142
+ const normalized = hostname.replace(/^\[|\]$/g, '');
143
+ const host = isIP(normalized) === 6 ? `[${normalized}]` : normalized;
144
+ try {
145
+ validatePublicUrl(`http://${host}`);
146
+ }
147
+ catch {
148
+ throw new BlockedOutboundRequestError('Access to non-public addresses is not allowed');
149
+ }
150
+ return normalized;
151
+ }
152
+ function validateOutboundUrl(urlString) {
153
+ try {
154
+ return validatePublicUrl(urlString);
155
+ }
156
+ catch (error) {
157
+ if (error instanceof Error && error.message.startsWith('Access to')) {
158
+ throw new BlockedOutboundRequestError(error.message);
159
+ }
160
+ throw error;
161
+ }
162
+ }
163
+ function createPinnedLookup(hostname, addresses) {
164
+ return (requestedHostname, options, callback) => {
165
+ if (requestedHostname.toLowerCase() !== hostname.toLowerCase()) {
166
+ callback(Object.assign(new Error('Unexpected hostname during pinned lookup'), { code: 'EACCES' }), '');
167
+ return;
168
+ }
169
+ if (options.all) {
170
+ callback(null, addresses);
171
+ }
172
+ else {
173
+ const requestedFamily = typeof options.family === 'string' ? Number(options.family.slice(-1)) : options.family;
174
+ const selected = addresses.find(({ family }) => !requestedFamily || family === requestedFamily);
175
+ if (!selected) {
176
+ callback(Object.assign(new Error('No approved address for requested family'), { code: 'ENOTFOUND' }), '');
177
+ return;
178
+ }
179
+ callback(null, selected.address, selected.family);
180
+ }
181
+ };
182
+ }
183
+ /** Resolve all addresses once and return a lookup callback pinned to an approved address. */
184
+ export async function resolvePublicTarget(hostname, resolver = lookup, signal) {
185
+ const normalizedHostname = validateHostname(hostname);
186
+ const family = isIP(normalizedHostname);
187
+ const addresses = family
188
+ ? [{ address: normalizedHostname, family }]
189
+ : await raceWithAbort(resolver(normalizedHostname, { all: true, order: 'verbatim' }), signal);
190
+ if (addresses.length === 0 || addresses.some(({ address }) => !isPublicAddress(address))) {
191
+ throw new BlockedOutboundRequestError('Access to non-public addresses is not allowed');
192
+ }
193
+ return createPinnedLookup(normalizedHostname, addresses);
194
+ }
195
+ const limitedClassificationResolver = createLimitedResolver(lookup);
196
+ /** Re-resolve the exact URL whose connection failed to distinguish policy blocks from ordinary network failures. */
197
+ export async function classifyOutboundFailure(input, resolver = lookup) {
198
+ let url;
199
+ try {
200
+ url = validateOutboundUrl(input.toString());
201
+ }
202
+ catch (error) {
203
+ if (error instanceof BlockedOutboundRequestError) {
204
+ return new BlockedOutboundRequestError();
205
+ }
206
+ return new OutboundRequestFailedError('Outbound destination unavailable');
207
+ }
208
+ const signal = AbortSignal.timeout(FAILURE_CLASSIFICATION_TIMEOUT_MS);
209
+ try {
210
+ const classificationResolver = resolver === lookup ? (hostname, options) => limitedClassificationResolver(hostname, options, signal) : resolver;
211
+ await resolvePublicTarget(url.hostname, classificationResolver, signal);
212
+ }
213
+ catch (error) {
214
+ if (error instanceof BlockedOutboundRequestError) {
215
+ return new BlockedOutboundRequestError();
216
+ }
217
+ }
218
+ return new OutboundRequestFailedError('Outbound destination unavailable');
219
+ }
220
+ function requestAbortSignal(request) {
221
+ const controller = new AbortController();
222
+ const abort = () => controller.abort();
223
+ request.once('aborted', abort);
224
+ request.socket.once('close', abort);
225
+ return {
226
+ signal: controller.signal,
227
+ cleanup: () => {
228
+ request.removeListener('aborted', abort);
229
+ request.socket.removeListener('close', abort);
230
+ },
231
+ };
232
+ }
233
+ /** Start a loopback-only proxy that pins every target connection to its validated DNS result. */
234
+ export async function createOutboundProxy(resolver = lookup) {
235
+ const limitedResolver = createLimitedResolver(resolver);
236
+ const server = new ProxyServer({
237
+ host: '127.0.0.1',
238
+ port: 0,
239
+ prepareRequestFunction: async ({ hostname, request }) => {
240
+ const { signal, cleanup } = requestAbortSignal(request);
241
+ try {
242
+ const dnsLookup = await resolvePublicTarget(hostname, (target, options) => limitedResolver(target, options, signal), signal);
243
+ return {
244
+ dnsLookup: dnsLookup,
245
+ };
246
+ }
247
+ catch (error) {
248
+ if (error instanceof DOMException && error.name === 'AbortError') {
249
+ throw error;
250
+ }
251
+ if (error instanceof BlockedOutboundRequestError) {
252
+ throw new RequestError('Blocked outbound destination', 403, { [BLOCKED_HEADER]: '1' });
253
+ }
254
+ throw new RequestError('Outbound destination unavailable', 502, { [FAILED_HEADER]: '1' });
255
+ }
256
+ finally {
257
+ cleanup();
258
+ }
259
+ },
260
+ });
261
+ // Bound concurrent proxy sockets so hostile pages cannot fan out unbounded resolver work.
262
+ server.server.maxConnections = MAX_PROXY_CONNECTIONS;
263
+ try {
264
+ await server.listen();
265
+ }
266
+ catch (error) {
267
+ await runBoundedCleanup(() => server.close(true));
268
+ throw error;
269
+ }
270
+ server.server.unref();
271
+ return {
272
+ url: `http://127.0.0.1:${server.port}`,
273
+ close: () => server.close(true),
274
+ };
275
+ }
276
+ let proxyState;
277
+ async function runBoundedCleanup(action) {
278
+ const cleanup = Promise.resolve()
279
+ .then(action)
280
+ .catch(() => undefined);
281
+ await Promise.race([cleanup, delay(PROXY_SHUTDOWN_TIMEOUT_MS, undefined, { ref: false })]);
282
+ }
283
+ function startProxyState() {
284
+ const pending = createOutboundProxy().then(async (proxy) => {
285
+ try {
286
+ return { proxy, dispatcher: new ProxyAgent(proxy.url) };
287
+ }
288
+ catch (error) {
289
+ await runBoundedCleanup(proxy.close);
290
+ throw error;
291
+ }
292
+ });
293
+ proxyState = pending;
294
+ void pending.catch(() => {
295
+ if (proxyState === pending) {
296
+ proxyState = undefined;
297
+ }
298
+ });
299
+ return pending;
300
+ }
301
+ async function getProxyState(signal) {
302
+ signal?.throwIfAborted();
303
+ return raceWithAbort(proxyState ?? startProxyState(), signal);
304
+ }
305
+ export async function getOutboundProxyUrl(signal) {
306
+ return (await getProxyState(signal)).proxy.url;
307
+ }
308
+ export async function closeOutboundProxy() {
309
+ const statePromise = proxyState;
310
+ if (!statePromise) {
311
+ return;
312
+ }
313
+ proxyState = undefined;
314
+ await runBoundedCleanup(async () => {
315
+ const state = await statePromise;
316
+ await Promise.allSettled([Promise.resolve().then(() => state.dispatcher.destroy()), Promise.resolve().then(state.proxy.close)]);
317
+ });
318
+ }
319
+ /** Fetch a public URL while validating every redirect through the pinned egress proxy. */
320
+ export async function fetchPublicUrl(urlString, init = {}) {
321
+ let url = validateOutboundUrl(urlString);
322
+ let headers = init.headers;
323
+ const dispatcher = await getProxyState(init.signal).then((state) => state.dispatcher);
324
+ for (let redirects = 0;; redirects++) {
325
+ const requestInit = { ...init, headers, redirect: 'manual', dispatcher };
326
+ let response;
327
+ try {
328
+ response = await undiciFetch(url.toString(), requestInit);
329
+ }
330
+ catch (error) {
331
+ if (init.signal?.aborted) {
332
+ throw error;
333
+ }
334
+ throw await classifyOutboundFailure(url);
335
+ }
336
+ if (response.headers.get(BLOCKED_HEADER) === '1') {
337
+ await response.body?.cancel();
338
+ throw new BlockedOutboundRequestError();
339
+ }
340
+ if (response.headers.get(FAILED_HEADER) === '1') {
341
+ await response.body?.cancel();
342
+ throw new OutboundRequestFailedError('Outbound destination unavailable');
343
+ }
344
+ const location = response.headers.get('location');
345
+ if (![301, 302, 303, 307, 308].includes(response.status) || !location) {
346
+ return response;
347
+ }
348
+ if (redirects >= MAX_REDIRECTS) {
349
+ await response.body?.cancel();
350
+ throw new Error(`Too many redirects (maximum ${MAX_REDIRECTS})`);
351
+ }
352
+ await response.body?.cancel();
353
+ if (init.body != null) {
354
+ throw new Error('Cannot redirect a request with a body');
355
+ }
356
+ const nextUrl = validateOutboundUrl(new URL(location, url).toString());
357
+ if (nextUrl.origin !== url.origin) {
358
+ const safeHeaders = new Headers(headers);
359
+ safeHeaders.delete('authorization');
360
+ safeHeaders.delete('cookie');
361
+ safeHeaders.delete('proxy-authorization');
362
+ headers = safeHeaders;
363
+ }
364
+ url = nextUrl;
365
+ }
366
+ }
367
+ //# sourceMappingURL=outbound-request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbound-request.js","sourceRoot":"","sources":["../../src/util/outbound-request.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};