simplify: use HttpsProxyAgent directly for proxy routing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
048d4433c2
commit
f5c777ec0c
Generated
+141
-1
@@ -13,6 +13,7 @@
|
|||||||
"blessed": "^0.1.81",
|
"blessed": "^0.1.81",
|
||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
"ethers": "^5.8.0",
|
"ethers": "^5.8.0",
|
||||||
|
"global-agent": "^4.1.2",
|
||||||
"https-proxy-agent": "^7.0.6",
|
"https-proxy-agent": "^7.0.6",
|
||||||
"undici": "^7.22.0",
|
"undici": "^7.22.0",
|
||||||
"ws": "^8.19.0"
|
"ws": "^8.19.0"
|
||||||
@@ -1107,6 +1108,40 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/define-data-property": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-define-property": "^1.0.0",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"gopd": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/define-properties": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"define-data-property": "^1.0.1",
|
||||||
|
"has-property-descriptors": "^1.0.0",
|
||||||
|
"object-keys": "^1.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/delayed-stream": {
|
"node_modules/delayed-stream": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
@@ -1208,6 +1243,18 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/escape-string-regexp": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ethereum-cryptography": {
|
"node_modules/ethereum-cryptography": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz",
|
||||||
@@ -1405,6 +1452,37 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/global-agent": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/global-agent/-/global-agent-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-CvUwIRwmDHu33Y71P8v1Pr8yo5/U2inzrdRNEtPdiYKBd8J4oQ6aDkt9WqZhMQDtAcTAl+akDTHssRYaBTTlhQ==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"globalthis": "^1.0.2",
|
||||||
|
"matcher": "^4.0.0",
|
||||||
|
"semver": "^7.3.5",
|
||||||
|
"serialize-error": "^8.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/globalthis": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"define-properties": "^1.2.1",
|
||||||
|
"gopd": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/gopd": {
|
"node_modules/gopd": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||||
@@ -1427,6 +1505,18 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/has-property-descriptors": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-define-property": "^1.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/has-symbols": {
|
"node_modules/has-symbols": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||||
@@ -1575,6 +1665,21 @@
|
|||||||
"integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==",
|
"integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/matcher": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/matcher/-/matcher-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-S6x5wmcDmsDRRU/c2dkccDwQPXoFczc5+HpQ2lON8pnvHlnvHAHj5WlLVvw6n6vNyHuVugYrFohYxbS+pvFpKQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"escape-string-regexp": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/math-intrinsics": {
|
"node_modules/math-intrinsics": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
@@ -1684,6 +1789,15 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/object-keys": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/picomatch": {
|
"node_modules/picomatch": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||||
@@ -1733,7 +1847,6 @@
|
|||||||
"version": "7.7.4",
|
"version": "7.7.4",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
||||||
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
||||||
"dev": true,
|
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"bin": {
|
"bin": {
|
||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
@@ -1742,6 +1855,21 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/serialize-error": {
|
||||||
|
"version": "8.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz",
|
||||||
|
"integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"type-fest": "^0.20.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/simple-update-notifier": {
|
"node_modules/simple-update-notifier": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
|
||||||
@@ -1822,6 +1950,18 @@
|
|||||||
"integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==",
|
"integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==",
|
||||||
"license": "Unlicense"
|
"license": "Unlicense"
|
||||||
},
|
},
|
||||||
|
"node_modules/type-fest": {
|
||||||
|
"version": "0.20.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
|
||||||
|
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
|
||||||
|
"license": "(MIT OR CC0-1.0)",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/undefsafe": {
|
"node_modules/undefsafe": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
"blessed": "^0.1.81",
|
"blessed": "^0.1.81",
|
||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
"ethers": "^5.8.0",
|
"ethers": "^5.8.0",
|
||||||
|
"global-agent": "^4.1.2",
|
||||||
"https-proxy-agent": "^7.0.6",
|
"https-proxy-agent": "^7.0.6",
|
||||||
"undici": "^7.22.0",
|
"undici": "^7.22.0",
|
||||||
"ws": "^8.19.0"
|
"ws": "^8.19.0"
|
||||||
|
|||||||
+3
-3
@@ -9,9 +9,6 @@
|
|||||||
* For the TUI dashboard version, use: npm run sniper-tui
|
* For the TUI dashboard version, use: npm run sniper-tui
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Load proxy patch BEFORE any other imports (must patch https before axios is loaded)
|
|
||||||
import './utils/proxy-patch.cjs';
|
|
||||||
|
|
||||||
import { validateMMConfig } from './config/index.js';
|
import { validateMMConfig } from './config/index.js';
|
||||||
import config from './config/index.js';
|
import config from './config/index.js';
|
||||||
import logger from './utils/logger.js';
|
import logger from './utils/logger.js';
|
||||||
@@ -21,6 +18,9 @@ import { executeSnipe } from './services/sniperExecutor.js';
|
|||||||
import { redeemSniperPositions } from './services/ctf.js';
|
import { redeemSniperPositions } from './services/ctf.js';
|
||||||
import { getSchedule, isAssetInSession, getNextSessionInfo } from './services/schedule.js';
|
import { getSchedule, isAssetInSession, getNextSessionInfo } from './services/schedule.js';
|
||||||
|
|
||||||
|
// Set proxy before any network calls
|
||||||
|
import './utils/proxy-patch.cjs';
|
||||||
|
|
||||||
// ── Validate config ────────────────────────────────────────────────────────────
|
// ── Validate config ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
+70
-202
@@ -1,261 +1,129 @@
|
|||||||
/**
|
/**
|
||||||
* proxy-patch.cjs
|
* proxy-patch.cjs
|
||||||
*
|
*
|
||||||
* Strategy: Patch https.request at the lowest level with domain filtering.
|
* Simple proxy patch using https-proxy-agent.
|
||||||
* This affects ALL HTTPS requests, but we only route Polymarket domains through proxy.
|
* Only routes Polymarket domains through proxy.
|
||||||
*
|
|
||||||
* RPC Polygon calls are NOT affected because:
|
|
||||||
* - They go to polygon-rpc.com (not in whitelist)
|
|
||||||
* - They use ethers.js JsonRpcProvider which uses fetch or its own transport
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const PROXY_URL = process.env.PROXY_URL || '';
|
const PROXY_URL = process.env.PROXY_URL || '';
|
||||||
|
|
||||||
if (PROXY_URL) {
|
if (PROXY_URL) {
|
||||||
|
const { HttpsProxyAgent } = require('https-proxy-agent');
|
||||||
const https = require('https');
|
const https = require('https');
|
||||||
const http = require('http');
|
const http = require('http');
|
||||||
const { URL } = require('url');
|
|
||||||
const net = require('net');
|
|
||||||
const tls = require('tls');
|
|
||||||
|
|
||||||
const proxyUrl = new URL(PROXY_URL);
|
const agent = new HttpsProxyAgent(PROXY_URL);
|
||||||
const proxyHost = proxyUrl.hostname;
|
|
||||||
const proxyPort = parseInt(proxyUrl.port) || (proxyUrl.protocol === 'https:' ? 443 : 80);
|
|
||||||
const proxyAuth = (proxyUrl.username || proxyUrl.password)
|
|
||||||
? Buffer.from(`${proxyUrl.username}:${proxyUrl.password}`).toString('base64')
|
|
||||||
: null;
|
|
||||||
|
|
||||||
// Polymarket domains ONLY
|
// Polymarket domains
|
||||||
const POLY_HOSTS = new Set([
|
const POLY_DOMAINS = [
|
||||||
'polymarket.com',
|
'polymarket.com',
|
||||||
'www.polymarket.com',
|
|
||||||
'clob.polymarket.com',
|
'clob.polymarket.com',
|
||||||
'gamma-api.polymarket.com',
|
'gamma-api.polymarket.com',
|
||||||
'data-api.polymarket.com',
|
'data-api.polymarket.com',
|
||||||
]);
|
];
|
||||||
|
|
||||||
function shouldProxy(hostname) {
|
function shouldProxy(hostname) {
|
||||||
// Check exact match or subdomain
|
if (!hostname) return false;
|
||||||
if (POLY_HOSTS.has(hostname)) return true;
|
for (const domain of POLY_DOMAINS) {
|
||||||
for (const host of POLY_HOSTS) {
|
if (hostname === domain || hostname.endsWith('.' + domain)) {
|
||||||
if (hostname.endsWith('.' + host)) return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store original request
|
// Store originals
|
||||||
const originalHttpsRequest = https.request;
|
const originalHttpsRequest = https.request;
|
||||||
const originalHttpRequest = http.request;
|
const originalHttpRequest = http.request;
|
||||||
|
|
||||||
// Create proxy-aware https.request
|
// Patch https.request
|
||||||
https.request = function(options, callback) {
|
https.request = function(options, callback) {
|
||||||
let hostname;
|
let hostname;
|
||||||
|
|
||||||
if (typeof options === 'string') {
|
if (typeof options === 'string') {
|
||||||
try {
|
try {
|
||||||
hostname = new URL(options).hostname;
|
const url = new URL(options);
|
||||||
|
hostname = url.hostname;
|
||||||
} catch {
|
} catch {
|
||||||
return originalHttpsRequest.apply(https, arguments);
|
return originalHttpsRequest.apply(https, arguments);
|
||||||
}
|
}
|
||||||
} else if (options.hostname || options.host) {
|
} else {
|
||||||
hostname = options.hostname || (typeof options.host === 'string' ? options.host.split(':')[0] : options.host);
|
hostname = options.hostname || options.host;
|
||||||
|
if (typeof hostname === 'string' && hostname.includes(':')) {
|
||||||
|
hostname = hostname.split(':')[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not Polymarket, use direct connection
|
// Only proxy Polymarket
|
||||||
if (!hostname || !shouldProxy(hostname)) {
|
if (!shouldProxy(hostname)) {
|
||||||
return originalHttpsRequest.apply(https, arguments);
|
return originalHttpsRequest.apply(https, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For Polymarket: create CONNECT tunnel through proxy
|
// Apply proxy agent
|
||||||
const targetHost = hostname;
|
if (typeof options === 'string') {
|
||||||
const targetPort = 443;
|
// Convert string URL to options object with agent
|
||||||
|
const url = new URL(options);
|
||||||
// Build CONNECT request headers
|
const newOptions = {
|
||||||
const connectHeaders = {
|
protocol: url.protocol,
|
||||||
'Host': `${targetHost}:${targetPort}`,
|
hostname: url.hostname,
|
||||||
};
|
port: url.port || 443,
|
||||||
if (proxyAuth) {
|
path: url.pathname + url.search,
|
||||||
connectHeaders['Proxy-Authorization'] = `Basic ${proxyAuth}`;
|
method: 'GET',
|
||||||
}
|
headers: {},
|
||||||
|
agent: agent,
|
||||||
// Create socket connection through proxy
|
|
||||||
const connectOptions = {
|
|
||||||
host: proxyHost,
|
|
||||||
port: proxyPort,
|
|
||||||
method: 'CONNECT',
|
|
||||||
path: `${targetHost}:${targetPort}`,
|
|
||||||
headers: connectHeaders,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Make CONNECT request to proxy
|
|
||||||
const connectReq = originalHttpRequest(connectOptions);
|
|
||||||
|
|
||||||
// Return a promise-like request that waits for tunnel
|
|
||||||
const deferredReq = {
|
|
||||||
on: function(event, handler) {
|
|
||||||
if (event === 'response' || event === 'error' || event === 'timeout') {
|
|
||||||
this._deferredHandlers = this._deferredHandlers || {};
|
|
||||||
this._deferredHandlers[event] = handler;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
once: function(event, handler) {
|
|
||||||
return this.on(event, handler);
|
|
||||||
},
|
|
||||||
write: function(chunk) {
|
|
||||||
if (this._realRequest) {
|
|
||||||
this._realRequest.write(chunk);
|
|
||||||
} else {
|
|
||||||
this._buffer = this._buffer || [];
|
|
||||||
this._buffer.push(chunk);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
end: function(chunk) {
|
|
||||||
if (chunk) this.write(chunk);
|
|
||||||
if (this._realRequest) {
|
|
||||||
this._realRequest.end();
|
|
||||||
} else {
|
|
||||||
this._ended = true;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
setTimeout: function(ms) {
|
|
||||||
this._timeout = ms;
|
|
||||||
if (this._realRequest) {
|
|
||||||
this._realRequest.setTimeout(ms);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
setHeader: function(name, value) {
|
|
||||||
this._headers = this._headers || {};
|
|
||||||
this._headers[name] = value;
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
abort: function() {
|
|
||||||
if (this._realRequest) {
|
|
||||||
this._realRequest.abort();
|
|
||||||
}
|
|
||||||
if (this._connectReq) {
|
|
||||||
this._connectReq.abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
connectReq.on('connect', (res, socket) => {
|
|
||||||
if (res.statusCode !== 200) {
|
|
||||||
const err = new Error(`Proxy CONNECT failed: ${res.statusCode}`);
|
|
||||||
if (deferredReq._deferredHandlers && deferredReq._deferredHandlers.error) {
|
|
||||||
deferredReq._deferredHandlers.error(err);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrap socket in TLS
|
|
||||||
const tlsOptions = {
|
|
||||||
socket: socket,
|
|
||||||
servername: targetHost,
|
|
||||||
rejectUnauthorized: options.rejectUnauthorized !== false,
|
|
||||||
};
|
};
|
||||||
const tlsSocket = tls.connect(tlsOptions);
|
if (callback) {
|
||||||
|
return originalHttpsRequest.call(https, newOptions, callback);
|
||||||
// Now make actual HTTPS request through tunnel
|
|
||||||
const requestOptions = typeof options === 'string'
|
|
||||||
? { ...new URL(options), createConnection: () => tlsSocket }
|
|
||||||
: { ...options, createConnection: () => tlsSocket };
|
|
||||||
|
|
||||||
const realReq = originalHttpsRequest(requestOptions, (res) => {
|
|
||||||
if (callback) callback(res);
|
|
||||||
if (deferredReq._deferredHandlers && deferredReq._deferredHandlers.response) {
|
|
||||||
deferredReq._deferredHandlers.response(res);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Apply deferred operations
|
|
||||||
if (deferredReq._headers) {
|
|
||||||
for (const [name, value] of Object.entries(deferredReq._headers)) {
|
|
||||||
realReq.setHeader(name, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (deferredReq._timeout) {
|
return originalHttpsRequest.call(https, newOptions);
|
||||||
realReq.setTimeout(deferredReq._timeout);
|
} else {
|
||||||
}
|
// Options object - just add agent
|
||||||
if (deferredReq._buffer) {
|
options.agent = agent;
|
||||||
for (const chunk of deferredReq._buffer) {
|
return originalHttpsRequest.apply(https, arguments);
|
||||||
realReq.write(chunk);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
if (deferredReq._ended) {
|
|
||||||
realReq.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward events
|
|
||||||
realReq.on('error', (err) => {
|
|
||||||
if (deferredReq._deferredHandlers && deferredReq._deferredHandlers.error) {
|
|
||||||
deferredReq._deferredHandlers.error(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
realReq.on('timeout', () => {
|
|
||||||
if (deferredReq._deferredHandlers && deferredReq._deferredHandlers.timeout) {
|
|
||||||
deferredReq._deferredHandlers.timeout();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
deferredReq._realRequest = realReq;
|
|
||||||
deferredReq._connectReq = connectReq;
|
|
||||||
});
|
|
||||||
|
|
||||||
connectReq.on('error', (err) => {
|
|
||||||
if (deferredReq._deferredHandlers && deferredReq._deferredHandlers.error) {
|
|
||||||
deferredReq._deferredHandlers.error(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
connectReq.end();
|
|
||||||
|
|
||||||
return deferredReq;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Also patch http.request for completeness (though CLOB uses HTTPS)
|
// Patch http.request (for HTTP proxy connections)
|
||||||
http.request = function(options, callback) {
|
http.request = function(options, callback) {
|
||||||
let hostname;
|
let hostname;
|
||||||
|
|
||||||
if (typeof options === 'string') {
|
if (typeof options === 'string') {
|
||||||
try {
|
try {
|
||||||
hostname = new URL(options).hostname;
|
const url = new URL(options);
|
||||||
|
hostname = url.hostname;
|
||||||
} catch {
|
} catch {
|
||||||
return originalHttpRequest.apply(http, arguments);
|
return originalHttpRequest.apply(http, arguments);
|
||||||
}
|
}
|
||||||
} else if (options.hostname || options.host) {
|
} else {
|
||||||
hostname = options.hostname || (typeof options.host === 'string' ? options.host.split(':')[0] : options.host);
|
hostname = options.hostname || options.host;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only proxy Polymarket domains
|
// Only proxy Polymarket
|
||||||
if (!hostname || !shouldProxy(hostname)) {
|
if (!shouldProxy(hostname)) {
|
||||||
return originalHttpRequest.apply(http, arguments);
|
return originalHttpRequest.apply(http, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For HTTP, route through proxy directly
|
// Apply same logic for HTTP
|
||||||
const targetUrl = typeof options === 'string' ? new URL(options) : null;
|
if (typeof options === 'string') {
|
||||||
const path = targetUrl ? targetUrl.pathname + targetUrl.search : (options.path || '/');
|
const url = new URL(options);
|
||||||
|
const newOptions = {
|
||||||
const proxyOptions = {
|
protocol: url.protocol,
|
||||||
host: proxyHost,
|
hostname: url.hostname,
|
||||||
port: proxyPort,
|
port: url.port || 80,
|
||||||
method: options.method || 'GET',
|
path: url.pathname + url.search,
|
||||||
path: path,
|
method: 'GET',
|
||||||
headers: { ...(options.headers || {}) },
|
headers: {},
|
||||||
};
|
agent: agent,
|
||||||
|
};
|
||||||
if (proxyAuth) {
|
if (callback) {
|
||||||
proxyOptions.headers['Proxy-Authorization'] = `Basic ${proxyAuth}`;
|
return originalHttpRequest.call(http, newOptions, callback);
|
||||||
|
}
|
||||||
|
return originalHttpRequest.call(http, newOptions);
|
||||||
|
} else {
|
||||||
|
options.agent = agent;
|
||||||
|
return originalHttpRequest.apply(http, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
return originalHttpRequest.call(http, proxyOptions, callback);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(`[proxy-patch] HTTPS/HTTP CONNECT tunnel active for Polymarket only`);
|
console.log('[proxy-patch] Proxy active for Polymarket domains');
|
||||||
console.log(`[proxy-patch] RPC Polygon and other domains use direct connection`);
|
|
||||||
} else {
|
|
||||||
console.log('[proxy-patch] No PROXY_URL set, skipping patch');
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user