diff --git a/contact/pubspec.lock b/contact/pubspec.lock index d58109b58..913981dd3 100644 --- a/contact/pubspec.lock +++ b/contact/pubspec.lock @@ -1056,6 +1056,14 @@ packages: url: "https://pub.dev" source: hosted version: "9.8.0" + sentry_dio: + dependency: transitive + description: + name: sentry_dio + sha256: bee438fd790c534da77f0a6c9cd04c54c818184b8a54bbe7d916489c8aad56a0 + url: "https://pub.dev" + source: hosted + version: "9.8.0" sentry_flutter: dependency: transitive description: diff --git a/core/lib/core.dart b/core/lib/core.dart index 24c76429c..aff2bfed4 100644 --- a/core/lib/core.dart +++ b/core/lib/core.dart @@ -62,6 +62,7 @@ export 'utils/html/html_utils.dart'; export 'utils/web_link_generator.dart'; export 'utils/sentry/sentry_manager.dart'; export 'utils/config/env_loader.dart'; +export 'utils/sentry/sentry_dio_helper.dart'; // Views export 'presentation/views/text/slogan_builder.dart'; diff --git a/core/lib/utils/application_manager.dart b/core/lib/utils/application_manager.dart index 7d7683513..495c5f8b7 100644 --- a/core/lib/utils/application_manager.dart +++ b/core/lib/utils/application_manager.dart @@ -30,6 +30,7 @@ class ApplicationManager { _versionCache = null; _cachedWebUserAgent = null; _cachedMobileUserAgent = null; + _isMobileUserAgentInitialized = false; } Future getPackageInfo() async { diff --git a/core/lib/utils/config/env_loader.dart b/core/lib/utils/config/env_loader.dart index 9b4c49f28..35c561e4c 100644 --- a/core/lib/utils/config/env_loader.dart +++ b/core/lib/utils/config/env_loader.dart @@ -29,6 +29,7 @@ class EnvLoader { ); } catch (e) { logWarning('EnvLoader::loadFcmConfigFileToEnv: Exception = $e'); + // FCM config is optional; reload base config to restore dotenv.env state await onCallBack?.call(); } } diff --git a/core/lib/utils/sentry/sentry_config.dart b/core/lib/utils/sentry/sentry_config.dart index a316b9940..8a2acaaf2 100644 --- a/core/lib/utils/sentry/sentry_config.dart +++ b/core/lib/utils/sentry/sentry_config.dart @@ -45,7 +45,7 @@ class SentryConfig { }); /// Load configuration from an env file. - static Future load() async { + static Future load() async { await EnvLoader.loadConfigFromEnv(); final sentryAvailable = dotenv.get('SENTRY_ENABLED', fallback: 'false'); @@ -54,12 +54,10 @@ class SentryConfig { final sentryDSN = dotenv.get('SENTRY_DSN', fallback: ''); final sentryEnvironment = dotenv.get('SENTRY_ENVIRONMENT', fallback: ''); - if (!isAvailable) { - throw Exception('Sentry is not available'); - } - - if (sentryDSN.trim().isEmpty || sentryEnvironment.trim().isEmpty) { - throw Exception('Sentry configuration is missing'); + if (!isAvailable || + sentryDSN.trim().isEmpty || + sentryEnvironment.trim().isEmpty) { + return null; } final appVersion = await ApplicationManager().getAppVersion(); diff --git a/core/lib/utils/sentry/sentry_dio_helper.dart b/core/lib/utils/sentry/sentry_dio_helper.dart new file mode 100644 index 000000000..06197c75c --- /dev/null +++ b/core/lib/utils/sentry/sentry_dio_helper.dart @@ -0,0 +1,15 @@ +import 'package:core/utils/sentry/sentry_manager.dart'; +import 'package:dio/dio.dart'; +import 'package:sentry_dio/sentry_dio.dart'; + +class SentryDioHelper { + static void addIfAvailable(Dio dio) { + if (!SentryManager.instance.isSentryAvailable) return; + + final alreadyHasSentry = dio.interceptors.any( + (i) => i.runtimeType.toString().contains('FailedRequestInterceptor')); + if (!alreadyHasSentry) { + dio.addSentry(); + } + } +} diff --git a/core/lib/utils/sentry/sentry_initializer.dart b/core/lib/utils/sentry/sentry_initializer.dart index 8a5c827fc..6d1281beb 100644 --- a/core/lib/utils/sentry/sentry_initializer.dart +++ b/core/lib/utils/sentry/sentry_initializer.dart @@ -11,14 +11,19 @@ class SentryInitializer { 'x-auth', 'x-token', 'api-key', + 'x-api-key', 'apikey', 'secret', 'bearer', + 'session', + 'password', ]; static Future init(FutureOr Function() appRunner) async { final config = await SentryConfig.load(); + if (config == null) return false; + await SentryFlutter.init( (options) { options.dsn = config.dsn; diff --git a/core/lib/utils/sentry/sentry_manager.dart b/core/lib/utils/sentry/sentry_manager.dart index d29e85085..9e0e4ba83 100644 --- a/core/lib/utils/sentry/sentry_manager.dart +++ b/core/lib/utils/sentry/sentry_manager.dart @@ -22,6 +22,7 @@ class SentryManager { try { if (_isSentryAvailable) { log('[SentryManager] Already initialized, skipping'); + await appRunner(); return; } _isSentryAvailable = await SentryInitializer.init(appRunner); diff --git a/core/pubspec.lock b/core/pubspec.lock index fe2f4a19b..7c94ce9c7 100644 --- a/core/pubspec.lock +++ b/core/pubspec.lock @@ -1009,6 +1009,14 @@ packages: url: "https://pub.dev" source: hosted version: "9.8.0" + sentry_dio: + dependency: "direct main" + description: + name: sentry_dio + sha256: bee438fd790c534da77f0a6c9cd04c54c818184b8a54bbe7d916489c8aad56a0 + url: "https://pub.dev" + source: hosted + version: "9.8.0" sentry_flutter: dependency: "direct main" description: diff --git a/core/pubspec.yaml b/core/pubspec.yaml index 620d7568e..fcb44e8da 100644 --- a/core/pubspec.yaml +++ b/core/pubspec.yaml @@ -105,6 +105,8 @@ dependencies: sentry_flutter: 9.8.0 + sentry_dio: 9.8.0 + dev_dependencies: flutter_test: sdk: flutter diff --git a/lib/main/bindings/network/network_bindings.dart b/lib/main/bindings/network/network_bindings.dart index ebad60955..df4dbcc16 100644 --- a/lib/main/bindings/network/network_bindings.dart +++ b/lib/main/bindings/network/network_bindings.dart @@ -8,7 +8,6 @@ import 'package:dio/dio.dart'; import 'package:flutter_appauth/flutter_appauth.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/http/http_client.dart'; -import 'package:sentry_dio/sentry_dio.dart'; import 'package:tmail_ui_user/features/contact/data/network/contact_api.dart'; import 'package:tmail_ui_user/features/email/data/network/email_api.dart'; import 'package:tmail_ui_user/features/email/data/network/mdn_api.dart'; @@ -102,14 +101,7 @@ class NetworkBindings extends Bindings { if (BuildUtils.isDebugMode) { dio.interceptors.add(LogInterceptor(requestBody: true)); } - if (SentryManager.instance.isSentryAvailable) { - // Guard against duplicate Sentry interceptor registration - final alreadyHasSentry = dio.interceptors - .any((i) => i.runtimeType.toString().contains('Sentry')); - if (!alreadyHasSentry) { - dio.addSentry(); - } - } + SentryDioHelper.addIfAvailable(dio); } void _bindingApi() { diff --git a/lib/main/bindings/network/network_isolate_binding.dart b/lib/main/bindings/network/network_isolate_binding.dart index f80a209fd..0ec431d37 100644 --- a/lib/main/bindings/network/network_isolate_binding.dart +++ b/lib/main/bindings/network/network_isolate_binding.dart @@ -4,7 +4,6 @@ import 'package:dio/dio.dart'; import 'package:flutter_appauth/flutter_appauth.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/http/http_client.dart'; -import 'package:sentry_dio/sentry_dio.dart'; import 'package:tmail_ui_user/features/email/data/local/html_analyzer.dart'; import 'package:tmail_ui_user/features/email/data/network/email_api.dart'; import 'package:tmail_ui_user/features/login/data/local/account_cache_manager.dart'; @@ -53,6 +52,7 @@ class NetworkIsolateBindings extends Bindings { void _bindingInterceptors() { final dio = Get.find(tag: BindingTag.isolateTag); + Get.put(DynamicUrlInterceptors()); final authorizationInterceptors = AuthorizationInterceptors( dio, Get.find(tag: BindingTag.isolateTag), @@ -67,14 +67,7 @@ class NetworkIsolateBindings extends Bindings { if (BuildUtils.isDebugMode) { dio.interceptors.add(LogInterceptor(requestBody: true)); } - if (SentryManager.instance.isSentryAvailable) { - // Guard against duplicate Sentry interceptor registration - final alreadyHasSentry = dio.interceptors - .any((i) => i.runtimeType.toString().contains('Sentry')); - if (!alreadyHasSentry) { - dio.addSentry(); - } - } + SentryDioHelper.addIfAvailable(dio); } void _bindingApi() { diff --git a/lib/main/main_entry.dart b/lib/main/main_entry.dart index bb7900e21..c251152f4 100644 --- a/lib/main/main_entry.dart +++ b/lib/main/main_entry.dart @@ -3,6 +3,7 @@ import 'package:core/utils/build_utils.dart'; import 'package:core/utils/config/env_loader.dart'; import 'package:core/utils/platform_info.dart'; import 'package:flutter/widgets.dart'; +import 'package:get/get.dart'; import 'package:tmail_ui_user/features/caching/config/hive_cache_config.dart'; import 'package:tmail_ui_user/main.dart'; import 'package:tmail_ui_user/main/bindings/main_bindings.dart'; @@ -22,11 +23,11 @@ Future runTmailPreload() async { await Future.wait([ MainBindings().dependencies(), HiveCacheConfig.instance.setUp(), - Executor().warmUp(log: BuildUtils.isDebugMode), EnvLoader.loadEnvFile(), if (PlatformInfo.isWeb) AssetPreloader.preloadHtmlEditorAssets(), - ]); + ], eagerError: false); + await Get.find().warmUp(log: BuildUtils.isDebugMode); await CozyIntegration.integrateCozy(); await HiveCacheConfig.instance.initializeEncryptionKey(); diff --git a/model/pubspec.lock b/model/pubspec.lock index fa3fab792..42699277f 100644 --- a/model/pubspec.lock +++ b/model/pubspec.lock @@ -1033,6 +1033,14 @@ packages: url: "https://pub.dev" source: hosted version: "9.8.0" + sentry_dio: + dependency: transitive + description: + name: sentry_dio + sha256: bee438fd790c534da77f0a6c9cd04c54c818184b8a54bbe7d916489c8aad56a0 + url: "https://pub.dev" + source: hosted + version: "9.8.0" sentry_flutter: dependency: transitive description: diff --git a/scribe/pubspec.lock b/scribe/pubspec.lock index e70428d0f..23a06007c 100644 --- a/scribe/pubspec.lock +++ b/scribe/pubspec.lock @@ -1039,6 +1039,14 @@ packages: url: "https://pub.dev" source: hosted version: "9.8.0" + sentry_dio: + dependency: transitive + description: + name: sentry_dio + sha256: bee438fd790c534da77f0a6c9cd04c54c818184b8a54bbe7d916489c8aad56a0 + url: "https://pub.dev" + source: hosted + version: "9.8.0" sentry_flutter: dependency: transitive description: