:::note[Fail-open par défaut]
Chaque exemple enveloppe l'appel Syvel dans un `try/catch`. Si l'API est injoignable (erreur réseau, timeout, quota dépassé), la vérification est **ignorée et l'utilisateur est laissé passer**. Ne laissez jamais un service tiers bloquer une inscription.
:::

## Installation

```bash
npm install @syvel/js
```

**Pré-requis :** Node.js 18+, navigateurs modernes, Deno. Zéro dépendance externe.

## Utilisation basique

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

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

try {
  const result = await syvel.checkEmail("user@yopmail.com");

  console.log(result.risk_score);  // 100
  console.log(result.is_risky);    // true
  console.log(result.reason);      // "disposable"
} catch {
  // API indisponible — continuer normalement
}
```

## Format de réponse

```typescript
interface CheckResult {
  email: string;                 // Email masqué (la partie locale n'est jamais exposée)
  is_risky: boolean;             // true si le score dépasse le seuil du projet (défaut 65)
  risk_score: number;            // 0–100  |  0–29 safe  |  30–49 low  |  50–79 warn  |  80+ block
  reason: string;                // "safe" | "disposable" | "undeliverable" | "role_account"
  deliverability_score: number;  // 0–100, probabilité de délivrabilité
  did_you_mean?: string;         // Suggestion de correction (ex. "gmail.com" pour "gmial.com")
  is_free_provider: boolean;     // Gmail, Yahoo, etc.
  is_corporate_email: boolean;   // Domaine professionnel avec MX business
  is_alias_email: boolean;       // Relais de confidentialité (SimpleLogin, iCloud Hide My Email…)
  mx_provider_label: string;     // Nom lisible du fournisseur MX
}
```

## Configuration

```typescript
const syvel = new Syvel({
  apiKey: "sv_votre_cle",

  // Timeout en ms — défaut 3000. L'API répond typiquement en < 300 ms.
  timeout: 3000,

  // Mode silencieux : retourne null au lieu de lever une exception.
  // Fail-open automatique sans try/catch.
  silent: true,
});
```

Avec `silent: true`, les erreurs retournent `null` au lieu de lever une exception :

```typescript
const syvel = new Syvel({ apiKey: "sv_votre_cle", silent: true });

const result = await syvel.checkEmail("user@example.com");
if (result?.is_risky) {
  // bloquer ou avertir
}
// result est null → API indisponible, laisser passer automatiquement
```

## Gestion des erreurs

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

try {
  const result = await syvel.checkEmail("user@example.com");
} catch (error) {
  if (error instanceof SyvelTimeoutError) {
    // Toujours fail open
  } else if (error instanceof SyvelRateLimitError) {
    // error.resetAt → timestamp ISO 8601 de réinitialisation du quota
  } else if (error instanceof SyvelValidationError) {
    // Email ou domaine malformé
  } else if (error instanceof SyvelAuthError) {
    // Clé API invalide ou manquante (401)
  } else if (error instanceof SyvelForbiddenError) {
    // Origine non autorisée dans la liste de la clé API (403)
  }
}
```

| Classe d'erreur | HTTP | Comportement |
|---|---|---|
| `SyvelTimeoutError` | — | Toujours fail open |
| `SyvelRateLimitError` | 429 | Toujours fail open — vérifier `resetAt` |
| `SyvelAuthError` | 401 | Corriger la clé API |
| `SyvelForbiddenError` | 403 | Vérifier les origines autorisées |
| `SyvelValidationError` | 422 | Entrée malformée |

## Formulaire HTML avec validation en temps réel

```html
<form id="signup-form">
  <input type="email" id="email" placeholder="votre@email.com" />
  <p id="email-error" style="color: red; display: none;"></p>
  <button type="submit">S'inscrire</button>
</form>

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

  const syvel = new Syvel({ apiKey: "sv_votre_cle", silent: true });
  const emailInput = document.getElementById("email");
  const emailError = document.getElementById("email-error");
  let debounceTimer;

  emailInput.addEventListener("input", () => {
    clearTimeout(debounceTimer);
    debounceTimer = setTimeout(async () => {
      const email = emailInput.value;
      if (!email.includes("@")) return;

      const result = await syvel.checkEmail(email);
      if (result?.is_risky) {
        emailError.textContent = "Merci d'utiliser une adresse email professionnelle.";
        emailError.style.display = "block";
      } else {
        emailError.style.display = "none";
      }
    }, 500);
  });
</script>
```

## React Hook

```tsx
import { useState, useCallback } from "react";
import { Syvel, type CheckResult } from "@syvel/js";

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

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

  const check = useCallback(async (email: string) => {
    if (!email.includes("@")) return;
    setLoading(true);
    const data = await syvel.checkEmail(email);
    setResult(data);
    setLoading(false);
  }, []);

  return { result, loading, check };
}
```

## Express

```typescript
import express from "express";
import { Syvel } from "@syvel/js";

const app = express();
const syvel = new Syvel({ apiKey: process.env.SYVEL_API_KEY, silent: true });

app.post("/register", async (req, res) => {
  const result = await syvel.checkEmail(req.body.email);

  if (result?.is_risky) {
    return res.status(422).json({ error: "Veuillez utiliser une adresse email professionnelle." });
  }
  // continuer l'inscription…
});
```

## Fastify

```typescript
import Fastify from "fastify";
import { Syvel } from "@syvel/js";

const app = Fastify();
const syvel = new Syvel({ apiKey: process.env.SYVEL_API_KEY, silent: true });

app.post("/register", async (request, reply) => {
  const { email } = request.body as { email: string };
  const result = await syvel.checkEmail(email);

  if (result?.is_risky) {
    return reply.status(422).send({ error: "Veuillez utiliser une adresse email professionnelle." });
  }
  // continuer l'inscription…
});
```

## Next.js (Route Handler)

```typescript
import { NextRequest, NextResponse } from "next/server";
import { Syvel } from "@syvel/js";

const syvel = new Syvel({ apiKey: process.env.SYVEL_API_KEY, silent: true });

export async function POST(request: NextRequest) {
  const { email } = await request.json();
  const result = await syvel.checkEmail(email);

  if (result?.is_risky) {
    return NextResponse.json(
      { error: "Veuillez utiliser une adresse email professionnelle." },
      { status: 422 }
    );
  }
  // continuer l'inscription…
}
```

## Ressources

- [npm — @syvel/js](https://www.npmjs.com/package/@syvel/js)
- [GitHub — syvel-js](https://github.com/Syvel-io/syvel-js)
- [JavaScript (Fetch) — sans dépendance SDK](/fr/docs/integrations/javascript-fetch)
- [Référence API — Vérification email](/fr/docs/api/check)
- [Authentification](/fr/docs/guides/authentication)
- [Codes d'erreur](/fr/docs/guides/errors)
- [Limites de débit](/fr/docs/guides/rate-limits)