Skip to content

Commit 5343bf8

Browse files
committed
Add resproxy API support
Add lookupResproxy method to IPinfoWrapper for looking up residential proxy information for IP addresses. The resproxy API endpoint returns: - ip: The IP address - last_seen: Last recorded date when the proxy was active - percent_days_seen: Percentage of days active in the last 7-day period - service: Name of the residential proxy service
1 parent 818588f commit 5343bf8

File tree

8 files changed

+73
-5
lines changed

8 files changed

+73
-5
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"ip": "175.107.211.204",
3+
"last_seen": "2026-01-14",
4+
"percent_days_seen": 50,
5+
"service": "DataImpulse"
6+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

__tests__/ipinfoWrapper.test.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as dotenv from "dotenv";
2-
import { AsnResponse, IPinfo } from "../src/common";
2+
import { AsnResponse, IPinfo, Resproxy } from "../src/common";
33
import IPinfoWrapper from "../src/ipinfoWrapper";
44

55
let ipinfoWrapper: IPinfoWrapper;
@@ -195,6 +195,24 @@ describe("IPinfoWrapper", () => {
195195
expect(data.bogon).toEqual(true);
196196
});
197197

198+
test("lookupResproxy", async () => {
199+
// test multiple times for cache.
200+
for (let i = 0; i < 5; i++) {
201+
const data: Resproxy = await ipinfoWrapper.lookupResproxy(
202+
"175.107.211.204"
203+
);
204+
expect(data.ip).toEqual("175.107.211.204");
205+
expect(data.last_seen).toEqual("2026-01-14");
206+
expect(data.percent_days_seen).toEqual(50);
207+
expect(data.service).toEqual("DataImpulse");
208+
}
209+
});
210+
211+
test("lookupResproxyEmpty", async () => {
212+
const data: Resproxy = await ipinfoWrapper.lookupResproxy("8.8.8.8");
213+
expect(data).toEqual({});
214+
});
215+
198216
test("Error is thrown for invalid token", async () => {
199217
const ipinfo = new IPinfoWrapper("invalid-token");
200218
await expect(ipinfo.lookupIp("1.2.3.4")).rejects.toThrow();

__tests__/jest.setup.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,22 @@ module.exports = async function globalSetup() {
3232
method: "POST",
3333
path: "/tools/map",
3434
response: path.resolve(__dirname, "./fixtures/tools/map.json")
35+
},
36+
{
37+
method: "GET",
38+
path: "/resproxy/175.107.211.204",
39+
response: path.resolve(
40+
__dirname,
41+
"./fixtures/resproxy/175.107.211.204.json"
42+
)
43+
},
44+
{
45+
method: "GET",
46+
path: "/resproxy/8.8.8.8",
47+
response: path.resolve(
48+
__dirname,
49+
"./fixtures/resproxy/8.8.8.8.json"
50+
)
3551
}
3652
]
3753
};

package-lock.json

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

src/common.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export const HOST: string = "ipinfo.io";
22
export const HOST_LITE: string = "api.ipinfo.io/lite";
33
export const HOST_CORE: string = "api.ipinfo.io/lookup";
44
export const HOST_PLUS: string = "api.ipinfo.io/lookup";
5+
export const HOST_RESPROXY: string = "ipinfo.io/resproxy";
56

67
// cache version
78
export const CACHE_VSN: string = "1";
@@ -244,6 +245,13 @@ export interface MapResponse {
244245
reportUrl: string;
245246
}
246247

248+
export interface Resproxy {
249+
ip: string;
250+
last_seen: string;
251+
percent_days_seen: number;
252+
service: string;
253+
}
254+
247255
export interface BatchResponse {
248256
[key: string]:
249257
| IPinfo

src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ export {
3131
Prefixes6,
3232
AsnResponse,
3333
MapResponse,
34-
BatchResponse
34+
BatchResponse,
35+
Resproxy
3536
} from "./common";
3637

3738
export default IPinfoWrapper;

src/ipinfoWrapper.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
AsnResponse,
1717
MapResponse,
1818
BatchResponse,
19+
Resproxy,
1920
BATCH_MAX_SIZE,
2021
BATCH_REQ_TIMEOUT_DEFAULT,
2122
REQUEST_TIMEOUT_DEFAULT,
@@ -215,6 +216,26 @@ export default class IPinfoWrapper {
215216
});
216217
}
217218

219+
/**
220+
* Lookup residential proxy information using the IP.
221+
*
222+
* @param ip IP address to check for residential proxy information.
223+
* @return Response containing Resproxy data if the IP is a residential proxy.
224+
*/
225+
public async lookupResproxy(ip: string): Promise<Resproxy> {
226+
const cacheKey = `resproxy:${ip}`;
227+
const data = await this.cache.get(IPinfoWrapper.cacheKey(cacheKey));
228+
if (data) {
229+
return data;
230+
}
231+
232+
return this.fetchApi(`resproxy/${ip}`).then(async (response) => {
233+
const resproxy = (await response.json()) as Resproxy;
234+
this.cache.set(IPinfoWrapper.cacheKey(cacheKey), resproxy);
235+
return resproxy;
236+
});
237+
}
238+
218239
/**
219240
* Get a mapping of a list of IPs on a world map.
220241
*

0 commit comments

Comments
 (0)