@k03mad/ip2geo 5.0.1 β†’ 6.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/.husky/pre-commit CHANGED
@@ -1,4 +1,2 @@
1
- #!/usr/bin/env sh
2
- . "$(dirname -- "$0")/_/husky.sh"
3
-
4
- npm run lint && npm run test
1
+ npm run lint
2
+ npm run test
package/README.md CHANGED
@@ -15,18 +15,22 @@ ip2geo
15
15
  ip2geo 1.1.1.1
16
16
  # {
17
17
  # ip: '1.1.1.1',
18
- # emoji: 'πŸ‡ΊπŸ‡Έ',
18
+ # continent: 'North America',
19
+ # continentCode: 'NA',
19
20
  # country: 'United States',
20
- # countryA2: 'US',
21
+ # countryCode: 'US',
22
+ # countryEmoji: 'πŸ‡ΊπŸ‡Έ',
21
23
  # region: 'District of Columbia',
24
+ # regionCode: 'DC',
22
25
  # city: 'Washington',
23
- # org: 'APNIC and Cloudflare DNS Resolver project',
24
- # isp: 'Cloudflare, Inc.',
25
- # ispDomain: 'cloudflare.com'
26
+ # connectionAsn: 13335,
27
+ # connectionOrg: 'APNIC and Cloudflare DNS Resolver project',
28
+ # connectionIsp: 'Cloudflare, Inc.',
29
+ # connectionDomain: 'cloudflare.com'
26
30
  # }
27
31
 
28
32
  ip2geo 1.1.1.1 8.8.8.8 --json
29
- # [{"ip":"1.1.1.1","emoji":"πŸ‡ΊπŸ‡Έ","country":"United States","countryA2":"US","region":"District of Columbia","city":"Washington","org":"APNIC and Cloudflare DNS Resolver project","isp":"Cloudflare, Inc.","ispDomain":"cloudflare.com"},{"ip":"8.8.8.8","emoji":"πŸ‡ΊπŸ‡Έ","country":"United States","countryA2":"US","region":"California","city":"Mountain View","org":"Google LLC","isp":"Google LLC","ispDomain":"google.com"}]
33
+ # [{"ip":"1.1.1.1","continent":"North America","continentCode":"NA","country":"United States","countryCode":"US","countryEmoji":"πŸ‡ΊπŸ‡Έ","region":"District of Columbia","regionCode":"DC","city":"Washington","connectionAsn":13335,"connectionOrg":"APNIC and Cloudflare DNS Resolver project","connectionIsp":"Cloudflare, Inc.","connectionDomain":"cloudflare.com"},{"ip":"8.8.8.8","continent":"North America","continentCode":"NA","country":"United States","countryCode":"US","countryEmoji":"πŸ‡ΊπŸ‡Έ","region":"California","regionCode":"CA","city":"Mountain View","connectionAsn":15169,"connectionOrg":"Google LLC","connectionIsp":"Google LLC","connectionDomain":"google.com"}]
30
34
  ```
31
35
 
32
36
  ## API
@@ -38,7 +42,8 @@ npm i @k03mad/ip2geo
38
42
  ```js
39
43
  import {ip2geo} from '@k03mad/ip2geo';
40
44
 
