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

@quarg/burnerguard

v1.0.0-rc1

Published

Detect disposable and burner email addresses. Static blocklist mode with zero dependencies, or connect to the BurnerGuard API for real-time risk scoring.

Readme

BurnerGuard

Stop disposable and burner email addresses from polluting your signup flow. BurnerGuard ships a curated blocklist with zero runtime dependencies, works in any JavaScript environment, and gives you a clean async API to verify emails against it.

Down the road, adding an API key will upgrade the same verify() call to real-time risk scoring from the BurnerGuard service — but the static library is fully functional on its own.

Part of the Quarg developer tools platform.


Why this library?

Disposable email detection sounds simple — just check a domain against a list. In practice, you end up solving the same problems every time:

  • Raw domain lists leave you to handle parsing, deduplication, lookup optimization, email validation, and keeping the list current. Every project rebuilds this from scratch.
  • Minimal wrappers give you a function but stop there — no allowlists to handle false positives, no batch operations, no way to bring your own data.
  • Full email verification platforms pull in DNS and SMTP dependencies, add latency, and introduce complexity you may not need when all you want is a fast domain check.

BurnerGuard fills the gap: a fast, flexible, self-updating email checker that works offline, supports allowlists, handles batch operations, and ships with zero runtime dependencies.

Honest limitations

A static blocklist catches known disposable domains, but it can't detect brand-new throwaway domains, catch-all configurations, or suspicious registration patterns. If you need real-time detection with domain age analysis, MX provider fingerprinting, velocity signals, and risk scoring, the BurnerGuard service is on the way. The upgrade path will be seamless — add an API key and the same verify() call returns enriched results.


Features

  • Fast lookups — Domains are stored in a Set for constant-time hash lookups. Subdomains are resolved by walking up the domain hierarchy, so even deep subdomains like a.b.c.throwaway.example resolve quickly.
  • Subdomain detection — If throwaway.example is blocked, mail.throwaway.example is automatically caught too. Works at any depth.
  • Allowlist support — Explicitly permit domains that would otherwise be matched. The allowlist takes priority at every level of the domain hierarchy, so you can block example.net but allow legit.example.net.
  • Flexible input — Pass a full email address or a bare domain to any method. BurnerGuard detects which one you gave it.
  • Batch operations — Verify a list of emails, filter them into matched and clean buckets, or check whether any email in a set matches.
  • Fully async — Every verification method returns a Promise, so the API won't change when service mode adds network calls. In static mode, the underlying work is synchronous — the async wrapper adds negligible overhead.
  • Bring your own data — Use the bundled blocklist out of the box, load from a local file, fetch from a URL, pass an inline array, or combine multiple sources. When custom sources are provided, the bundled list steps aside unless you explicitly keep it.
  • Stays current — The bundled blocklist is updated automatically and published as new patch versions. Just run npm update to get the latest domains.
  • Lazy-loaded and memory-conscious — The bundled blocklist is loaded via dynamic import() only when create() is called, not at module import time. If you're using custom sources exclusively, the bundled data is never loaded at all.
  • Universal — No Node.js built-ins in the core path. Works in Node.js, Deno, Bun, Angular, React, Vite, edge runtimes, and serverless functions. File-based sources dynamically import node:fs only when you opt into them.
  • Zero runtime dependencies — Nothing beyond platform built-ins.
  • TypeScript-first — Full type definitions with a private-constructor factory pattern that guarantees every instance is fully initialized before you can use it.

Requirements

Node.js 20 or later. Works in Deno, Bun, and edge runtimes with no additional configuration.

Installation

npm install @quarg/burnerguard
yarn add @quarg/burnerguard
pnpm add @quarg/burnerguard

Quick start

import {BurnerGuard} from '@quarg/burnerguard';

const guard = await BurnerGuard.create();

const result = await guard.verify('[email protected]');
// {
//   isMatch: true,
//   domain: 'throwaway.example',
//   matchedOn: 'blocklist',
//   isAllowlisted: false
// }

Usage

Verifying a single email or domain

verify() accepts a full email address or a bare domain. It returns a VerifyResult with everything you need to make a decision.

await guard.verify('[email protected]');       // email address
await guard.verify('throwaway.example');             // bare domain — works too
await guard.verify('mail.throwaway.example');        // subdomain — caught automatically
await guard.verify('[email protected]');          // clean — { isMatch: false, ... }

Verifying a batch

verifyBatch() checks multiple inputs and returns a result for each, in the same order.

const results = await guard.verifyBatch([
    '[email protected]',
    '[email protected]',
    '[email protected]'
]);
// [{ isMatch: false, ... }, { isMatch: true, ... }, { isMatch: false, ... }]

Filtering a list

filter() splits your list into two buckets: matched (disposable) and clean.

const {matched, clean} = await guard.filter([
    '[email protected]',
    '[email protected]',
    '[email protected]'
]);
// matched: ['[email protected]']
// clean: ['[email protected]', '[email protected]']

Checking if any email matches

hasMatch() short-circuits on the first match — useful when you just need a yes/no answer for a batch.

await guard.hasMatch(['[email protected]', '[email protected]']); // true
await guard.hasMatch(['[email protected]', '[email protected]']); // false

Blocking and allowing domains at runtime

You can add domains to the blocklist or allowlist after initialization. These changes apply to the current instance only.

