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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@arc-js/cp-request

v0.0.2

Published

CP-REQUEST est une bibliothèque TypeScript complète pour gérer les requêtes HTTP et WebSocket avec une API unifiée et type-safe. Elle offre une solution robuste pour les communications client-serveur avec gestion automatique des erreurs, validation des sc

Readme

@arc-js/cp-request

License TypeScript Browser Node.js

@arc-js/cp-request est une bibliothèque TypeScript complète pour gérer les requêtes HTTP et WebSocket avec une API unifiée et type-safe. Elle offre une solution robuste pour les communications client-serveur avec gestion automatique des erreurs, validation des schémas et support multi-langue.

✨ Fonctionnalités Principales

🌐 HTTP Request (HttpRequest)

  • Méthodes HTTP complètes : GET, POST, PUT, DELETE
  • Gestion intelligente des erreurs : mapping automatique des codes HTTP vers des types de notification
  • Validation de schéma : intégration avec JON pour la validation des données
  • Support multi-langue : messages d'erreur en français et anglais
  • Authentification : support Basic Auth
  • Types de réponse : JSON, text, arraybuffer, blob
  • Intercepteurs : actions personnalisées pour succès/erreur

🔌 WebSocket Request (WsRequest)

  • Connexion WebSocket managée : avec reconnexion automatique
  • File d'attente de messages : messages stockés si non connecté
  • API unifiée : même interface que HttpRequest pour la cohérence
  • Gestion d'état : suivi de la connexion et tentatives de reconnexion
  • Validation des messages : schémas JON pour les données entrantes

🛡️ Sécurité & Fiabilité

  • Validation stricte : des paramètres d'entrée
  • Gestion des timeouts : configuration flexible
  • Protection contre les erreurs : fallbacks et valeurs par défaut
  • Logs détaillés : en mode développement seulement

📦 Installation

Via npm/yarn/pnpm

npm install @arc-js/cp-request
# ou
yarn add @arc-js/cp-request
# ou
pnpm add @arc-js/cp-request

Importation directe (CDN)

<script src="@arc-js/cp-request/cp-request.all.js"></script>

🚀 Démarrage Rapide

TypeScript/ES Modules

import { HttpRequest, WsRequest } from '@arc-js/cp-request';
// ou
import CPRequest from '@arc-js/cp-request';

CommonJS

const { HttpRequest, WsRequest } = require('@arc-js/cp-request');

Navigateur (global)

<script src="@arc-js/cp-request/cp-request.all.js"></script>
<script>
  // Disponible globalement
  const httpRequest = new HttpRequest();
  const wsRequest = new WsRequest();
</script>

📚 Documentation API

Configuration Initiale

// Configuration de base
const httpRequest = new HttpRequest()
  .initConfig('http://api.example.com', 'fr');

const wsRequest = new WsRequest()
  .initConfig('wss://ws.example.com', 'en');

Interface HTTPRequestParams

interface HTTPRequestParams {
    method: "GET" | "POST" | "PUT" | "DELETE";
    path: string;
    headers?: Record<string, string>;
    params?: Record<string, any>;
    body?: any;
    responseType?: "json" | "arraybuffer" | "blob" | "text";
    auth?: {
        username: string;
        password: string;
    };
}

Interface WSRequestParams

interface WSRequestParams {
    path: string;
    headers?: Record<string, string>;
    auth?: {
        username: string;
        password: string;
    };
    autoReconnect?: boolean;
    reconnectDelay?: number;
    maxReconnectAttempts?: number;
}

Réponse Standardisée

interface HTTPRequestResponse {
    response: {
        code: number;
        type: string;  // "success", "error", "warning", "info", "error_auth", "error_auth_required"
        message: any;
    };
    data: any;
    error?: any;
    errors?: any[];
}

🔧 Utilisation Détaillée

Requêtes HTTP

Récupérer plusieurs éléments (findAllRequests)

const httpRequest = new HttpRequest()
  .initConfig('http://api.example.com', 'fr');

