From 437c46f5ff79716c01f556b648110e78e3b7f593 Mon Sep 17 00:00:00 2001 From: dab246 Date: Tue, 3 Mar 2026 11:43:45 +0700 Subject: [PATCH] fix(sentry): resolve minified exception types on web release --- Dockerfile | 3 +- .../domain/exceptions/address_exception.dart | 6 +-- .../domain/exceptions/app_base_exception.dart | 9 +++- .../exceptions/download_file_exception.dart | 7 +-- .../lib/domain/exceptions/file_exception.dart | 6 +-- .../domain/exceptions/platform_exception.dart | 6 +-- core/lib/utils/mail/mail_address.dart | 2 +- core/lib/utils/sentry/sentry_config.dart | 6 +++ core/lib/utils/sentry/sentry_initializer.dart | 51 ++++++++++++++----- .../exceptions/local_storage_exception.dart | 2 +- .../caching/utils/local_storage_manager.dart | 2 +- .../utils/session_storage_manager.dart | 2 +- .../handle_label_for_email_extension.dart | 4 +- .../labels/data/network/label_api.dart | 2 +- .../domain/exceptions/label_exceptions.dart | 4 +- .../handle_label_action_type_extension.dart | 2 +- .../exceptions/authentication_exception.dart | 9 +++- .../mailbox/data/network/mailbox_api.dart | 2 +- .../null_session_or_accountid_exception.dart | 2 +- .../set_mailbox_rights_exception.dart | 2 +- .../presentation/mailbox_controller.dart | 2 +- .../exceptions/verify_name_exception.dart | 4 +- .../data/network/forwarding_api.dart | 4 +- .../domain/exceptions/forward_exception.dart | 8 +-- .../change_identity_as_default_extension.dart | 2 +- ...complete_contact_text_field_with_tags.dart | 8 +-- .../vacation/vacation_controller.dart | 2 +- .../data/network/public_asset_api.dart | 2 +- .../exceptions/public_asset_exceptions.dart | 2 +- .../quotas/data/network/quotas_api.dart | 2 +- .../domain/exceptions/quotas_exception.dart | 4 +- .../search_mailbox_controller.dart | 2 +- .../data/network/server_settings_api.dart | 10 ++-- .../exceptions/server_settings_exception.dart | 6 +-- .../get_server_setting_interactor.dart | 2 +- .../update_server_setting_interactor.dart | 2 +- .../thread_detail_repository_impl.dart | 2 +- .../empty_thread_detail_exception.dart | 2 +- .../labels/add_label_to_thread_extension.dart | 2 +- .../remove_label_from_thread_extension.dart | 2 +- .../upload/data/network/file_uploader.dart | 2 +- .../exceptions/pick_file_exception.dart | 2 +- .../domain/exceptions/upload_exception.dart | 2 +- .../local_file_picker_interactor.dart | 2 +- .../local_image_picker_interactor.dart | 2 +- lib/main/error/request_error.dart | 12 ++--- lib/main/exceptions/permission_exception.dart | 3 ++ lib/main/exceptions/remote_exception.dart | 5 +- lib/main/utils/toast_manager.dart | 1 - ...server_settings_data_source_impl_test.dart | 4 +- .../server_settings_repository_impl_test.dart | 4 +- .../get_server_setting_interactor_test.dart | 2 +- ...update_server_setting_interactor_test.dart | 2 +- 53 files changed, 133 insertions(+), 109 deletions(-) diff --git a/Dockerfile b/Dockerfile index 801f4819b..1eb78d5fc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,10 +20,11 @@ ENV GITHUB_SHA=$GITHUB_SHA \ SENTRY_RELEASE=$SENTRY_RELEASE RUN ./scripts/prebuild.sh && \ + if [ -z "$GITHUB_SHA" ]; then echo "GITHUB_SHA is required for SENTRY_DIST"; exit 1; fi && \ flutter build web --release --source-maps \ --dart-define=SENTRY_RELEASE=$SENTRY_RELEASE \ --dart-define=SENTRY_DIST=$GITHUB_SHA && \ - if [ -n "$SENTRY_AUTH_TOKEN" ] && [ -n "$SENTRY_ORG" ] && [ -n "$SENTRY_PROJECT" ] && [ -n "$SENTRY_RELEASE" ]; then \ + if [ -n "$SENTRY_AUTH_TOKEN" ] && [ -n "$SENTRY_ORG" ] && [ -n "$SENTRY_PROJECT" ] && [ -n "$SENTRY_RELEASE" ] && [ -n "$GITHUB_SHA" ]; then \ echo "Sentry configuration detected, uploading sourcemaps..." && \ curl -sL https://sentry.io/get-cli/ | SENTRY_CLI_VERSION=2.20.7 bash && \ sentry-cli releases new "$SENTRY_RELEASE" && \ diff --git a/core/lib/domain/exceptions/address_exception.dart b/core/lib/domain/exceptions/address_exception.dart index d2433dca3..85e3ee9f3 100644 --- a/core/lib/domain/exceptions/address_exception.dart +++ b/core/lib/domain/exceptions/address_exception.dart @@ -1,12 +1,8 @@ import 'package:core/domain/exceptions/app_base_exception.dart'; -import 'package:equatable/equatable.dart'; -class AddressException extends AppBaseException with EquatableMixin { +class AddressException extends AppBaseException { const AddressException(super.message); @override String get exceptionName => 'AddressException'; - - @override - List get props => [message, exceptionName]; } diff --git a/core/lib/domain/exceptions/app_base_exception.dart b/core/lib/domain/exceptions/app_base_exception.dart index 0436e18ac..f6ea6d72c 100644 --- a/core/lib/domain/exceptions/app_base_exception.dart +++ b/core/lib/domain/exceptions/app_base_exception.dart @@ -1,15 +1,20 @@ -abstract class AppBaseException implements Exception { +import 'package:equatable/equatable.dart'; + +abstract class AppBaseException with EquatableMixin implements Exception { final String? message; const AppBaseException([this.message]); @override String toString() { - if (message != null && message!.isNotEmpty) { + if (message?.isNotEmpty == true) { return '$exceptionName: $message'; } return exceptionName; } String get exceptionName; + + @override + List get props => [message]; } diff --git a/core/lib/domain/exceptions/download_file_exception.dart b/core/lib/domain/exceptions/download_file_exception.dart index 6f6cc4963..fdb820113 100644 --- a/core/lib/domain/exceptions/download_file_exception.dart +++ b/core/lib/domain/exceptions/download_file_exception.dart @@ -1,12 +1,7 @@ import 'package:core/domain/exceptions/app_base_exception.dart'; -import 'package:equatable/equatable.dart'; -abstract class DownloadFileException extends AppBaseException - with EquatableMixin { +abstract class DownloadFileException extends AppBaseException { const DownloadFileException(super.message); - - @override - List get props => [message, exceptionName]; } class CommonDownloadFileException extends DownloadFileException { diff --git a/core/lib/domain/exceptions/file_exception.dart b/core/lib/domain/exceptions/file_exception.dart index 3ba770ea9..65091ef0b 100644 --- a/core/lib/domain/exceptions/file_exception.dart +++ b/core/lib/domain/exceptions/file_exception.dart @@ -1,11 +1,7 @@ import 'package:core/domain/exceptions/app_base_exception.dart'; -import 'package:equatable/equatable.dart'; -abstract class FileException extends AppBaseException with EquatableMixin { +abstract class FileException extends AppBaseException { const FileException(super.message); - - @override - List get props => [message, exceptionName]; } class NotFoundFileInFolderException extends FileException { diff --git a/core/lib/domain/exceptions/platform_exception.dart b/core/lib/domain/exceptions/platform_exception.dart index 962ee74cb..a00bc6d1b 100644 --- a/core/lib/domain/exceptions/platform_exception.dart +++ b/core/lib/domain/exceptions/platform_exception.dart @@ -1,14 +1,10 @@ import 'package:core/domain/exceptions/app_base_exception.dart'; -import 'package:equatable/equatable.dart'; -class PlatformException extends AppBaseException with EquatableMixin { +class PlatformException extends AppBaseException { const PlatformException(super.message); @override String get exceptionName => 'PlatformException'; - - @override - List get props => [message, exceptionName]; } class NoSupportPlatformException extends PlatformException { diff --git a/core/lib/utils/mail/mail_address.dart b/core/lib/utils/mail/mail_address.dart index e313dab1c..51da79a6d 100644 --- a/core/lib/utils/mail/mail_address.dart +++ b/core/lib/utils/mail/mail_address.dart @@ -88,7 +88,7 @@ class MailAddress with EquatableMixin { if (postChar == '.') { var lastChar = address[pos - 1]; if (lastChar == '@' || lastChar == '.') { - throw const AddressException('Subdomain expected before "." or duplicate "." in "address"'); + throw AddressException('Subdomain expected before "." or duplicate "." in "$address"'); } domainSB.write('.'); pos++; diff --git a/core/lib/utils/sentry/sentry_config.dart b/core/lib/utils/sentry/sentry_config.dart index 9e0fb1d25..72c55e990 100644 --- a/core/lib/utils/sentry/sentry_config.dart +++ b/core/lib/utils/sentry/sentry_config.dart @@ -1,6 +1,7 @@ import 'package:core/utils/application_manager.dart'; import 'package:core/utils/build_utils.dart'; import 'package:core/utils/config/env_loader.dart'; +import 'package:core/utils/app_logger.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; /// Holds configuration values for initializing Sentry. @@ -69,6 +70,11 @@ class SentryConfig { final appVersion = await ApplicationManager().getAppVersion(); const sentryDist = String.fromEnvironment('SENTRY_DIST'); + logTrace( + 'SentryConfig::load: sentryDist is $sentryDist,' + 'appVersion is $appVersion', + webConsoleEnabled: true, + ); return SentryConfig( dsn: sentryDSN, diff --git a/core/lib/utils/sentry/sentry_initializer.dart b/core/lib/utils/sentry/sentry_initializer.dart index 530f3aabe..189fd371c 100644 --- a/core/lib/utils/sentry/sentry_initializer.dart +++ b/core/lib/utils/sentry/sentry_initializer.dart @@ -55,27 +55,54 @@ class SentryInitializer { SentryEvent event, Hint? hint, ) async { - final req = event.request; - if (req == null) return event; + event.request = _sanitizeRequest(event.request); + event.exceptions = _deminifyExceptions(event.exceptions); - final sanitizedHeaders = Map.from(req.headers) - ..removeWhere( - (k, _) => _blockedHeaderPatterns.any( - (p) => k.toLowerCase().contains(p), - ), - ); + return event; + } - final sanitizedRequest = SentryRequest( + static SentryRequest? _sanitizeRequest(SentryRequest? req) { + if (req == null) return null; + + return SentryRequest( url: req.url, method: req.method, - headers: sanitizedHeaders, + headers: _sanitizeHeaders(req.headers), queryString: req.queryString, cookies: null, data: null, ); + } - event.request = sanitizedRequest; + static Map _sanitizeHeaders(Map headers) { + return Map.from(headers) + ..removeWhere( + (key, _) => _blockedHeaderPatterns.any( + (pattern) => key.toLowerCase().contains(pattern), + ), + ); + } - return event; + static List? _deminifyExceptions( + List? exceptions, + ) { + if (exceptions == null) return null; + + return exceptions.map((e) { + if (e.type?.startsWith('minified:') == true) { + final rawValue = e.value?.trim() ?? ''; + final extractedType = RegExp(r'^([A-Za-z_][A-Za-z0-9_]*)\s*:') + .firstMatch(rawValue) + ?.group(1) ?? + RegExp(r"Instance of '([^']+)'").firstMatch(rawValue)?.group(1); + if (extractedType != null && + extractedType.isNotEmpty && + extractedType != 'minified' && + !extractedType.startsWith('minified:')) { + e.type = extractedType; + } + } + return e; + }).toList(); } } diff --git a/lib/features/caching/exceptions/local_storage_exception.dart b/lib/features/caching/exceptions/local_storage_exception.dart index e901206a9..c78f21dde 100644 --- a/lib/features/caching/exceptions/local_storage_exception.dart +++ b/lib/features/caching/exceptions/local_storage_exception.dart @@ -1,7 +1,7 @@ import 'package:core/domain/exceptions/app_base_exception.dart'; class NotFoundDataWithThisKeyException extends AppBaseException { - NotFoundDataWithThisKeyException([super.message]); + const NotFoundDataWithThisKeyException([super.message]); @override String get exceptionName => 'NotFoundDataWithThisKeyException'; diff --git a/lib/features/caching/utils/local_storage_manager.dart b/lib/features/caching/utils/local_storage_manager.dart index 0ff67c6d6..317c19374 100644 --- a/lib/features/caching/utils/local_storage_manager.dart +++ b/lib/features/caching/utils/local_storage_manager.dart @@ -17,7 +17,7 @@ class LocalStorageManager { if (entry != null) { return entry.value; } else { - throw NotFoundDataWithThisKeyException(); + throw const NotFoundDataWithThisKeyException(); } } diff --git a/lib/features/caching/utils/session_storage_manager.dart b/lib/features/caching/utils/session_storage_manager.dart index 9f0d787f7..3d8f8bd55 100644 --- a/lib/features/caching/utils/session_storage_manager.dart +++ b/lib/features/caching/utils/session_storage_manager.dart @@ -19,7 +19,7 @@ class SessionStorageManager { if (entry != null) { return entry.value; } else { - throw NotFoundDataWithThisKeyException(); + throw const NotFoundDataWithThisKeyException(); } } diff --git a/lib/features/email/presentation/extensions/handle_label_for_email_extension.dart b/lib/features/email/presentation/extensions/handle_label_for_email_extension.dart index 5e9c55762..6264ba13d 100644 --- a/lib/features/email/presentation/extensions/handle_label_for_email_extension.dart +++ b/lib/features/email/presentation/extensions/handle_label_for_email_extension.dart @@ -82,7 +82,7 @@ extension HandleLabelForEmailExtension on SingleEmailController { emitFailure( controller: this, failure: AddALabelToAnEmailFailure( - exception: LabelKeywordIsNull(), + exception: const LabelKeywordIsNull(), labelDisplay: labelDisplay, ), ); @@ -290,7 +290,7 @@ extension HandleLabelForEmailExtension on SingleEmailController { emitFailure( controller: this, failure: RemoveALabelFromAnEmailFailure( - exception: LabelKeywordIsNull(), + exception: const LabelKeywordIsNull(), labelDisplay: labelDisplay, ), ); diff --git a/lib/features/labels/data/network/label_api.dart b/lib/features/labels/data/network/label_api.dart index 26b8b0074..9ee2767a8 100644 --- a/lib/features/labels/data/network/label_api.dart +++ b/lib/features/labels/data/network/label_api.dart @@ -110,7 +110,7 @@ class LabelApi final labelId = label.id; if (labelId == null) { - throw LabelIdIsNull(); + throw const LabelIdIsNull(); } final method = SetLabelMethod(accountId)..addDestroy({labelId}); diff --git a/lib/features/labels/domain/exceptions/label_exceptions.dart b/lib/features/labels/domain/exceptions/label_exceptions.dart index 1770d432d..3ba151ba0 100644 --- a/lib/features/labels/domain/exceptions/label_exceptions.dart +++ b/lib/features/labels/domain/exceptions/label_exceptions.dart @@ -1,14 +1,14 @@ import 'package:core/domain/exceptions/app_base_exception.dart'; class LabelKeywordIsNull extends AppBaseException { - LabelKeywordIsNull([super.message = 'Label keyword is null']); + const LabelKeywordIsNull([super.message = 'Label keyword is null']); @override String get exceptionName => 'LabelKeywordIsNull'; } class LabelIdIsNull extends AppBaseException { - LabelIdIsNull([super.message = 'Label id is null']); + const LabelIdIsNull([super.message = 'Label id is null']); @override String get exceptionName => 'LabelIdIsNull'; diff --git a/lib/features/labels/presentation/extensions/handle_label_action_type_extension.dart b/lib/features/labels/presentation/extensions/handle_label_action_type_extension.dart index eb620daa9..b6f1ce8ca 100644 --- a/lib/features/labels/presentation/extensions/handle_label_action_type_extension.dart +++ b/lib/features/labels/presentation/extensions/handle_label_action_type_extension.dart @@ -93,7 +93,7 @@ extension HandleLabelActionTypeExtension on LabelController { if (labelId == null) { consumeState( - Stream.value(Left(EditLabelFailure(LabelIdIsNull()))), + Stream.value(Left(EditLabelFailure(const LabelIdIsNull()))), ); return; } diff --git a/lib/features/login/domain/exceptions/authentication_exception.dart b/lib/features/login/domain/exceptions/authentication_exception.dart index 44fe9dc44..4617bf268 100644 --- a/lib/features/login/domain/exceptions/authentication_exception.dart +++ b/lib/features/login/domain/exceptions/authentication_exception.dart @@ -55,7 +55,7 @@ class DownloadAttachmentHasTokenExpiredException extends AppBaseException { final String refreshToken; DownloadAttachmentHasTokenExpiredException(this.refreshToken) - : super('Token expired for refresh token: $refreshToken'); + : super('Token expired for refresh token'); @override String get exceptionName => 'DownloadAttachmentHasTokenExpiredException'; @@ -102,3 +102,10 @@ class SaasServerUriIsNull extends AppBaseException { @override String get exceptionName => 'SaasServerUriIsNull'; } + +class AutoRedirectToAppAfterStoreAuthorizeDestinationUrlException extends AppBaseException { + AutoRedirectToAppAfterStoreAuthorizeDestinationUrlException([super.message]); + + @override + String get exceptionName => 'AutoRedirectToAppAfterStoreAuthorizeDestinationUrlException'; +} diff --git a/lib/features/mailbox/data/network/mailbox_api.dart b/lib/features/mailbox/data/network/mailbox_api.dart index 126ff3f39..7b3742e4e 100644 --- a/lib/features/mailbox/data/network/mailbox_api.dart +++ b/lib/features/mailbox/data/network/mailbox_api.dart @@ -438,7 +438,7 @@ class MailboxAPI with HandleSetErrorMixin, SessionMixin, MailAPIMixin { if (setMailboxResponse?.updated?.containsKey(request.mailboxId.id) ?? false) { return true; } else { - throw SetMailboxRightsException(); + throw const SetMailboxRightsException(); } } diff --git a/lib/features/mailbox/domain/exceptions/null_session_or_accountid_exception.dart b/lib/features/mailbox/domain/exceptions/null_session_or_accountid_exception.dart index 95410785f..706a1e79b 100644 --- a/lib/features/mailbox/domain/exceptions/null_session_or_accountid_exception.dart +++ b/lib/features/mailbox/domain/exceptions/null_session_or_accountid_exception.dart @@ -1,7 +1,7 @@ import 'package:core/domain/exceptions/app_base_exception.dart'; class NullSessionOrAccountIdException extends AppBaseException { - NullSessionOrAccountIdException( + const NullSessionOrAccountIdException( [super.message = 'session and accountId should not be null']); @override diff --git a/lib/features/mailbox/domain/exceptions/set_mailbox_rights_exception.dart b/lib/features/mailbox/domain/exceptions/set_mailbox_rights_exception.dart index 00febf377..ac670d892 100644 --- a/lib/features/mailbox/domain/exceptions/set_mailbox_rights_exception.dart +++ b/lib/features/mailbox/domain/exceptions/set_mailbox_rights_exception.dart @@ -1,7 +1,7 @@ import 'package:core/domain/exceptions/app_base_exception.dart'; class SetMailboxRightsException extends AppBaseException { - SetMailboxRightsException( + const SetMailboxRightsException( [super.message = 'Failed to update mailbox rights.']); @override diff --git a/lib/features/mailbox/presentation/mailbox_controller.dart b/lib/features/mailbox/presentation/mailbox_controller.dart index 74e7cf082..a32971257 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -1507,7 +1507,7 @@ class MailboxController extends BaseMailboxController consumeState(_subaddressingInteractor.execute(session, accountId, allowSubaddressingRequest)); } else { handleSubAddressingFailure( - SubaddressingFailure.withException(NullSessionOrAccountIdException()), + SubaddressingFailure.withException(const NullSessionOrAccountIdException()), ); } diff --git a/lib/features/mailbox_creator/domain/exceptions/verify_name_exception.dart b/lib/features/mailbox_creator/domain/exceptions/verify_name_exception.dart index f06468578..dbca55a19 100644 --- a/lib/features/mailbox_creator/domain/exceptions/verify_name_exception.dart +++ b/lib/features/mailbox_creator/domain/exceptions/verify_name_exception.dart @@ -1,8 +1,6 @@ -import 'package:equatable/equatable.dart'; import 'package:core/domain/exceptions/app_base_exception.dart'; -abstract class VerifyNameException extends AppBaseException - with EquatableMixin { +abstract class VerifyNameException extends AppBaseException { static const emptyName = 'The name cannot be empty!'; static const duplicatedName = 'The name already exists!'; static const nameContainSpecialCharacter = diff --git a/lib/features/manage_account/data/network/forwarding_api.dart b/lib/features/manage_account/data/network/forwarding_api.dart index d9c9296ec..f54e2fc1c 100644 --- a/lib/features/manage_account/data/network/forwarding_api.dart +++ b/lib/features/manage_account/data/network/forwarding_api.dart @@ -37,7 +37,7 @@ class ForwardingAPI with HandleSetErrorMixin { final tMailForwardResult = result?.list.firstOrNull; if (tMailForwardResult == null) { - throw NotFoundForwardException(); + throw const NotFoundForwardException(); } return tMailForwardResult; @@ -86,6 +86,6 @@ class ForwardingAPI with HandleSetErrorMixin { return (newForward, methodException); } - throw methodException ?? NotFoundForwardException(); + throw methodException ?? const NotFoundForwardException(); } } \ No newline at end of file diff --git a/lib/features/manage_account/domain/exceptions/forward_exception.dart b/lib/features/manage_account/domain/exceptions/forward_exception.dart index ac8b95729..911648522 100644 --- a/lib/features/manage_account/domain/exceptions/forward_exception.dart +++ b/lib/features/manage_account/domain/exceptions/forward_exception.dart @@ -1,28 +1,28 @@ import 'package:core/domain/exceptions/app_base_exception.dart'; class NotFoundForwardException extends AppBaseException { - NotFoundForwardException([super.message]); + const NotFoundForwardException([super.message]); @override String get exceptionName => 'NotFoundForwardException'; } class UpdateForwardException extends AppBaseException { - UpdateForwardException([super.message]); + const UpdateForwardException([super.message]); @override String get exceptionName => 'UpdateForwardException'; } class RecipientListIsEmptyException extends AppBaseException { - RecipientListIsEmptyException([super.message]); + const RecipientListIsEmptyException([super.message]); @override String get exceptionName => 'RecipientListIsEmptyException'; } class RecipientListWithInvalidEmailsException extends AppBaseException { - RecipientListWithInvalidEmailsException([super.message]); + const RecipientListWithInvalidEmailsException([super.message]); @override String get exceptionName => 'RecipientListWithInvalidEmailsException'; diff --git a/lib/features/manage_account/presentation/extensions/change_identity_as_default_extension.dart b/lib/features/manage_account/presentation/extensions/change_identity_as_default_extension.dart index cdaf3ffc1..3922fa929 100644 --- a/lib/features/manage_account/presentation/extensions/change_identity_as_default_extension.dart +++ b/lib/features/manage_account/presentation/extensions/change_identity_as_default_extension.dart @@ -37,7 +37,7 @@ extension VerifyDefaultIdentitySupportedExtension on IdentitiesController { } else { consumeState( Stream.value( - Left(EditDefaultIdentityFailure(NullSessionOrAccountIdException())), + Left(EditDefaultIdentityFailure(const NullSessionOrAccountIdException())), ), ); } diff --git a/lib/features/manage_account/presentation/forward/widgets/autocomplete_contact_text_field_with_tags.dart b/lib/features/manage_account/presentation/forward/widgets/autocomplete_contact_text_field_with_tags.dart index d6c63494c..9cc597424 100644 --- a/lib/features/manage_account/presentation/forward/widgets/autocomplete_contact_text_field_with_tags.dart +++ b/lib/features/manage_account/presentation/forward/widgets/autocomplete_contact_text_field_with_tags.dart @@ -301,7 +301,7 @@ class _AutocompleteContactTextFieldWithTagsState extends State 'PublicAssetQuotaExceededException'; diff --git a/lib/features/quotas/data/network/quotas_api.dart b/lib/features/quotas/data/network/quotas_api.dart index 935757785..a5f47cb06 100644 --- a/lib/features/quotas/data/network/quotas_api.dart +++ b/lib/features/quotas/data/network/quotas_api.dart @@ -28,7 +28,7 @@ class QuotasAPI { if (getQuotaResponse?.list.isNotEmpty == true) { return getQuotaResponse!.list; } else { - throw NotFoundQuotasException(); + throw const NotFoundQuotasException(); } } } diff --git a/lib/features/quotas/domain/exceptions/quotas_exception.dart b/lib/features/quotas/domain/exceptions/quotas_exception.dart index d021aab73..300ebcc45 100644 --- a/lib/features/quotas/domain/exceptions/quotas_exception.dart +++ b/lib/features/quotas/domain/exceptions/quotas_exception.dart @@ -1,14 +1,14 @@ import 'package:core/domain/exceptions/app_base_exception.dart'; class NotFoundQuotasException extends AppBaseException { - NotFoundQuotasException([super.message]); + const NotFoundQuotasException([super.message]); @override String get exceptionName => 'NotFoundQuotasException'; } class QuotasNotSupportedException extends AppBaseException { - QuotasNotSupportedException([super.message]); + const QuotasNotSupportedException([super.message]); @override String get exceptionName => 'QuotasNotSupportedException'; diff --git a/lib/features/search/mailbox/presentation/search_mailbox_controller.dart b/lib/features/search/mailbox/presentation/search_mailbox_controller.dart index f9b5ee6a6..87ace5b8c 100644 --- a/lib/features/search/mailbox/presentation/search_mailbox_controller.dart +++ b/lib/features/search/mailbox/presentation/search_mailbox_controller.dart @@ -494,7 +494,7 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa )); } else { handleSubAddressingFailure( - SubaddressingFailure.withException(NullSessionOrAccountIdException()), + SubaddressingFailure.withException(const NullSessionOrAccountIdException()), ); } diff --git a/lib/features/server_settings/data/network/server_settings_api.dart b/lib/features/server_settings/data/network/server_settings_api.dart index 726868edf..801a14278 100644 --- a/lib/features/server_settings/data/network/server_settings_api.dart +++ b/lib/features/server_settings/data/network/server_settings_api.dart @@ -39,7 +39,7 @@ class ServerSettingsAPI with HandleSetErrorMixin { )?.list.firstOrNull; if (serverSettings == null) { - throw NotFoundServerSettingsException(); + throw const NotFoundServerSettingsException(); } return serverSettings; @@ -81,10 +81,10 @@ class ServerSettingsAPI with HandleSetErrorMixin { )?.updated ?? {}; if (updateServerSettingsResult.isEmpty) { - throw CanNotUpdateServerSettingsException(); + throw const CanNotUpdateServerSettingsException(); } } on ErrorMethodResponseException catch (_) { - throw CanNotUpdateServerSettingsException(); + throw const CanNotUpdateServerSettingsException(); } try { @@ -94,12 +94,12 @@ class ServerSettingsAPI with HandleSetErrorMixin { )?.list.firstOrNull; if (updatedServerSettings == null) { - throw CanNotUpdateServerSettingsException(); + throw const CanNotUpdateServerSettingsException(); } return updatedServerSettings; } on ErrorMethodResponseException catch (_) { - throw CanNotUpdateServerSettingsException(); + throw const CanNotUpdateServerSettingsException(); } } } \ No newline at end of file diff --git a/lib/features/server_settings/domain/exceptions/server_settings_exception.dart b/lib/features/server_settings/domain/exceptions/server_settings_exception.dart index b9c9c7aa9..4dd368c64 100644 --- a/lib/features/server_settings/domain/exceptions/server_settings_exception.dart +++ b/lib/features/server_settings/domain/exceptions/server_settings_exception.dart @@ -1,21 +1,21 @@ import 'package:core/domain/exceptions/app_base_exception.dart'; class NotFoundServerSettingsException extends AppBaseException { - NotFoundServerSettingsException([super.message]); + const NotFoundServerSettingsException([super.message]); @override String get exceptionName => 'NotFoundServerSettingsException'; } class NotFoundSettingOptionException extends AppBaseException { - NotFoundSettingOptionException([super.message]); + const NotFoundSettingOptionException([super.message]); @override String get exceptionName => 'NotFoundSettingOptionException'; } class CanNotUpdateServerSettingsException extends AppBaseException { - CanNotUpdateServerSettingsException([super.message]); + const CanNotUpdateServerSettingsException([super.message]); @override String get exceptionName => 'CanNotUpdateServerSettingsException'; diff --git a/lib/features/server_settings/domain/usecases/get_server_setting_interactor.dart b/lib/features/server_settings/domain/usecases/get_server_setting_interactor.dart index 85f32a7df..5033f28c6 100644 --- a/lib/features/server_settings/domain/usecases/get_server_setting_interactor.dart +++ b/lib/features/server_settings/domain/usecases/get_server_setting_interactor.dart @@ -17,7 +17,7 @@ class GetServerSettingInteractor { final serverSetting = await _serverSettingsRepository.getServerSettings(accountId); final settingOption = serverSetting.settings; if (settingOption == null) { - yield Left(GetServerSettingFailure(NotFoundSettingOptionException())); + yield Left(GetServerSettingFailure(const NotFoundSettingOptionException())); } else { yield Right(GetServerSettingSuccess(settingOption)); } diff --git a/lib/features/server_settings/domain/usecases/update_server_setting_interactor.dart b/lib/features/server_settings/domain/usecases/update_server_setting_interactor.dart index 0e230d30d..3107529dc 100644 --- a/lib/features/server_settings/domain/usecases/update_server_setting_interactor.dart +++ b/lib/features/server_settings/domain/usecases/update_server_setting_interactor.dart @@ -27,7 +27,7 @@ class UpdateServerSettingInteractor { ); final settingOption = serverSetting.settings; if (settingOption == null) { - yield Left(UpdateServerSettingFailure(NotFoundServerSettingsException())); + yield Left(UpdateServerSettingFailure(const NotFoundServerSettingsException())); } else { yield Right(UpdateServerSettingSuccess(settingOption)); } diff --git a/lib/features/thread_detail/data/repository/thread_detail_repository_impl.dart b/lib/features/thread_detail/data/repository/thread_detail_repository_impl.dart index 3471abfb6..3a9f45b98 100644 --- a/lib/features/thread_detail/data/repository/thread_detail_repository_impl.dart +++ b/lib/features/thread_detail/data/repository/thread_detail_repository_impl.dart @@ -32,7 +32,7 @@ class ThreadDetailRepositoryImpl implements ThreadDetailRepository { .getThreadById(threadId, accountId); if (originalEmailIds.isEmpty) { - throw EmptyThreadDetailException(); + throw const EmptyThreadDetailException(); } final filteredEmailIds = await Future.wait( diff --git a/lib/features/thread_detail/domain/exceptions/empty_thread_detail_exception.dart b/lib/features/thread_detail/domain/exceptions/empty_thread_detail_exception.dart index a037dd95d..7d73ec2b7 100644 --- a/lib/features/thread_detail/domain/exceptions/empty_thread_detail_exception.dart +++ b/lib/features/thread_detail/domain/exceptions/empty_thread_detail_exception.dart @@ -1,7 +1,7 @@ import 'package:core/domain/exceptions/app_base_exception.dart'; class EmptyThreadDetailException extends AppBaseException { - EmptyThreadDetailException([super.message]); + const EmptyThreadDetailException([super.message]); @override String get exceptionName => 'EmptyThreadDetailException'; diff --git a/lib/features/thread_detail/presentation/extension/labels/add_label_to_thread_extension.dart b/lib/features/thread_detail/presentation/extension/labels/add_label_to_thread_extension.dart index b85d867ab..62ce79100 100644 --- a/lib/features/thread_detail/presentation/extension/labels/add_label_to_thread_extension.dart +++ b/lib/features/thread_detail/presentation/extension/labels/add_label_to_thread_extension.dart @@ -112,7 +112,7 @@ extension AddLabelToThreadExtension on ThreadDetailController { consumeState( Stream.value(Left( AddALabelToAThreadFailure( - exception: LabelKeywordIsNull(), + exception: const LabelKeywordIsNull(), labelDisplay: labelDisplay, ), )), diff --git a/lib/features/thread_detail/presentation/extension/labels/remove_label_from_thread_extension.dart b/lib/features/thread_detail/presentation/extension/labels/remove_label_from_thread_extension.dart index 5cbc97a87..6579e9e49 100644 --- a/lib/features/thread_detail/presentation/extension/labels/remove_label_from_thread_extension.dart +++ b/lib/features/thread_detail/presentation/extension/labels/remove_label_from_thread_extension.dart @@ -44,7 +44,7 @@ extension RemoveLabelFromThreadExtension on ThreadDetailController { emitFailure( controller: this, failure: RemoveALabelFromAThreadFailure( - exception: LabelKeywordIsNull(), + exception: const LabelKeywordIsNull(), labelDisplay: labelDisplay, ), ); diff --git a/lib/features/upload/data/network/file_uploader.dart b/lib/features/upload/data/network/file_uploader.dart index dd8599854..aab9b5fca 100644 --- a/lib/features/upload/data/network/file_uploader.dart +++ b/lib/features/upload/data/network/file_uploader.dart @@ -226,7 +226,7 @@ class FileUploader { charset: fileCharset); } else { logWarning('FileUploader::_parsingResponse(): DataResponseIsNullException'); - throw DataResponseIsNullException(); + throw const DataResponseIsNullException(); } } } \ No newline at end of file diff --git a/lib/features/upload/domain/exceptions/pick_file_exception.dart b/lib/features/upload/domain/exceptions/pick_file_exception.dart index f83dbe4d4..e8cdedd37 100644 --- a/lib/features/upload/domain/exceptions/pick_file_exception.dart +++ b/lib/features/upload/domain/exceptions/pick_file_exception.dart @@ -1,7 +1,7 @@ import 'package:core/domain/exceptions/app_base_exception.dart'; class PickFileCanceledException extends AppBaseException { - PickFileCanceledException([super.message]); + const PickFileCanceledException([super.message]); @override String get exceptionName => 'PickFileCanceledException'; diff --git a/lib/features/upload/domain/exceptions/upload_exception.dart b/lib/features/upload/domain/exceptions/upload_exception.dart index 0b5627a08..f47f5d35d 100644 --- a/lib/features/upload/domain/exceptions/upload_exception.dart +++ b/lib/features/upload/domain/exceptions/upload_exception.dart @@ -1,7 +1,7 @@ import 'package:core/domain/exceptions/app_base_exception.dart'; class DataResponseIsNullException extends AppBaseException { - DataResponseIsNullException([super.message]); + const DataResponseIsNullException([super.message]); @override String get exceptionName => 'DataResponseIsNullException'; diff --git a/lib/features/upload/domain/usecases/local_file_picker_interactor.dart b/lib/features/upload/domain/usecases/local_file_picker_interactor.dart index dd7cf46fa..f1c1b9432 100644 --- a/lib/features/upload/domain/usecases/local_file_picker_interactor.dart +++ b/lib/features/upload/domain/usecases/local_file_picker_interactor.dart @@ -29,7 +29,7 @@ class LocalFilePickerInteractor { .toList(); yield Right(LocalFilePickerSuccess(listFileInfo)); } else { - yield Left(LocalFilePickerFailure(PickFileCanceledException())); + yield Left(LocalFilePickerFailure(const PickFileCanceledException())); } } catch (exception) { yield Left(LocalFilePickerFailure(exception)); diff --git a/lib/features/upload/domain/usecases/local_image_picker_interactor.dart b/lib/features/upload/domain/usecases/local_image_picker_interactor.dart index ca91a31be..913cbd4fd 100644 --- a/lib/features/upload/domain/usecases/local_image_picker_interactor.dart +++ b/lib/features/upload/domain/usecases/local_image_picker_interactor.dart @@ -26,7 +26,7 @@ class LocalImagePickerInteractor { final fileInfo = filePickerResult!.files.first.toFileInfo(); yield Right(LocalImagePickerSuccess(fileInfo)); } else { - yield Left(LocalImagePickerFailure(PickFileCanceledException())); + yield Left(LocalImagePickerFailure(const PickFileCanceledException())); } } catch (exception) { yield Left(LocalImagePickerFailure(exception)); diff --git a/lib/main/error/request_error.dart b/lib/main/error/request_error.dart index 1a09afdfa..1a35bec3a 100644 --- a/lib/main/error/request_error.dart +++ b/lib/main/error/request_error.dart @@ -1,26 +1,22 @@ -import 'package:equatable/equatable.dart'; -import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart'; import 'package:core/domain/exceptions/app_base_exception.dart'; +import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart'; -class InvalidCapability extends AppBaseException with EquatableMixin { +class InvalidCapability extends AppBaseException { const InvalidCapability([super.message]); @override String get exceptionName => 'InvalidCapability'; - - @override - List get props => [message]; } class SessionMissingCapability extends InvalidCapability { final Set capabilityIdentifiers; - const SessionMissingCapability(this.capabilityIdentifiers) + SessionMissingCapability(this.capabilityIdentifiers) : super('Missing capabilities $capabilityIdentifiers'); @override String get exceptionName => 'SessionMissingCapability'; @override - List get props => [capabilityIdentifiers, ...super.props]; + List get props => [capabilityIdentifiers]; } diff --git a/lib/main/exceptions/permission_exception.dart b/lib/main/exceptions/permission_exception.dart index a35e594a1..0f26bfac7 100644 --- a/lib/main/exceptions/permission_exception.dart +++ b/lib/main/exceptions/permission_exception.dart @@ -7,6 +7,9 @@ abstract class PermissionException with EquatableMixin implements Exception { String get exceptionName; + @override + List get props => [message]; + @override String toString() { if (message != null) { diff --git a/lib/main/exceptions/remote_exception.dart b/lib/main/exceptions/remote_exception.dart index da2a466be..ab638fddf 100644 --- a/lib/main/exceptions/remote_exception.dart +++ b/lib/main/exceptions/remote_exception.dart @@ -110,17 +110,16 @@ class NoNetworkError extends RemoteException { } class RefreshTokenFailedException extends RemoteException { - final int? statusCode; RefreshTokenFailedException({ super.message = 'Refresh Token failed with 400 Bad Request. The session is invalid/revoked.', - this.statusCode = 400, + super.code = 400, }); @override String get exceptionName => 'RefreshTokenFailedException'; @override - String toString() => "$exceptionName(status: $statusCode): $message"; + String toString() => "$exceptionName(status: $code): $message"; } diff --git a/lib/main/utils/toast_manager.dart b/lib/main/utils/toast_manager.dart index e639ca5c5..f90f69b38 100644 --- a/lib/main/utils/toast_manager.dart +++ b/lib/main/utils/toast_manager.dart @@ -10,7 +10,6 @@ import 'package:core/presentation/utils/app_toast.dart'; import 'package:core/utils/app_logger.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_appauth_web/authorization_exception.dart'; import 'package:flutter_svg/svg.dart'; import 'package:jmap_dart_client/jmap/core/error/method/error_method_response.dart'; import 'package:jmap_dart_client/jmap/core/error/method/exception/error_method_response_exception.dart'; diff --git a/test/features/server_settings/data/datasource_impl/remote_server_settings_data_source_impl_test.dart b/test/features/server_settings/data/datasource_impl/remote_server_settings_data_source_impl_test.dart index 18b2230b0..9eebeb37f 100644 --- a/test/features/server_settings/data/datasource_impl/remote_server_settings_data_source_impl_test.dart +++ b/test/features/server_settings/data/datasource_impl/remote_server_settings_data_source_impl_test.dart @@ -45,7 +45,7 @@ void main() { test('should rethrow exception when ServerSettingsAPI throws exception',() async { // arrange when(serverSettingsAPI.getServerSettings(any)) - .thenThrow(NotFoundServerSettingsException()); + .thenThrow(const NotFoundServerSettingsException()); // assert expect( @@ -71,7 +71,7 @@ void main() { test('should rethrow exception when ServerSettingsAPI throws exception',() async { // arrange when(serverSettingsAPI.updateServerSettings(any, any, any)) - .thenThrow(CanNotUpdateServerSettingsException()); + .thenThrow(const CanNotUpdateServerSettingsException()); // assert expect( diff --git a/test/features/server_settings/data/repository/server_settings_repository_impl_test.dart b/test/features/server_settings/data/repository/server_settings_repository_impl_test.dart index 33608936f..f549ced87 100644 --- a/test/features/server_settings/data/repository/server_settings_repository_impl_test.dart +++ b/test/features/server_settings/data/repository/server_settings_repository_impl_test.dart @@ -38,7 +38,7 @@ void main() { test('should rethrow exception when ServerSettingsDataSource throws exception', () async { // arrange when(serverSettingsDataSource.getServerSettings(accountId)) - .thenThrow(NotFoundServerSettingsException()); + .thenThrow(const NotFoundServerSettingsException()); // assert expect( @@ -64,7 +64,7 @@ void main() { test('should rethrow exception when ServerSettingsDataSource throws exception', () async { // arrange when(serverSettingsDataSource.updateServerSettings(session, accountId, serverSettings)) - .thenThrow(NotFoundServerSettingsException()); + .thenThrow(const NotFoundServerSettingsException()); // assert expect( diff --git a/test/features/server_settings/domain/usecases/get_server_setting_interactor_test.dart b/test/features/server_settings/domain/usecases/get_server_setting_interactor_test.dart index c57c44355..2c1ff2834 100644 --- a/test/features/server_settings/domain/usecases/get_server_setting_interactor_test.dart +++ b/test/features/server_settings/domain/usecases/get_server_setting_interactor_test.dart @@ -39,7 +39,7 @@ void main() { test('should return left with exception returned from repository', () { // arrange - final exception = NotFoundServerSettingsException(); + const exception = NotFoundServerSettingsException(); when(serverSettingsRepository.getServerSettings(any)).thenThrow(exception); // assert diff --git a/test/features/server_settings/domain/usecases/update_server_setting_interactor_test.dart b/test/features/server_settings/domain/usecases/update_server_setting_interactor_test.dart index e3912abf3..fe26dd41d 100644 --- a/test/features/server_settings/domain/usecases/update_server_setting_interactor_test.dart +++ b/test/features/server_settings/domain/usecases/update_server_setting_interactor_test.dart @@ -45,7 +45,7 @@ void main() { test('should return left with exception returned from repository', () { // arrange - final exception = NotFoundServerSettingsException(); + const exception = NotFoundServerSettingsException(); when(serverSettingsRepository.updateServerSettings(any, any, any)) .thenThrow(exception);