await guard.block('sketchy.example');
(await guard.verify('[email protected]')).isMatch; // true

await guard.allow('false-positive.example');
(await guard.verify('[email protected]')).isMatch; // false

Adding extra domains at creation

If you know upfront which domains to add, pass them as options. These are merged with the bundled blocklist.

const guard = await BurnerGuard.create({
    additionalBlockedDomains: ['sketchy.example'],
    additionalAllowedDomains: ['legit-but-flagged.example']
});

Loading from custom sources

You can load domain lists from local files, remote URLs, or inline arrays. When custom sources are provided, the bundled blocklist is not loaded by default — pass useBundledBlocklist: true to keep it.

// From local files (Node.js only)
const guard = await BurnerGuard.create({
    sources: [
        {type: 'block', filePath: '/path/to/my-blocklist.txt'},
        {type: 'allow', filePath: '/path/to/my-allowlist.txt'}
    ]
});

// From a URL (works everywhere — uses native fetch)
const guard = await BurnerGuard.create({
    sources: [{
        type: 'block',
        url: 'https://example.com/my-blocklist.txt'
    }]
});

// From an inline array
const guard = await BurnerGuard.create({
    sources: [{type: 'block', list: ['spam.example', 'junk.example']}]
});

// Mix and match — bundled list + custom sources
const guard = await BurnerGuard.create({
    useBundledBlocklist: true,
    sources: [{type: 'block', list: ['my-extra-domain.example']}]
});

Service mode (coming soon)

Service mode is not yet available. When it launches, you'll add an API key and the same verify() call will return enriched results with risk scoring. No code changes required.

const guard = await BurnerGuard.create({
    apiKey: 'bg_live_...',
    threshold: 0.7
});

const result = await guard.verify('[email protected]');
// {
//   isMatch: true,
//   domain: 'sketchy.example',
//   matchedOn: 'domainAge',
//   isAllowlisted: false,
//   verdict: 'block',
//   riskScore: 0.94,
//   signals: {
//     blocklist: false,
//     domainAgeDays: 4,
//     mxProvider: 'catch-all',
//     catchAll: true,
//     roleAddress: false,
//     patternCluster: false,
//     velocity: false
//   }
// }

API Reference

BurnerGuard.create(options?)

Creates and initializes a new instance. Returns Promise<BurnerGuard>.

| Option | Type | Default | Description | |--------|------|---------|-------------| | apiKey | string | — | BurnerGuard API key. Enables service mode (coming soon). | | threshold | number | 0.5 | Risk score threshold (0.0–1.0). Service mode only. | | sources | DomainListSource[] | — | Domain list sources: file path, URL, or inline array. | | additionalBlockedDomains | string[] | — | Extra domains to add to the blocklist. | | additionalAllowedDomains | string[] | — | Extra domains to add to the allowlist. | | useBundledBlocklist | boolean | true* | Whether to load the bundled blocklist. *Defaults to false when custom sources are provided. | | useBundledAllowlist | boolean | false | Whether to load the bundled allowlist. |

Async methods

| Method | Returns | Description | |--------|---------|-------------| | verify(emailOrDomain, options?) | Promise<VerifyResult> | Verify a single email or domain. | | verifyBatch(emailsOrDomains, options?) | Promise<VerifyResult[]> | Verify multiple inputs. Returns results in the same order. | | filter(emailsOrDomains, options?) | Promise<FilterResult> | Split inputs into {matched, clean}. | | hasMatch(emailsOrDomains, options?) | Promise<boolean> | Returns true if any input matches. Short-circuits on first match. | | block(domain) | Promise<void> | Add a domain to the blocklist at runtime. | | allow(domain) | Promise<void> | Add a domain to the allowlist at runtime. |

Sync methods

| Method | Returns | Description | |--------|---------|-------------| | extractDomain(email) | string \| null | Extract the domain portion from an email address. | | isValidEmail(email) | boolean | Check whether a string is a valid email address (syntax only). |

Properties

| Property | Type | Description | |----------|------|-------------| | blocklistSize | number | Number of domains currently in the blocklist. | | allowlistSize | number | Number of domains currently in the allowlist. |

VerifyResult

Returned by verify() in static mode.

{
    isMatch: boolean;        // true if the domain matched the blocklist
    domain: string | null;   // the extracted domain, or null for invalid input
    matchedOn: string | null; // the signal that triggered the match (e.g., "blocklist"), or null
    isAllowlisted: boolean;  // true if the allowlist overrode a potential match
}

EnrichedVerifyResult

Returned by verify() in service mode (coming soon). Extends VerifyResult with additional fields.

{
    // ... all VerifyResult fields, plus:
    verdict: 'allow' | 'block' | 'suspect';
    riskScore: number;    // 0.0 (safe) to 1.0 (certain threat)
    signals: RiskSignals; // detailed signal breakdown
}

FilterResult

Returned by filter().

{
    matched: string[];  // inputs that matched the blocklist
    clean: string[];    // inputs that did not match (or were allowlisted)
}

Bundled data and updates

BurnerGuard ships with a pre-processed copy of the disposable-email-domains community blocklist and allowlist. It works offline out of the box — no network calls needed.

The bundled data is updated automatically and published as new patch versions. Just run npm update to pick up new domains. No manual list management required.

To update the bundled data manually:

npm run update-blocklist
npm run build

Acknowledgements

License

MIT — see LICENSE.