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

@andy-defer/react-client-kit

v1.0.4

Published

React client kit for Authentication Kit, Nemesis, and Laravel Actions

Readme

React Client Kit

Client HTTP et authentification pour React avec TypeScript

npm version license TypeScript React


📋 Table des matières


Introduction

React Client Kit est une bibliothèque qui fournit des hooks React typés pour la communication avec des APIs REST, avec un focus sur l'authentification et la gestion des tokens.

Philosophie

  • TypeScript-first : Typage complet pour une expérience de développement fluide
  • Headless : Pas de composants UI, seulement des hooks et des utilitaires
  • Flexible : Support de multiples méthodes d'authentification (email, OTP, etc.)
  • Configurable : Endpoints personnalisables pour s'adapter à votre API
  • Testable : Injection de dépendances pour faciliter les tests

Cas d'usage

  • 🔐 Authentification email/password
  • 📡 Appels API typés
  • 🎯 Gestion automatique des tokens
  • 🔄 Réinitialisation de mot de passe
  • ✅ Vérification d'email

Installation

# Avec npm
npm install @andy-defer/react-client-kit

# Avec yarn
yarn add @andy-defer/react-client-kit

# Avec pnpm
pnpm add @andy-defer/react-client-kit

Dépendances

Le package utilise les bibliothèques suivantes en peerDependencies :

{
  "react": "^18.2.0",
  "react-dom": "^18.2.0",
  "axios": "^1.6.0"
}

Philosophie

Pourquoi ce package ?

| Problème | Solution | |----------|----------| | Réécrire les mêmes appels API dans chaque projet | ✅ Hooks React réutilisables | | Gestion manuelle du token en localStorage | ✅ Gestion automatique | | Duplication des types TypeScript | ✅ Types partagés et générés | | Configuration répétée d'Axios | ✅ Client préconfiguré | | Pas de typage pour les erreurs API | ✅ Erreurs typées | | Chaque projet gère les tokens différemment | ✅ Standardisation |


Démarrage rapide

Exemple minimal

import React from 'react';
import { useClientKit } from '@andy-defer/react-client-kit';

function App() {
  const { auth, actions } = useClientKit({
    baseURL: 'https://api.example.com',
    modelType: 'App\\Models\\User',
  });

  const handleLogin = async () => {
    const result = await auth.login('[email protected]', 'password123');
    if (result.success) {
      console.log('Connecté !', result.data);
    }
  };

  const fetchUsers = async () => {
    const users = await actions.get('/users');
    console.log(users);
  };

  return (
    <div>
      {auth.isAuthenticated ? (
        <>
          <p>Bonjour {auth.user?.name}</p>
          <button onClick={auth.logout}>Déconnexion</button>
          <button onClick={fetchUsers}>Charger les utilisateurs</button>
        </>
      ) : (
        <button onClick={handleLogin}>Connexion</button>
      )}
    </div>
  );
}

export default App;

Hooks

useClientKit

Hook combiné qui fournit à la fois l'authentification et le client HTTP.

import { useClientKit } from '@andy-defer/react-client-kit';

const { auth, actions } = useClientKit({
  baseURL: 'https://api.example.com',
  modelType: 'App\\Models\\User',
  tokenStorage: 'localStorage',
  tokenKey: 'my_app_token',
  onTokenChange: (token) => {
    console.log('Token changé:', token ? 'présent' : 'absent');
  },
});

Configuration

| Prop | Type | Requis | Défaut | Description | |------|------|--------|--------|-------------| | baseURL | string | ✅ | - | URL de base de l'API | | modelType | string | ❌ | - | Type du modèle pour l'authentification | | tokenStorage | 'localStorage' \| 'sessionStorage' | ❌ | 'localStorage' | Type de stockage du token | | tokenKey | string | ❌ | 'client_kit_token' | Clé de stockage du token | | onTokenChange | (token: string \| null) => void | ❌ | - | Callback lors du changement de token |

Retour

| Propriété | Type | Description | |-----------|------|-------------| | auth | UseMailAuthenticationKitReturn<T> | État et méthodes d'authentification | | actions | UseActionClientReturn | Méthodes HTTP |


useMailAuthenticationKit

Hook d'authentification par email.

import { useMailAuthenticationKit } from '@andy-defer/react-client-kit';

const auth = useMailAuthenticationKit({
  baseURL: 'https://api.example.com',
  modelType: 'App\\Models\\User',
});

Méthodes

register(data: RegisterRequest): Promise<ApiResult<AuthRegisteredData & { auth: T }>>

Inscription d'un nouvel utilisateur.

