iploop 1.0.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/README.md +76 -0
- package/index.d.ts +51 -0
- package/index.js +152 -0
- package/package.json +21 -0
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# IPLoop Node.js SDK
|
|
2
|
+
|
|
3
|
+
Residential proxy SDK — route requests through millions of real devices across 111+ countries.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install iploop
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
const IPLoop = require('iploop');
|
|
15
|
+
|
|
16
|
+
const ip = new IPLoop('your-api-key');
|
|
17
|
+
|
|
18
|
+
// Fetch any URL through a residential proxy
|
|
19
|
+
const res = await ip.get('https://httpbin.org/ip');
|
|
20
|
+
console.log(res.body);
|
|
21
|
+
|
|
22
|
+
// Target a specific country
|
|
23
|
+
const de = await ip.get('https://example.com', { country: 'DE' });
|
|
24
|
+
|
|
25
|
+
// POST request
|
|
26
|
+
const post = await ip.post('https://api.example.com/data', {
|
|
27
|
+
body: JSON.stringify({ key: 'value' }),
|
|
28
|
+
headers: { 'Content-Type': 'application/json' }
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Sticky Sessions
|
|
33
|
+
|
|
34
|
+
Keep the same IP across multiple requests:
|
|
35
|
+
|
|
36
|
+
```javascript
|
|
37
|
+
const session = ip.session({ country: 'US', city: 'newyork' });
|
|
38
|
+
const page1 = await session.get('https://site.com/page1'); // same IP
|
|
39
|
+
const page2 = await session.get('https://site.com/page2'); // same IP
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Geo-Targeting
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
const ip = new IPLoop('key', { country: 'JP' }); // All requests through Japan
|
|
46
|
+
// Or per-request:
|
|
47
|
+
const res = await ip.get('https://example.com', { country: 'GB' });
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## TypeScript
|
|
51
|
+
|
|
52
|
+
Full TypeScript support included:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import IPLoop from 'iploop';
|
|
56
|
+
const ip = new IPLoop('your-api-key', { country: 'US' });
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## API
|
|
60
|
+
|
|
61
|
+
- `ip.get(url, options?)` — GET request
|
|
62
|
+
- `ip.post(url, options?)` — POST request
|
|
63
|
+
- `ip.put(url, options?)` — PUT request
|
|
64
|
+
- `ip.delete(url, options?)` — DELETE request
|
|
65
|
+
- `ip.fetch(url, options?)` — Custom request
|
|
66
|
+
- `ip.session(options?)` — Create sticky session
|
|
67
|
+
- `ip.countries()` — List available countries
|
|
68
|
+
|
|
69
|
+
## Links
|
|
70
|
+
|
|
71
|
+
- Website: [iploop.io](https://iploop.io)
|
|
72
|
+
- Twitter: [@iploop_io](https://x.com/iploop_io)
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
MIT
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
declare class IPLoop {
|
|
2
|
+
constructor(apiKey: string, options?: {
|
|
3
|
+
gateway?: string;
|
|
4
|
+
port?: number;
|
|
5
|
+
country?: string;
|
|
6
|
+
city?: string;
|
|
7
|
+
timeout?: number;
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
fetch(url: string, options?: RequestOptions): Promise<IPLoopResponse>;
|
|
11
|
+
get(url: string, options?: RequestOptions): Promise<IPLoopResponse>;
|
|
12
|
+
post(url: string, options?: RequestOptions): Promise<IPLoopResponse>;
|
|
13
|
+
put(url: string, options?: RequestOptions): Promise<IPLoopResponse>;
|
|
14
|
+
delete(url: string, options?: RequestOptions): Promise<IPLoopResponse>;
|
|
15
|
+
session(options?: SessionOptions): IPLoopSession;
|
|
16
|
+
countries(): Promise<string[]>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface RequestOptions {
|
|
20
|
+
method?: string;
|
|
21
|
+
headers?: Record<string, string>;
|
|
22
|
+
body?: string | object;
|
|
23
|
+
country?: string;
|
|
24
|
+
city?: string;
|
|
25
|
+
session?: string;
|
|
26
|
+
timeout?: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface SessionOptions {
|
|
30
|
+
country?: string;
|
|
31
|
+
city?: string;
|
|
32
|
+
session?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface IPLoopResponse {
|
|
36
|
+
status: number;
|
|
37
|
+
statusCode: number;
|
|
38
|
+
headers: Record<string, string>;
|
|
39
|
+
body: string;
|
|
40
|
+
text(): Promise<string>;
|
|
41
|
+
json(): Promise<any>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
declare class IPLoopSession {
|
|
45
|
+
fetch(url: string, options?: RequestOptions): Promise<IPLoopResponse>;
|
|
46
|
+
get(url: string, options?: RequestOptions): Promise<IPLoopResponse>;
|
|
47
|
+
post(url: string, options?: RequestOptions): Promise<IPLoopResponse>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export = IPLoop;
|
|
51
|
+
export { IPLoop, IPLoopSession, RequestOptions, SessionOptions, IPLoopResponse };
|
package/index.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
const http = require('http');
|
|
2
|
+
const https = require('https');
|
|
3
|
+
const { URL } = require('url');
|
|
4
|
+
|
|
5
|
+
class IPLoop {
|
|
6
|
+
constructor(apiKey, options = {}) {
|
|
7
|
+
this.apiKey = apiKey;
|
|
8
|
+
this.gateway = options.gateway || 'gateway.iploop.io';
|
|
9
|
+
this.port = options.port || 8880;
|
|
10
|
+
this.country = options.country || null;
|
|
11
|
+
this.city = options.city || null;
|
|
12
|
+
this.timeout = options.timeout || 30000;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
_buildAuth(options = {}) {
|
|
16
|
+
const parts = [this.apiKey];
|
|
17
|
+
const country = options.country || this.country;
|
|
18
|
+
const city = options.city || this.city;
|
|
19
|
+
const session = options.session || null;
|
|
20
|
+
|
|
21
|
+
if (country) parts.push(`country-${country}`);
|
|
22
|
+
if (city) parts.push(`city-${city}`);
|
|
23
|
+
if (session) parts.push(`session-${session}`);
|
|
24
|
+
|
|
25
|
+
return `user:${parts.join('-')}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
fetch(url, options = {}) {
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
const target = new URL(url);
|
|
31
|
+
const auth = this._buildAuth(options);
|
|
32
|
+
|
|
33
|
+
const proxyOptions = {
|
|
34
|
+
hostname: this.gateway,
|
|
35
|
+
port: this.port,
|
|
36
|
+
path: url,
|
|
37
|
+
method: options.method || 'GET',
|
|
38
|
+
headers: {
|
|
39
|
+
...this._defaultHeaders(target, options),
|
|
40
|
+
...(options.headers || {}),
|
|
41
|
+
'Proxy-Authorization': 'Basic ' + Buffer.from(auth).toString('base64'),
|
|
42
|
+
'Host': target.hostname,
|
|
43
|
+
},
|
|
44
|
+
timeout: options.timeout || this.timeout,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const req = http.request(proxyOptions, (res) => {
|
|
48
|
+
let data = '';
|
|
49
|
+
res.on('data', chunk => data += chunk);
|
|
50
|
+
res.on('end', () => {
|
|
51
|
+
resolve({
|
|
52
|
+
status: res.statusCode,
|
|
53
|
+
statusCode: res.statusCode,
|
|
54
|
+
headers: res.headers,
|
|
55
|
+
text: () => Promise.resolve(data),
|
|
56
|
+
json: () => Promise.resolve(JSON.parse(data)),
|
|
57
|
+
body: data,
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
req.on('error', reject);
|
|
63
|
+
req.on('timeout', () => {
|
|
64
|
+
req.destroy();
|
|
65
|
+
reject(new Error('Request timeout'));
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
if (options.body) {
|
|
69
|
+
req.write(typeof options.body === 'string' ? options.body : JSON.stringify(options.body));
|
|
70
|
+
}
|
|
71
|
+
req.end();
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
get(url, options = {}) {
|
|
76
|
+
return this.fetch(url, { ...options, method: 'GET' });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
post(url, options = {}) {
|
|
80
|
+
return this.fetch(url, { ...options, method: 'POST' });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
put(url, options = {}) {
|
|
84
|
+
return this.fetch(url, { ...options, method: 'PUT' });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
delete(url, options = {}) {
|
|
88
|
+
return this.fetch(url, { ...options, method: 'DELETE' });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
session(options = {}) {
|
|
92
|
+
const sessionId = options.session || `sess-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
93
|
+
return new IPLoopSession(this, { ...options, session: sessionId });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
_defaultHeaders(target, options = {}) {
|
|
97
|
+
const country = options.country || this.country || 'US';
|
|
98
|
+
const langs = {
|
|
99
|
+
US: 'en-US,en;q=0.9',
|
|
100
|
+
GB: 'en-GB,en;q=0.9',
|
|
101
|
+
DE: 'de-DE,de;q=0.9,en;q=0.8',
|
|
102
|
+
FR: 'fr-FR,fr;q=0.9,en;q=0.8',
|
|
103
|
+
JP: 'ja-JP,ja;q=0.9,en;q=0.8',
|
|
104
|
+
BR: 'pt-BR,pt;q=0.9,en;q=0.8',
|
|
105
|
+
IL: 'he-IL,he;q=0.9,en;q=0.8',
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
|
|
110
|
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
111
|
+
'Accept-Language': langs[country] || langs.US,
|
|
112
|
+
'Accept-Encoding': 'gzip, deflate, br',
|
|
113
|
+
'Cache-Control': 'no-cache',
|
|
114
|
+
'Sec-Fetch-Dest': 'document',
|
|
115
|
+
'Sec-Fetch-Mode': 'navigate',
|
|
116
|
+
'Sec-Fetch-Site': 'none',
|
|
117
|
+
'Sec-Ch-Ua': '"Chromium";v="122", "Not(A:Brand";v="24"',
|
|
118
|
+
'Sec-Ch-Ua-Mobile': '?0',
|
|
119
|
+
'Sec-Ch-Ua-Platform': '"Windows"',
|
|
120
|
+
'Upgrade-Insecure-Requests': '1',
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async countries() {
|
|
125
|
+
return ['US', 'GB', 'DE', 'FR', 'JP', 'BR', 'IN', 'AU', 'CA', 'IL',
|
|
126
|
+
'KR', 'SG', 'NL', 'SE', 'CH', 'ES', 'IT', 'PL', 'TR', 'ZA',
|
|
127
|
+
'NG', 'PH', 'MX', 'AR', 'CL', 'CO', 'EG', 'KE', 'TH', 'VN'];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
class IPLoopSession {
|
|
132
|
+
constructor(client, options) {
|
|
133
|
+
this.client = client;
|
|
134
|
+
this.options = options;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
fetch(url, options = {}) {
|
|
138
|
+
return this.client.fetch(url, { ...this.options, ...options });
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
get(url, options = {}) {
|
|
142
|
+
return this.fetch(url, { ...options, method: 'GET' });
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
post(url, options = {}) {
|
|
146
|
+
return this.fetch(url, { ...options, method: 'POST' });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
module.exports = IPLoop;
|
|
151
|
+
module.exports.IPLoop = IPLoop;
|
|
152
|
+
module.exports.default = IPLoop;
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "iploop",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "IPLoop Residential Proxy SDK — route requests through millions of real devices",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"keywords": ["proxy", "residential-proxy", "web-scraping", "rotating-proxy", "socks5", "http-proxy", "iploop", "sdk"],
|
|
8
|
+
"author": "IPLoop <partners@iploop.io>",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"homepage": "https://iploop.io",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/iploop/iploop-node"
|
|
14
|
+
},
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=14"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"node-fetch": "^2.7.0"
|
|
20
|
+
}
|
|
21
|
+
}
|