UNPKG

ip2info

Version:

Simple client for real-time IPV4 and IPV6 lookup and validation. Over 99% of IP addresses covered Worldwide. Over 30 distinct attributes for each request.

126 lines (124 loc) 4.37 kB
// index.js class IPMonster { static config = { apiKey: null, baseUrl: 'https://api.bestipapi.com/query', timeout: 5000 }; static configure(options) { this.config = { ...this.config, ...options }; } static validate(ip) { if (!ip || typeof ip !== 'string') return false; const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; const ipv6Regex = /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^::1$|^::$/; return ipv4Regex.test(ip) || ipv6Regex.test(ip); } static async lookup(ip, options = {}) { if (!this.validate(ip)) { throw new Error('Invalid IP address format'); } const apiKey = options.apiKey || this.config.apiKey || process.env.IPMONSTER_API_KEY; if (!apiKey) { throw new Error('API key not configured. Use IPMonster.configure({ apiKey: "your-key" }) or set IPMONSTER_API_KEY environment variable'); } const baseUrl = options.baseUrl || this.config.baseUrl; const timeout = options.timeout || this.config.timeout; const output = options.output || 'json'; const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeout); try { const url = new URL(`${baseUrl}/single`); url.searchParams.set('ip', ip); if (output !== 'json') { url.searchParams.set('output', output); } const response = await fetch(url.toString(), { method: 'GET', headers: { 'X-API-KEY': apiKey, 'Content-Type': 'application/json', 'User-Agent': 'ip-monster-npm/1.0.0' }, signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { let errorMessage; try { const errorData = await response.json(); errorMessage = errorData.message || `HTTP ${response.status}`; } catch { errorMessage = `HTTP ${response.status}: ${response.statusText}`; } throw new Error(`IP Monster API error: ${errorMessage}`); } return await response.json(); } catch (error) { clearTimeout(timeoutId); if (error.name === 'AbortError') { throw new Error(`Request timeout after ${timeout}ms`); } throw error; } } static async batchLookup(ips, options = {}) { if (!Array.isArray(ips)) { throw new Error('IPs must be an array'); } if (ips.length === 0) { throw new Error('At least one IP address is required'); } if (ips.length > 300) { throw new Error('Maximum of 300 IP addresses per request'); } const validIPs = ips.filter(ip => this.validate(ip)); if (validIPs.length === 0) { throw new Error(`No valid IP Addresses to process`); } const apiKey = options.apiKey || this.config.apiKey || process.env.IPMONSTER_API_KEY; if (!apiKey) { throw new Error('API key not configured'); } const baseUrl = options.baseUrl || this.config.baseUrl; const timeout = options.timeout || this.config.timeout; const output = options.output || 'json'; const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeout); try { const url = new URL(`${baseUrl}/multiple`); url.searchParams.set('ip', validIPs.join(',')); if (output !== 'json') { url.searchParams.set('output', output); } const response = await fetch(url.toString(), { method: 'GET', headers: { 'X-API-KEY': apiKey, 'Content-Type': 'application/json', 'User-Agent': 'ip-monster-npm/1.0.0' }, signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { let errorMessage; try { const errorData = await response.json(); errorMessage = errorData.message || `HTTP ${response.status}`; } catch { errorMessage = `HTTP ${response.status}: ${response.statusText}`; } throw new Error(`IP Monster API error: ${errorMessage}`); } return await response.json(); } catch (error) { clearTimeout(timeoutId); if (error.name === 'AbortError') { throw new Error(`Request timeout after ${timeout}ms`); } throw error; } } } module.exports = IPMonster;