httpRequest.findAllRequests(
  {
    method: 'GET',
    path: '/users',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer token'
    },
    params: {
      page: 1,
      limit: 20,
      sort: 'name'
    }
  },
  {}, // otherParams
  (response) => {
    console.log('Succès:', response.data); // Tableau d'utilisateurs
  },
  (response) => {
    console.error('Erreur:', response.error);
  }
);

Récupérer un seul élément (findOneRequest)

httpRequest.findOneRequest(
  {
    method: 'GET',
    path: '/users/123'
  },
  {},
  (response) => {
    console.log('Utilisateur:', response.data);
  },
  (response) => {
    console.error('Erreur:', response.errors);
  }
);

Créer une ressource (POST)

httpRequest.findOneRequest(
  {
    method: 'POST',
    path: '/users',
    body: {
      name: 'John Doe',
      email: '[email protected]'
    }
  },
  {},
  (response) => {
    console.log('Créé avec succès:', response.data);
  }
);

Authentification Basic

httpRequest.findAllRequests(
  {
    method: 'GET',
    path: '/secure-data',
    auth: {
      username: 'admin',
      password: 'secret123'
    }
  }
);

WebSocket

Connexion WebSocket

const wsRequest = new WsRequest()
  .initConfig('wss://ws.example.com', 'fr');

wsRequest.connect({
  path: '/socket',
  autoReconnect: true,
  reconnectDelay: 3000,
  maxReconnectAttempts: 5
});

Envoyer et recevoir des messages

// Récupérer plusieurs éléments via WebSocket
wsRequest.findAllMessages(
  {
    action: 'GET_USERS',
    filters: { active: true }
  },
  (response) => {
    console.log('Utilisateurs actifs:', response.data);
  },
  (response) => {
    console.error('Erreur WebSocket:', response.error);
  }
);

// Récupérer un élément spécifique
wsRequest.findOneMessage(
  {
    action: 'GET_USER',
    id: 456
  },
  (response) => {
    console.log('Utilisateur:', response.data);
  }
);

Gestion de la file d'attente

Les messages sont automatiquement mis en file d'attente si la connexion WebSocket n'est pas encore établie et envoyés une fois la connexion rétablie.

Actions Personnalisées

Custom Map Actions

const customMapAction: HttpRequestMapAction = (
  code,
  type,
  message,
  data,
  cleanedData,
  error,
  errors
) => {
  // Logique personnalisée de transformation
  return {
    response: { code, type, message },
    data: cleanedData ? cleanedData.processed : null,
    metadata: { timestamp: new Date().toISOString() },
    error,
    errors
  };
};

httpRequest.findAllRequests(
  { method: 'GET', path: '/data' },
  {},
  new JON.Object('fr'), // schéma
  customMapAction,      // mapAction personnalisée
  undefined,            // errMapAction (par défaut)
  undefined,            // successAction (par défaut)
  undefined             // errorAction (par défaut)
);

Custom Success/Error Actions

const successAction: HttpRequestReponseAction = async (response) => {
  // Enregistrer dans l'historique
  await logToDatabase({
    type: 'request_success',
    code: response.response.code,
    data: response.data
  });
  
  // Afficher une notification
  showNotification('Succès', response.response.message);
};

const errorAction: HttpRequestReponseAction = (response) => {
  // Journaliser l'erreur
  console.error('Request failed:', response);
  
  // Afficher un message d'erreur
  alert(`Erreur \${response.response.code}: \${response.response.message}`);
};

🎯 Exemples Complets

Exemple 1 : Application avec Authentification

class ApiService {
  private http: HttpRequest;
  
  constructor(baseUrl: string, lang: 'fr' | 'en' = 'fr') {
    this.http = new HttpRequest().initConfig(baseUrl, lang);
  }
  
  async login(email: string, password: string) {
    return this.http.findOneRequest(
      {
        method: 'POST',
        path: '/auth/login',
        body: { email, password }
      },
      {},
      (response) => {
        // Stocker le token
        localStorage.setItem('token', response.data.token);
        
        // Rediriger
        window.location.href = '/dashboard';
      },
      (response) => {
        // Afficher l'erreur
        alert(`Échec de connexion: \${response.response.message}`);
      }
    );
  }
  