const result = await auth.register({
  model_type: 'App\\Models\\User',
  name: 'John Doe',
  email: '[email protected]',
  password: 'Password123!',
  password_confirmation: 'Password123!',
  with_token: true,
});
login(email: string, password: string): Promise<ApiResult<AuthLoginData & { auth: T }>>

Connexion d'un utilisateur existant.

const result = await auth.login('[email protected]', 'password123');
logout(): Promise<ApiResult<void>>

Déconnexion de l'utilisateur courant.

await auth.logout();
forgotPassword(email: string): Promise<ApiResult<PasswordResetLinkSentData>>

Demande de réinitialisation de mot de passe.

const result = await auth.forgotPassword('[email protected]');
resetPassword(data: ResetPasswordRequest): Promise<ApiResult<PasswordResetSuccessData>>

Réinitialisation du mot de passe avec OTP.

const result = await auth.resetPassword({
  model_type: 'App\\Models\\User',
  email: '[email protected]',
  token: '123456',
  password: 'NewPassword123!',
  password_confirmation: 'NewPassword123!',
});
verifyEmail(data: VerifyEmailRequest): Promise<ApiResult<EmailVerifiedData>>

Vérification d'email avec OTP.

const result = await auth.verifyEmail({
  model_type: 'App\\Models\\User',
  email: '[email protected]',
  token: '123456',
});
sendVerificationOTP(authId: number): Promise<ApiResult<EmailVerificationSentData>>

Envoi d'un OTP de vérification.

const result = await auth.sendVerificationOTP(1);
resendVerificationOTP(authId: number): Promise<ApiResult<EmailVerificationResentData>>

Renvoi d'un OTP de vérification.

const result = await auth.resendVerificationOTP(1);

États

| Propriété | Type | Description | |-----------|------|-------------| | token | string \| null | Token d'authentification actuel | | user | T \| null | Données de l'utilisateur authentifié | | isAuthenticated | boolean | État d'authentification | | isLoading | boolean | Indique si une requête est en cours | | error | ErrorResponseData \| null | Dernière erreur |


useActionClient

Hook pour les appels HTTP typés avec gestion automatique du token.

import { useActionClient } from '@andy-defer/react-client-kit';

const actions = useActionClient({
  baseURL: 'https://api.example.com',
  token: 'my-token',
});

Méthodes

get<T>(path: string, config?: ApiClientRequestConfig): Promise<T>

Requête GET typée.

const user = await actions.get<User>('/users/1');
post<T, R>(path: string, data?: T, config?: ApiClientRequestConfig): Promise<R>

Requête POST typée.

// post<RequestType, ResponseType>
const user = await actions.post<CreateUserRequest, UserResponse>(
  '/users',
  { name: 'John', email: '[email protected]' }
);
put<T, R>(path: string, data?: T, config?: ApiClientRequestConfig): Promise<R>

Requête PUT typée.

const user = await actions.put<UpdateUserRequest, UserResponse>(
  '/users/1',
  { name: 'John Updated' }
);
patch<T, R>(path: string, data?: T, config?: ApiClientRequestConfig): Promise<R>

Requête PATCH typée.

const user = await actions.patch<Partial<UpdateUserRequest>, UserResponse>(
  '/users/1',
  { email: '[email protected]' }
);
delete<T>(path: string, config?: ApiClientRequestConfig): Promise<T>

Requête DELETE typée.

await actions.delete('/users/1');
request<T>(config: ApiClientRequestConfig): Promise<T>

Requête personnalisée avec contrôle total.

const data = await actions.request<{ id: number }>({
  method: 'POST',
  url: '/custom',
  data: { foo: 'bar' },
});

Core

ApiClient

Client HTTP avec gestion automatique des tokens.

import { ApiClient } from '@andy-defer/react-client-kit';

const client = new ApiClient('https://api.example.com', 'auth_token', 'localStorage');
client.setToken('my-jwt-token');

const user = await client.get<User>('/users/1');

Méthodes

| Méthode | Description | |---------|-------------| | getToken(): string \| null | Récupère le token actuel | | setToken(token: string \| null): void | Stocke ou supprime le token | | get<T>(path, config): Promise<T> | Requête GET | | post<T>(path, data, config): Promise<T> | Requête POST | | put<T>(path, data, config): Promise<T> | Requête PUT | | patch<T>(path, data, config): Promise<T> | Requête PATCH | | delete<T>(path, config): Promise<T> | Requête DELETE | | request<T>(config): Promise<T> | Requête personnalisée | | getAxiosInstance(): AxiosInstance | Instance Axios sous-jacente |


TokenStorage

