@push.rocks/smartwhois
a package for looking up domain and IP registration data via WHOIS and RDAP
@push.rocks/smartwhois speaks both registration data protocols: classic port-43 WHOIS (with IANA server discovery, referral following, and response parsing) and RDAP (with IANA bootstrap resolution for TLDs and RIRs). A growing number of TLDs (.global, .finance, ...) no longer operate a WHOIS server at all and disclose registration data via RDAP only — this package covers both worlds behind one typed API.
Issue Reporting and Security
For reporting bugs, issues, or security vulnerabilities, please visit community.foss.global/. This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a code.foss.global/ account to submit Pull Requests directly.
Install
pnpm install @push.rocks/smartwhois
Usage
The primary class is SmartWhois. It exposes WHOIS lookups, RDAP lookups, domain delegation parsing, and TLD validation.
import { SmartWhois } from '@push.rocks/smartwhois';
const smartWhois = new SmartWhois();
WHOIS for a Domain
getWhoisForDomain performs a full port-43 WHOIS lookup: it discovers the TLD's WHOIS server via IANA, follows registrar referrals, parses the responses, and returns a normalized IWhoisInfo:
const whoisInfo = await smartWhois.getWhoisForDomain('task.vc');
console.log(whoisInfo.isRegistered); // true
console.log(whoisInfo.registrar);
console.log(whoisInfo.createdDate, whoisInfo.updatedDate, whoisInfo.expiryDate);
console.log(whoisInfo.domainStatus); // e.g. ['clientTransferProhibited']
console.log(whoisInfo.dnsSec); // 'signedDelegation' | 'unsigned'
console.log(whoisInfo.originalWhoisInfo); // raw parsed responses per WHOIS server
URLs are accepted as well — https://example.com/some/path is reduced to its registrable domain first.
RDAP for a Domain
getRdapForDomain queries the TLD's RDAP registry, resolved through the IANA bootstrap file. RDAP answers are authoritative: a 200 means registered, a 404 means the registry has no such delegation.
const rdapRecord = await smartWhois.getRdapForDomain('hard.global');
if (rdapRecord === null) {
// the TLD has no RDAP service in the IANA bootstrap
} else {
console.log(rdapRecord.isRegistered);
console.log(rdapRecord.registrar, rdapRecord.registrarIanaId);
console.log(rdapRecord.createdDate, rdapRecord.updatedDate, rdapRecord.expiryDate);
console.log(rdapRecord.nameservers); // lowercased ldhNames
console.log(rdapRecord.statuses); // RDAP status vocabulary
console.log(rdapRecord.dnssec); // secureDNS.delegationSigned
console.log(rdapRecord.abuseEmail, rdapRecord.abusePhone);
console.log(rdapRecord.raw); // the registry's verbatim answer
}
The result contract:
- resolves to an
IRdapDomainRecordfor both registered and unregistered domains - resolves to
nullwhen the TLD has no RDAP service in the IANA bootstrap (or the input is not a domain) - rejects when neither the bootstrap nor any listed registry gave a usable answer
RDAP for an IP
getRdapForIp (also reachable as getWhoisForIp) resolves the responsible RIR via the IANA IPv4/IPv6 bootstrap files (longest-prefix match) and returns the network registration record:
const ipRecord = await smartWhois.getRdapForIp('8.8.8.8');
if (ipRecord) {
console.log(ipRecord.registrantOrg); // 'Google LLC'
console.log(ipRecord.registrantCountry);
console.log(ipRecord.networkRange); // '8.8.8.0/24'
console.log(ipRecord.networkCidrs);
console.log(ipRecord.abuseEmail);
}
The RdapClient
The RDAP capability is its own class, available as smartWhois.rdap or standalone. It caches the IANA bootstrap files (24h TTL, with in-flight deduplication, a short negative cache for failed fetches, and stale-cache fallback), prefers https base urls, and fails over across all base urls listed for a TLD or RIR:
import { RdapClient } from '@push.rocks/smartwhois';
const rdapClient = new RdapClient({
requestTimeoutMs: 5000, // per http request (bootstrap fetch and each registry query)
totalTimeoutMs: 10000, // per lookup across all of a TLD's/RIR's base urls
userAgent: 'my-app/1.0',
});
const baseUrls = await rdapClient.getBaseUrlsForTld('global'); // [] = no RDAP service
const domainRecord = await rdapClient.lookupDomain('hard.global');
const ipRecord = await rdapClient.lookupIp('2001:4860:4860::8888');
const networkInfo = rdapClient.parseIpNetworkInfo({
startAddress: '203.0.113.0',
endAddress: '203.0.113.255',
}); // { networkRange: '203.0.113.0/24', networkCidrs: ['203.0.113.0/24'] }
Domain Delegation
getDomainDelegation splits a domain or URL into its components (TLD, registrable domain, subdomain, ...):
const delegation = await smartWhois.getDomainDelegation('https://www.example.com/path');
console.log(delegation.domain); // 'example.com'
console.log(delegation.publicSuffix); // 'com'
console.log(delegation.subdomain); // 'www'
Additional HTTP Data
getAdditionalWhoisDataForDomain probes the domain over http and https and returns status codes and headers:
const additionalData = await smartWhois.getAdditionalWhoisDataForDomain('example.com');
console.log(additionalData.httpStatus, additionalData.httpsStatus);
Validating TLDs
isValidTld checks a TLD against the live IANA TLD list:
const isValid = await smartWhois.isValidTld('.com'); // true
Error Handling
Network lookups can fail. WHOIS lookups record per-server errors inside originalWhoisInfo; RDAP lookups reject when no registry gave a usable answer:
try {
const record = await smartWhois.getRdapForDomain('example.global');
} catch (error) {
console.error('RDAP lookup failed:', error);
}
License and Legal Information
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the repository license file.
Please note: The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
Trademarks
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
Company Information
Task Venture Capital GmbH
Registered at District Court Bremen HRB 35230 HB, Germany
For any legal inquiries or further information, please contact us via email at hello@task.vc.
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.