  async getProfile() {
    const token = localStorage.getItem('token');
    
    return this.http.findOneRequest(
      {
        method: 'GET',
        path: '/profile',
        headers: {
          'Authorization': `Bearer \${token}`
        }
      }
    );
  }
}

Exemple 2 : Chat en Temps Réel

class ChatService {
  private ws: WsRequest;
  private messageHandlers: ((message: any) => void)[] = [];
  
  constructor(wsUrl: string) {
    this.ws = new WsRequest().initConfig(wsUrl, 'fr');
    
    this.ws.connect({
      path: '/chat',
      autoReconnect: true,
      reconnectDelay: 2000
    });
  }
  
  async sendMessage(roomId: string, content: string) {
    return this.ws.findOneMessage(
      {
        action: 'SEND_MESSAGE',
        roomId,
        content,
        timestamp: Date.now()
      },
      (response) => {
        console.log('Message envoyé:', response.data);
      },
      (response) => {
        console.error('Erreur d\'envoi:', response.error);
      }
    );
  }
  
  async getMessages(roomId: string, limit = 50) {
    return this.ws.findAllMessages(
      {
        action: 'GET_MESSAGES',
        roomId,
        limit
      },
      (response) => {
        // Traiter les messages
        response.data.forEach(message => {
          this.messageHandlers.forEach(handler => handler(message));
        });
      }
    );
  }
  
  onMessage(handler: (message: any) => void) {
    this.messageHandlers.push(handler);
  }
}

Exemple 3 : Upload de Fichiers

async uploadFile(file: File, onProgress?: (progress: number) => void) {
  const formData = new FormData();
  formData.append('file', file);
  formData.append('metadata', JSON.stringify({
    name: file.name,
    type: file.type,
    size: file.size
  }));
  
  return this.http.findOneRequest(
    {
      method: 'POST',
      path: '/upload',
      body: formData,
      // Pas de Content-Type pour FormData, le navigateur le définit automatiquement
    },
    {
      // Configuration fetch supplémentaire
      onUploadProgress: (progressEvent) => {
        if (onProgress) {
          const percent = (progressEvent.loaded / progressEvent.total) * 100;
          onProgress(percent);
        }
      }
    },
    (response) => {
      console.log('Fichier uploadé:', response.data);
      showNotification('Succès', 'Fichier uploadé avec succès');
    },
    (response) => {
      console.error('Échec upload:', response.error);
      showNotification('Erreur', 'Échec de l\'upload du fichier');
    }
  );
}

🔧 Configuration Avancée

Types de Notification Personnalisés

import { getNotifRequestType } from '@arc-js/cp-request';

// Étendre les types de notification
function customGetNotifRequestType(status: number): string {
  const baseType = getNotifRequestType(status);
  
  // Ajouter des types personnalisés
  if (status === 429) {
    return 'rate_limit';
  }
  if (status === 503) {
    return 'maintenance';
  }
  
  return baseType;
}

Schémas de Validation Personnalisés

import JON from '@arc-js/jon';

// Créer un schéma de validation personnalisé
const userSchema = new JON.Object('fr').struct({
  id: new JON.Number('fr').required(),
  name: new JON.String('fr').min(2).max(100).required(),
  email: new JON.String('fr').email().required(),
  age: new JON.Number('fr').min(0).max(150),
  roles: new JON.Array('fr').types(
    new JON.Enum('fr').choices('admin', 'user', 'guest')
  ).default(['user'])
});

// Utiliser le schéma dans une requête
httpRequest.findOneRequest(
  { method: 'GET', path: '/user/123' },
  {},
  userSchema, // Schéma personnalisé
  // ... autres paramètres
);

Middleware et Intercepteurs

class RequestLogger {
  static async logRequest(urlParams: HTTPRequestParams) {
    console.log('[REQUEST]', {
      timestamp: new Date().toISOString(),
      method: urlParams.method,
      path: urlParams.path,
      hasBody: !!urlParams.body
    });
  }
  
  static async logResponse(response: HTTPRequestResponse) {
    console.log('[RESPONSE]', {
      timestamp: new Date().toISOString(),
      code: response.response.code,
      type: response.response.type,
      hasData: !!response.data
    });
  }
}