Gestionnaire de stockage des tokens.

import { TokenStorage } from '@andy-defer/react-client-kit';

const storage = new TokenStorage('localStorage');
storage.set('auth_token', 'my-token');
const token = storage.get('auth_token');

Méthodes

| Méthode | Description | |---------|-------------| | get(key: string): string \| null | Récupère une valeur | | set(key: string, value: string): void | Stocke une valeur | | remove(key: string): void | Supprime une valeur |


Types

Request Types

interface RegisterRequest {
  model_type: string;
  with_token?: boolean;
  name: string;
  email: string;
  password: string;
  password_confirmation: string;
}

interface LoginRequest {
  model_type: string;
  email: string;
  password: string;
}

interface ResetPasswordRequest {
  model_type: string;
  email: string;
  token: string;
  password: string;
  password_confirmation: string;
}

interface VerifyEmailRequest {
  model_type: string;
  email: string;
  token: string;
}

Response Types

interface ErrorResponseData {
  message: string;
  status: number;
  errorCode?: string;
  errors?: Record<string, string[]>;
}

interface AuthLoginData {
  message: string;
  auth: Record<string, unknown>;
  token: string;
}

interface AuthRegisteredData {
  message: string;
  auth: Record<string, unknown>;
  token?: string;
}

Api Result

interface ApiResult<T> {
  success: boolean;
  data?: T;
  error?: ErrorResponseData;
}

Endpoints

interface MailAuthEndpoints {
  register?: string;
  login?: string;
  forgotPassword?: string;
  resetPassword?: string;
  verifyEmail?: string;
  sendVerification?: string;
  resendVerification?: string;
  logout?: string;
}

// Endpoints par défaut
const DEFAULT_ENDPOINTS = {
  register: '/register',
  login: '/login',
  forgotPassword: '/forgot-password',
  resetPassword: '/reset-password',
  verifyEmail: '/email/verify',
  sendVerification: '/email/verification',
  resendVerification: '/email/resend',
  logout: '/logout',
};

Exemples

Exemple 1 : Formulaire de connexion

import React, { useState } from 'react';
import { useClientKit } from '@andy-defer/react-client-kit';

function LoginForm() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState<string | null>(null);

  const { auth } = useClientKit({
    baseURL: 'https://api.example.com',
    modelType: 'App\\Models\\User',
  });

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setError(null);

    const result = await auth.login(email, password);

    if (result.success) {
      console.log('Connecté !');
    } else {
      setError(result.error?.message || 'Erreur de connexion');
    }
  };

  if (auth.isLoading) {
    return <div>Chargement...</div>;
  }

  if (auth.isAuthenticated) {
    return <div>Bienvenue {auth.user?.name}</div>;
  }

  return (
    <form onSubmit={handleSubmit}>
      {error && <div style={{ color: 'red' }}>{error}</div>}
      <input
        type="email"
        placeholder="Email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        required
      />
      <input
        type="password"
        placeholder="Mot de passe"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        required
      />
      <button type="submit">Se connecter</button>
    </form>
  );
}

Exemple 2 : Formulaire d'inscription

import React, { useState } from 'react';
import { useClientKit } from '@andy-defer/react-client-kit';

function RegisterForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    password: '',
    password_confirmation: '',
  });

  const { auth } = useClientKit({
    baseURL: 'https://api.example.com',
    modelType: 'App\\Models\\User',
  });

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();

    const result = await auth.register({
      model_type: 'App\\Models\\User',
      ...formData,
      with_token: true,
    });

    if (result.success) {
      console.log('Inscription réussie !');
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        placeholder="Nom"
        value={formData.name}
        onChange={(e) => setFormData({ ...formData, name: e.target.value })}
        required
      />
      <input
        type="email"
        placeholder="Email"
        value={formData.email}
        onChange={(e) => setFormData({ ...formData, email: e.target.value })}
        required
      />
      <input
        type="password"
        placeholder="Mot de passe"
        value={formData.password}
        onChange={(e) => setFormData({ ...formData, password: e.target.value })}
        required
      />
      <input
        type="password"
        placeholder="Confirmation"
        value={formData.password_confirmation}
        onChange={(e) => setFormData({ ...formData, password_confirmation: e.target.value })}
        required
      />
      <button type="submit" disabled={auth.isLoading}>
        {auth.isLoading ? 'Inscription...' : "S'inscrire"}
      </button>
    </form>
  );
}

Exemple 3 : Réinitialisation de mot de passe

import React, { useState } from 'react';
import { useClientKit } from '@andy-defer/react-client-kit';

