node-ipdox 1.0.3 → 1.0.5
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 +2 -1
- package/dist/integration/ipdox.providers.int.test.d.ts +1 -0
- package/dist/integration/ipdox.providers.int.test.js +50 -0
- package/dist/ipdox.js +4 -0
- package/dist/ipdox.test.d.ts +1 -0
- package/dist/ipdox.test.js +86 -0
- package/dist/types/IPDOXResponse.d.ts +2 -0
- package/package.json +11 -13
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ import { IPDox } from "node-ipdox";
|
|
|
18
18
|
const ipdox = new IPDox({
|
|
19
19
|
cacheMaxItems: 5000,
|
|
20
20
|
cacheMaxAge: 43200000,
|
|
21
|
-
maxRetries: 10
|
|
21
|
+
maxRetries: 10
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
ipdox
|
|
@@ -69,6 +69,7 @@ export interface IPDOXResponse {
|
|
|
69
69
|
isTOR: boolean; // Boolean indicating if the IP address is a TOR node (might be undefined)
|
|
70
70
|
isProxy: boolean; // Boolean indicating if the IP address is a proxy (might be undefined)
|
|
71
71
|
};
|
|
72
|
+
timeZone?: string; // Time zone
|
|
72
73
|
source: string; // Source API
|
|
73
74
|
}
|
|
74
75
|
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const vitest_1 = require("vitest");
|
|
13
|
+
const index_1 = require("../index");
|
|
14
|
+
const RUN = process.env.RUN_INTEGRATION === "1";
|
|
15
|
+
const TEST_IP = process.env.TEST_IP || "8.8.8.8";
|
|
16
|
+
// Run only when explicitly enabled
|
|
17
|
+
(RUN ? vitest_1.describe : vitest_1.describe.skip)("Integration: real providers", () => {
|
|
18
|
+
(0, vitest_1.it)("ipwho.is", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
19
|
+
const ipdox = new index_1.IPDox({ maxRetries: 1 });
|
|
20
|
+
// @ts-expect-error call provider directly to avoid randomness
|
|
21
|
+
const r = yield ipdox.fetchIPWhoDotIs(TEST_IP);
|
|
22
|
+
(0, vitest_1.expect)(r).toBeTruthy();
|
|
23
|
+
(0, vitest_1.expect)(r.source).toBe("ipwho.is");
|
|
24
|
+
(0, vitest_1.expect)(r.ip).toBeTypeOf("string");
|
|
25
|
+
}), 20000);
|
|
26
|
+
(0, vitest_1.it)("ip-api.com", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
27
|
+
const ipdox = new index_1.IPDox({ maxRetries: 1 });
|
|
28
|
+
// @ts-expect-error call provider directly to avoid randomness
|
|
29
|
+
const r = yield ipdox.fetchIPHyphenAPIDotCom(TEST_IP);
|
|
30
|
+
(0, vitest_1.expect)(r).toBeTruthy();
|
|
31
|
+
(0, vitest_1.expect)(r.source).toBe("ip-api.com");
|
|
32
|
+
(0, vitest_1.expect)(r.ip).toBeTypeOf("string");
|
|
33
|
+
}), 20000);
|
|
34
|
+
(0, vitest_1.it)("freeipapi.com", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
35
|
+
const ipdox = new index_1.IPDox({ maxRetries: 1 });
|
|
36
|
+
// @ts-expect-error call provider directly to avoid randomness
|
|
37
|
+
const r = yield ipdox.fetchFreeIPAPIDotCom(TEST_IP);
|
|
38
|
+
(0, vitest_1.expect)(r).toBeTruthy();
|
|
39
|
+
(0, vitest_1.expect)(r.source).toBe("freeipapi.com");
|
|
40
|
+
(0, vitest_1.expect)(r.ip).toBeTypeOf("string");
|
|
41
|
+
}), 20000);
|
|
42
|
+
(0, vitest_1.it)("ipapi.co", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
43
|
+
const ipdox = new index_1.IPDox({ maxRetries: 1 });
|
|
44
|
+
// @ts-expect-error call provider directly to avoid randomness
|
|
45
|
+
const r = yield ipdox.fetchIPAPIDotCo(TEST_IP);
|
|
46
|
+
(0, vitest_1.expect)(r).toBeTruthy();
|
|
47
|
+
(0, vitest_1.expect)(r.source).toBe("ipapi.co");
|
|
48
|
+
(0, vitest_1.expect)(r.ip).toBeTypeOf("string");
|
|
49
|
+
}), 20000);
|
|
50
|
+
});
|
package/dist/ipdox.js
CHANGED
|
@@ -115,6 +115,7 @@ class IPDox {
|
|
|
115
115
|
isp: response.data.isp,
|
|
116
116
|
proxy: response.data.proxy,
|
|
117
117
|
isHosting: response.data.hosting,
|
|
118
|
+
timeZone: response.data.timezone,
|
|
118
119
|
source: "ip-api.com"
|
|
119
120
|
};
|
|
120
121
|
this.cacheResponse(ip, formattedResponse);
|
|
@@ -141,6 +142,7 @@ class IPDox {
|
|
|
141
142
|
isp: response.data.isp,
|
|
142
143
|
proxy: response.data.proxy,
|
|
143
144
|
isHosting: response.data.hosting,
|
|
145
|
+
timeZone: response.data.timeZones[0],
|
|
144
146
|
source: "freeipapi.com"
|
|
145
147
|
};
|
|
146
148
|
this.cacheResponse(ip, formattedResponse);
|
|
@@ -167,6 +169,7 @@ class IPDox {
|
|
|
167
169
|
isp: response.data.connection.isp,
|
|
168
170
|
proxy: false,
|
|
169
171
|
isHosting: false,
|
|
172
|
+
timeZone: response.data.timezone.id,
|
|
170
173
|
source: "ipwho.is"
|
|
171
174
|
};
|
|
172
175
|
this.cacheResponse(ip, formattedResponse);
|
|
@@ -191,6 +194,7 @@ class IPDox {
|
|
|
191
194
|
longitude: response.data.longitude,
|
|
192
195
|
zip: response.data.postal,
|
|
193
196
|
isp: response.data.org,
|
|
197
|
+
timeZone: response.data.timezone,
|
|
194
198
|
source: "ipapi.co"
|
|
195
199
|
};
|
|
196
200
|
this.cacheResponse(ip, formattedResponse);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const vitest_1 = require("vitest");
|
|
16
|
+
const axios_1 = __importDefault(require("axios"));
|
|
17
|
+
const index_1 = require("./index");
|
|
18
|
+
vitest_1.vi.mock("axios");
|
|
19
|
+
const mockedAxios = axios_1.default;
|
|
20
|
+
(0, vitest_1.describe)("IPDox", () => {
|
|
21
|
+
(0, vitest_1.beforeEach)(() => {
|
|
22
|
+
vitest_1.vi.clearAllMocks();
|
|
23
|
+
});
|
|
24
|
+
(0, vitest_1.it)("returns undefined for empty ip", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
25
|
+
const ipdox = new index_1.IPDox();
|
|
26
|
+
const res = yield ipdox.doxIP({ ip: "" });
|
|
27
|
+
(0, vitest_1.expect)(res).toBeUndefined();
|
|
28
|
+
}));
|
|
29
|
+
(0, vitest_1.it)("formats response from ipwho.is provider", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
30
|
+
const ipdox = new index_1.IPDox({ maxRetries: 1 });
|
|
31
|
+
mockedAxios.get = vitest_1.vi.fn().mockResolvedValue({
|
|
32
|
+
data: {
|
|
33
|
+
success: true,
|
|
34
|
+
ip: "8.8.8.8",
|
|
35
|
+
country_code: "US",
|
|
36
|
+
city: "Mountain View",
|
|
37
|
+
continent_code: "NA",
|
|
38
|
+
latitude: 37.386,
|
|
39
|
+
longitude: -122.0838,
|
|
40
|
+
postal: "94039",
|
|
41
|
+
connection: { isp: "Google LLC" },
|
|
42
|
+
timezone: { id: "America/Los_Angeles" }
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
// Call provider directly to avoid randomness
|
|
46
|
+
// @ts-expect-error Accessing class method for test
|
|
47
|
+
const r = yield ipdox.fetchIPWhoDotIs("8.8.8.8");
|
|
48
|
+
(0, vitest_1.expect)(r).toMatchObject({
|
|
49
|
+
ip: "8.8.8.8",
|
|
50
|
+
country: "US",
|
|
51
|
+
city: "Mountain View",
|
|
52
|
+
continent: "NA",
|
|
53
|
+
latitude: 37.386,
|
|
54
|
+
longitude: -122.0838,
|
|
55
|
+
zip: "94039",
|
|
56
|
+
isp: "Google LLC",
|
|
57
|
+
timeZone: "America/Los_Angeles",
|
|
58
|
+
source: "ipwho.is"
|
|
59
|
+
});
|
|
60
|
+
}));
|
|
61
|
+
(0, vitest_1.it)("caches responses by ip", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
62
|
+
const ipdox = new index_1.IPDox({ maxRetries: 1 });
|
|
63
|
+
mockedAxios.get = vitest_1.vi.fn().mockResolvedValue({
|
|
64
|
+
data: {
|
|
65
|
+
success: true,
|
|
66
|
+
ip: "1.1.1.1",
|
|
67
|
+
country_code: "AU",
|
|
68
|
+
city: "Sydney",
|
|
69
|
+
continent_code: "OC",
|
|
70
|
+
latitude: -33.86,
|
|
71
|
+
longitude: 151.21,
|
|
72
|
+
postal: "2000",
|
|
73
|
+
connection: { isp: "Cloudflare" },
|
|
74
|
+
timezone: { id: "Australia/Sydney" }
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
// @ts-expect-error Accessing class method for test
|
|
78
|
+
const r1 = yield ipdox.fetchIPWhoDotIs("1.1.1.1");
|
|
79
|
+
(0, vitest_1.expect)(r1).toBeTruthy();
|
|
80
|
+
// Second call should be served from cache; axios.get should not be called again if provider is called through cache path
|
|
81
|
+
// @ts-expect-error Use cache via public doxIP path
|
|
82
|
+
ipdox.cache.set("1.1.1.1", r1);
|
|
83
|
+
const r2 = yield ipdox.doxIP({ ip: "1.1.1.1" });
|
|
84
|
+
(0, vitest_1.expect)(r2).toEqual(r1);
|
|
85
|
+
}));
|
|
86
|
+
});
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* @property {boolean} proxyInfo.isVPN Is the IP address a VPN?
|
|
17
17
|
* @property {boolean} proxyInfo.isTOR Is the IP address a TOR node?
|
|
18
18
|
* @property {boolean} proxyInfo.isProxy Is the IP address a proxy?
|
|
19
|
+
* @property {string} timeZone The time zone
|
|
19
20
|
* @property {string} source The source of the data
|
|
20
21
|
*/
|
|
21
22
|
export interface IPDOXResponse {
|
|
@@ -34,5 +35,6 @@ export interface IPDOXResponse {
|
|
|
34
35
|
isTOR: boolean;
|
|
35
36
|
isProxy: boolean;
|
|
36
37
|
};
|
|
38
|
+
timeZone?: string;
|
|
37
39
|
source: string;
|
|
38
40
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-ipdox",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "node-ipdox is a Node.js library for GeoIP lookup, leveraging various free GeoIP APIs. It provides a unified response format and incorporates local caching to minimize duplicate requests.",
|
|
5
5
|
"author": "Mikel Calvo <contact@mikecalvo.net> (www.mikelcalvo.net)",
|
|
6
6
|
"keywords": [
|
|
@@ -15,28 +15,26 @@
|
|
|
15
15
|
"license": "ISC",
|
|
16
16
|
"readmeFilename": "README.md",
|
|
17
17
|
"homepage": "https://github.com/mikelcalvo/ipdox#readme",
|
|
18
|
-
"bugs": {
|
|
19
|
-
"url": "https://github.com/mikelcalvo/ipdox/issues"
|
|
20
|
-
},
|
|
18
|
+
"bugs": { "url": "https://github.com/mikelcalvo/ipdox/issues" },
|
|
21
19
|
"main": "./dist/index.js",
|
|
22
20
|
"types": "./dist/index.d.ts",
|
|
23
21
|
"files": ["dist"],
|
|
24
22
|
"scripts": {
|
|
25
|
-
"test": "
|
|
26
|
-
"
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:watch": "vitest",
|
|
25
|
+
"test:integration": "RUN_INTEGRATION=1 vitest run src/integration/ipdox.providers.int.test.ts",
|
|
26
|
+
"format": "prettier --write \"**/*.ts\" \"**/*.js\" \"**/*.json\" --ignore-path .prettierignore",
|
|
27
27
|
"build": "tsc"
|
|
28
28
|
},
|
|
29
29
|
"repository": {
|
|
30
30
|
"type": "git",
|
|
31
31
|
"url": "git+https://github.com/mikelcalvo/node-ipdox.git"
|
|
32
32
|
},
|
|
33
|
-
"dependencies": {
|
|
34
|
-
"axios": "1.6.8",
|
|
35
|
-
"lru-cache": "^10.2.0"
|
|
36
|
-
},
|
|
33
|
+
"dependencies": { "axios": "1.11.0", "lru-cache": "^11.1.0" },
|
|
37
34
|
"devDependencies": {
|
|
38
|
-
"@types/node": "
|
|
39
|
-
"prettier": "3.2
|
|
40
|
-
"typescript": "^5.
|
|
35
|
+
"@types/node": "24.3.0",
|
|
36
|
+
"prettier": "3.6.2",
|
|
37
|
+
"typescript": "^5.9.2",
|
|
38
|
+
"vitest": "3.2.4"
|
|
41
39
|
}
|
|
42
40
|
}
|