// Envelopper les méthodes existantes
const originalFindAllRequests = HttpRequest.prototype.findAllRequests;
HttpRequest.prototype.findAllRequests = async function(...args) {
  await RequestLogger.logRequest(args[0]);
  const result = await originalFindAllRequests.apply(this, args);
  await RequestLogger.logResponse(result);
  return result;
};

📋 Table des Codes de Notification

| Code HTTP | Type | Description | Action Recommandée | |-----------|------|-------------|-------------------| | 200 | success | Requête réussie | Traiter les données | | 201 | success | Ressource créée | Mettre à jour l'UI | | 204 | success | Pas de contenu | Rafraîchir si nécessaire | | 400 | error | Mauvaise requête | Corriger les données envoyées | | 401 | error_auth_required | Non authentifié | Rediriger vers login | | 403 | error_auth | Non autorisé | Vérifier les permissions | | 404 | error | Non trouvé | Afficher message d'erreur | | 409 | error_auth | Conflit | Résoudre le conflit de données | | 419 | error_auth_required | Session expirée | Renouveler la session | | 422 | warning | Données invalides | Corriger la validation | | 429 | warning | Trop de requêtes | Attendre avant de réessayer | | 500 | error | Erreur serveur | Signaler l'administrateur | | 503 | error | Service indisponible | Réessayer plus tard |

🚨 Gestion des Erreurs

Erreurs de Réseau

try {
  await httpRequest.findAllRequests({
    method: 'GET',
    path: '/data'
  });
} catch (error) {
  if (error.message.includes('Failed to fetch')) {
    // Pas de connexion internet
    showOfflineMessage();
  } else if (error.response?.code === 500) {
    // Erreur serveur
    showServerError();
  } else {
    // Erreur inconnue
    console.error('Erreur inattendue:', error);
  }
}

Retry Automatique

async function fetchWithRetry(urlParams, maxRetries = 3) {
  let lastError;
  
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await httpRequest.findOneRequest(urlParams);
    } catch (error) {
      lastError = error;
      
      // Attendre avant de réessayer (backoff exponentiel)
      await new Promise(resolve => 
        setTimeout(resolve, 1000 * Math.pow(2, i))
      );
    }
  }
  
  throw lastError;
}

🔧 Build et Développement

Structure du Projet

@arc-js/cp-request/
├── cp-request.all.js
├── cp-request.all.min.js
├── index.d.ts
├── index.js
├── index.min.d.ts
├── index.min.js
├── package.json
├── tsconfig.json
└── README.md

📋 Compatibilité

Navigateurs Supportés

  • Chrome 60+
  • Firefox 55+
  • Safari 12+
  • Edge 79+
  • Opera 47+

Environnements

  • Node.js 18+
  • Deno 1.30+
  • Bun 1.0+
  • React Native (avec polyfill fetch)
  • Electron

Dépendances

  • @arc-js/jon (pour la validation)
  • @arc-js/pajo (pour la manipulation de chemins)
  • @arc-js/qust (pour la manipulation de query strings)
  • @arc-js/timez (pour la gestion du temps)

🛡️ Meilleures Pratiques

Sécurité

  1. Toujours valider les entrées : utiliser les schémas JON
  2. Ne pas exposer les tokens : dans les logs de développement
  3. Utiliser HTTPS/SSL : toujours en production
  4. Sanitizer les headers : éviter l'injection de headers

Performance

  1. Réutiliser les instances : créer une instance par base URL
  2. Limiter les requêtes parallèles : utiliser une file d'attente si nécessaire
  3. Mettre en cache : les réponses statiques
  4. Compresser les données : gzip/brotli pour les bodies volumineux

Maintenance

  1. Centraliser la configuration : dans un service dédié
  2. Logger proprement : différents niveaux selon l'environnement
  3. Versionner les APIs : dans le path (/api/v1/)
  4. Documenter les endpoints : avec des exemples

📄 Licence

MIT License - Voir le fichier LICENSE pour plus de détails.

🐛 Signaler un Bug

Envoyez nous un mail à l'adresse [email protected] pour :

  • Signaler un bug
  • Proposer une amélioration
  • Poser une question

@arc-js/cp-request - Une solution complète pour les communications client-serveur.

Développé par l'équipe INICODE