@prosopo/ipinfo 0.2.14 → 0.2.15

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.
@@ -1,150 +1,147 @@
1
- export class MaxMindBackend {
2
- constructor(config) {
3
- this.cityReader = null;
4
- this.asnReader = null;
5
- this.config = config;
1
+ class MaxMindBackend {
2
+ constructor(config) {
3
+ this.cityReader = null;
4
+ this.asnReader = null;
5
+ this.config = config;
6
+ }
7
+ async initialize() {
8
+ const { Reader } = await import("@maxmind/geoip2-node");
9
+ if (this.config.cityDbPath) {
10
+ try {
11
+ this.cityReader = await Reader.open(this.config.cityDbPath);
12
+ this.config.logger?.info(() => ({
13
+ msg: "MaxMind City reader initialized",
14
+ data: { dbPath: this.config.cityDbPath }
15
+ }));
16
+ } catch (error) {
17
+ this.config.logger?.warn(() => ({
18
+ msg: "Failed to initialize MaxMind City reader",
19
+ err: error,
20
+ data: { dbPath: this.config.cityDbPath }
21
+ }));
22
+ }
6
23
  }
7
- async initialize() {
8
- const { Reader } = await import("@maxmind/geoip2-node");
9
- if (this.config.cityDbPath) {
10
- try {
11
- this.cityReader = await Reader.open(this.config.cityDbPath);
12
- this.config.logger?.info(() => ({
13
- msg: "MaxMind City reader initialized",
14
- data: { dbPath: this.config.cityDbPath },
15
- }));
16
- }
17
- catch (error) {
18
- this.config.logger?.warn(() => ({
19
- msg: "Failed to initialize MaxMind City reader",
20
- err: error,
21
- data: { dbPath: this.config.cityDbPath },
22
- }));
23
- }
24
- }
25
- if (this.config.asnDbPath) {
26
- try {
27
- this.asnReader = await Reader.open(this.config.asnDbPath);
28
- this.config.logger?.info(() => ({
29
- msg: "MaxMind ASN reader initialized",
30
- data: { dbPath: this.config.asnDbPath },
31
- }));
32
- }
33
- catch (error) {
34
- this.config.logger?.warn(() => ({
35
- msg: "Failed to initialize MaxMind ASN reader",
36
- err: error,
37
- data: { dbPath: this.config.asnDbPath },
38
- }));
39
- }
40
- }
24
+ if (this.config.asnDbPath) {
25
+ try {
26
+ this.asnReader = await Reader.open(this.config.asnDbPath);
27
+ this.config.logger?.info(() => ({
28
+ msg: "MaxMind ASN reader initialized",
29
+ data: { dbPath: this.config.asnDbPath }
30
+ }));
31
+ } catch (error) {
32
+ this.config.logger?.warn(() => ({
33
+ msg: "Failed to initialize MaxMind ASN reader",
34
+ err: error,
35
+ data: { dbPath: this.config.asnDbPath }
36
+ }));
37
+ }
41
38
  }
42
- isAvailable() {
43
- return this.cityReader !== null || this.asnReader !== null;
39
+ }
40
+ isAvailable() {
41
+ return this.cityReader !== null || this.asnReader !== null;
42
+ }
43
+ async lookup(ip) {
44
+ if (!this.isAvailable()) {
45
+ return {
46
+ isValid: false,
47
+ error: "MaxMind readers not initialized",
48
+ ip
49
+ };
44
50
  }
45
- async lookup(ip) {
46
- if (!this.isAvailable()) {
47
- return {
48
- isValid: false,
49
- error: "MaxMind readers not initialized",
50
- ip,
51
- };
52
- }
51
+ try {
52
+ let cityData;
53
+ let asnData;
54
+ if (this.cityReader) {
53
55
  try {
54
- let cityData;
55
- let asnData;
56
- if (this.cityReader) {
57
- try {
58
- cityData = this.cityReader.city(ip);
59
- }
60
- catch (error) {
61
- this.config.logger?.debug(() => ({
62
- msg: "MaxMind City lookup failed",
63
- data: { ip },
64
- err: error,
65
- }));
66
- }
67
- }
68
- if (this.asnReader) {
69
- try {
70
- asnData = this.asnReader.asn(ip);
71
- }
72
- catch (error) {
73
- this.config.logger?.debug(() => ({
74
- msg: "MaxMind ASN lookup failed",
75
- data: { ip },
76
- err: error,
77
- }));
78
- }
79
- }
80
- if (!cityData && !asnData) {
81
- return {
82
- isValid: false,
83
- error: "No MaxMind data available for IP",
84
- ip,
85
- };
86
- }
87
- const result = {
88
- ip,
89
- isValid: true,
90
- isVPN: cityData?.traits?.isAnonymousVpn ?? false,
91
- isTor: cityData?.traits?.isTorExitNode ?? false,
92
- isProxy: (cityData?.traits?.isPublicProxy ?? false) ||
93
- (cityData?.traits?.isResidentialProxy ?? false),
94
- isDatacenter: cityData?.traits?.isHostingProvider ?? false,
95
- isAbuser: false,
96
- isMobile: false,
97
- isSatellite: cityData?.traits?.isSatelliteProvider ?? false,
98
- isCrawler: false,
99
- country: cityData?.country?.names?.en,
100
- countryCode: cityData?.country?.isoCode,
101
- region: cityData?.subdivisions?.[0]?.names?.en,
102
- city: cityData?.city?.names?.en,
103
- latitude: cityData?.location?.latitude,
104
- longitude: cityData?.location?.longitude,
105
- timezone: cityData?.location?.timeZone,
106
- asnNumber: cityData?.traits?.autonomousSystemNumber ??
107
- asnData?.autonomousSystemNumber,
108
- asnOrganization: cityData?.traits?.autonomousSystemOrganization ??
109
- asnData?.autonomousSystemOrganization,
110
- providerName: cityData?.traits?.autonomousSystemOrganization ??
111
- asnData?.autonomousSystemOrganization,
112
- providerType: mapUserType(cityData?.traits?.userType),
113
- };
114
- return result;
56
+ cityData = this.cityReader.city(ip);
57
+ } catch (error) {
58
+ this.config.logger?.debug(() => ({
59
+ msg: "MaxMind City lookup failed",
60
+ data: { ip },
61
+ err: error
62
+ }));
115
63
  }
116
- catch (error) {
117
- return {
118
- isValid: false,
119
- error: `MaxMind lookup error: ${error instanceof Error ? error.message : String(error)}`,
120
- ip,
121
- };
64
+ }
65
+ if (this.asnReader) {
66
+ try {
67
+ asnData = this.asnReader.asn(ip);
68
+ } catch (error) {
69
+ this.config.logger?.debug(() => ({
70
+ msg: "MaxMind ASN lookup failed",
71
+ data: { ip },
72
+ err: error
73
+ }));
122
74
  }
75
+ }
76
+ if (!cityData && !asnData) {
77
+ return {
78
+ isValid: false,
79
+ error: "No MaxMind data available for IP",
80
+ ip
81
+ };
82
+ }
83
+ const result = {
84
+ ip,
85
+ isValid: true,
86
+ // Threat indicators - GeoLite2 free DBs do not populate these
87
+ isVPN: cityData?.traits?.isAnonymousVpn ?? false,
88
+ isTor: cityData?.traits?.isTorExitNode ?? false,
89
+ isProxy: (cityData?.traits?.isPublicProxy ?? false) || (cityData?.traits?.isResidentialProxy ?? false),
90
+ isDatacenter: cityData?.traits?.isHostingProvider ?? false,
91
+ isAbuser: false,
92
+ isMobile: false,
93
+ isSatellite: cityData?.traits?.isSatelliteProvider ?? false,
94
+ isCrawler: false,
95
+ // Geolocation from City DB
96
+ country: cityData?.country?.names?.en,
97
+ countryCode: cityData?.country?.isoCode,
98
+ region: cityData?.subdivisions?.[0]?.names?.en,
99
+ city: cityData?.city?.names?.en,
100
+ latitude: cityData?.location?.latitude,
101
+ longitude: cityData?.location?.longitude,
102
+ timezone: cityData?.location?.timeZone,
103
+ // ASN info - prefer City DB traits, fall back to ASN DB
104
+ asnNumber: cityData?.traits?.autonomousSystemNumber ?? asnData?.autonomousSystemNumber,
105
+ asnOrganization: cityData?.traits?.autonomousSystemOrganization ?? asnData?.autonomousSystemOrganization,
106
+ // Provider info from ASN
107
+ providerName: cityData?.traits?.autonomousSystemOrganization ?? asnData?.autonomousSystemOrganization,
108
+ providerType: mapUserType(cityData?.traits?.userType)
109
+ };
110
+ return result;
111
+ } catch (error) {
112
+ return {
113
+ isValid: false,
114
+ error: `MaxMind lookup error: ${error instanceof Error ? error.message : String(error)}`,
115
+ ip
116
+ };
123
117
  }
118
+ }
124
119
  }
125
120
  function mapUserType(userType) {
126
- switch (userType) {
127
- case "hosting":
128
- case "content_delivery_network":
129
- return "hosting";
130
- case "college":
131
- case "school":
132
- case "library":
133
- return "education";
134
- case "government":
135
- case "military":
136
- return "government";
137
- case "business":
138
- return "business";
139
- case "residential":
140
- case "cellular":
141
- case "dialup":
142
- case "cafe":
143
- case "traveler":
144
- case "router":
145
- return "isp";
146
- default:
147
- return undefined;
148
- }
121
+ switch (userType) {
122
+ case "hosting":
123
+ case "content_delivery_network":
124
+ return "hosting";
125
+ case "college":
126
+ case "school":
127
+ case "library":
128
+ return "education";
129
+ case "government":
130
+ case "military":
131
+ return "government";
132
+ case "business":
133
+ return "business";
134
+ case "residential":
135
+ case "cellular":
136
+ case "dialup":
137
+ case "cafe":
138
+ case "traveler":
139
+ case "router":
140
+ return "isp";
141
+ default:
142
+ return void 0;
143
+ }
149
144
  }
150
- //# sourceMappingURL=maxmind.js.map
145
+ export {
146
+ MaxMindBackend
147
+ };
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const ipapi = require("./backends/ipapi.cjs");
4
+ const maxmind = require("./backends/maxmind.cjs");
5
+ function isNonRoutable(ip) {
6
+ const normalized = ip.replace(/^::ffff:/i, "");
7
+ if (normalized.startsWith("127.") || normalized.startsWith("10.") || normalized.startsWith("192.168.") || normalized.startsWith("169.254.") || normalized === "0.0.0.0") {
8
+ return true;
9
+ }
10
+ if (normalized.startsWith("172.")) {
11
+ const second = Number.parseInt(normalized.split(".")[1] ?? "", 10);
12
+ if (second >= 16 && second <= 31) return true;
13
+ }
14
+ if (normalized === "::1" || normalized === "::") return true;
15
+ if (/^f[cd]/i.test(normalized)) return true;
16
+ if (/^fe[89ab]/i.test(normalized)) return true;
17
+ return false;
18
+ }
19
+ class IpInfoService {
20
+ constructor(config) {
21
+ this.maxmindBackend = null;
22
+ this.ipapiBackend = null;
23
+ this.config = config;
24
+ if (config.maxmindCityDbPath || config.maxmindAsnDbPath) {
25
+ this.maxmindBackend = new maxmind.MaxMindBackend({
26
+ cityDbPath: config.maxmindCityDbPath,
27
+ asnDbPath: config.maxmindAsnDbPath,
28
+ logger: config.logger
29
+ });
30
+ }
31
+ if (config.ipapiUrl) {
32
+ this.ipapiBackend = new ipapi.IpapiBackend({
33
+ baseUrl: config.ipapiUrl,
34
+ apiKey: config.ipapiKey,
35
+ logger: config.logger
36
+ });
37
+ }
38
+ }
39
+ async initialize() {
40
+ if (this.maxmindBackend) {
41
+ await this.maxmindBackend.initialize();
42
+ }
43
+ this.config.logger?.info(() => ({
44
+ msg: "IpInfoService initialized",
45
+ data: {
46
+ maxmindAvailable: this.maxmindBackend?.isAvailable() ?? false,
47
+ ipapiAvailable: this.ipapiBackend?.isAvailable() ?? false
48
+ }
49
+ }));
50
+ }
51
+ isAvailable() {
52
+ return (this.maxmindBackend?.isAvailable() ?? false) || (this.ipapiBackend?.isAvailable() ?? false);
53
+ }
54
+ async lookup(ip) {
55
+ if (isNonRoutable(ip)) {
56
+ return {
57
+ isValid: false,
58
+ error: "Non-routable IP address",
59
+ ip
60
+ };
61
+ }
62
+ if (this.ipapiBackend?.isAvailable()) {
63
+ const result = await this.ipapiBackend.lookup(ip);
64
+ if (result.isValid) {
65
+ return result;
66
+ }
67
+ this.config.logger?.debug(() => ({
68
+ msg: "ipapi.is lookup failed, falling back to MaxMind",
69
+ data: {
70
+ ip,
71
+ error: "error" in result ? result.error : "unknown"
72
+ }
73
+ }));
74
+ if (this.maxmindBackend?.isAvailable()) {
75
+ return this.maxmindBackend.lookup(ip);
76
+ }
77
+ return result;
78
+ }
79
+ if (this.maxmindBackend?.isAvailable()) {
80
+ return this.maxmindBackend.lookup(ip);
81
+ }
82
+ return {
83
+ isValid: false,
84
+ error: "No IP info backend available",
85
+ ip
86
+ };
87
+ }
88
+ }
89
+ exports.IpInfoService = IpInfoService;
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const TIMEOUT_MS = 700;
4
+ class IpapiBackend {
5
+ constructor(config) {
6
+ this.config = config;
7
+ }
8
+ isAvailable() {
9
+ return Boolean(this.config.baseUrl);
10
+ }
11
+ async lookup(ip) {
12
+ try {
13
+ if (!ip || typeof ip !== "string") {
14
+ return {
15
+ isValid: false,
16
+ error: "Invalid IP address provided",
17
+ ip: ip || "undefined"
18
+ };
19
+ }
20
+ const body = { q: ip };
21
+ if (this.config.apiKey) {
22
+ body.key = this.config.apiKey;
23
+ }
24
+ const controller = new AbortController();
25
+ const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
26
+ try {
27
+ const response = await fetch(this.config.baseUrl, {
28
+ method: "POST",
29
+ headers: {
30
+ "Content-Type": "application/json",
31
+ Accept: "application/json"
32
+ },
33
+ body: JSON.stringify(body),
34
+ signal: controller.signal
35
+ });
36
+ clearTimeout(timeoutId);
37
+ if (!response.ok) {
38
+ return {
39
+ isValid: false,
40
+ error: `API request failed with status ${response.status}: ${response.statusText}`,
41
+ ip
42
+ };
43
+ }
44
+ const data = await response.json();
45
+ if (data.is_bogon) {
46
+ return {
47
+ isValid: false,
48
+ error: "IP address is bogon (non-routable)",
49
+ ip
50
+ };
51
+ }
52
+ const result = {
53
+ ip: data.ip,
54
+ isValid: true,
55
+ isVPN: data.is_vpn,
56
+ isTor: data.is_tor,
57
+ isProxy: data.is_proxy,
58
+ isDatacenter: data.is_datacenter,
59
+ isAbuser: data.is_abuser,
60
+ isMobile: data.is_mobile,
61
+ isSatellite: data.is_satellite,
62
+ isCrawler: data.is_crawler,
63
+ providerName: data.company?.name || data.datacenter?.datacenter,
64
+ providerType: data.company?.type || data.asn?.type,
65
+ asnNumber: data.asn?.asn,
66
+ asnOrganization: data.asn?.org,
67
+ country: data.location?.country,
68
+ countryCode: data.location?.country_code,
69
+ region: data.location?.state,
70
+ city: data.location?.city,
71
+ latitude: data.location?.latitude,
72
+ longitude: data.location?.longitude,
73
+ timezone: data.location?.timezone,
74
+ vpnService: data.vpn?.service,
75
+ vpnType: data.vpn?.type,
76
+ abuserScore: Number.parseFloat(
77
+ data.asn?.abuser_score.split(" ")[0] || "0"
78
+ ),
79
+ companyAbuserScore: Number.parseFloat(
80
+ data.company?.abuser_score.split(" ")[0] || "0"
81
+ )
82
+ };
83
+ return result;
84
+ } catch (fetchError) {
85
+ clearTimeout(timeoutId);
86
+ if (fetchError instanceof Error && fetchError.name === "AbortError") {
87
+ return {
88
+ isValid: false,
89
+ error: `Request timed out after ${TIMEOUT_MS}ms`,
90
+ ip
91
+ };
92
+ }
93
+ throw fetchError;
94
+ }
95
+ } catch (error) {
96
+ return {
97
+ isValid: false,
98
+ error: `Network or parsing error: ${error instanceof Error ? error.message : String(error)}`,
99
+ ip
100
+ };
101
+ }
102
+ }
103
+ }
104
+ exports.IpapiBackend = IpapiBackend;
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
25
+ class MaxMindBackend {
26
+ constructor(config) {
27
+ this.cityReader = null;
28
+ this.asnReader = null;
29
+ this.config = config;
30
+ }
31
+ async initialize() {
32
+ const { Reader } = await import("@maxmind/geoip2-node");
33
+ if (this.config.cityDbPath) {
34
+ try {
35
+ this.cityReader = await Reader.open(this.config.cityDbPath);
36
+ this.config.logger?.info(() => ({
37
+ msg: "MaxMind City reader initialized",
38
+ data: { dbPath: this.config.cityDbPath }
39
+ }));
40
+ } catch (error) {
41
+ this.config.logger?.warn(() => ({
42
+ msg: "Failed to initialize MaxMind City reader",
43
+ err: error,
44
+ data: { dbPath: this.config.cityDbPath }
45
+ }));
46
+ }
47
+ }
48
+ if (this.config.asnDbPath) {
49
+ try {
50
+ this.asnReader = await Reader.open(this.config.asnDbPath);
51
+ this.config.logger?.info(() => ({
52
+ msg: "MaxMind ASN reader initialized",
53
+ data: { dbPath: this.config.asnDbPath }
54
+ }));
55
+ } catch (error) {
56
+ this.config.logger?.warn(() => ({
57
+ msg: "Failed to initialize MaxMind ASN reader",
58
+ err: error,
59
+ data: { dbPath: this.config.asnDbPath }
60
+ }));
61
+ }
62
+ }
63
+ }
64
+ isAvailable() {
65
+ return this.cityReader !== null || this.asnReader !== null;
66
+ }
67
+ async lookup(ip) {
68
+ if (!this.isAvailable()) {
69
+ return {
70
+ isValid: false,
71
+ error: "MaxMind readers not initialized",
72
+ ip
73
+ };
74
+ }
75
+ try {
76
+ let cityData;
77
+ let asnData;
78
+ if (this.cityReader) {
79
+ try {
80
+ cityData = this.cityReader.city(ip);
81
+ } catch (error) {
82
+ this.config.logger?.debug(() => ({
83
+ msg: "MaxMind City lookup failed",
84
+ data: { ip },
85
+ err: error
86
+ }));
87
+ }
88
+ }
89
+ if (this.asnReader) {
90
+ try {
91
+ asnData = this.asnReader.asn(ip);
92
+ } catch (error) {
93
+ this.config.logger?.debug(() => ({
94
+ msg: "MaxMind ASN lookup failed",
95
+ data: { ip },
96
+ err: error
97
+ }));
98
+ }
99
+ }
100
+ if (!cityData && !asnData) {
101
+ return {
102
+ isValid: false,
103
+ error: "No MaxMind data available for IP",
104
+ ip
105
+ };
106
+ }
107
+ const result = {
108
+ ip,
109
+ isValid: true,
110
+ // Threat indicators - GeoLite2 free DBs do not populate these
111
+ isVPN: cityData?.traits?.isAnonymousVpn ?? false,
112
+ isTor: cityData?.traits?.isTorExitNode ?? false,
113
+ isProxy: (cityData?.traits?.isPublicProxy ?? false) || (cityData?.traits?.isResidentialProxy ?? false),
114
+ isDatacenter: cityData?.traits?.isHostingProvider ?? false,
115
+ isAbuser: false,
116
+ isMobile: false,
117
+ isSatellite: cityData?.traits?.isSatelliteProvider ?? false,
118
+ isCrawler: false,
119
+ // Geolocation from City DB
120
+ country: cityData?.country?.names?.en,
121
+ countryCode: cityData?.country?.isoCode,
122
+ region: cityData?.subdivisions?.[0]?.names?.en,
123
+ city: cityData?.city?.names?.en,
124
+ latitude: cityData?.location?.latitude,
125
+ longitude: cityData?.location?.longitude,
126
+ timezone: cityData?.location?.timeZone,
127
+ // ASN info - prefer City DB traits, fall back to ASN DB
128
+ asnNumber: cityData?.traits?.autonomousSystemNumber ?? asnData?.autonomousSystemNumber,
129
+ asnOrganization: cityData?.traits?.autonomousSystemOrganization ?? asnData?.autonomousSystemOrganization,
130
+ // Provider info from ASN
131
+ providerName: cityData?.traits?.autonomousSystemOrganization ?? asnData?.autonomousSystemOrganization,
132
+ providerType: mapUserType(cityData?.traits?.userType)
133
+ };
134
+ return result;
135
+ } catch (error) {
136
+ return {
137
+ isValid: false,
138
+ error: `MaxMind lookup error: ${error instanceof Error ? error.message : String(error)}`,
139
+ ip
140
+ };
141
+ }
142
+ }
143
+ }
144
+ function mapUserType(userType) {
145
+ switch (userType) {
146
+ case "hosting":
147
+ case "content_delivery_network":
148
+ return "hosting";
149
+ case "college":
150
+ case "school":
151
+ case "library":
152
+ return "education";
153
+ case "government":
154
+ case "military":
155
+ return "government";
156
+ case "business":
157
+ return "business";
158
+ case "residential":
159
+ case "cellular":
160
+ case "dialup":
161
+ case "cafe":
162
+ case "traveler":
163
+ case "router":
164
+ return "isp";
165
+ default:
166
+ return void 0;
167
+ }
168
+ }
169
+ exports.MaxMindBackend = MaxMindBackend;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const IpInfoService = require("./IpInfoService.cjs");
4
+ exports.IpInfoService = IpInfoService.IpInfoService;
package/dist/index.js CHANGED
@@ -1,2 +1,4 @@
1
- export { IpInfoService } from "./IpInfoService.js";
2
- //# sourceMappingURL=index.js.map
1
+ import { IpInfoService } from "./IpInfoService.js";
2
+ export {
3
+ IpInfoService
4
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prosopo/ipinfo",
3
- "version": "0.2.14",
3
+ "version": "0.2.15",
4
4
  "description": "IP information service with MaxMind and ipapi.is backends",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -27,7 +27,7 @@
27
27
  "dependencies": {
28
28
  "@maxmind/geoip2-node": "5.0.0",
29
29
  "@prosopo/logger": "1.0.2",
30
- "@prosopo/types": "4.3.0"
30
+ "@prosopo/types": "4.3.1"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@prosopo/config": "3.3.1",