Skip to content

Commit d0bbf44

Browse files
author
Thordata
committed
chore: bump sdk-spec submodule
1 parent 453c5b6 commit d0bbf44

File tree

6 files changed

+126
-22
lines changed

6 files changed

+126
-22
lines changed

examples/smoke_proxy_protocols.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import "dotenv/config";
2+
import { Thordata } from "../src/thordata.js";
3+
4+
function printProxyEndpoint(proxyUrl: string) {
5+
const u = new URL(proxyUrl);
6+
console.log("proxy_endpoint:", `${u.protocol}//${u.hostname}:${u.port}`);
7+
console.log("proxy_user_prefix:", decodeURIComponent(u.username).slice(0, 50));
8+
}
9+
10+
async function runOne(protocol: string) {
11+
// IMPORTANT: set BOTH global and product-specific protocol to avoid .env overriding
12+
process.env.THORDATA_PROXY_PROTOCOL = protocol;
13+
process.env.THORDATA_RESIDENTIAL_PROXY_PROTOCOL = protocol;
14+
15+
const client = new Thordata();
16+
const proxy = Thordata.Proxy.residentialFromEnv().country("us");
17+
18+
const proxyUrl = proxy.toProxyUrl();
19+
console.log("====", protocol, "====");
20+
printProxyEndpoint(proxyUrl);
21+
22+
const out = await client.request("https://ipinfo.thordata.com", { proxy });
23+
console.log(out);
24+
}
25+
26+
async function main() {
27+
for (const p of ["http", "https", "socks5h"]) {
28+
await runOne(p);
29+
}
30+
}
31+
32+
main().catch((e) => {
33+
console.error(e);
34+
process.exit(1);
35+
});

package-lock.json

Lines changed: 51 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,17 @@
5151
"author": "Thordata Developer Team",
5252
"license": "MIT",
5353
"dependencies": {
54-
"axios": "^1.7.0"
54+
"axios": "^1.7.0",
55+
"http-proxy-agent": "^7.0.2",
56+
"https-proxy-agent": "^7.0.6",
57+
"socks-proxy-agent": "^8.0.5"
5558
},
5659
"devDependencies": {
5760
"@eslint/js": "^9.39.2",
5861
"@types/node": "^22.8.1",
5962
"@vitest/coverage-v8": "^4.0.16",
6063
"dotenv": "^16.4.5",
6164
"eslint": "^9.39.2",
62-
"http-proxy-agent": "^7.0.2",
63-
"https-proxy-agent": "^7.0.6",
6465
"nock": "^14.0.10",
6566
"prettier": "^3.7.4",
6667
"ts-node": "^10.9.2",

src/client.ts

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { HttpsProxyAgent } from "https-proxy-agent";
44
import { HttpProxyAgent } from "http-proxy-agent";
5+
import { SocksProxyAgent } from "socks-proxy-agent";
56
import axios, { AxiosInstance } from "axios";
67
import https from "node:https";
78
import { Engine, TaskStatus } from "./enums.js";
@@ -138,7 +139,8 @@ export class ThordataClient {
138139
// We need "https://openapi.thordata.com/api" for other endpoints
139140
const apiBase = this.baseUrls.locationsBaseUrl.replace(/\/locations$/, "");
140141
const whitelistBase = process.env.THORDATA_WHITELIST_BASE_URL || "https://api.thordata.com/api";
141-
const proxyApiBase = process.env.THORDATA_PROXY_API_BASE_URL || "https://api.thordata.com/api";
142+
const proxyApiBase =
143+
process.env.THORDATA_PROXY_API_BASE_URL || "https://openapi.thordata.com/api";
142144

143145
this.usageStatsUrl = `${apiBase}/account/usage-statistics`;
144146
this.proxyUsersUrl = `${apiBase}/proxy-users`;
@@ -594,12 +596,21 @@ export class ThordataClient {
594596
// Disable axios proxy logic & env proxy interference; use explicit agents
595597
axiosConfig.proxy = false;
596598

597-
// IMPORTANT:
598-
// - httpAgent is used for http:// targets
599-
// - httpsAgent is used for https:// targets
600-
// Both should point to a proxy agent that can CONNECT through the proxy.
601-
axiosConfig.httpAgent = new HttpProxyAgent(proxyUrl);
602-
axiosConfig.httpsAgent = new HttpsProxyAgent(proxyUrl);
599+
const scheme = new URL(proxyUrl).protocol; // "http:" | "https:" | "socks5:" | "socks5h:"
600+
601+
if (scheme.startsWith("socks")) {
602+
const agent = new SocksProxyAgent(proxyUrl);
603+
axiosConfig.httpAgent = agent;
604+
axiosConfig.httpsAgent = agent;
605+
} else if (scheme === "https:") {
606+
const agent = new HttpsProxyAgent(proxyUrl);
607+
axiosConfig.httpAgent = agent;
608+
axiosConfig.httpsAgent = agent;
609+
} else {
610+
const agent = new HttpProxyAgent(proxyUrl);
611+
axiosConfig.httpAgent = agent;
612+
axiosConfig.httpsAgent = agent;
613+
}
603614
}
604615

605616
return this.execute(async () => {

src/proxy.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -256,11 +256,25 @@ export class Proxy {
256256
// Resolve endpoint (allow Dashboard shard host via env)
257257
const productUpper = this.product.toUpperCase();
258258

259+
const envNonEmpty = (v?: string) => {
260+
const s = (v ?? "").trim();
261+
return s ? s : undefined;
262+
};
263+
259264
const protocol =
260-
process.env[`THORDATA_${productUpper}_PROXY_PROTOCOL`] ??
261-
process.env.THORDATA_PROXY_PROTOCOL ??
265+
envNonEmpty(process.env[`THORDATA_${productUpper}_PROXY_PROTOCOL`]) ??
266+
envNonEmpty(process.env.THORDATA_PROXY_PROTOCOL) ??
262267
"https";
263268

269+
const allowed = new Set(["http", "https", "socks5", "socks5h"]);
270+
if (!allowed.has(protocol)) {
271+
throw new Error(
272+
`Invalid THORDATA_*_PROXY_PROTOCOL: ${protocol}. Use http/https/socks5/socks5h`,
273+
);
274+
}
275+
276+
const normalizedProtocol = protocol === "socks5" ? "socks5h" : protocol;
277+
264278
const host =
265279
process.env[`THORDATA_${productUpper}_PROXY_HOST`] ??
266280
process.env.THORDATA_PROXY_HOST ??
@@ -284,7 +298,7 @@ export class Proxy {
284298
const username = encodeURIComponent(this.buildUsername());
285299
const password = encodeURIComponent(this.credentials.password);
286300

287-
return `${protocol}://${username}:${password}@${host}:${port}`;
301+
return `${normalizedProtocol}://${username}:${password}@${host}:${port}`;
288302
}
289303

290304
/**

0 commit comments

Comments
 (0)