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 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",
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": "echo \"Error: no test specified\" && exit 1",
26
- "format": "prettier --write \"**/*.ts\" \"**/*.js\" \"**/*.json\"",
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": "20.12.7",
39
- "prettier": "3.2.5",
40
- "typescript": "^5.4.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
  }