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

bridgedirecte

v0.3.1

Published

RESTful API bridge for EcoleDirecte via wrapdirecte

Readme

bridgeDirecte 🌸 Flower 1.1

RESTful API bridge for EcoleDirecte, powered by wrapdirecte and Cloudflare Workers.


Utilisation

Le bridge peut être utilisé de deux manières :

1. via npm (recommandé)

Vous pouvez utiliser bridgedirecte comme une bibliothèque dans votre propre Worker Cloudflare.

import { createBridge } from 'bridgedirecte'

// Exportation de l'instance configurée
export default createBridge({
  allowedOrigins: ['https://votre-site.com'], // défaut ["*"]
  appName: 'monApplication', // défaut: nom dans package.json
  appVersion: '1.0.0', // défaut: version dans package.json
  forceHttps: true, // refuse les requêtes non sécurisées, défaut true
})

Si vous souhaitez simplement faire une nouvelle instance vierge :

git clone https://bridge.directe.qzz.io/new
npm i
npx wrangler deploy

Vous pourrez modifier les paramètres de configuration dans le fichier worker.js.

2. par clonage du code source

git clone https://bridge.directe.qzz.io/sourcecode

Si vous clonez le code source directement, vous pouvez configurer l'instance via un fichier bridgedirecte.config.jsonc à la racine du projet :

{
  "allowedOrigins": ["*"],
  "appName": "bridgeDirecteCustom",
  "appVersion": "1.0.0",
  "forceHttps": true,
}

Configuration

| Réglage | Description | Défaut | | ---------------- | ------------------------------------- | -------------- | | allowedOrigins | Liste des origines autorisées (CORS) | ["*"] | | appName | Nom de l'application (User-Agent) | package.json | | appVersion | Version de l'application (User-Agent) | package.json | | forceHttps | Exiger HTTPS (sauf localhost) | true |

[!CAUTION] Si vous fournissez des réglages à createBridge() ET qu'un fichier bridgedirecte.config.jsonc est présent, le bridge renverra une erreur "Bad config".


Authentification

Le bridge est stateless. Chaque requête (sauf /login et /login/2fa) nécessite :

| Header | Description | Exemple | | --------------- | --------------------------------------- | -------------------- | | Authorization | Token Bearer obtenu après /login | Bearer eyJhbGci... | | Account-ID | ID numérique du compte élève à utiliser | 1234 |


Endpoints

🔐 Authentification

POST /login

Connexion avec identifiants EcoleDirecte.

Query (Optionnel) : ?direct=true pour bypasser le 2FA si vous avez un 2faProof.

Body :

{
  "username": "mon.identifiant",
  "password": "monMotDePasse",
  "2faProof": "mon2faProof (requis si direct=true)",
  "uuid": "optionnel-uuid"
}

Réponse (succès) :

{
  "success": true,
  "status": "authenticated",
  "token": "eyJhbGci...",
  "faProof": "leProofAStocker",
  "accounts": [{ "id": 123456, "firstName": "Jean", "lastName": "Dupont" }]
}

Réponse (2FA requis) :

{
  "success": true,
  "status": "needs_2fa",
  "challenge": {
    "question": "Quel est le prénom de votre professeur principal ?",
    "proposals": []
  },
  "partialToken": "eyJhbGci..."
}

POST /login/2fa

Soumettre la réponse 2FA.

Headers requis : Authorization: Bearer <partial_token>

Body :

{
  "answer": "reponse",
  "username": "votre_username",
  "password": "votre_password",
  "uuid": "optionnel"
}

Réponse :

{
  "success": true,
  "status": "authenticated",
  "token": "eyJhbGci...",
  "faProof": "leProofAStocker",
  "accounts": [{ "id": 123456 }]
}

📚 Notes

GET /grades

Headers : Authorization, Account-ID
Query : ?year=2025-2026 (défaut : année scolaire en cours)

Réponse :

{
  "grades": [...],
  "periods": [...],
  "settings": {}
}

📝 Devoirs

GET /homework