41
- const info = await ip2geo('1.1.1.1', {
45
+ const info = await ip2geo({
46
+ ip: '1.1.1.1', // make key falsy to use current external IP
42
47
  // defaults
43
48
  cacheDir: path.join(os.tmpdir(), '.ip2geo'),
44
49
  cacheFileName: 'ips.log',
@@ -51,13 +56,17 @@ const info = await ip2geo('1.1.1.1', {
51
56
 
52
57
  // info {
53
58
  // ip: '1.1.1.1',
54
- // emoji: 'πŸ‡ΊπŸ‡Έ',
59
+ // continent: 'North America',
60
+ // continentCode: 'NA',
55
61
  // country: 'United States',
56
- // countryA2: 'US',
62
+ // countryCode: 'US',
63
+ // countryEmoji: 'πŸ‡ΊπŸ‡Έ',
57
64
  // region: 'District of Columbia',
65
+ // regionCode: 'DC',
58
66
  // city: 'Washington',
59
- // org: 'APNIC and Cloudflare DNS Resolver project',
60
- // isp: 'Cloudflare, Inc.',
61
- // ispDomain: 'cloudflare.com'
67
+ // connectionAsn: 13335,
68
+ // connectionOrg: 'APNIC and Cloudflare DNS Resolver project',
69
+ // connectionIsp: 'Cloudflare, Inc.',
70
+ // connectionDomain: 'cloudflare.com'
62
71
  // }
63
72
  ```
package/app/cli.js CHANGED
@@ -10,26 +10,30 @@ const args = process.argv.slice(2);
10
10
  const argsIps = args.filter(arg => !arg.startsWith('-'));
11
11
 
12
12
  if (args.includes('-h') || args.includes('--help')) {
13
- const prefix = codeText('$');
14
- const name = nameText('ip2geo');
15
- const json = codeText('// json output for parse');
16
- const multi = codeText('// multi IPs');
13
+ const cmd = `${codeText('$')} ${nameText('ip2geo')}`;
17
14
 
18
15
  log([
19
16
  '',
20
- `${prefix} ${name}`,
21
- `${prefix} ${name} 1.1.1.1`,
22
- `${prefix} ${name} 1.1.1.1 -j ${json}`,
23
- `${prefix} ${name} 1.1.1.1 --json ${json}`,
24
- `${prefix} ${name} 1.1.1.1 8.8.8.8 ${multi}`,
25
- `${prefix} ${name} 1.1.1.1,8.8.8.8 ${multi}`,
17
+ `${cmd} ${codeText('# current external ip')}`,
18
+ `${cmd} 1.1.1.1`,
19
+ '',
20
+ `${cmd} -h`,
21
+ `${cmd} --help`,
22
+ '',
23
+ `${cmd} 1.1.1.1 -j`,
24
+ `${cmd} 1.1.1.1 --json`,
25
+ '',
26
+ `${cmd} 1.1.1.1 8.8.8.8`,
27
+ `${cmd} 1.1.1.1,8.8.8.8`,
26
28
  '',
27
29
  ]);
30
+
31
+ process.exit(0);
28
32
  }
29
33
 
30
34
  const output = argsIps.length === 0
31
35
  ? [await ip2geo()]
32
- : await Promise.all(argsIps.map(arg => Promise.all(arg.split(',').map(ip => ip2geo(ip)))));
36
+ : await Promise.all(argsIps.map(arg => Promise.all(arg.split(',').map(ip => ip2geo({ip})))));
33
37
 
34
38
  const flatten = output.flat();
35
39
 
@@ -0,0 +1,151 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+
4
+ import _debug from 'debug';
5
+
6
+ const debug = _debug('mad:geoip');
7
+
8
+ const outputKeys = [
9
+ 'ip',
10
+ 'continent',
11
+ 'continentCode',
12
+ 'country',
13
+ 'countryCode',
14
+ 'countryEmoji',
15
+ 'region',
16
+ 'regionCode',
17
+ 'city',
18
+ 'connectionAsn',
19
+ 'connectionOrg',
20
+ 'connectionIsp',
21
+ 'connectionDomain',
22
+ ];
23
+
24
+ /**
25
+ * @param {Array<string>} dataArr
26
+ * @returns {object}
27
+ */
28
+ export const collectOutputData = dataArr => {
29
+ const outputData = {};
30
+
31
+ outputKeys.forEach((key, i) => {
32
+ outputData[key] = dataArr[i];
33
+ });
34
+
35
+ return outputData;
36
+ };
37
+
38
+ /**
39
+ * @param {string} ip
40
+ * @param {string} cacheDir
41
+ * @param {string} cacheFileName
42
+ * @returns {string}
43
+ */
44
+ const getCacheFileFullPath = (ip, cacheDir, cacheFileName) => {
45
+ const [firstOctet] = ip.split(/\.|:/);
46
+ return path.join(cacheDir, `${firstOctet}_${cacheFileName}`);
47
+ };
48
+
49
+ /**
50
+ * @param {string} ip
51
+ * @param {string} cacheDir
52
+ * @param {string} cacheFileName
53
+ * @param {string} cacheFileSeparator
54
+ * @param {string} cacheFileNewline
55
+ * @returns {Promise<object>}
56
+ */
57
+ export const readFromFsCache = async (ip, cacheDir, cacheFileName, cacheFileSeparator, cacheFileNewline) => {
58
+ const cacheFileFull = getCacheFileFullPath(ip, cacheDir, cacheFileName);
59
+
60
+ try {
61
+ await fs.mkdir(cacheDir, {recursive: true});
62
+ const content = await fs.readFile(cacheFileFull, {encoding: 'utf8'});
63
+
64
+ if (content) {
65
+ const data = content.split(cacheFileNewline);
66
+
67
+ for (const elem of data) {
68
+ const fileData = elem.split(cacheFileSeparator);
69
+
70
+ if (ip === fileData[0]) {
71
+ const outputData = collectOutputData(fileData);
72
+ debug('get from fs cache: %o %o', cacheFileFull, outputData);
73
+ return outputData;
74
+ }
75
+ }
76
+ }
77
+ } catch (err) {
78
+ if (err.code === 'ENOENT') {
79
+ await fs.appendFile(cacheFileFull, '');
80
+ } else {
81
+ throw err;
82
+ }
83
+ }
84
+ };
85
+
86
+ /**
87
+ * @param {string} ip
88
+ * @param {object} data
89
+ * @param {string} cacheDir
90
+ * @param {string} cacheFileName
91
+ * @param {string} cacheFileSeparator
92
+ * @param {string} cacheFileNewline
93
+ * @returns {Promise<void>}
94
+ */
95
+ export const writeToFsCache = async (ip, data, cacheDir, cacheFileName, cacheFileSeparator, cacheFileNewline) => {
96
+ const cacheFileFull = getCacheFileFullPath(ip, cacheDir, cacheFileName);
97
+
98
+ await fs.mkdir(cacheDir, {recursive: true});
99
+ await fs.appendFile(cacheFileFull, Object.values(data).join(cacheFileSeparator) + cacheFileNewline);
100
+
101
+ debug('set to fs cache: %o %o', cacheFileFull, data);
102
+ };
103
+
104
+ /**
105
+ * @param {string} ip
106
+ * @param {Map} cacheMap
107
+ * @param {number} cacheMapMaxEntries
108
+ * @returns {object|undefined}
109
+ */
110
+ export const readFromMapCache = (ip, cacheMap, cacheMapMaxEntries) => {
111
+ if (cacheMapMaxEntries > 0) {
112
+ const mapCache = cacheMap.get(ip);
113
+
114
+ if (mapCache) {
115
+ debug('get from map cache: %o', mapCache);
116
+ return mapCache;
117
+ }
118
+ }
119
+ };
120
+
121
+ /**
122
+ * @param {object} body
123
+ * @param {string} body.ip
124
+ * @param {Map} cacheMap
125
+ * @param {number} cacheMapMaxEntries
126
+ */
127
+ export const writeToMapCache = (body, cacheMap, cacheMapMaxEntries) => {
128
+ if (cacheMapMaxEntries > 0) {
129
+ cacheMap.set(body.ip, body);
130
+ debug('set to map cache: %o', body);
131
+ }
132
+ };
133
+
134
+ /**
135
+ * @param {Map} cacheMap
136
+ * @param {number} cacheMapMaxEntries
137
+ */
138
+ export const removeFromMapCacheIfLimit = (cacheMap, cacheMapMaxEntries) => {
139
+ if (cacheMap.size > cacheMapMaxEntries) {
140
+ debug('remove from map cache by limit: size %o, limit: %o', cacheMap.size, cacheMapMaxEntries);
141
+
142
+ for (const [key] of cacheMap) {
143
+ debug('remove from map cache by limit: key %o', key);
144
+ cacheMap.delete(key);
145
+
146
+ if (cacheMap.size <= cacheMapMaxEntries) {
147
+ break;
148
+ }
149
+ }
150
+ }
151
+ };
package/app/lib/ip2geo.js CHANGED
@@ -1,14 +1,44 @@
1
- import fs from 'node:fs/promises';
2
1
  import os from 'node:os';
3
2
  import path from 'node:path';
4
3
 
5
4
  import {request} from '@k03mad/request';
6
- import _debug from 'debug';
5
+ import {logErrorExit} from '@k03mad/simple-log';
7
6
 
8
- const debug = _debug('mad:geoip');
7
+ import {
8
+ collectOutputData,
9
+ readFromFsCache,
10
+ readFromMapCache,
11
+ removeFromMapCacheIfLimit,
12
+ writeToFsCache,
13
+ writeToMapCache,
14
+ } from '../helpers/cache.js';
15
+
16
+ const API = 'https://ipwho.is/';
17
+
18
+ export const DEFAULT_CACHE_FILE_DIR = path.join(os.tmpdir(), '.ip2geo-cache');
19
+ export const DEFAULT_CACHE_FILE_NAME = 'ip.log';
20
+ export const DEFAULT_CACHE_FILE_SEPARATOR = ';;';
21
+ export const DEFAULT_CACHE_FILE_NEWLINE = '\n';
22
+ export const DEFAULT_CACHE_MAP_MAX_ENTRIES = Number.POSITIVE_INFINITY;
23
+ export const DEFAULT_RPS = 3;
24
+
25
+ export const cacheStorage = new Map();
9
26
 
10
27
  /**
11
- * @typedef {object} GeoIpOutput
28
+ * @typedef {object} ReqInput
29
+ * @property {object} [opts]
30
+ * @property {object} [opts.ip]
31
+ * @property {string} [opts.cacheDir]
32
+ * @property {string} [opts.cacheFileName]
33
+ * @property {string} [opts.cacheFileSeparator]
34
+ * @property {string} [opts.cacheFileNewline]
35
+ * @property {Map} [opts.cacheMap]
36
+ * @property {number} [opts.cacheMapMaxEntries]
37
+ * @property {number} [opts.rps]
38
+ */
39
+
40
+ /**
41
+ * @typedef {object} ReqOutput
12
42
  * @property {string} [ip]
13
43
  * @property {string} [emoji]
14
44
  * @property {string} [country]
@@ -20,104 +50,12 @@ const debug = _debug('mad:geoip');
20
50
  * @property {string} [ispDomain]
21
51
  */
22
52
 
23
- const API = 'https://ipwho.is/';
24
-
25
- const DEFAULT_CACHE_FILE_DIR = path.join(os.tmpdir(), '.ip2geo');
26
- const DEFAULT_CACHE_FILE_NAME = 'ips.log';
27
- const DEFAULT_CACHE_FILE_SEPARATOR = ';;';
28
- const DEFAULT_CACHE_FILE_NEWLINE = '\n';
29
- const DEFAULT_CACHE_MAP_MAX_ENTRIES = Number.POSITIVE_INFINITY;
30
- const DEFAULT_RPS = 3;
31
-
32
- export const cacheStorage = new Map();
33
-
34
- const outputKeys = [
35
- 'ip',
36
- 'emoji',
37
- 'country',
38
- 'countryA2',
39
- 'region',
40
- 'city',
41
- 'org',
42
- 'isp',
43
- 'ispDomain',
44
- ];
45
-
46
- /**
47
- * @param {Array<string>} dataArr
48
- * @returns {GeoIpOutput}
49
- */
50
- const collectOutputData = dataArr => {
51
- const outputData = {};
52
-
53
- outputKeys.forEach((key, i) => {
54
- outputData[key] = dataArr[i];
55
- });
56
-
57
- return outputData;
58
- };
59
-
60
- /**
61
- * @param {string} ip
62
- * @param {string} cacheDir
63
- * @param {string} cacheFileName
64
- * @returns {string}
65
- */
66
- const getCacheFileFullPath = (ip, cacheDir, cacheFileName) => {
67
- const [firstOctet] = ip.split(/\.|:/);
68
- return path.join(cacheDir, `${firstOctet}_${cacheFileName}`);
69
- };
70
-
71
53
  /**
72
- * @param {string} ip
73
- * @param {string} cacheDir
74
- * @param {string} cacheFileName
75
- * @returns {Promise<string>}
54
+ * @param {ReqInput} opts
55
+ * @returns {Promise<ReqOutput>}
76
56
  */
77
- const readFromFsCache = async (ip, cacheDir, cacheFileName) => {
78
- try {
79
- await fs.mkdir(cacheDir, {recursive: true});
80
- return await fs.readFile(getCacheFileFullPath(ip, cacheDir, cacheFileName), {encoding: 'utf8'});
81
- } catch (err) {
82
- if (err.code === 'ENOENT') {
83
- await fs.appendFile(getCacheFileFullPath(ip, cacheDir, cacheFileName), '');
84
- } else {
85
- throw err;
86
- }
87
- }
88
- };
89
-
90
- /**
91
- * @param {string} ip
92
- * @param {Array[string]} data
93
- * @param {string} cacheDir
94
- * @param {string} cacheFileName
95
- * @param {string} cacheFileSeparator
96
- * @param {string} cacheFileNewline
97
- * @returns {Promise<void>}
98
- */
99
- const writeToFsCache = async (ip, data, cacheDir, cacheFileName, cacheFileSeparator, cacheFileNewline) => {
100
- await fs.mkdir(cacheDir, {recursive: true});
101
-
102
- await fs.appendFile(
103
- getCacheFileFullPath(ip, cacheDir, cacheFileName),
104
- data.join(cacheFileSeparator) + cacheFileNewline,
105
- );
106
- };
107
-
108
- /**
109
- * @param {string} [ip]
110
- * @param {object} [opts]
111
- * @param {string} [opts.cacheDir]
112
- * @param {string} [opts.cacheFileName]
113
- * @param {string} [opts.cacheFileSeparator]
114
- * @param {string} [opts.cacheFileNewline]
115
- * @param {Map} [opts.cacheMap]
116
- * @param {number} [opts.cacheMapMaxEntries]
117
- * @param {number} [opts.rps]
118
- * @returns {Promise<GeoIpOutput>}
119
- */
120
- export const ip2geo = async (ip = '', {
57
+ export const ip2geo = async ({
58
+ ip = '',
121
59
  cacheDir = DEFAULT_CACHE_FILE_DIR,
122
60
  cacheFileName = DEFAULT_CACHE_FILE_NAME,
123
61
  cacheFileSeparator = DEFAULT_CACHE_FILE_SEPARATOR,
@@ -127,82 +65,50 @@ export const ip2geo = async (ip = '', {
127
65
  rps = DEFAULT_RPS,
128
66
  } = {}) => {
129
67
  if (ip) {
130
- if (cacheMapMaxEntries > 0) {
131
- const ipData = cacheMap.get(ip);
68
+ const mapCache = readFromMapCache(ip, cacheMap, cacheMapMaxEntries);
132
69
 
133
- if (ipData) {
134
- debug('get from map cache: %o', ipData);
135
- return ipData;
136
- }
70
+ if (mapCache) {
71
+ return mapCache;
137
72
  }
138
73
 
139
74
  const fsCache = await readFromFsCache(ip, cacheDir, cacheFileName);
140
75
 
141
76
  if (fsCache) {
142
- const data = fsCache.split(cacheFileNewline);
143
-
144
- for (const elem of data) {
145
- const fileData = elem.split(cacheFileSeparator);
146
-
147
- if (ip === fileData[0]) {
148
- const outputData = collectOutputData(fileData);
149
- debug('get from fs cache: %o', outputData);
150
-
151
- if (cacheMapMaxEntries > 0) {
152
- cacheMap.set(ip, outputData);
153
- debug('set to map cache: %o', outputData);
154
- }
155
-
156
- return outputData;
157
- }
158
- }
77
+ writeToMapCache(fsCache, cacheMap, cacheMapMaxEntries);
78
+ return fsCache;
159
79
  }
160
80
  }
161
81
 
162
- const {body} = await request(API + ip, {}, {rps});
82
+ const reqUrl = API + ip;
83
+ const {body} = await request(reqUrl, {}, {rps});
163
84
 
164
85
  if (!body?.ip) {
165
- throw new Error(`API error:\n${body}`);
86
+ logErrorExit(['API error', `request: ${reqUrl}`, `response body: ${body}`]);
166
87
  }
167
88
 
168
- const usedData = [
89
+ const outputData = collectOutputData([
169
90
  body.ip,
170
- body?.flag?.emoji,
91
+ body?.continent,
92
+ body?.continent_code,
171
93
  body?.country,
172
94
  body?.country_code,
95
+ body?.flag?.emoji,
173
96
  body?.region,
97
+ body?.region_code,
174
98
  body?.city,
99
+ body?.connection?.asn,
175
100
  body?.connection?.org,
176
101
  body?.connection?.isp,
177
102
  body?.connection?.domain,
178
- ];
179
-
180
- const outputData = collectOutputData(usedData);
103
+ ]);
181
104
 
182
- if (cacheMapMaxEntries > 0) {
183
- cacheMap.set(body.ip, outputData);
184
- debug('set to map cache: %o', outputData);
185
- }
105
+ writeToMapCache(outputData, cacheMap, cacheMapMaxEntries);
106
+ removeFromMapCacheIfLimit(cacheMap, cacheMapMaxEntries);
186
107
 
187
108
  await writeToFsCache(
188
- body.ip, usedData,
109
+ body.ip, outputData,
189
110
  cacheDir, cacheFileName, cacheFileSeparator, cacheFileNewline,
190
111
  );
191
112
 
192
- debug('set to fs cache: %o', outputData);
193
-
194
- if (cacheMap.size > cacheMapMaxEntries) {
195
- debug('remove from map cache by limit: size %o, limit: %o', cacheMap.size, cacheMapMaxEntries);
196
-
197
- for (const [key] of cacheMap) {
198
- debug('remove from map cache by limit: key %o', key);
199
- cacheMap.delete(key);
200
-
201
- if (cacheMap.size <= cacheMapMaxEntries) {
202
- break;
203
- }
204
- }
205
- }
206
-
207
113
  return outputData;
208
114
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k03mad/ip2geo",
3
- "version": "5.0.1",
3
+ "version": "6.0.0",
4
4
  "description": "GeoIP library",
5
5
  "maintainers": [
6
6
  "Kirill Molchanov <k03.mad@gmail.com"
@@ -25,9 +25,9 @@
25
25
  "debug": "4.3.4"
26
26
  },
27
27
  "devDependencies": {
28
- "@k03mad/eslint-config": "19.5.0",
28
+ "@k03mad/eslint-config": "20.2.0",
29
29
  "eslint": "8.56.0",
30
- "husky": "8.0.3",
30
+ "husky": "9.0.5",
31
31
  "mocha": "10.2.0"
32
32
  },
33
33
  "scripts": {
@@ -38,6 +38,6 @@
38
38
  "clean:modules": "rm -rf ./node_modules || true",
39
39
  "clean:eslint:cache": "rm -rf .eslintcache || true",
40
40
  "setup": "npm run clean && pnpm i",
41
- "prepare": "husky install || true"
41
+ "prepare": "husky || true"
42
42
  }
43
43
  }
@@ -22,7 +22,7 @@ describe(testName, () => {
22
22
  it('should remove fs cache dir if exist', () => removeCacheFolder(opts.cacheDir));
23
23
 
24
24
  it(`should return correct response for IP: "${REQUEST_IPV4.ip}"`, async () => {
25
- const data = await ip2geo(REQUEST_IPV4.ip, opts);
25
+ const data = await ip2geo({ip: REQUEST_IPV4.ip, ...opts});
26
26
  assert.deepEqual(data, REQUEST_IPV4);
27
27
  });
28
28
 
@@ -26,7 +26,7 @@ describe(testName, () => {
26
26
  it('should remove fs cache dir if exist', () => removeCacheFolder(opts.cacheDir));
27
27
 
28
28
  it(`should return correct response for IP: "${REQUEST_IPV4.ip}"`, async () => {
29
- const data = await ip2geo(REQUEST_IPV4.ip, opts);
29
+ const data = await ip2geo({ip: REQUEST_IPV4.ip, ...opts});
30
30
  assert.deepEqual(data, REQUEST_IPV4);
31
31
  });
32
32
 
@@ -19,7 +19,7 @@ describe(testName, () => {
19
19
  it('should remove fs cache dir if exist', () => removeCacheFolder(opts.cacheDir));
20
20
 
21
21
  it(`should return correct response for IP: "${REQUEST_IPV4.ip}"`, async () => {
22
- const data = await ip2geo(REQUEST_IPV4.ip, opts);
22
+ const data = await ip2geo({ip: REQUEST_IPV4.ip, ...opts});
23
23
  assert.deepEqual(data, REQUEST_IPV4);
24
24
  });
25
25
 
@@ -29,7 +29,7 @@ describe(testName, () => {
29
29
  });
30
30
 
31
31
  it(`should return correct response for IP: "${REQUEST_IPV6.ip}"`, async () => {
32
- const data = await ip2geo(REQUEST_IPV6.ip, opts);
32
+ const data = await ip2geo({ip: REQUEST_IPV6.ip, ...opts});
33
33
  assert.deepEqual(data, REQUEST_IPV6);
34
34
  });
35
35
 
@@ -30,7 +30,7 @@ describe(testName, () => {
30
30
 
31
31
  firstReqIps.forEach(ip => {
32
32
  it(`should request geo for IP: "${ip}"`, async () => {
33
- await ip2geo(ip, opts);
33
+ await ip2geo({ip, ...opts});
34
34
  });
35
35
  });
36
36
 
@@ -41,7 +41,7 @@ describe(testName, () => {
41
41
 
42
42
  secondReqIps.forEach(ip => {
43
43
  it(`should request geo for IP: "${ip}"`, async () => {
44
- await ip2geo(ip, opts);
44
+ await ip2geo({ip, ...opts});
45
45
  });
46
46
  });
47
47
 
@@ -19,7 +19,7 @@ describe(testName, () => {
19
19
  it('should remove fs cache dir if exist', () => removeCacheFolder(opts.cacheDir));
20
20
 
21
21
  it(`should return correct response for IP: "${REQUEST_IPV4_MAP_OFF_ONLY.ip}"`, async () => {
22
- const data = await ip2geo(REQUEST_IPV4_MAP_OFF_ONLY.ip, opts);
22
+ const data = await ip2geo({ip: REQUEST_IPV4_MAP_OFF_ONLY.ip, ...opts});
23
23
  assert.deepEqual(data, REQUEST_IPV4_MAP_OFF_ONLY);
24
24
  });
25
25
 
package/tests/default.js CHANGED
@@ -15,7 +15,7 @@ describe(testName, () => {
15
15
 
16
16
  describe('with ip arg', () => {
17
17
  it(`should return correct response for IP: "${REQUEST_IPV4.ip}"`, async () => {
18
- const data = await ip2geo(REQUEST_IPV4.ip);
18
+ const data = await ip2geo({ip: REQUEST_IPV4.ip});
19
19
  assert.deepEqual(data, REQUEST_IPV4);
20
20
  });
21
21
 
@@ -1,45 +1,47 @@
1
- import os from 'node:os';
2
- import path from 'node:path';
3
-
4
- export const DEFAULT_OPTS = {
5
- cacheDir: path.join(os.tmpdir(), '.ip2geo'),
6
- cacheFileName: 'ips.log',
7
- cacheFileSeparator: ';;',
8
- cacheFileNewline: '\n',
9
- };
10
-
11
1
  export const REQUEST_IPV4 = {
12
2
  ip: '8.8.8.8',
13
- emoji: 'πŸ‡ΊπŸ‡Έ',
3
+ continent: 'North America',
4
+ continentCode: 'NA',
14
5
  country: 'United States',
15
- countryA2: 'US',
6
+ countryCode: 'US',
7
+ countryEmoji: 'πŸ‡ΊπŸ‡Έ',
16
8
  region: 'California',
9
+ regionCode: 'CA',
17
10
  city: 'Mountain View',
18
- org: 'Google LLC',
19
- isp: 'Google LLC',
20
- ispDomain: 'google.com',
11
+ connectionAsn: 15_169,
12
+ connectionOrg: 'Google LLC',
13
+ connectionIsp: 'Google LLC',
14
+ connectionDomain: 'google.com',
21
15
  };
22
16
 
23
17
  export const REQUEST_IPV4_MAP_OFF_ONLY = {
24
18
  ip: '1.1.1.1',
25
- emoji: 'πŸ‡ΊπŸ‡Έ',
19
+ continent: 'North America',
20
+ continentCode: 'NA',
26
21
  country: 'United States',
27
- countryA2: 'US',
22
+ countryCode: 'US',
23
+ countryEmoji: 'πŸ‡ΊπŸ‡Έ',
28
24
  region: 'District of Columbia',
25
+ regionCode: 'DC',
29
26
  city: 'Washington',
30
- org: 'APNIC and Cloudflare DNS Resolver project',
31
- isp: 'Cloudflare, Inc.',
32
- ispDomain: 'cloudflare.com',
27
+ connectionAsn: 13_335,
28
+ connectionOrg: 'APNIC and Cloudflare DNS Resolver project',
29
+ connectionIsp: 'Cloudflare, Inc.',
30
+ connectionDomain: 'cloudflare.com',
33
31
  };
34
32
 
35
33
  export const REQUEST_IPV6 = {
36
34
  ip: '2a00:dd80:40:100::',
37
- emoji: 'πŸ‡³πŸ‡±',
35
+ continent: 'Europe',
36
+ continentCode: 'EU',
38
37
  country: 'Netherlands',
39
- countryA2: 'NL',
38
+ countryCode: 'NL',
39
+ countryEmoji: 'πŸ‡³πŸ‡±',
40
40
  region: 'North Holland',
41
+ regionCode: 'NH',
41
42
  city: 'Amsterdam',
42
- org: '',
43
- isp: 'NetActuate Inc',
44
- ispDomain: '',
43
+ connectionAsn: 0,
44
+ connectionOrg: '',
45
+ connectionIsp: 'NetActuate Inc',
46
+ connectionDomain: '',
45
47
  };
@@ -21,7 +21,7 @@ describe(testName, () => {
21
21
 
22
22
  Array.from({length: opts.requestsCount}).forEach(() => {
23
23
  it(`should return correct response for IP: "${REQUEST_IPV4.ip}"`, async () => {
24
- const data = await ip2geo(REQUEST_IPV4.ip, opts);
24
+ const data = await ip2geo({ip: REQUEST_IPV4.ip, ...opts});
25
25
  assert.deepEqual(data, REQUEST_IPV4);
26
26
  });
27
27
  });
@@ -31,7 +31,7 @@ describe(testName, () => {
31
31
  });
32
32
 
33
33
  it(`should return empty response for IP: "${response.ip}"`, async () => {
34
- const data = await ip2geo(response.ip, opts);
34
+ const data = await ip2geo({ip: response.ip, ...opts});
35
35
  assert.deepEqual(data, response);
36
36
  });
37
37
  });
package/tests/ip-v6.js CHANGED
@@ -19,7 +19,7 @@ describe(testName, () => {
19
19
  it('should remove fs cache dir if exist', () => removeCacheFolder(opts.cacheDir));
20
20
 
21
21
  it(`should return correct response for IP: "${REQUEST_IPV6.ip}"`, async () => {
22
- const data = await ip2geo(REQUEST_IPV6.ip, opts);
22
+ const data = await ip2geo({ip: REQUEST_IPV6.ip, ...opts});
23
23
  assert.deepEqual(data, REQUEST_IPV6);
24
24
  });
25
25
 
@@ -2,12 +2,17 @@ import assert from 'node:assert/strict';
2
2
  import fs from 'node:fs/promises';
3
3
  import path from 'node:path';
4
4
 
5
- import {DEFAULT_OPTS} from '../helpers/consts.js';
5
+ import {
6
+ DEFAULT_CACHE_FILE_DIR,
7
+ DEFAULT_CACHE_FILE_NAME,
8
+ DEFAULT_CACHE_FILE_NEWLINE,
9
+ DEFAULT_CACHE_FILE_SEPARATOR,
10
+ } from '../../app/index.js';
6
11
 
7
12
  /**
8
13
  * @param {string} cacheDir
9
14
  */
10
- export const removeCacheFolder = async (cacheDir = DEFAULT_OPTS.cacheDir) => {
15
+ export const removeCacheFolder = async (cacheDir = DEFAULT_CACHE_FILE_DIR) => {
11
16
  try {
12
17
  await fs.rm(cacheDir, {recursive: true, force: true});
13
18
  } catch (err) {
@@ -26,10 +31,10 @@ export const removeCacheFolder = async (cacheDir = DEFAULT_OPTS.cacheDir) => {
26
31
  * @param {object} opts.response
27
32
  */
28
33
  export const checkCacheFile = async ({
29
- cacheDir = DEFAULT_OPTS.cacheDir,
30
- cacheFileName = DEFAULT_OPTS.cacheFileName,
31
- cacheFileSeparator = DEFAULT_OPTS.cacheFileSeparator,
32
- cacheFileNewline = DEFAULT_OPTS.cacheFileNewline,
34
+ cacheDir = DEFAULT_CACHE_FILE_DIR,
35
+ cacheFileName = DEFAULT_CACHE_FILE_NAME,
36
+ cacheFileSeparator = DEFAULT_CACHE_FILE_SEPARATOR,
37
+ cacheFileNewline = DEFAULT_CACHE_FILE_NEWLINE,
33
38
  response,
34
39
  }) => {
35
40
  const cacheFile = `${response.ip.split(/\.|:/)[0]}_${cacheFileName}`;