@k03mad/ip2geo 2.0.0 → 2.2.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 +36 -16
- package/app/cli.js +39 -0
- package/app/helpers/array.js +5 -0
- package/app/helpers/colors.js +6 -0
- package/app/helpers/logging.js +26 -0
- package/app/lib/ip2geo.js +2 -2
- package/package.json +5 -1
- package/tests/helpers/path.js +7 -0
- package/tests/opts-assigned-ipv6.js +50 -0
- package/tests/opts-assigned-subfolder.js +11 -3
- package/tests/opts-assigned.js +6 -3
- package/tests/opts-default.js +2 -2
package/README.md
CHANGED
|
@@ -4,35 +4,55 @@
|
|
|
4
4
|
— Runtime cache \
|
|
5
5
|
— Filesystem infinity cache
|
|
6
6
|
|
|
7
|
+
## Global
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm i @k03mad/ip2geo -g
|
|
11
|
+
|
|
12
|
+
ip2geo 1.1.1.1
|
|
13
|
+
# {
|
|
14
|
+
# ip: '1.1.1.1',
|
|
15
|
+
# emoji: '🇺🇸',
|
|
16
|
+
# country: 'United States',
|
|
17
|
+
# countryA2: 'US',
|
|
18
|
+
# region: 'District of Columbia',
|
|
19
|
+
# city: 'Washington',
|
|
20
|
+
# org: 'APNIC and Cloudflare DNS Resolver project',
|
|
21
|
+
# isp: 'Cloudflare, Inc.',
|
|
22
|
+
# ispDomain: 'cloudflare.com'
|
|
23
|
+
# }
|
|
24
|
+
|
|
25
|
+
ip2geo 1.1.1.1 --json
|
|
26
|
+
# {"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"}
|
|
27
|
+
```
|
|
28
|
+
|
|
7
29
|
## API
|
|
8
30
|
|
|
9
31
|
```bash
|
|
10
32
|
npm i @k03mad/ip2geo --save-exact
|
|
11
|
-
echo
|
|
33
|
+
echo .geoip >> .gitignore
|
|
12
34
|
```
|
|
13
35
|
|
|
14
36
|
```js
|
|
15
37
|
import {ip2geo} from '@k03mad/ip2geo';
|
|
16
38
|
|
|
17
|
-
const {
|
|
18
|
-
ip,
|
|
19
|
-
emoji,
|
|
20
|
-
country,
|
|
21
|
-
countryA2,
|
|
22
|
-
city,
|
|
23
|
-
isp,
|
|
24
|
-
} = await ip2geo('1.1.1.1', {
|
|
39
|
+
const info = await ip2geo('1.1.1.1', {
|
|
25
40
|
// defaults
|
|
26
|
-
cacheDir: 'geoip',
|
|
41
|
+
cacheDir: '.geoip',
|
|
27
42
|
cacheFileName: 'ips.log',
|
|
28
43
|
cacheFileSeparator: ';;',
|
|
29
44
|
cacheFileNewline: '\n',
|
|
30
45
|
});
|
|
31
46
|
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
47
|
+
// info {
|
|
48
|
+
// ip: '1.1.1.1',
|
|
49
|
+
// emoji: '🇺🇸',
|
|
50
|
+
// country: 'United States',
|
|
51
|
+
// countryA2: 'US',
|
|
52
|
+
// region: 'District of Columbia',
|
|
53
|
+
// city: 'Washington',
|
|
54
|
+
// org: 'APNIC and Cloudflare DNS Resolver project',
|
|
55
|
+
// isp: 'Cloudflare, Inc.',
|
|
56
|
+
// ispDomain: 'cloudflare.com'
|
|
57
|
+
// }
|
|
38
58
|
```
|
package/app/cli.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import {codeText, errorText, nameText} from './helpers/colors.js';
|
|
4
|
+
import {log, throwError} from './helpers/logging.js';
|
|
5
|
+
|
|
6
|
+
import {ip2geo} from './index.js';
|
|
7
|
+
|
|
8
|
+
const jsonParam = '--json';
|
|
9
|
+
|
|
10
|
+
let args = process.argv.slice(2);
|
|
11
|
+
|
|
12
|
+
if (args.length === 0) {
|
|
13
|
+
const prefix = codeText('$');
|
|
14
|
+
const name = nameText('ip2geo');
|
|
15
|
+
|
|
16
|
+
throwError([
|
|
17
|
+
errorText('IP(s) should be passed as args'),
|
|
18
|
+
'',
|
|
19
|
+
`${prefix} ${name} 1.1.1.1`,
|
|
20
|
+
`${prefix} ${name} 1.1.1.1 8.8.8.8`,
|
|
21
|
+
]);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let json;
|
|
25
|
+
|
|
26
|
+
if (args.includes(jsonParam)) {
|
|
27
|
+
json = true;
|
|
28
|
+
args = args.filter(elem => elem !== jsonParam);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
await Promise.all(args.map(async arg => {
|
|
32
|
+
const output = await ip2geo(arg);
|
|
33
|
+
|
|
34
|
+
if (json) {
|
|
35
|
+
return log(JSON.stringify(output));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
log(output);
|
|
39
|
+
}));
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
|
|
3
|
+
import {convertToArray} from './array.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {any|any[]} msg
|
|
7
|
+
* @returns {void}
|
|
8
|
+
*/
|
|
9
|
+
export const log = msg => convertToArray(msg)
|
|
10
|
+
.forEach(elem => console.log(elem));
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param {any|any[]} msg
|
|
14
|
+
* @returns {void}
|
|
15
|
+
*/
|
|
16
|
+
export const logError = msg => convertToArray(msg)
|
|
17
|
+
.forEach(elem => console.error(elem));
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {any|any[]} msg
|
|
21
|
+
* @returns {void}
|
|
22
|
+
*/
|
|
23
|
+
export const throwError = msg => {
|
|
24
|
+
logError(msg);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
};
|
package/app/lib/ip2geo.js
CHANGED
|
@@ -21,7 +21,7 @@ const debug = _debug('mad:geoip');
|
|
|
21
21
|
|
|
22
22
|
const API = 'https://ipwho.is/';
|
|
23
23
|
|
|
24
|
-
const DEFAULT_CACHE_FILE_DIR = 'geoip';
|
|
24
|
+
const DEFAULT_CACHE_FILE_DIR = '.geoip';
|
|
25
25
|
const DEFAULT_CACHE_FILE_NAME = 'ips.log';
|
|
26
26
|
const DEFAULT_CACHE_FILE_SEPARATOR = ';;';
|
|
27
27
|
const DEFAULT_CACHE_FILE_NEWLINE = '\n';
|
|
@@ -61,7 +61,7 @@ const collectOutputData = dataArr => {
|
|
|
61
61
|
* @returns {string}
|
|
62
62
|
*/
|
|
63
63
|
const getCacheFileFullPath = (ip, cacheDir, cacheFileName) => {
|
|
64
|
-
const [firstOctet] = ip.split(
|
|
64
|
+
const [firstOctet] = ip.split(/\.|:/);
|
|
65
65
|
return path.join(cacheDir, `${firstOctet}_${cacheFileName}`);
|
|
66
66
|
};
|
|
67
67
|
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@k03mad/ip2geo",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "GeoIP library",
|
|
5
5
|
"maintainers": [
|
|
6
6
|
"Kirill Molchanov <k03.mad@gmail.com"
|
|
7
7
|
],
|
|
8
|
+
"bin": {
|
|
9
|
+
"ip2geo": "app/cli.js"
|
|
10
|
+
},
|
|
8
11
|
"main": "app/index.js",
|
|
9
12
|
"repository": {
|
|
10
13
|
"type": "git",
|
|
@@ -17,6 +20,7 @@
|
|
|
17
20
|
},
|
|
18
21
|
"dependencies": {
|
|
19
22
|
"@k03mad/request": "5.4.1",
|
|
23
|
+
"chalk": "5.3.0",
|
|
20
24
|
"debug": "4.3.4"
|
|
21
25
|
},
|
|
22
26
|
"devDependencies": {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import {describe, it} from 'node:test';
|
|
3
|
+
|
|
4
|
+
import {ip2geo} from '../app/index.js';
|
|
5
|
+
|
|
6
|
+
import {getCurrentFilename} from './helpers/path.js';
|
|
7
|
+
import {checkCacheFile, removeCacheFolder} from './shared/fs.js';
|
|
8
|
+
|
|
9
|
+
const testName = getCurrentFilename(import.meta.url);
|
|
10
|
+
|
|
11
|
+
describe(testName, () => {
|
|
12
|
+
const CACHE_FILE_DIR = testName;
|
|
13
|
+
const CACHE_FILE_NAME = 'ips.log';
|
|
14
|
+
const CACHE_FILE_SEPARATOR = ';;';
|
|
15
|
+
const CACHE_FILE_NEWLINE = '\n';
|
|
16
|
+
|
|
17
|
+
const REQUEST_IP = '2a00:dd80:40:100::';
|
|
18
|
+
|
|
19
|
+
const cacheFile = `${REQUEST_IP.split(/\.|:/)[0]}_${CACHE_FILE_NAME}`;
|
|
20
|
+
|
|
21
|
+
const response = {
|
|
22
|
+
ip: REQUEST_IP,
|
|
23
|
+
emoji: '🇳🇱',
|
|
24
|
+
country: 'Netherlands',
|
|
25
|
+
countryA2: 'NL',
|
|
26
|
+
region: 'North Holland',
|
|
27
|
+
city: 'Amsterdam',
|
|
28
|
+
org: '',
|
|
29
|
+
isp: 'NetActuate Inc',
|
|
30
|
+
ispDomain: '',
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
removeCacheFolder(CACHE_FILE_DIR);
|
|
34
|
+
|
|
35
|
+
it(`should return correct response for IP: "${REQUEST_IP}"`, async () => {
|
|
36
|
+
const data = await ip2geo(REQUEST_IP, {
|
|
37
|
+
cacheDir: CACHE_FILE_DIR,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
assert.deepEqual(data, response);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
checkCacheFile(
|
|
44
|
+
CACHE_FILE_DIR,
|
|
45
|
+
cacheFile,
|
|
46
|
+
CACHE_FILE_SEPARATOR,
|
|
47
|
+
CACHE_FILE_NEWLINE,
|
|
48
|
+
response,
|
|
49
|
+
);
|
|
50
|
+
});
|
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
|
+
import path from 'node:path';
|
|
2
3
|
import {describe, it} from 'node:test';
|
|
3
4
|
|
|
4
5
|
import {ip2geo} from '../app/index.js';
|
|
5
6
|
|
|
7
|
+
import {getCurrentFilename} from './helpers/path.js';
|
|
6
8
|
import {checkCacheFile, removeCacheFolder} from './shared/fs.js';
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
const testName = getCurrentFilename(import.meta.url);
|
|
11
|
+
const SUBFOLDERS = 5;
|
|
12
|
+
|
|
13
|
+
describe(testName, () => {
|
|
14
|
+
const CACHE_FILE_DIR = path.join(
|
|
15
|
+
...Array.from({length: SUBFOLDERS}, () => testName),
|
|
16
|
+
);
|
|
17
|
+
|
|
10
18
|
const CACHE_FILE_NAME = 'ips.log';
|
|
11
19
|
const CACHE_FILE_SEPARATOR = ';;';
|
|
12
20
|
const CACHE_FILE_NEWLINE = '\n';
|
|
13
21
|
|
|
14
22
|
const REQUEST_IP = '9.9.9.9';
|
|
15
23
|
|
|
16
|
-
const cacheFile = `${REQUEST_IP.split(
|
|
24
|
+
const cacheFile = `${REQUEST_IP.split(/\.|:/)[0]}_${CACHE_FILE_NAME}`;
|
|
17
25
|
|
|
18
26
|
const response = {
|
|
19
27
|
ip: REQUEST_IP,
|
package/tests/opts-assigned.js
CHANGED
|
@@ -3,17 +3,20 @@ import {describe, it} from 'node:test';
|
|
|
3
3
|
|
|
4
4
|
import {ip2geo} from '../app/index.js';
|
|
5
5
|
|
|
6
|
+
import {getCurrentFilename} from './helpers/path.js';
|
|
6
7
|
import {checkCacheFile, removeCacheFolder} from './shared/fs.js';
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
const testName = getCurrentFilename(import.meta.url);
|
|
10
|
+
|
|
11
|
+
describe(testName, () => {
|
|
12
|
+
const CACHE_FILE_DIR = testName;
|
|
10
13
|
const CACHE_FILE_NAME = 'ips.md';
|
|
11
14
|
const CACHE_FILE_SEPARATOR = '-_-';
|
|
12
15
|
const CACHE_FILE_NEWLINE = '%%%';
|
|
13
16
|
|
|
14
17
|
const REQUEST_IP = '8.8.8.8';
|
|
15
18
|
|
|
16
|
-
const cacheFile = `${REQUEST_IP.split(
|
|
19
|
+
const cacheFile = `${REQUEST_IP.split(/\.|:/)[0]}_${CACHE_FILE_NAME}`;
|
|
17
20
|
|
|
18
21
|
const response = {
|
|
19
22
|
ip: REQUEST_IP,
|
package/tests/opts-default.js
CHANGED
|
@@ -6,14 +6,14 @@ import {ip2geo} from '../app/index.js';
|
|
|
6
6
|
import {checkCacheFile, removeCacheFolder} from './shared/fs.js';
|
|
7
7
|
|
|
8
8
|
describe('opts-default', () => {
|
|
9
|
-
const CACHE_FILE_DIR = 'geoip';
|
|
9
|
+
const CACHE_FILE_DIR = '.geoip';
|
|
10
10
|
const CACHE_FILE_NAME = 'ips.log';
|
|
11
11
|
const CACHE_FILE_SEPARATOR = ';;';
|
|
12
12
|
const CACHE_FILE_NEWLINE = '\n';
|
|
13
13
|
|
|
14
14
|
const REQUEST_IP = '1.1.1.1';
|
|
15
15
|
|
|
16
|
-
const cacheFile = `${REQUEST_IP.split(
|
|
16
|
+
const cacheFile = `${REQUEST_IP.split(/\.|:/)[0]}_${CACHE_FILE_NAME}`;
|
|
17
17
|
|
|
18
18
|
const response = {
|
|
19
19
|
ip: REQUEST_IP,
|