import 'dart:convert'; import 'dart:html' as html; import 'package:http/http.dart' as http; /// Client HTTP authentifié pour les routes `/api/*` protégées. /// /// POURQUOI CE FICHIER EXISTE /// Les routes `/api/epg`, `/api/recordings` et `/api/season-passes` sont /// montées derrière `authMiddleware` côté serveur. Or plusieurs écrans les /// appelaient avec `package:http` nu, qui n'envoie ni en-tête `Authorization` /// ni cookie : sur le web, `BrowserClient` a `withCredentials = false`, donc /// le cookie `session` reste à quai. Toutes ces requêtes repartaient en 401 — /// guide TV vide, liste d'enregistrements vide, season passes vides. /// /// Ce wrapper injecte le même jeton que `ApiClient` et `XtreamService` /// (`localStorage['auth_token']`), de sorte qu'il n'existe qu'une seule /// source de vérité pour la session. class AuthedHttp { AuthedHttp._(); /// Jeton de session posé par `ApiClient.setToken` à la connexion. static String? get _token { final t = html.window.localStorage['auth_token']; return (t != null && t.isNotEmpty) ? t : null; } /// IPTV sélectionnée (persistée par `playlistPersistenceProvider`). /// /// Envoyée à chaque appel : sans elle le serveur prenait la playlist la /// plus récente, et guide, enregistrements et Auto NBA visaient la /// mauvaise IPTV quand plusieurs étaient configurées. static String? get selectedPlaylistId { try { final stored = html.window.localStorage['selected_playlist']; if (stored == null) return null; final id = (jsonDecode(stored) as Map)['id']; return (id is String && id.isNotEmpty) ? id : null; } catch (_) { return null; } } static Map _headers([Map? extra]) { final token = _token; final playlistId = selectedPlaylistId; return { if (playlistId != null) 'X-Playlist-Id': playlistId, if (extra != null) ...extra, if (token != null) 'Authorization': 'Bearer $token', }; } static Future get(Uri url, {Map? headers}) => http.get(url, headers: _headers(headers)); static Future post( Uri url, { Map? headers, Object? body, }) => http.post(url, headers: _headers(headers), body: body); static Future put( Uri url, { Map? headers, Object? body, }) => http.put(url, headers: _headers(headers), body: body); static Future delete( Uri url, { Map? headers, Object? body, }) => http.delete(url, headers: _headers(headers), body: body); }