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

@communecter/cocolight-api-client

v1.0.119

Published

Client Axios simplifié pour l'API cocolight

Readme

Cocolight API Client

Ce module fournit un client JavaScript prêt à l'emploi pour interagir avec l'API Cocolight. Il encapsule la gestion des appels HTTP, l'authentification, la validation des schémas, la gestion des erreurs, ainsi qu'un ensemble de normalisations des données pour simplifier l'intégration côté client.

📦 Installation

npm install @communecter/cocolight-api-client

🧭 Objectif

Ce client facilite l'intégration avec l'API Cocolight en offrant :

  • Des appels simplifiés avec axios
  • Un système de validation des entrées/sorties avec AJV
  • La gestion automatique du token d'accès et du token de rafraîchissement
  • Un circuit breaker configurable
  • Un logger intégré avec Pino
  • Des outils de transformation de données compatibles MongoDB/EJSON
  • La gestion des appels API à partir de métadonnées JSON (endpoints)

🧱 Architecture

Le projet est structuré autour des fichiers suivants :

src/
  ApiClient.js         # Client principal : logique d'appel, authentification, validation, transformation
  EJSONType.js         # Support pour les ObjectID MongoDB avec EJSON
  endpoints.module.js  # Fichier généré avec les définitions d'endpoints (voir ci-dessous)
  error.js             # Erreurs personnalisées (ApiClientError, CircuitBreakerError)
package.json           # Dépendances, scripts, métadonnées

imports

ESM

import Cocolight from "@communecter/cocolight-api-client";

const { Api, ApiClient, tokenStorageStrategy } = Cocolight;

CommonJS

const { ApiClient, Api, tokenStorageStrategy } = require("@communecter/cocolight-api-client").default;

🔗 Intégration via CDN

Vous pouvez inclure le client directement dans une page HTML :

<script src="https://cdn.jsdelivr.net/npm/@communecter/cocolight-api-client@latest/dist/cocolight-api-client.browser.js"></script>
<script>
  const client = new CocolightApiClient.ApiClient({
    baseURL: "https://www.communecter.org"
  });

client.callEndpoint("AUTHENTICATE_URL", {
        email: "EMAIL",
        password: "PASSWORD"
      }).then(res => {
          const { accessToken, refreshToken, user } = res.data;
          console.log("✅ Authentifié :", user.username);
        })
        .then(() => {
          return client.callEndpoint("ME_INFO_URL");
        })
        .then(res => {
          console.log("👤 Profil utilisateur :", res.data);
        })
        .then(() => {
          console.log("userId :", client.userId);
        })
      .catch(err => console.error("Erreur :", err));
</script>

🔧 Utilisation de base

import { ApiClient } from "@communecter/cocolight-api-client";

const client = new ApiClient({
  baseURL: "https://mon-api.com"
});

try {
    const authResponse = await client.callEndpoint("AUTHENTICATE_URL", {
      email: "EMAIL",
      password: "PASSWORD"
    });

    const { accessToken, refreshToken, user } = authResponse.data;

    console.log("✅ Authentifié :", user.username);

    const meResponse = await client.callEndpoint("ME_INFO_URL");

    console.log("👤 Profil utilisateur :", meResponse.data);

    console.log("userId :", client.userId);
  } catch (error) {
    console.error("❌ Erreur durant la session :", error.message, error.details);
  }

📜 API détaillée

new ApiClient(options)

| Option | Type | Description | |---------------------------|------------|-------------| | baseURL (requis) | string | URL de base de l'API | | accessToken | string | Token d'accès initial | | refreshToken | string | Token de rafraîchissement | | refreshUrl | string | URL pour rafraîchir le token (défaut : /api/cocolight/refreshtoken) | | endpoints | Array | Liste des endpoints (par défaut : endpoints.module.js) | | timeout | number | Timeout en ms (défaut : 30000) | | debug | boolean | Active le logger debug (défaut : false) | | maxRetries | number | Nombre de tentatives max (défaut : 0) | | circuitBreakerThreshold | number | Seuil d'erreurs avant blocage (défaut : 5) | | circuitBreakerResetTime | number | Délai de réactivation (en ms, défaut : 60000) | | fromJSONValue | boolean | Applique EJSON.fromJSONValue sur les réponses (défaut : true) |

Méthodes principales

callEndpoint(constant, data, transform, validate)

