npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

network-toolkit

v0.1.8

Published

TypeScript toolkit for reverse IP lookups with pluggable, dynamic data sources.

Readme

network-toolkit

TypeScript toolkit for reverse IP lookups and domain-to-IP resolution, with pluggable, dynamic data sources.

  • reverseIpLookUp — given an IP address, discover domains hosted on it by querying a set of built-in (and/or custom) sources.
  • domainToIp — given a domain name, resolve its IPv4/IPv6 addresses using the same pluggable-source architecture.

Every source runs independently: a source failing (network error, rate limit, etc.) never fails the whole lookup, and results are streamed back to you as soon as each source finishes.

Install

npm install network-toolkit

Requirements

Node.js >= 18.

reverseIpLookUp

import { reverseIpLookUp } from 'network-toolkit';

await reverseIpLookUp('8.8.8.8', (result) => {
  console.log(result.source, result.domains, result.error);
});

onFound is called once per source, as soon as that source finishes, with:

interface ReverseIpSourceResult {
  source: string;
  domains: string[];
  /** Present only if the source threw/failed. */
  error?: string;
}

Execution modes

By default, sources run concurrently through a pool of workers. You can instead run them sequentially, stopping as soon as one succeeds — useful when any single successful answer is good enough and you want to avoid hitting every source unnecessarily.

// Default: run every source concurrently, wait for all of them.
await reverseIpLookUp('8.8.8.8', onFound);

// Run sources one at a time, in order, and stop at the first source
// that resolves without throwing (even if it returns zero domains).
await reverseIpLookUp('8.8.8.8', onFound, { mode: 'sequential' });

// Same as above, but keep going to the next source if a successful
// source comes back with zero domains.
await reverseIpLookUp('8.8.8.8', onFound, {
  mode: 'sequential',
  continueWhenEmpty: true,
});

Cancellation

Pass an AbortSignal to cancel early: no new sources start, and the promise resolves once every in-flight source has finished (and emitted).

const controller = new AbortController();

const lookup = reverseIpLookUp('8.8.8.8', onFound, { signal: controller.signal });

controller.abort();
await lookup;

Configuration

interface ReverseIpLookupBaseConfig {
  /** Only run these preset sources by name. Omit to run all presets. */
  sources?: string[];
  /** Preset source names to exclude, applied after `sources`. */
  excludeSources?: string[];
  /** Additional user-defined sources to run alongside/instead of presets. */
  customSources?: ReverseIpSource[];
  /** Timeout hint (ms) forwarded to each source. */
  timeoutMs?: number;
  /** Abort the lookup: no new sources start, and `reverseIpLookUp` resolves once in-flight ones finish. */
  signal?: AbortSignal;
}

interface ReverseIpLookupConcurrentConfig extends ReverseIpLookupBaseConfig {
  mode?: 'concurrent'; // default
  /** Number of sources processed concurrently. Defaults to running all sources at once. */
  thread?: number;
}

interface ReverseIpLookupSequentialConfig extends ReverseIpLookupBaseConfig {
  mode: 'sequential';
  /**
   * When a source succeeds but returns zero domains, keep going to the next
   * source instead of stopping. Defaults to `false`.
   */
  continueWhenEmpty?: boolean;
}

type ReverseIpLookupConfig = ReverseIpLookupConcurrentConfig | ReverseIpLookupSequentialConfig;

Preset sources

| name | description | | ------------------- | ------------------------------------------------------------------------- | | dns-ptr | Native PTR (reverse DNS) lookup via Node's dns module. | | hacker-target | Free HackerTarget "Reverse IP Lookup" API (shared hosts). | | rapiddns | Free RapidDNS "Reverse IP" lookup page (rapiddns.io/sameip). | | robtex | Free Robtex passive DNS API (freeapi.robtex.com/pdns/reverse). | | shodan-internetdb | Free, keyless Shodan InternetDB API (internetdb.shodan.io). | | alienvault-otx | Free, keyless AlienVault OTX passive DNS API. | | urlscan | Free, keyless urlscan.io search API (page.ip query, rate-limited). | | mnemonic | Free, keyless mnemonic Passive DNS API (api.mnemonic.no/pdns/v3). | | netlas | Free, keyless Netlas.io "responses" search API (rate-limited). | | dnsdumpster | Free DNSDumpster "reverse ip" quick-tool (harvests a short-lived token). | | ip138 | Free ip138.com (Chinese) "site.ip138.com" reverse-IP HTML page. | | whose-domains | Free, keyless whose.domains reverse-IP API. |

// Only use dns-ptr
reverseIpLookUp('8.8.8.8', onFound, { sources: ['dns-ptr'] });

// Use everything except hacker-target
reverseIpLookUp('8.8.8.8', onFound, { excludeSources: ['hacker-target'] });

domainToIp

import { domainToIp } from 'network-toolkit';

const addresses = await domainToIp('example.com');
// [{ type: 'V4', data: '93.184.216.34' }, { type: 'V6', data: '2606:2800:...' }]

Unlike reverseIpLookUp, domainToIp returns a single de-duplicated array (merged across all sources) rather than streaming per-source results.

Configuration

interface DomainToIpConfig {
  /** Only run these preset sources by name. Omit to run all presets. */
  sources?: string[];
  /** Preset source names to exclude, applied after `sources`. */
  excludeSources?: string[];
  /** Additional user-defined sources to run alongside/instead of presets. */
  customSources?: DomainToIpSource[];
  /** Timeout hint (ms) forwarded to each source. */
  timeoutMs?: number;
  /** Number of sources processed concurrently. Defaults to running all sources at once. */
  thread?: number;
  /** Abort the lookup: no new sources start, and `domainToIp` resolves once in-flight ones finish. */
  signal?: AbortSignal;
}

Preset sources

| name | description | | ----- | --------------------------------------------------------------- | | dns | Native A/AAAA lookup via Node's dns module (no external API). |

// Only use dns
domainToIp('example.com', { sources: ['dns'] });

Custom sources

Any object implementing the relevant source interface can be added, alongside or instead of the presets.

Custom reverse-IP source

import type { ReverseIpSource } from 'network-toolkit';

const mySource: ReverseIpSource = {
  name: 'my-source',
  async lookup(ip, options) {
    // return an array of domain strings
    return [];
  },
};

reverseIpLookUp('8.8.8.8', onFound, { customSources: [mySource] });

Custom domain-to-IP source

import type { DomainToIpSource } from 'network-toolkit';

const mySource: DomainToIpSource = {
  name: 'my-source',
  async resolve(domain, options) {
    // return an array of { type: 'V4' | 'V6', data: string }
    return [];
  },
};

domainToIp('example.com', { customSources: [mySource] });

Development

bun install
bun run test
bun run typecheck
bun run build   # bumps the patch version, then builds dist/

License

MIT