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

@syvel/js

v0.1.0

Published

Disposable email detection SDK for JavaScript and TypeScript

Readme

@syvel/js

npm version npm downloads license

Official JavaScript/TypeScript SDK for Syvel — disposable email detection API.

Works in browser, Node.js 18+, React, Next.js, and Deno. Zero dependencies. TypeScript-first. Fail-open by default.

Install

npm install @syvel/js
# or
yarn add @syvel/js
# or
pnpm add @syvel/js

Quick start

import { Syvel } from "@syvel/js";

const syvel = new Syvel({ apiKey: "sv_your_key" });

try {
  const result = await syvel.checkEmail("[email protected]");

  if (result.is_risky) {
    // block or warn the user
  }
} catch {
  // API unavailable — fail open, let the user through
}

Always wrap Syvel calls in a try/catch. If the API is unreachable (network error, timeout, quota exceeded), the check should be skipped and the user let through. Never let a third-party service block a sign-up.

Configuration

const syvel = new Syvel({
  apiKey: "sv_your_key",

  // Timeout in ms (default: 3000).
  // Keep it low — the API typically responds in under 300 ms.
  timeout: 3000,

  // Silent mode: returns null instead of throwing on any error.
  // Ideal for fire-and-forget checks with automatic fail-open behaviour.
  silent: true,
});

API

syvel.checkEmail(email)

Check a full email address. Passing the full email (rather than just the domain) enables local-part analysis: role accounts (admin@, info@…), random-string patterns, and other signals that can only be detected from the local part.

const result = await syvel.checkEmail("[email protected]");
// result.is_risky        → true
// result.risk_score      → 100
// result.reason          → "disposable"
// result.did_you_mean    → null

syvel.check(domain)

Check a bare domain.

const result = await syvel.check("yopmail.com");

Response

| Field | Type | Description | | ---------------------- | ---------------- | ---------------------------------------------------------------- | | email | string | Masked input — local part is never exposed in plain text | | is_risky | boolean | true if risk_score ≥ threshold (default: 65) | | risk_score | number | 0 (safe) to 100 (confirmed disposable) | | reason | string | "safe" · "disposable" · "undeliverable" · "role_account" | | deliverability_score | number | 0 (unlikely) to 100 (very likely to be delivered) | | did_you_mean | string \| null | Typo correction suggestion | | is_free_provider | boolean | Consumer webmail (Gmail, Yahoo…) | | is_corporate_email | boolean | Business domain with professional MX | | is_alias_email | boolean | Privacy alias service (SimpleLogin, AnonAddy…) | | mx_provider_label | string \| null | Human-readable MX provider name |

Error handling

The SDK exports typed error classes so you can handle specific cases:

import {
  Syvel,
  SyvelAuthError,
  SyvelForbiddenError,
  SyvelRateLimitError,
  SyvelTimeoutError,
  SyvelValidationError,
} from "@syvel/js";

try {
  const result = await syvel.checkEmail("[email protected]");
} catch (err) {
  if (err instanceof SyvelAuthError) {
    // Invalid API key — check your configuration
  } else if (err instanceof SyvelRateLimitError) {
    // Quota exceeded — err.resetAt contains the reset timestamp
    console.log("Quota resets at", err.resetAt);
  } else if (err instanceof SyvelTimeoutError) {
    // Request timed out — fail open, let the user through
  } else {
    // Network error or unexpected error — fail open
  }
}

| Error class | Cause | | ---------------------- | ---------------------------------------------- | | SyvelAuthError | Invalid or missing API key (HTTP 401) | | SyvelForbiddenError | Origin not whitelisted for this key (HTTP 403) | | SyvelValidationError | Invalid email or domain format (HTTP 422) | | SyvelRateLimitError | Monthly quota exceeded (HTTP 429) | | SyvelTimeoutError | Request exceeded the configured timeout | | SyvelError | Base class — all other API errors |

All error classes extend SyvelError, which extends the native Error.

Examples

HTML form with debounced validation

<form id="signup-form">
  <input type="email" id="email" placeholder="[email protected]" />
  <p id="email-error" style="color:red; display:none"></p>
  <button type="submit">Sign up</button>
</form>

<script type="module">
  import { Syvel } from "https://cdn.jsdelivr.net/npm/@syvel/js";

  const syvel = new Syvel({ apiKey: "sv_your_key" });
  const emailInput = document.getElementById("email");
  const emailError = document.getElementById("email-error");
  let timer;

  emailInput.addEventListener("input", () => {
    clearTimeout(timer);
    timer = setTimeout(async () => {
      if (!emailInput.value.includes("@")) return;
      try {
        const result = await syvel.checkEmail(emailInput.value);
        if (result?.is_risky) {
          emailError.textContent = "Please use a professional email address.";
          emailError.style.display = "block";
        } else {
          emailError.style.display = "none";
        }
      } catch {
        emailError.style.display = "none"; // fail open
      }
    }, 500);
  });
</script>

React hook

import { useState, useCallback } from "react";
import { Syvel } from "@syvel/js";

const syvel = new Syvel({ apiKey: import.meta.env.VITE_SYVEL_API_KEY });

export function useEmailCheck() {
  const [result, setResult] = useState(null);
  const [loading, setLoading] = useState(false);

  const check = useCallback(async (email: string) => {
    if (!email.includes("@")) return;
    setLoading(true);
    try {
      setResult(await syvel.checkEmail(email));
    } catch {
      setResult(null); // fail open
    } finally {
      setLoading(false);
    }
  }, []);

  return { result, loading, check };
}

React Hook Form

import { useForm } from "react-hook-form";
import { Syvel } from "@syvel/js";

const syvel = new Syvel({ apiKey: "sv_your_key" });

function SignupForm() {
  const {
    register,
    handleSubmit,
    setError,
    formState: { errors },
  } = useForm();

  const onSubmit = async (data) => {
    try {
      const result = await syvel.checkEmail(data.email);
      if (result?.is_risky) {
        setError("email", { message: "Please use a valid email address." });
        return;
      }
    } catch {
      // Syvel unavailable — fail open
    }
    // continue with registration...
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("email")} type="email" />
      {errors.email && <p>{errors.email.message}</p>}
      <button type="submit">Sign up</button>
    </form>
  );
}

Documentation

Full documentation, API reference, and more examples: syvel.io/docs/integrations/javascript

License

MIT