Effectue un appel à un endpoint défini via endpoints.module.js.

  • constant: nom unique du endpoint
  • data: objet avec pathParams et données du corps
  • transform: true (par défaut), false, ou fonction de transformation
  • validate: true (par défaut), permet de valider la réponse via AJV

setToken(token) / getToken()

Gère le token d'accès.

setRefreshToken(rt) / getRefreshToken()

Gère le token de rafraîchissement.

resetSession()

Réinitialise la session utilisateur.

Événements

  • refreshSuccess — déclenché après un rafraîchissement réussi
  • validationError — déclenché si AJV détecte des erreurs
  • sessionReset — déclenché par resetSession()

🛠️ Scripts disponibles

Depuis package.json :

  • npm run test — Lance les tests via Jest
  • npm run exemple — Lance un exemple
  • npm run lint / lint:fix — Vérifie et corrige le code avec ESLint
  • npm run build — Génère les builds navigateur + Node via Webpack
  • npm run generate:* — Génère les modules, documentation ou données de test depuis les fichiers JSON d’API

🧩 Dépendances principales

  • axios & axios-retry — pour les appels HTTP robustes
  • ajv & ajv-formats — pour la validation JSON Schema
  • ejson — pour la compatibilité MongoDB (ObjectID, dates...)
  • pino — logger performant, compatible navigateur
  • events — pour la gestion des événements custom côté client

🗃️ Format des endpoints

Chaque endpoint dans endpoints.module.js suit le schéma :

{
  constant: "GET_USER_INFO",
  method: "GET",
  path: "/api/users/{userId}",
  auth: "bearer",
  pathParams: { type: "object", properties: { userId: { type: "string" } }, required: ["userId"] },
  request: { ...schemaAjv },
  responses: { "200": { ...schemaAjv } },
  postActions: [
    { type: "setToken", path: "accessToken" },
    { type: "setUserId", path: "user._id" }
  ]
}

🔒 Sécurité et circuit breaker

Un circuit breaker est intégré :

  • Blocage temporaire après trop d’échecs (circuitBreakerThreshold)
  • Réactivation après un délai (circuitBreakerResetTime)
  • Journalisation complète avec pino

🧪 Validation AJV

Chaque appel est validé avant (requête) et après (réponse) via AJV. En cas d’erreur, l’événement validationError est déclenché avec les détails.

🔄 Rafraîchissement automatique

Si une réponse retourne 401, le client tente automatiquement un appel POST vers refreshUrl avec le refreshToken, et réessaie l’appel initial si réussi.

🧼 Transformation des données

Les réponses sont normalisées :

  • Champs dates, images, IDs MongoDB
  • Structures communes comme results, news, notif, replies, etc.
  • Conversion EJSON via EJSON.fromJSONValue()

🧙 Valeurs dynamiques

Dans les données pathParams, il est possible d’utiliser des alias dynamiques :

pathParams: {
  userId: "@userId",
  accessToken: "@accessToken"
}

🎩 API de façade : Api

La classe Api fournit une interface unifiée pour gérer les utilisateurs, organisations, projets et actualités. Elle encapsule les appels à ApiClient et permet de manipuler les entités comme des objets métier avec des méthodes pratiques.

🧪 Authentification

Api.userLogin(email, password, options)

Crée une instance d’Api authentifiée.

const api = await Api.userLogin("[email protected]", "password123", { baseURL: "https://api.monapp.com" });
const user = await api.me();

Api.userApi(options)

Retourne une instance UserApi si tu veux gérer manuellement l’authentification :

const userApi = Api.userApi({ baseURL: "..." });
const user = await userApi.login("email", "mdp");

🔐 Session et utilisateur courant

api.me()

Retourne l'utilisateur actuellement connecté (User).

const user = await api.me();
console.log(user.data.email);

👤 Utilisateurs

api.user(userData)

Crée une instance User (autre que le connecté).

const otherUser = await api.user({ slug: "caroline" });
console.log(otherUser.data.description);

🏛️ Organisations

api.organization({ id | slug })

Retourne une instance d’Organization. Récupère automatiquement le profil public.

const orga = await api.organization({ slug: "asso-verte" });
console.log(orga.data.name);

🏗️ Projets

api.project({ id | slug })

Retourne une instance Project. Récupère automatiquement le profil public.

const projet = await api.project({ id: "647..." });

📦 Entités métiers

Les entités suivantes partagent une API commune grâce aux mixins : User, Organization, Project, News.

Propriétés