function ResetPassword() {
  const [email, setEmail] = useState('');
  const [otp, setOtp] = useState('');
  const [password, setPassword] = useState('');
  const [step, setStep] = useState<'request' | 'reset'>('request');

  const { auth } = useClientKit({
    baseURL: 'https://api.example.com',
    modelType: 'App\\Models\\User',
  });

  const handleRequestReset = async () => {
    const result = await auth.forgotPassword(email);
    if (result.success) {
      setStep('reset');
    }
  };

  const handleReset = async () => {
    const result = await auth.resetPassword({
      model_type: 'App\\Models\\User',
      email,
      token: otp,
      password,
      password_confirmation: password,
    });

    if (result.success) {
      alert('Mot de passe réinitialisé !');
    }
  };

  return (
    <div>
      {step === 'request' ? (
        <div>
          <input
            type="email"
            placeholder="Email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
          />
          <button onClick={handleRequestReset} disabled={auth.isLoading}>
            {auth.isLoading ? 'Envoi...' : 'Envoyer l\'OTP'}
          </button>
        </div>
      ) : (
        <div>
          <input
            type="text"
            placeholder="Code OTP"
            value={otp}
            onChange={(e) => setOtp(e.target.value)}
          />
          <input
            type="password"
            placeholder="Nouveau mot de passe"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
          />
          <button onClick={handleReset} disabled={auth.isLoading}>
            {auth.isLoading ? 'Réinitialisation...' : 'Réinitialiser'}
          </button>
        </div>
      )}
    </div>
  );
}

Exemple 4 : Appel API protégé

import React, { useEffect, useState } from 'react';
import { useClientKit } from '@andy-defer/react-client-kit';

interface User {
  id: number;
  name: string;
  email: string;
}

function ProtectedData() {
  const [users, setUsers] = useState<User[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const { auth, actions } = useClientKit({
    baseURL: 'https://api.example.com',
    modelType: 'App\\Models\\User',
  });

  useEffect(() => {
    if (auth.isAuthenticated) {
      fetchUsers();
    }
  }, [auth.isAuthenticated]);

  const fetchUsers = async () => {
    setLoading(true);
    setError(null);

    try {
      const data = await actions.get<User[]>('/users');
      setUsers(data);
    } catch (err: any) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  if (!auth.isAuthenticated) {
    return <div>Veuillez vous connecter</div>;
  }

  if (loading) return <div>Chargement...</div>;
  if (error) return <div style={{ color: 'red' }}>{error}</div>;

  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>
          {user.name} ({user.email})
        </li>
      ))}
    </ul>
  );
}

Exemple 5 : Endpoints personnalisés

import { useClientKit } from '@andy-defer/react-client-kit';

function App() {
  const { auth } = useClientKit({
    baseURL: 'https://api.example.com',
    modelType: 'App\\Models\\User',
    endpoints: {
      register: '/auth/register',
      login: '/auth/login',
      logout: '/auth/logout',
      forgotPassword: '/auth/password/email',
      resetPassword: '/auth/password/reset',
      verifyEmail: '/auth/email/verify',
      sendVerification: '/auth/email/verification',
      resendVerification: '/auth/email/resend',
    },
  });

  // Les méthodes utilisent maintenant les endpoints personnalisés
  const handleLogin = async () => {
    await auth.login('[email protected]', 'password123');
  };

  return <button onClick={handleLogin}>Connexion</button>;
}

Performance

Optimisation

  • Mémoïsation : Les clients sont mémoïsés pour éviter les re-créations
  • Lazy initialization : Le token est chargé uniquement au besoin
  • Pas de re-rendus inutiles : Les hooks sont optimisés pour minimiser les re-rendus

Recommandations

| Cas d'usage | Recommandation | |-------------|----------------| | Appel API simple | useActionClient directement | | App complète | useClientKit pour tout avoir | | Tests unitaires | Utiliser factory pour injecter des mocks |


Compatibilité

| Environnement | Support | |---------------|---------| | React | 18.0+ | | TypeScript | 5.0+ | | Chrome | 60+ | | Firefox | 55+ | | Safari | 12+ | | Edge | 79+ | | Node.js | 18+ (pour les builds) |


Contribuer

Les contributions sont les bienvenues !

  1. Forkez le projet
  2. Créez votre branche (git checkout -b feature/amazing-feature)
  3. Committez vos changements (git commit -m 'Add some amazing feature')
  4. Poussez vers la branche (git push origin feature/amazing-feature)
  5. Ouvrez une Pull Request

Licence

Ce projet est sous licence MIT. Voir le fichier LICENSE pour plus d'informations.


Liens utiles