Headers : Authorization, Account-ID
Query : ?date=2026-04-08 (défaut : aujourd'hui)

Réponse : CleanHomework[]


PATCH /homework

Marquer un devoir comme fait ou non fait.

Headers : Authorization, Account-ID
Query : ?id=<homeworkId>

Body :

{ "done": true }

Réponse :

{ "success": true, "id": 987654, "done": true }

POST /homework/:id/comment

Ajouter un commentaire à un devoir.

Headers : Authorization, Account-ID

Body :

{ "content": "Mon commentaire" }

Réponse :

{ "success": true, "commentId": 111 }

📅 Emploi du temps

GET /timetable

Headers : Authorization, Account-ID
Query : ?from=2026-04-01&to=2026-04-07 (défaut : semaine courante)

Réponse : CleanCourse[]


GET /timetable/ical

Headers : Authorization, Account-ID

Réponse :

{ "success": true, "url": "https://api.ecoledirecte.com/ical/..." }

🚫 Absences

GET /absences

Headers : Authorization, Account-ID

Réponse : CleanAbsence[]


📰 Timeline

GET /timeline

Timeline personnelle de l'élève.

Headers : Authorization, Account-ID

Réponse : CleanTimelineEvent[]


GET /timeline/school

Timeline commune (toute l'école).

Headers : Authorization, Account-ID

Réponse :

{
  "events": [...],
  "postits": [...]
}

📄 Documents

GET /documents

Headers : Authorization, Account-ID

Réponse :

{
  "factures": [...],
  "notes": [...]
}

☁️ Cloud

GET /cloud

Headers : Authorization, Account-ID
Query : ?depth=3 (défaut : 3)

Réponse : CleanCloudNode[]


POST /cloud/folder

Créer un dossier.

Headers : Authorization, Account-ID

Body :

{ "path": "parent/chemin", "name": "nouveauDossier" }

POST /cloud/copy

Copier des fichiers/dossiers.

Body :

{ "destination": "dest/chemin", "nodes": [...] }

POST /cloud/move

Déplacer des fichiers/dossiers.

Body :

{ "destination": "dest/chemin", "nodes": [...] }

DELETE /cloud

Supprimer des fichiers/dossiers.

Body :

{ "nodes": [...] }

POST /cloud/restore

Restaurer des fichiers/dossiers supprimés.

Body :

{ "nodes": [...] }

POST /cloud/export

Exporter un fichier vers le cloud.

Body :

{
  "fileId": "abc123",
  "source": "CAHIER_DE_TEXTES"
}

source : "CAHIER_DE_TEXTES" ou "MESSAGERIE"


✉️ Messagerie

GET /messages

Headers : Authorization, Account-ID
Query : ?year=2025-2026

Réponse :

{
  "received": [...],
  "sent": [...],
  "draft": [...],
  "archived": [...],
  "folders": [...]
}

GET /messages/:id

Contenu complet d'un message.

Headers : Authorization, Account-ID
Query : ?year=2025-2026&glance=true (glance=true marque le message comme non lu lors de l'ouverture)

Réponse : CleanMessage avec champ content


GET /messages/folder/:folderId

Messages d'un dossier spécifique.

Headers : Authorization, Account-ID

Réponse : CleanMessage[]


GET /messages/contacts/:type

Récupérer les contacts.

Headers : Authorization, Account-ID
Paramètre : :type = professeurs | personnels | entreprises

Réponse : Contact[]


POST /messages

Envoyer un message.

Headers : Authorization, Account-ID

Body :

{
  "subject": "Objet du message",
  "content": "Contenu du message",
  "recipients": [{ "id": 123, "type": "P" }],
  "year": "2025-2026"
}

Réponse :

{ "success": true, "messageId": 456789 }

PUT /messages/:id/read

Marquer un message comme lu.

Headers : Authorization, Account-ID
Query : ?year=2025-2026

Réponse :

{ "success": true }

PUT /messages/:id/unread

Marquer un message comme non lu.

Headers : Authorization, Account-ID
Query : ?year=2025-2026

Réponse :

{ "success": true }

PUT /messages/:id/archive

Archiver un message.

Headers : Authorization, Account-ID
Query : ?year=2025-2026

Réponse :

{ "success": true }

PUT /messages/:id/unarchive

Désarchiver un message.

Headers : Authorization, Account-ID
Query : ?year=2025-2026

Réponse :

{ "success": true }

PATCH /messages/:id/move

Déplacer un message vers un autre dossier.

Headers : Authorization, Account-ID

Body :

{ "folder": 12345 }

Réponse :

{ "success": true }

POST /messages/folder

Créer un nouveau dossier.

Headers : Authorization, Account-ID

Body :

{ "name": "Nom du dossier" }

Réponse :

{ "success": true, "id": 12345 }

DELETE /messages/folder/:folderId

Supprimer un dossier.

Headers : Authorization, Account-ID

Réponse :

{ "success": true }

⚙️ Paramètres

GET /settings

Headers : Authorization, Account-ID
Query : ?loginId=123 (optionnel)


PATCH /settings

Mettre à jour les paramètres du compte.

Headers : Authorization, Account-ID

Body :

{
  "identifiant": "nouvelIdentifiant",
  "nouveauMotDePasse": "nouveauMotDePasse",
  "confirmationMotDePasse": "nouveauMotDePasse",
  "email": "[email protected]",
  "portable": "0612345678",
  "questionSecrete": "Question secrète",
  "reponse": "Réponse",
  "uuid": "optionnel"
}

PATCH /settings/param

Mettre à jour un paramètre individuel.

Headers : Authorization, Account-ID

Body :

{ "value": "nouvelle-valeur" }

Format des erreurs

Toutes les erreurs suivent ce format :

{
  "success": false,
  "error": "Description de l'erreur",
  "code": 400
}

| Code | Signification | | ---- | -------------------------------- | | 400 | Requête invalide (body, params) | | 401 | Non authentifié / token invalide | | 404 | Route introuvable | | 500 | Erreur interne du serveur | | 503 | Module indisponible |


IP Spoofing

Le bridge injecte automatiquement un header X-Forwarded-For avec une IP française aléatoire sur chaque requête vers EcoleDirecte, en utilisant les préfixes des principaux opérateurs :

| Préfixe | Opérateur | | ----------- | ------------- | | 80.12.* | Orange | | 82.224.* | Free | | 176.128.* | SFR | | 90.1.* | Orange Mobile |


Licence

AGPL 3.0 — Voir LICENSE pour les détails.