| Propriété | Description | |------------------|-------------| | data | Proxy combiné serverData + draftData | | draftData | Données modifiables avant save() | | initialDraftData | Snapshot initial pour détection des changements | | serverData | Dernières données serveur | | isConnected | Vrai si ApiClient a un token | | userId | ID de l'utilisateur connecté | | isMe | Vrai si l'entité correspond à l'utilisateur courant |


Méthodes génériques

entity.save()

Sauvegarde les données via les blocs modifiés (UPDATE_BLOCK_*, ADD_*).

entity.refresh()

Recharge les données depuis le serveur.

entity.hasChanges()

Retourne true si le draft est différent du snapshot initial.


✏️ Méthodes d’édition (communes à toutes les entités)

| Méthode | Description | |------------------------|-------------| | updateDescription | Met à jour les champs shortDescription, description, descMentions | | updateInfo | Nom, email, téléphone, etc. | | updateSocial | Réseaux sociaux (Facebook, GitHub...) | | updateLocality | Adresse, géolocalisation | | updateSlug | Slug de l’URL | | updateImageProfil | Upload de l’avatar |


📰 Actualités (News)

Créées à partir d’un User, Organization ou Project.

Création

const news = await orga.news();
news.data.text = "Nouvelle actu !";
await news.save();

Gestion

| Méthode | Description | |----------------|-------------| | addMention({ slug \| id }) | Ajoute une mention à la news | | addImage(file) | Ajoute une image (via validation MIME) | | addFile(file) | Ajoute un fichier (PDF, CSV...) | | delete() | Supprime la news | | refresh() | Recharge la news | | get() | Récupère les données à partir de l’ID |


🔄 Utilisation des schémas de validation (AJV)

Toutes les entités sont basées sur les constantes de schéma :

  • ADD_*
  • UPDATE_BLOCK_*
  • PROFIL_IMAGE

Ces constantes sont mappées automatiquement pour les appels save(), updateX(), etc.


✅ Exemple : mise à jour d’un projet

const projet = await api.project({ slug: "bio-bazar" });
projet.data.description = "Nouveau descriptif de mon projet.";
if (projet.hasChanges()) {
  await projet.save();
}

👤 API : Utilisateur (User)

Une instance User offre un ensemble de méthodes métier pour interagir avec les projets, organisations et actualités de l’utilisateur.


🔍 Chargement

const user = await api.user({ slug: "caroline" });
await user.get();

🏭 Création d'entités depuis User

Un utilisateur peut créer :

➕ Organisation

const orga = await user.organization({ name: "Ma nouvelle asso" });
await orga.save(); // appelle ADD_ORGANIZATION puis rafraîchit les données

➕ Projet

const projet = await user.project({ name: "Mon projet citoyen" });
await projet.save(); // appelle ADD_PROJECT

➕ Actualité

const news = await user.news({ text: "Hello world 🌍" });
await news.save(); // appelle ADD_NEWS

📦 Récupération des projets de l'utilisateur

user.getProjects()

Retourne la liste des projets créés ou co-administrés par l’utilisateur.

const { results: projets } = await user.getProjects();
console.log("Projets liés à l'utilisateur :", projets.map(p => p.data.name));

🧑‍🤝‍🧑 Récupération des organisations de l'utilisateur

user.getOrganizations()

Retourne les organisations où il est membre (admin ou non).

const { results: orgs } = await user.getOrganizations();
console.log("Organisations :", orgs.map(o => o.data.name));

📰 Actualités associées

user.getNews()

Retourne toutes les actualités liées à l’utilisateur.

const newsList = await user.getNews({ indexStep: 5 });

user.news(newsData)

Crée une nouvelle actualité, ou charge une existante si id est fourni.

const actu = await user.news({ text: "Ceci est une nouvelle actu" });
await actu.save();

⚙️ Mise à jour du profil utilisateur

Les méthodes updateX disponibles sont :

  • updateDescription(data)
  • updateInfo(data)
  • updateSocial(data)
  • updateLocality(data)
  • updateSlug({ slug })
  • updateImageProfil({ profil_avatar })
  • updateSettings({ type, value })

🔑 Sécurité et gestion de compte

Modifier mot de passe

await user.changePassword({
  oldPassword: "secret1",
  newPassword: "secret2",
  newPassword2: "secret2"
});

Supprimer son compte

await user.delete({ reason: "Je souhaite quitter la plateforme" });

Licence

MIT

👤 Auteur

Thomas Craipeau