- Fix cold-start privacy bug: apply persisted collection preference on launch - Disable Firebase collection in debug builds to avoid polluting prod data - Add Crashlytics custom keys (is_logged_in, channel), user identifier, and WebSocket reconnection breadcrumbs for actionable crash reports - Record non-fatal errors for server failures, WebSocket errors, and global asset fetch failures (skip timeouts/network errors to avoid noise) - Update is_logged_in key and user identifier on login/logout transitions - Log auth reconnection exhaustion before forced logout - Add FirebaseAnalyticsObserver with named routes for automatic screen tracking - Add static routeName constants to avoid duplicated string literals - Add Firebase Performance Dio interceptor for automatic HTTP request tracing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
71 lines
2.4 KiB
Dart
71 lines
2.4 KiB
Dart
import 'package:dio/dio.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:frosty/apis/firebase_performance_interceptor.dart';
|
|
|
|
/// Centralized Dio client configuration with interceptors and error handling
|
|
class DioClient {
|
|
static Dio createClient({List<Interceptor>? additionalInterceptors}) {
|
|
final dio = Dio();
|
|
|
|
// Optimized configuration based on 2024-2025 best practices
|
|
dio.options = BaseOptions(
|
|
connectTimeout: const Duration(
|
|
seconds: 8,
|
|
), // Balanced for various networks
|
|
receiveTimeout: const Duration(
|
|
seconds: 15,
|
|
), // Allow for larger API responses
|
|
sendTimeout: const Duration(seconds: 10), // Reasonable for uploads
|
|
headers: {
|
|
'User-Agent': 'Frosty (Flutter Twitch Client)',
|
|
'Accept': 'application/json',
|
|
'Content-Type': 'application/json',
|
|
'Connection': 'keep-alive', // Enable connection reuse
|
|
},
|
|
followRedirects: true,
|
|
maxRedirects: 3, // Reduced for better performance
|
|
persistentConnection: true, // Enable connection pooling
|
|
);
|
|
|
|
// Simple logging for debug builds
|
|
if (kDebugMode) {
|
|
dio.interceptors.add(
|
|
InterceptorsWrapper(
|
|
onRequest: (options, handler) {
|
|
debugPrint('→ ${options.method} ${options.uri}');
|
|
handler.next(options);
|
|
},
|
|
onResponse: (response, handler) {
|
|
final statusCode = response.statusCode ?? 0;
|
|
final emoji = statusCode >= 200 && statusCode < 300 ? '✅' : '❌';
|
|
debugPrint(
|
|
'$emoji ${response.statusCode} ${response.requestOptions.method} ${response.requestOptions.uri}',
|
|
);
|
|
handler.next(response);
|
|
},
|
|
onError: (error, handler) {
|
|
debugPrint(
|
|
'❌ ${error.type.name} ${error.requestOptions.method} ${error.requestOptions.uri}',
|
|
);
|
|
if (error.response != null) {
|
|
debugPrint(' Status: ${error.response!.statusCode}');
|
|
}
|
|
handler.next(error);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
// Trace HTTP requests as Firebase Performance metrics
|
|
dio.interceptors.add(FirebasePerformanceInterceptor());
|
|
|
|
// Add any additional interceptors provided
|
|
if (additionalInterceptors != null) {
|
|
for (final interceptor in additionalInterceptors) {
|
|
dio.interceptors.add(interceptor);
|
|
}
|
|
}
|
|
|
|
return dio;
|
|
}
|
|
}
|