import 'dart:async'; import 'dart:io'; import 'package:http/http.dart' as http; import 'errors/auth_exception.dart'; import 'errors/network_exception.dart'; import 'errors/not_found_exception.dart'; import 'errors/server_exception.dart'; /// Runs [send] and converts transport-level failures (socket/timeout/client /// errors) into a [NetworkException] tagged with [label] (e.g. `Talk `). /// Passes through whatever [send] produces, including `null` for the base-class /// request hooks that may skip the call. Future sendGuarded( String label, Future? Function() send, ) async { try { return await send(); } on SocketException catch (e) { throw NetworkException(technicalDetails: '$label: ${e.message}'); } on TimeoutException catch (e) { throw NetworkException.timeout(technicalDetails: '$label: $e'); } on http.ClientException catch (e) { throw NetworkException(technicalDetails: '$label: ${e.message}'); } } /// Collapses whitespace and caps an HTTP error body at 500 chars so it can be /// embedded in an [AppException]'s technical details without dumping headers. String previewBody(String body) { final collapsed = body.replaceAll(RegExp(r'\s+'), ' ').trim(); return collapsed.length > 500 ? '${collapsed.substring(0, 500)}…' : collapsed; } /// Builds a `