/** * SDK TypeScript non-officiel pour l'API PasDeVélib. * https://api.pasdevelib.app/docs * * Aucune dépendance, aucune étape de build — copiez ce fichier tel quel * dans votre projet (ou importez-le directement si votre bundler * accepte les imports d'URL). * * Usage : * const pdv = new PasDeVelibClient('VOTRE_CLE_API'); * const evolution = await pdv.stats('bordeaux', { kind: 'evolution' }); */ export type City = 'paris' | 'bordeaux' | 'lyon' | 'toulouse' | 'lille' | 'rennes' | 'strasbourg'; export type StatKind = 'period' | 'evolution' | 'patterns' | 'records' | 'traffic' | 'stuck' | 'weather' | 'typology'; export type Period = 'day' | 'week' | 'month'; export class PasDeVelibApiError extends Error { constructor(public status: number, message: string) { super(message); this.name = 'PasDeVelibApiError'; } } export class PasDeVelibClient { constructor( private apiKey: string, private baseUrl: string = 'https://api.pasdevelib.app' ) {} /** * Récupère un indicateur pour une ville donnée. * Voir https://api.pasdevelib.app/docs/metiers pour le détail de * chaque `kind` (structure de réponse variable). */ async stats(city: City, options?: { kind?: StatKind; period?: Period }): Promise { const params = new URLSearchParams({ city }); if (options?.kind) params.set('kind', options.kind); if (options?.period) params.set('period', options.period); const res = await fetch(`${this.baseUrl}/v1/stats?${params.toString()}`, { headers: { 'X-API-Key': this.apiKey }, }); if (!res.ok) { const body = await res.text().catch(() => ''); const messages: Record = { 400: 'Paramètre city ou kind invalide.', 401: "Clé API manquante, invalide, ou accès non actif — voir https://api.pasdevelib.app/request-access.", 429: 'Limite quotidienne de 200 requêtes/jour atteinte.', }; throw new PasDeVelibApiError(res.status, messages[res.status] ?? `Erreur API (${res.status}) : ${body}`); } return res.json(); } }