thordata-js-sdk 0.2.0 → 0.3.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/LICENSE +20 -20
- package/README.md +235 -123
- package/dist/examples/basic_serp.js +3 -3
- package/dist/examples/basic_serp.js.map +1 -1
- package/dist/examples/location_api.js +47 -0
- package/dist/examples/location_api.js.map +1 -0
- package/dist/examples/proxy_datacenter.js +1 -1
- package/dist/examples/proxy_datacenter.js.map +1 -1
- package/dist/examples/proxy_isp.js +1 -1
- package/dist/examples/proxy_isp.js.map +1 -1
- package/dist/examples/proxy_mobile.js +1 -1
- package/dist/examples/proxy_mobile.js.map +1 -1
- package/dist/examples/proxy_residential.js +2 -2
- package/dist/examples/proxy_residential.js.map +1 -1
- package/dist/examples/serp_google_news.d.ts +0 -6
- package/dist/examples/serp_google_news.js +7 -10
- package/dist/examples/serp_google_news.js.map +1 -1
- package/dist/src/client.d.ts +110 -6
- package/dist/src/client.js +185 -42
- package/dist/src/client.js.map +1 -1
- package/dist/src/enums.d.ts +221 -3
- package/dist/src/enums.js +291 -2
- package/dist/src/enums.js.map +1 -1
- package/dist/src/errors.d.ts +37 -5
- package/dist/src/errors.js +61 -17
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +7 -5
- package/dist/src/index.js +21 -5
- package/dist/src/index.js.map +1 -1
- package/dist/src/models.d.ts +137 -12
- package/dist/src/models.js +1 -0
- package/dist/src/models.js.map +1 -1
- package/dist/src/proxy.d.ts +59 -0
- package/dist/src/proxy.js +83 -11
- package/dist/src/proxy.js.map +1 -1
- package/dist/src/retry.d.ts +25 -3
- package/dist/src/retry.js +16 -0
- package/dist/src/retry.js.map +1 -1
- package/dist/src/thordata.d.ts +5 -2
- package/dist/src/thordata.js +36 -6
- package/dist/src/thordata.js.map +1 -1
- package/dist/src/utils.d.ts +18 -8
- package/dist/src/utils.js +58 -34
- package/dist/src/utils.js.map +1 -1
- package/package.json +5 -6
- package/dist/examples/proxy_demo.js +0 -69
- package/dist/examples/proxy_demo.js.map +0 -1
- package/dist/examples/proxy_ip_check.d.ts +0 -1
- package/dist/examples/proxy_ip_check.js +0 -37
- package/dist/examples/proxy_ip_check.js.map +0 -1
- /package/dist/examples/{proxy_demo.d.ts → location_api.d.ts} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"location_api.js","sourceRoot":"","sources":["../../examples/location_api.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAE3B,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC;QAC3E,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;QACzE,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;IAE9B,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IAEnC,8CAA8C;IAC9C,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACvC,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC;IAC5D,OAAO,CAAC,GAAG,CAAC,YAAY,SAAS,CAAC,MAAM,YAAY,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,CACT,eAAe,SAAS;SACrB,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC;SAC1B,IAAI,CAAC,IAAI,CAAC,EAAE,CAChB,CAAC;IAEF,qBAAqB;IACrB,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IAC5D,OAAO,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,MAAM,SAAS,CAAC,CAAC;IAChD,OAAO,CAAC,GAAG,CACT,eAAe,MAAM;SAClB,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;SACxB,IAAI,CAAC,IAAI,CAAC,EAAE,CAChB,CAAC;IAEF,6BAA6B;IAC7B,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC;IAC1E,OAAO,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,MAAM,SAAS,CAAC,CAAC;IAChD,OAAO,CAAC,GAAG,CACT,eAAe,MAAM;SAClB,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;SACvB,IAAI,CAAC,IAAI,CAAC,EAAE,CAChB,CAAC;IAEF,mBAAmB;IACnB,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,MAAM,OAAO,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CACT,eAAe,IAAI;SAChB,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC;SAC1C,IAAI,CAAC,IAAI,CAAC,EAAE,CAChB,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;AAChD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
|
|
@@ -11,7 +11,7 @@ async function main() {
|
|
|
11
11
|
const testUrl = "http://httpbin.org/ip";
|
|
12
12
|
console.log("Datacenter Proxy Demo\n");
|
|
13
13
|
const proxy = Thordata.Proxy.datacenterFromEnv();
|
|
14
|
-
const result = await client.request(testUrl, { proxy });
|
|
14
|
+
const result = (await client.request(testUrl, { proxy }));
|
|
15
15
|
console.log("Datacenter IP:", result.origin);
|
|
16
16
|
}
|
|
17
17
|
main().catch(console.error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy_datacenter.js","sourceRoot":"","sources":["../../examples/proxy_datacenter.ts"],"names":[],"mappings":"AAAA,+BAA+B;
|
|
1
|
+
{"version":3,"file":"proxy_datacenter.js","sourceRoot":"","sources":["../../examples/proxy_datacenter.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAE/B,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAM9C,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,4BAA4B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,4BAA4B,EAAE,CAAC;QAC3F,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,2EAA2E,CAAC,CAAC;QACzF,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC9B,MAAM,OAAO,GAAG,uBAAuB,CAAC;IAExC,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IAEvC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,iBAAiB,EAAE,CAAC;IACjD,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAoB,CAAC;IAC7E,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;AAC/C,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
|
|
@@ -13,7 +13,7 @@ async function main() {
|
|
|
13
13
|
const testUrl = "http://httpbin.org/ip";
|
|
14
14
|
console.log("Static ISP Proxy Demo\n");
|
|
15
15
|
const proxy = Thordata.Proxy.ispFromEnv();
|
|
16
|
-
const result = await client.request(testUrl, { proxy });
|
|
16
|
+
const result = (await client.request(testUrl, { proxy }));
|
|
17
17
|
console.log("Static ISP IP:", result.origin);
|
|
18
18
|
console.log("Expected IP :", process.env.THORDATA_ISP_HOST);
|
|
19
19
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy_isp.js","sourceRoot":"","sources":["../../examples/proxy_isp.ts"],"names":[],"mappings":"AAAA,wBAAwB;
|
|
1
|
+
{"version":3,"file":"proxy_isp.js","sourceRoot":"","sources":["../../examples/proxy_isp.ts"],"names":[],"mappings":"AAAA,wBAAwB;AAExB,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAM9C,KAAK,UAAU,IAAI;IACjB,IACE,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAC9B,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB;QAClC,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAClC,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,iFAAiF,CAAC,CAAC;QAC/F,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC9B,MAAM,OAAO,GAAG,uBAAuB,CAAC;IAExC,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IAEvC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;IAC1C,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAoB,CAAC;IAC7E,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAC7C,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AAC/D,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
|
|
@@ -11,7 +11,7 @@ async function main() {
|
|
|
11
11
|
const testUrl = "http://httpbin.org/ip";
|
|
12
12
|
console.log("Mobile Proxy Demo\n");
|
|
13
13
|
const proxy = Thordata.Proxy.mobileFromEnv().country("gb");
|
|
14
|
-
const result = await client.request(testUrl, { proxy });
|
|
14
|
+
const result = (await client.request(testUrl, { proxy }));
|
|
15
15
|
console.log("UK Mobile IP:", result.origin);
|
|
16
16
|
}
|
|
17
17
|
main().catch(console.error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy_mobile.js","sourceRoot":"","sources":["../../examples/proxy_mobile.ts"],"names":[],"mappings":"AAAA,2BAA2B;
|
|
1
|
+
{"version":3,"file":"proxy_mobile.js","sourceRoot":"","sources":["../../examples/proxy_mobile.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAE3B,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAM9C,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,CAAC;QACnF,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,mEAAmE,CAAC,CAAC;QACjF,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC9B,MAAM,OAAO,GAAG,uBAAuB,CAAC;IAExC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IAEnC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAoB,CAAC;IAC7E,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;AAC9C,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
|
|
@@ -12,7 +12,7 @@ async function main() {
|
|
|
12
12
|
console.log("Residential Proxy Demo\n");
|
|
13
13
|
// Basic usage
|
|
14
14
|
const proxy1 = Thordata.Proxy.residentialFromEnv().country("us");
|
|
15
|
-
const r1 = await client.request(testUrl, { proxy: proxy1 });
|
|
15
|
+
const r1 = (await client.request(testUrl, { proxy: proxy1 }));
|
|
16
16
|
console.log("US Residential IP:", r1.origin);
|
|
17
17
|
// With sticky session
|
|
18
18
|
const proxy2 = Thordata.Proxy.residentialFromEnv()
|
|
@@ -20,7 +20,7 @@ async function main() {
|
|
|
20
20
|
.city("tokyo")
|
|
21
21
|
.session("my_session")
|
|
22
22
|
.sticky(30);
|
|
23
|
-
const r2 = await client.request(testUrl, { proxy: proxy2 });
|
|
23
|
+
const r2 = (await client.request(testUrl, { proxy: proxy2 }));
|
|
24
24
|
console.log("Tokyo Sticky IP :", r2.origin);
|
|
25
25
|
}
|
|
26
26
|
main().catch(console.error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy_residential.js","sourceRoot":"","sources":["../../examples/proxy_residential.ts"],"names":[],"mappings":"AAAA,gCAAgC;
|
|
1
|
+
{"version":3,"file":"proxy_residential.js","sourceRoot":"","sources":["../../examples/proxy_residential.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAEhC,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAM9C,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,6BAA6B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,6BAA6B,EAAE,CAAC;QAC7F,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,6EAA6E,CAAC,CAAC;QAC3F,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC9B,MAAM,OAAO,GAAG,uBAAuB,CAAC;IAExC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;IAExC,cAAc;IACd,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,kBAAkB,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,MAAM,EAAE,GAAG,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAoB,CAAC;IACjF,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;IAE7C,sBAAsB;IACtB,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,kBAAkB,EAAE;SAC/C,OAAO,CAAC,IAAI,CAAC;SACb,IAAI,CAAC,OAAO,CAAC;SACb,OAAO,CAAC,YAAY,CAAC;SACrB,MAAM,CAAC,EAAE,CAAC,CAAC;IACd,MAAM,EAAE,GAAG,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAoB,CAAC;IACjF,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;AAC/C,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* SERP Google News Demo
|
|
3
|
-
*
|
|
4
|
-
* Usage:
|
|
5
|
-
* npx ts-node examples/serp_google_news.ts
|
|
6
|
-
*/
|
|
1
|
+
// examples/serp_google_news.ts
|
|
7
2
|
import "dotenv/config";
|
|
8
3
|
import { ThordataClient, Engine } from "../src/index.js";
|
|
9
4
|
async function main() {
|
|
@@ -29,7 +24,8 @@ async function main() {
|
|
|
29
24
|
printNewsResults(results);
|
|
30
25
|
}
|
|
31
26
|
catch (e) {
|
|
32
|
-
|
|
27
|
+
const error = e;
|
|
28
|
+
console.error("❌ Search failed:", error.message);
|
|
33
29
|
}
|
|
34
30
|
// 2. Advanced News Filters
|
|
35
31
|
console.log("\n📰 2. Advanced Filters (Sort by Date)");
|
|
@@ -40,16 +36,17 @@ async function main() {
|
|
|
40
36
|
country: "us",
|
|
41
37
|
language: "en",
|
|
42
38
|
num: 5,
|
|
43
|
-
so: 1,
|
|
39
|
+
so: 1,
|
|
44
40
|
});
|
|
45
41
|
printNewsResults(results);
|
|
46
42
|
}
|
|
47
43
|
catch (e) {
|
|
48
|
-
|
|
44
|
+
const error = e;
|
|
45
|
+
console.error("❌ Advanced search failed:", error.message);
|
|
49
46
|
}
|
|
50
47
|
}
|
|
51
48
|
function printNewsResults(results) {
|
|
52
|
-
const news = results?.news ?? [];
|
|
49
|
+
const news = (results?.news ?? []);
|
|
53
50
|
console.log(`✅ Found ${news.length} news items:`);
|
|
54
51
|
news.slice(0, 5).forEach((item) => {
|
|
55
52
|
console.log(` ${item.rank}. [${item.source}] ${item.title}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serp_google_news.js","sourceRoot":"","sources":["../../examples/serp_google_news.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"serp_google_news.js","sourceRoot":"","sources":["../../examples/serp_google_news.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAE/B,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzD,KAAK,UAAU,IAAI;IACjB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC;IACjD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACnE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC;QAChC,YAAY,EAAE,KAAK;QACnB,UAAU,EAAE,CAAC;KACd,CAAC,CAAC;IAEH,uBAAuB;IACvB,OAAO,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC;IACjE,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC;YACtC,KAAK,EAAE,eAAe;YACtB,MAAM,EAAE,MAAM,CAAC,WAAW;YAC1B,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;YACd,GAAG,EAAE,CAAC;SACP,CAAC,CAAC;QACH,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,KAAK,GAAG,CAAU,CAAC;QACzB,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACnD,CAAC;IAED,2BAA2B;IAC3B,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;IACvD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC;YACtC,KAAK,EAAE,yBAAyB;YAChC,MAAM,EAAE,MAAM,CAAC,WAAW;YAC1B,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;YACd,GAAG,EAAE,CAAC;YACN,EAAE,EAAE,CAAC;SACN,CAAC,CAAC;QACH,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,KAAK,GAAG,CAAU,CAAC;QACzB,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC;AAUD,SAAS,gBAAgB,CAAC,OAAgC;IACxD,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,IAAI,IAAI,EAAE,CAAe,CAAC;IAEjD,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,MAAM,cAAc,CAAC,CAAC;IAElD,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QAChC,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAC/D,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;AACrC,CAAC,CAAC,CAAC"}
|
package/dist/src/client.d.ts
CHANGED
|
@@ -1,15 +1,33 @@
|
|
|
1
|
-
import { SerpOptions, UniversalOptions, ScraperTaskOptions, WaitForTaskOptions } from "./models.js";
|
|
1
|
+
import { SerpOptions, UniversalOptions, ScraperTaskOptions, WaitForTaskOptions, ProxyTypeParam, CountryInfo, StateInfo, CityInfo, AsnInfo } from "./models.js";
|
|
2
2
|
import { type ThordataBaseUrls } from "./endpoints.js";
|
|
3
3
|
import { Proxy } from "./proxy.js";
|
|
4
|
+
/**
|
|
5
|
+
* Configuration options for ThordataClient.
|
|
6
|
+
*/
|
|
4
7
|
export interface ThordataClientConfig {
|
|
8
|
+
/** API token for SERP and Universal APIs */
|
|
5
9
|
scraperToken: string;
|
|
10
|
+
/** Public token for Web Scraper API and Location API */
|
|
6
11
|
publicToken?: string;
|
|
12
|
+
/** Public key for Web Scraper API and Location API */
|
|
7
13
|
publicKey?: string;
|
|
14
|
+
/** Request timeout in milliseconds (default: 30000) */
|
|
8
15
|
timeoutMs?: number;
|
|
16
|
+
/** Maximum number of retries on failure (default: 0) */
|
|
9
17
|
maxRetries?: number;
|
|
18
|
+
/** Custom base URLs for API endpoints */
|
|
10
19
|
baseUrls?: Partial<ThordataBaseUrls>;
|
|
20
|
+
/** Custom User-Agent string */
|
|
11
21
|
userAgent?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Whether to verify SSL certificates (default: true).
|
|
24
|
+
* Set to false only for testing with self-signed certificates.
|
|
25
|
+
*/
|
|
26
|
+
verifySsl?: boolean;
|
|
12
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Main client for interacting with Thordata APIs.
|
|
30
|
+
*/
|
|
13
31
|
export declare class ThordataClient {
|
|
14
32
|
private scraperToken;
|
|
15
33
|
private publicToken?;
|
|
@@ -26,19 +44,105 @@ export declare class ThordataClient {
|
|
|
26
44
|
private scraperDownloadUrl;
|
|
27
45
|
constructor(config: ThordataClientConfig);
|
|
28
46
|
/**
|
|
29
|
-
*
|
|
47
|
+
* Execute request with retry logic.
|
|
30
48
|
*/
|
|
31
49
|
private execute;
|
|
32
|
-
|
|
33
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Perform a search using the SERP API.
|
|
52
|
+
*
|
|
53
|
+
* Supported engines: google, bing, yandex, duckduckgo
|
|
54
|
+
* Plus Google specialized engines: google_news, google_shopping, etc.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* // Basic Google search
|
|
59
|
+
* const results = await client.serpSearch({
|
|
60
|
+
* query: "pizza",
|
|
61
|
+
* engine: Engine.GOOGLE,
|
|
62
|
+
* country: "us",
|
|
63
|
+
* });
|
|
64
|
+
*
|
|
65
|
+
* // Google News (recommended: use dedicated engine)
|
|
66
|
+
* const news = await client.serpSearch({
|
|
67
|
+
* query: "AI regulation",
|
|
68
|
+
* engine: Engine.GOOGLE_NEWS,
|
|
69
|
+
* });
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
serpSearch(options: SerpOptions): Promise<Record<string, unknown>>;
|
|
73
|
+
/**
|
|
74
|
+
* Scrape a URL using the Universal/Web Unlocker API.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* // Basic HTML scraping
|
|
79
|
+
* const html = await client.universalScrape({
|
|
80
|
+
* url: "https://example.com",
|
|
81
|
+
* jsRender: false,
|
|
82
|
+
* });
|
|
83
|
+
*
|
|
84
|
+
* // With JS rendering and wait for element
|
|
85
|
+
* const html = await client.universalScrape({
|
|
86
|
+
* url: "https://example.com/spa",
|
|
87
|
+
* jsRender: true,
|
|
88
|
+
* waitFor: ".main-content",
|
|
89
|
+
* });
|
|
90
|
+
*
|
|
91
|
+
* // Screenshot
|
|
92
|
+
* const png = await client.universalScrape({
|
|
93
|
+
* url: "https://example.com",
|
|
94
|
+
* jsRender: true,
|
|
95
|
+
* outputFormat: "png",
|
|
96
|
+
* });
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
universalScrape(options: UniversalOptions): Promise<string | Buffer | Record<string, unknown>>;
|
|
100
|
+
/**
|
|
101
|
+
* Create a new Web Scraper task.
|
|
102
|
+
*/
|
|
34
103
|
createScraperTask(options: ScraperTaskOptions): Promise<string>;
|
|
104
|
+
/**
|
|
105
|
+
* Verify that public credentials are available.
|
|
106
|
+
*/
|
|
35
107
|
private requirePublicCreds;
|
|
108
|
+
/**
|
|
109
|
+
* Get the status of a Web Scraper task.
|
|
110
|
+
*/
|
|
36
111
|
getTaskStatus(taskId: string): Promise<string>;
|
|
112
|
+
/**
|
|
113
|
+
* Get the download URL for a completed task's results.
|
|
114
|
+
*/
|
|
37
115
|
getTaskResult(taskId: string, fileType?: "json" | "csv" | "xlsx"): Promise<string>;
|
|
116
|
+
/**
|
|
117
|
+
* Wait for a task to complete.
|
|
118
|
+
*/
|
|
38
119
|
waitForTask(taskId: string, options?: WaitForTaskOptions): Promise<string>;
|
|
120
|
+
/**
|
|
121
|
+
* Make an HTTP request through a proxy.
|
|
122
|
+
*/
|
|
39
123
|
request(url: string, config?: {
|
|
40
124
|
proxy?: Proxy;
|
|
41
125
|
timeout?: number;
|
|
42
|
-
[key: string]:
|
|
43
|
-
}): Promise<
|
|
126
|
+
[key: string]: unknown;
|
|
127
|
+
}): Promise<unknown>;
|
|
128
|
+
/**
|
|
129
|
+
* Internal method to call locations API.
|
|
130
|
+
*/
|
|
131
|
+
private getLocations;
|
|
132
|
+
/**
|
|
133
|
+
* List all supported countries for a proxy type.
|
|
134
|
+
*/
|
|
135
|
+
listCountries(proxyType?: ProxyTypeParam): Promise<CountryInfo[]>;
|
|
136
|
+
/**
|
|
137
|
+
* List states/regions for a country.
|
|
138
|
+
*/
|
|
139
|
+
listStates(countryCode: string, proxyType?: ProxyTypeParam): Promise<StateInfo[]>;
|
|
140
|
+
/**
|
|
141
|
+
* List cities for a country (and optionally state).
|
|
142
|
+
*/
|
|
143
|
+
listCities(countryCode: string, stateCode?: string, proxyType?: ProxyTypeParam): Promise<CityInfo[]>;
|
|
144
|
+
/**
|
|
145
|
+
* List ASNs for a country.
|
|
146
|
+
*/
|
|
147
|
+
listAsns(countryCode: string, proxyType?: ProxyTypeParam): Promise<AsnInfo[]>;
|
|
44
148
|
}
|
package/dist/src/client.js
CHANGED
|
@@ -2,11 +2,22 @@
|
|
|
2
2
|
import axios from "axios";
|
|
3
3
|
import https from "node:https";
|
|
4
4
|
import { Engine, TaskStatus } from "./enums.js";
|
|
5
|
-
import { ThordataError, ThordataTimeoutError } from "./errors.js";
|
|
6
|
-
import { buildAuthHeaders, buildPublicHeaders, handleAxiosError, toFormBody, raiseForCode, safeParseJson, withRetry, } from "./utils.js";
|
|
5
|
+
import { ThordataError, ThordataTimeoutError, ThordataConfigError } from "./errors.js";
|
|
6
|
+
import { buildAuthHeaders, buildPublicHeaders, handleAxiosError, toFormBody, raiseForCode, safeParseJson, withRetry, buildUserAgent, } from "./utils.js";
|
|
7
7
|
import { resolveBaseUrls } from "./endpoints.js";
|
|
8
|
-
import { buildUserAgent } from "./utils.js";
|
|
9
8
|
import { Proxy } from "./proxy.js";
|
|
9
|
+
/**
|
|
10
|
+
* Normalize proxy type parameter to numeric value.
|
|
11
|
+
*/
|
|
12
|
+
function normalizeProxyType(proxyType) {
|
|
13
|
+
if (typeof proxyType === "number") {
|
|
14
|
+
return proxyType;
|
|
15
|
+
}
|
|
16
|
+
return proxyType === "residential" ? 1 : 2;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Main client for interacting with Thordata APIs.
|
|
20
|
+
*/
|
|
10
21
|
export class ThordataClient {
|
|
11
22
|
scraperToken;
|
|
12
23
|
publicToken;
|
|
@@ -23,15 +34,17 @@ export class ThordataClient {
|
|
|
23
34
|
scraperDownloadUrl;
|
|
24
35
|
constructor(config) {
|
|
25
36
|
if (!config.scraperToken) {
|
|
26
|
-
throw new
|
|
37
|
+
throw new ThordataConfigError("scraperToken is required");
|
|
27
38
|
}
|
|
28
39
|
this.scraperToken = config.scraperToken;
|
|
29
40
|
this.publicToken = config.publicToken;
|
|
30
41
|
this.publicKey = config.publicKey;
|
|
31
42
|
this.timeoutMs = config.timeoutMs ?? 30000;
|
|
32
|
-
this.maxRetries = config.maxRetries ?? 0;
|
|
43
|
+
this.maxRetries = config.maxRetries ?? 0;
|
|
44
|
+
const verifySsl = config.verifySsl ?? true;
|
|
33
45
|
this.http = axios.create({
|
|
34
46
|
timeout: this.timeoutMs,
|
|
47
|
+
httpsAgent: new https.Agent({ rejectUnauthorized: verifySsl }),
|
|
35
48
|
});
|
|
36
49
|
this.baseUrls = resolveBaseUrls(process.env, config.baseUrls);
|
|
37
50
|
this.serpUrl = `${this.baseUrls.scraperapiBaseUrl}/request`;
|
|
@@ -39,16 +52,12 @@ export class ThordataClient {
|
|
|
39
52
|
this.universalUrl = `${this.baseUrls.universalapiBaseUrl}/request`;
|
|
40
53
|
this.scraperStatusUrl = `${this.baseUrls.webScraperApiBaseUrl}/tasks-status`;
|
|
41
54
|
this.scraperDownloadUrl = `${this.baseUrls.webScraperApiBaseUrl}/tasks-download`;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
buildUserAgent(
|
|
45
|
-
// fallback: avoid relying on npm_package_version in runtime
|
|
46
|
-
process.env.npm_package_version || "0.0.0");
|
|
47
|
-
// Set default headers for all requests
|
|
55
|
+
const pkgVersion = process.env.npm_package_version || "0.0.0";
|
|
56
|
+
this.userAgent = config.userAgent ?? buildUserAgent(pkgVersion);
|
|
48
57
|
this.http.defaults.headers.common["User-Agent"] = this.userAgent;
|
|
49
58
|
}
|
|
50
59
|
/**
|
|
51
|
-
*
|
|
60
|
+
* Execute request with retry logic.
|
|
52
61
|
*/
|
|
53
62
|
async execute(requestFn) {
|
|
54
63
|
return withRetry(async () => {
|
|
@@ -63,16 +72,39 @@ export class ThordataClient {
|
|
|
63
72
|
// --------------------------
|
|
64
73
|
// 1) SERP API
|
|
65
74
|
// --------------------------
|
|
75
|
+
/**
|
|
76
|
+
* Perform a search using the SERP API.
|
|
77
|
+
*
|
|
78
|
+
* Supported engines: google, bing, yandex, duckduckgo
|
|
79
|
+
* Plus Google specialized engines: google_news, google_shopping, etc.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```typescript
|
|
83
|
+
* // Basic Google search
|
|
84
|
+
* const results = await client.serpSearch({
|
|
85
|
+
* query: "pizza",
|
|
86
|
+
* engine: Engine.GOOGLE,
|
|
87
|
+
* country: "us",
|
|
88
|
+
* });
|
|
89
|
+
*
|
|
90
|
+
* // Google News (recommended: use dedicated engine)
|
|
91
|
+
* const news = await client.serpSearch({
|
|
92
|
+
* query: "AI regulation",
|
|
93
|
+
* engine: Engine.GOOGLE_NEWS,
|
|
94
|
+
* });
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
66
97
|
async serpSearch(options) {
|
|
67
98
|
const { query, engine = Engine.GOOGLE, num, start, country, language, searchType, device, renderJs, noCache, outputFormat = "json", ...extra } = options;
|
|
68
99
|
if (!query) {
|
|
69
|
-
throw new
|
|
100
|
+
throw new ThordataConfigError("query is required for serpSearch");
|
|
70
101
|
}
|
|
71
102
|
const engineStr = String(engine).toLowerCase();
|
|
72
103
|
const payload = {
|
|
73
104
|
engine: engineStr,
|
|
74
105
|
json: outputFormat.toLowerCase() === "html" ? "0" : "1",
|
|
75
106
|
};
|
|
107
|
+
// Yandex uses 'text' instead of 'q'
|
|
76
108
|
if (engineStr === "yandex") {
|
|
77
109
|
payload.text = query;
|
|
78
110
|
}
|
|
@@ -87,15 +119,9 @@ export class ThordataClient {
|
|
|
87
119
|
payload.gl = country.toLowerCase();
|
|
88
120
|
if (language)
|
|
89
121
|
payload.hl = language.toLowerCase();
|
|
122
|
+
// tbm parameter (only for specific Google engines)
|
|
90
123
|
if (searchType) {
|
|
91
|
-
|
|
92
|
-
const tbmMap = {
|
|
93
|
-
images: "isch",
|
|
94
|
-
shopping: "shop",
|
|
95
|
-
news: "nws",
|
|
96
|
-
videos: "vid",
|
|
97
|
-
};
|
|
98
|
-
payload.tbm = tbmMap[st] ?? st;
|
|
124
|
+
payload.tbm = searchType.toLowerCase();
|
|
99
125
|
}
|
|
100
126
|
if (device)
|
|
101
127
|
payload.device = device.toLowerCase();
|
|
@@ -126,15 +152,46 @@ export class ThordataClient {
|
|
|
126
152
|
// --------------------------
|
|
127
153
|
// 2) Universal / Web Unlocker
|
|
128
154
|
// --------------------------
|
|
155
|
+
/**
|
|
156
|
+
* Scrape a URL using the Universal/Web Unlocker API.
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```typescript
|
|
160
|
+
* // Basic HTML scraping
|
|
161
|
+
* const html = await client.universalScrape({
|
|
162
|
+
* url: "https://example.com",
|
|
163
|
+
* jsRender: false,
|
|
164
|
+
* });
|
|
165
|
+
*
|
|
166
|
+
* // With JS rendering and wait for element
|
|
167
|
+
* const html = await client.universalScrape({
|
|
168
|
+
* url: "https://example.com/spa",
|
|
169
|
+
* jsRender: true,
|
|
170
|
+
* waitFor: ".main-content",
|
|
171
|
+
* });
|
|
172
|
+
*
|
|
173
|
+
* // Screenshot
|
|
174
|
+
* const png = await client.universalScrape({
|
|
175
|
+
* url: "https://example.com",
|
|
176
|
+
* jsRender: true,
|
|
177
|
+
* outputFormat: "png",
|
|
178
|
+
* });
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
129
181
|
async universalScrape(options) {
|
|
130
182
|
const { url, jsRender = false, outputFormat = "html", country, blockResources, cleanContent, wait, waitFor, headers: customHeaders, cookies, ...extra } = options;
|
|
131
183
|
if (!url) {
|
|
132
|
-
throw new
|
|
184
|
+
throw new ThordataConfigError("url is required for universalScrape");
|
|
185
|
+
}
|
|
186
|
+
const format = String(outputFormat).toLowerCase();
|
|
187
|
+
// Validate output format
|
|
188
|
+
if (format !== "html" && format !== "png") {
|
|
189
|
+
throw new ThordataConfigError(`Invalid outputFormat: "${outputFormat}". Supported values: "html", "png"`);
|
|
133
190
|
}
|
|
134
191
|
const payload = {
|
|
135
192
|
url,
|
|
136
193
|
js_render: jsRender ? "True" : "False",
|
|
137
|
-
type:
|
|
194
|
+
type: format,
|
|
138
195
|
};
|
|
139
196
|
if (country)
|
|
140
197
|
payload.country = country.toLowerCase();
|
|
@@ -146,27 +203,30 @@ export class ThordataClient {
|
|
|
146
203
|
payload.wait = String(wait);
|
|
147
204
|
if (waitFor)
|
|
148
205
|
payload.wait_for = waitFor;
|
|
149
|
-
if (customHeaders && customHeaders.length > 0)
|
|
206
|
+
if (customHeaders && customHeaders.length > 0) {
|
|
150
207
|
payload.headers = JSON.stringify(customHeaders);
|
|
151
|
-
|
|
208
|
+
}
|
|
209
|
+
if (cookies && cookies.length > 0) {
|
|
152
210
|
payload.cookies = JSON.stringify(cookies);
|
|
211
|
+
}
|
|
153
212
|
Object.assign(payload, extra);
|
|
154
213
|
const headers = buildAuthHeaders(this.scraperToken);
|
|
155
214
|
return this.execute(async () => {
|
|
156
215
|
const res = await this.http.post(this.universalUrl, toFormBody(payload), {
|
|
157
216
|
headers,
|
|
158
|
-
responseType:
|
|
217
|
+
responseType: format === "png" ? "arraybuffer" : "json",
|
|
159
218
|
});
|
|
160
|
-
if (
|
|
219
|
+
if (format === "png") {
|
|
161
220
|
return Buffer.from(res.data);
|
|
162
221
|
}
|
|
163
222
|
const data = safeParseJson(res.data);
|
|
164
|
-
if (data && typeof data === "object" && "code" in data
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
223
|
+
if (data && typeof data === "object" && "code" in data) {
|
|
224
|
+
const dataObj = data;
|
|
225
|
+
if (dataObj.code !== 200) {
|
|
226
|
+
raiseForCode("Universal API error", dataObj, res.status);
|
|
227
|
+
}
|
|
169
228
|
}
|
|
229
|
+
// Return HTML string
|
|
170
230
|
if (data && typeof data === "object" && "html" in data) {
|
|
171
231
|
return data.html;
|
|
172
232
|
}
|
|
@@ -176,6 +236,9 @@ export class ThordataClient {
|
|
|
176
236
|
// --------------------------
|
|
177
237
|
// 3) Web Scraper API
|
|
178
238
|
// --------------------------
|
|
239
|
+
/**
|
|
240
|
+
* Create a new Web Scraper task.
|
|
241
|
+
*/
|
|
179
242
|
async createScraperTask(options) {
|
|
180
243
|
const { fileName, spiderId, spiderName, parameters, universalParams, includeErrors = true, } = options;
|
|
181
244
|
const payload = {
|
|
@@ -205,11 +268,17 @@ export class ThordataClient {
|
|
|
205
268
|
return String(taskId);
|
|
206
269
|
});
|
|
207
270
|
}
|
|
271
|
+
/**
|
|
272
|
+
* Verify that public credentials are available.
|
|
273
|
+
*/
|
|
208
274
|
requirePublicCreds() {
|
|
209
275
|
if (!this.publicToken || !this.publicKey) {
|
|
210
|
-
throw new
|
|
276
|
+
throw new ThordataConfigError("publicToken and publicKey are required for Web Scraper public API calls");
|
|
211
277
|
}
|
|
212
278
|
}
|
|
279
|
+
/**
|
|
280
|
+
* Get the status of a Web Scraper task.
|
|
281
|
+
*/
|
|
213
282
|
async getTaskStatus(taskId) {
|
|
214
283
|
this.requirePublicCreds();
|
|
215
284
|
const headers = buildPublicHeaders(this.publicToken, this.publicKey);
|
|
@@ -227,6 +296,9 @@ export class ThordataClient {
|
|
|
227
296
|
return TaskStatus.UNKNOWN;
|
|
228
297
|
});
|
|
229
298
|
}
|
|
299
|
+
/**
|
|
300
|
+
* Get the download URL for a completed task's results.
|
|
301
|
+
*/
|
|
230
302
|
async getTaskResult(taskId, fileType = "json") {
|
|
231
303
|
this.requirePublicCreds();
|
|
232
304
|
const headers = buildPublicHeaders(this.publicToken, this.publicKey);
|
|
@@ -234,13 +306,16 @@ export class ThordataClient {
|
|
|
234
306
|
return this.execute(async () => {
|
|
235
307
|
const res = await this.http.post(this.scraperDownloadUrl, toFormBody(payload), { headers });
|
|
236
308
|
const data = safeParseJson(res.data);
|
|
237
|
-
|
|
238
|
-
|
|
309
|
+
const dataObj = data?.data;
|
|
310
|
+
if (data?.code === 200 && dataObj?.download) {
|
|
311
|
+
return dataObj.download;
|
|
239
312
|
}
|
|
240
313
|
raiseForCode("Get task result failed", data, res.status);
|
|
241
|
-
return ""; // unreachable
|
|
242
314
|
});
|
|
243
315
|
}
|
|
316
|
+
/**
|
|
317
|
+
* Wait for a task to complete.
|
|
318
|
+
*/
|
|
244
319
|
async waitForTask(taskId, options = {}) {
|
|
245
320
|
const pollIntervalMs = options.pollIntervalMs ?? 5000;
|
|
246
321
|
const maxWaitMs = options.maxWaitMs ?? 10 * 60 * 1000;
|
|
@@ -265,22 +340,90 @@ export class ThordataClient {
|
|
|
265
340
|
// --------------------------
|
|
266
341
|
// 4) Proxy Network
|
|
267
342
|
// --------------------------
|
|
343
|
+
/**
|
|
344
|
+
* Make an HTTP request through a proxy.
|
|
345
|
+
*/
|
|
268
346
|
async request(url, config = {}) {
|
|
269
347
|
if (!url) {
|
|
270
|
-
throw new
|
|
348
|
+
throw new ThordataConfigError("url is required for request");
|
|
271
349
|
}
|
|
350
|
+
const { proxy, timeout, ...rest } = config;
|
|
272
351
|
const axiosConfig = {
|
|
273
|
-
...
|
|
274
|
-
timeout:
|
|
275
|
-
httpsAgent: new https.Agent({ rejectUnauthorized: false }),
|
|
352
|
+
...rest,
|
|
353
|
+
timeout: timeout ?? this.timeoutMs,
|
|
276
354
|
};
|
|
277
|
-
if (
|
|
278
|
-
axiosConfig.proxy =
|
|
355
|
+
if (proxy instanceof Proxy) {
|
|
356
|
+
axiosConfig.proxy = proxy.toAxiosConfig();
|
|
279
357
|
}
|
|
280
358
|
return this.execute(async () => {
|
|
281
359
|
const res = await this.http.get(url, axiosConfig);
|
|
282
360
|
return res.data;
|
|
283
361
|
});
|
|
284
362
|
}
|
|
363
|
+
// --------------------------
|
|
364
|
+
// 5) Location API
|
|
365
|
+
// --------------------------
|
|
366
|
+
/**
|
|
367
|
+
* Internal method to call locations API.
|
|
368
|
+
*/
|
|
369
|
+
async getLocations(endpoint, params = {}) {
|
|
370
|
+
this.requirePublicCreds();
|
|
371
|
+
const queryParams = new URLSearchParams({
|
|
372
|
+
token: this.publicToken,
|
|
373
|
+
key: this.publicKey,
|
|
374
|
+
...Object.fromEntries(Object.entries(params).map(([k, v]) => [k, String(v)])),
|
|
375
|
+
});
|
|
376
|
+
const url = `${this.baseUrls.locationsBaseUrl}/${endpoint}?${queryParams.toString()}`;
|
|
377
|
+
return this.execute(async () => {
|
|
378
|
+
const res = await this.http.get(url);
|
|
379
|
+
const data = safeParseJson(res.data);
|
|
380
|
+
if (data?.code === 200 && Array.isArray(data.data)) {
|
|
381
|
+
return data.data;
|
|
382
|
+
}
|
|
383
|
+
if (Array.isArray(data)) {
|
|
384
|
+
return data;
|
|
385
|
+
}
|
|
386
|
+
raiseForCode(`Location API (${endpoint}) failed`, data, res.status);
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* List all supported countries for a proxy type.
|
|
391
|
+
*/
|
|
392
|
+
async listCountries(proxyType = "residential") {
|
|
393
|
+
return this.getLocations("countries", {
|
|
394
|
+
proxy_type: normalizeProxyType(proxyType),
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* List states/regions for a country.
|
|
399
|
+
*/
|
|
400
|
+
async listStates(countryCode, proxyType = "residential") {
|
|
401
|
+
return this.getLocations("states", {
|
|
402
|
+
proxy_type: normalizeProxyType(proxyType),
|
|
403
|
+
country_code: countryCode.toUpperCase(),
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* List cities for a country (and optionally state).
|
|
408
|
+
*/
|
|
409
|
+
async listCities(countryCode, stateCode, proxyType = "residential") {
|
|
410
|
+
const params = {
|
|
411
|
+
proxy_type: normalizeProxyType(proxyType),
|
|
412
|
+
country_code: countryCode.toUpperCase(),
|
|
413
|
+
};
|
|
414
|
+
if (stateCode) {
|
|
415
|
+
params.state_code = stateCode.toLowerCase();
|
|
416
|
+
}
|
|
417
|
+
return this.getLocations("cities", params);
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* List ASNs for a country.
|
|
421
|
+
*/
|
|
422
|
+
async listAsns(countryCode, proxyType = "residential") {
|
|
423
|
+
return this.getLocations("asn", {
|
|
424
|
+
proxy_type: normalizeProxyType(proxyType),
|
|
425
|
+
country_code: countryCode.toUpperCase(),
|
|
426
|
+
});
|
|
427
|
+
}
|
|
285
428
|
}
|
|
286
429
|
//# sourceMappingURL=client.js.map
|