node-iplocate
Version:
Find geolocation data from IP addresses (e.g. city, country, timezone) using the IPLocate.io API
154 lines (151 loc) • 4.63 kB
JavaScript
import { isValidIp } from 'ip-utils';
// src/errors.ts
var IPLocateError = class extends Error {
constructor(message) {
super(message);
this.name = "IPLocateError";
}
};
var InvalidIPError = class extends IPLocateError {
constructor(ip) {
super(`Invalid IP address: ${ip}`);
this.name = "InvalidIPError";
}
};
var AuthenticationError = class extends IPLocateError {
constructor(message = "Invalid API key") {
super(message);
this.name = "AuthenticationError";
}
};
var NotFoundError = class extends IPLocateError {
constructor(message = "IP address not found") {
super(message);
this.name = "NotFoundError";
}
};
var RateLimitError = class extends IPLocateError {
constructor(message = "Rate limit exceeded. Upgrade your plan at https://iplocate.io/account") {
super(message);
this.name = "RateLimitError";
}
};
var APIError = class extends IPLocateError {
constructor(message, statusCode) {
super(message);
this.name = "APIError";
this.statusCode = statusCode;
}
};
// src/utils.ts
function encodeIP(ip) {
return encodeURIComponent(ip);
}
var DEFAULT_BASE_URL = "https://iplocate.io/api";
var DEFAULT_TIMEOUT = 5e3;
var IPLocate = class {
/**
* Create a new IPLocate client
* @param apiKey Your IPLocate API key
* @param options Configuration options
*/
constructor(apiKey, options = {}) {
if (!apiKey || typeof apiKey !== "string") {
throw new IPLocateError("API key is required");
}
this.apiKey = apiKey;
this.baseUrl = options.baseUrl?.replace(/\/$/, "") || DEFAULT_BASE_URL;
this.timeout = options.timeout || DEFAULT_TIMEOUT;
this.httpClientOptions = options.httpClientOptions || {};
}
/**
* Look up geolocation and threat intelligence data for an IP address
* @param ip The IP address to look up
* @returns Promise resolving to lookup response
*/
async lookup(ip) {
if (!isValidIp(ip)) {
throw new InvalidIPError(ip);
}
const endpoint = `${this.baseUrl}/lookup/${encodeIP(ip)}`;
return this.makeRequest(endpoint);
}
/**
* Look up geolocation and threat intelligence data for the client's current IP address
* @returns Promise resolving to lookup response
*/
async lookupSelf() {
const endpoint = `${this.baseUrl}/lookup/`;
return this.makeRequest(endpoint);
}
/**
* Make HTTP request to the IPLocate API
* @param endpoint The API endpoint URL
* @returns Promise resolving to lookup response
*/
async makeRequest(endpoint) {
const url = new URL(endpoint);
url.searchParams.set("apikey", this.apiKey);
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
try {
const response = await fetch(url.toString(), {
method: "GET",
...this.httpClientOptions,
headers: {
"Accept": "application/json",
"User-Agent": "node-iplocate/2.0.1",
...this.httpClientOptions.headers
},
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
await this.handleErrorResponse(response);
}
const data = await response.json();
return data;
} catch (error) {
clearTimeout(timeoutId);
if (error instanceof IPLocateError) {
throw error;
}
if (error instanceof Error) {
if (error.name === "AbortError") {
throw new IPLocateError(`Request timeout after ${this.timeout}ms`);
}
throw new IPLocateError(`Request failed: ${error.message}`);
}
throw new IPLocateError("Unknown error occurred");
}
}
/**
* Handle error responses from the API
* @param response The fetch response object
*/
async handleErrorResponse(response) {
let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
try {
const errorData = await response.json();
if (errorData.error) {
errorMessage = errorData.error;
}
} catch {
}
switch (response.status) {
case 400:
throw new InvalidIPError(errorMessage);
case 403:
throw new AuthenticationError(errorMessage);
case 404:
throw new NotFoundError(errorMessage);
case 429:
throw new RateLimitError(errorMessage);
default:
throw new APIError(errorMessage, response.status);
}
}
};
export { APIError, AuthenticationError, IPLocate, IPLocateError, InvalidIPError, NotFoundError, RateLimitError, IPLocate as default };
//# sourceMappingURL=index.mjs.map
//# sourceMappingURL=index.mjs.map