From 5202e2b2db7d3f8fbb573a0940c7ca30f981bd0f Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Wed, 26 Nov 2025 18:03:44 +0100 Subject: [PATCH] Refactor error messages messaging (#16094) We should try catch locally gmail errors when: - fetching message list - fetching messages - refreshing aliases - fetching folders --- ...oogle-email-alias-error-handler.service.ts | 33 +++ .../google-email-alias-manager.service.ts | 14 +- .../microsoft-email-alias-manager.service.ts | 0 .../email-alias-manager.module.ts | 6 +- .../email-alias-manager.service.spec.ts | 4 +- .../services/email-alias-manager.service.ts | 4 +- ...onnected-account-refresh-tokens.service.ts | 4 +- .../gmail-folders-error-handler.service.ts | 33 +++ .../gmail-get-all-folders.service.ts | 6 +- .../imap-get-all-folders.service.ts | 0 .../microsoft-get-all-folders.service.ts | 0 .../messaging-folder-sync-manager.module.ts | 8 +- .../services/sync-message-folders.service.ts | 6 +- .../gmail/messaging-gmail-driver.module.ts | 3 - .../gmail/mocks/gmail-api-error-mocks.ts | 180 +++------------ .../mocks/gmail-batch-api-error-mocks.ts | 217 ++++++++++++++++++ ...essage-list-fetch-error-handler.service.ts | 35 +-- ...l-messages-import-error-handler.service.ts | 38 +-- .../gmail-network-error-handler.service.ts | 23 -- .../gmail/types/gmail-api-batch-error.type.ts | 7 + .../gmail/types/gmail-api-error.type.ts | 4 + .../__tests__/parse-gaxios-error.spec.ts | 16 +- ...rse-gmail-message-list-fetch-error.spec.ts | 28 +-- .../parse-gmail-messages-import-error.spec.ts | 112 +++------ .../utils/is-gmail-api-batch-error.util.ts | 21 ++ .../utils/is-gmail-api-error-error.util.ts | 18 ++ ...util.ts => is-gmail-network-error.util.ts} | 13 +- ...ts => parse-gmail-api-batch-error.util.ts} | 27 +-- ....util.ts => parse-gmail-api-error.util.ts} | 66 ++---- .../utils/parse-gmail-network-error.util.ts | 16 ++ ...ssaging-message-list-fetch.service.spec.ts | 0 .../messaging-messages-import.service.spec.ts | 0 32 files changed, 543 insertions(+), 399 deletions(-) create mode 100644 packages/twenty-server/src/modules/connected-account/email-alias-manager/drivers/google/services/google-email-alias-error-handler.service.ts rename packages/twenty-server/src/modules/connected-account/email-alias-manager/drivers/google/{ => services}/google-email-alias-manager.service.ts (69%) rename packages/twenty-server/src/modules/connected-account/email-alias-manager/drivers/microsoft/{ => services}/microsoft-email-alias-manager.service.ts (100%) create mode 100644 packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/gmail/services/gmail-folders-error-handler.service.ts rename packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/gmail/{ => services}/gmail-get-all-folders.service.ts (91%) rename packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/imap/{ => services}/imap-get-all-folders.service.ts (100%) rename packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/microsoft/{ => services}/microsoft-get-all-folders.service.ts (100%) create mode 100644 packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/mocks/gmail-batch-api-error-mocks.ts delete mode 100644 packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/gmail-network-error-handler.service.ts create mode 100644 packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-api-batch-error.type.ts create mode 100644 packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-api-error.type.ts create mode 100644 packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-api-batch-error.util.ts create mode 100644 packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-api-error-error.util.ts rename packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/{is-axios-gaxios-error.util.ts => is-gmail-network-error.util.ts} (70%) rename packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/{parse-gmail-messages-import-error.util.ts => parse-gmail-api-batch-error.util.ts} (81%) rename packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/{parse-gmail-message-list-fetch-error.util.ts => parse-gmail-api-error.util.ts} (62%) create mode 100644 packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-network-error.util.ts rename packages/twenty-server/src/modules/messaging/message-import-manager/services/{ => __tests__}/messaging-message-list-fetch.service.spec.ts (100%) rename packages/twenty-server/src/modules/messaging/message-import-manager/services/{ => __tests__}/messaging-messages-import.service.spec.ts (100%) diff --git a/packages/twenty-server/src/modules/connected-account/email-alias-manager/drivers/google/services/google-email-alias-error-handler.service.ts b/packages/twenty-server/src/modules/connected-account/email-alias-manager/drivers/google/services/google-email-alias-error-handler.service.ts new file mode 100644 index 0000000000..5503b7526f --- /dev/null +++ b/packages/twenty-server/src/modules/connected-account/email-alias-manager/drivers/google/services/google-email-alias-error-handler.service.ts @@ -0,0 +1,33 @@ +import { Injectable, Logger } from '@nestjs/common'; + +import { + MessageImportDriverException, + MessageImportDriverExceptionCode, +} from 'src/modules/messaging/message-import-manager/drivers/exceptions/message-import-driver.exception'; +import { isGmailApiError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-api-error-error.util'; +import { isGmailNetworkError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-network-error.util'; +import { parseGmailApiError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-api-error.util'; +import { parseGmailNetworkError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-network-error.util'; + +@Injectable() +export class GmailEmailAliasErrorHandlerService { + private readonly logger = new Logger(GmailEmailAliasErrorHandlerService.name); + + constructor() {} + + public handleError(error: unknown): void { + this.logger.error(`Google: Error getting email aliases: ${error}`); + if (isGmailNetworkError(error)) { + throw parseGmailNetworkError(error); + } + + if (isGmailApiError(error)) { + throw parseGmailApiError(error); + } + + throw new MessageImportDriverException( + 'Unknown error', + MessageImportDriverExceptionCode.UNKNOWN, + ); + } +} diff --git a/packages/twenty-server/src/modules/connected-account/email-alias-manager/drivers/google/google-email-alias-manager.service.ts b/packages/twenty-server/src/modules/connected-account/email-alias-manager/drivers/google/services/google-email-alias-manager.service.ts similarity index 69% rename from packages/twenty-server/src/modules/connected-account/email-alias-manager/drivers/google/google-email-alias-manager.service.ts rename to packages/twenty-server/src/modules/connected-account/email-alias-manager/drivers/google/services/google-email-alias-manager.service.ts index aaa62dd9be..fd0a8c9030 100644 --- a/packages/twenty-server/src/modules/connected-account/email-alias-manager/drivers/google/google-email-alias-manager.service.ts +++ b/packages/twenty-server/src/modules/connected-account/email-alias-manager/drivers/google/services/google-email-alias-manager.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common'; import { google } from 'googleapis'; +import { GmailEmailAliasErrorHandlerService } from 'src/modules/connected-account/email-alias-manager/drivers/google/services/google-email-alias-error-handler.service'; import { OAuth2ClientManagerService } from 'src/modules/connected-account/oauth2-client-manager/services/oauth2-client-manager.service'; import { type ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; @@ -9,6 +10,7 @@ import { type ConnectedAccountWorkspaceEntity } from 'src/modules/connected-acco export class GoogleEmailAliasManagerService { constructor( private readonly oAuth2ClientManagerService: OAuth2ClientManagerService, + private readonly gmailEmailAliasErrorHandlerService: GmailEmailAliasErrorHandlerService, ) {} public async getHandleAliases( @@ -24,10 +26,14 @@ export class GoogleEmailAliasManagerService { auth: oAuth2Client, }); - const emailsResponse = await peopleClient.people.get({ - resourceName: 'people/me', - personFields: 'emailAddresses', - }); + const emailsResponse = await peopleClient.people + .get({ + resourceName: 'people/me', + personFields: 'emailAddresses', + }) + .catch((error) => { + throw this.gmailEmailAliasErrorHandlerService.handleError(error); + }); const emailAddresses = emailsResponse.data.emailAddresses; diff --git a/packages/twenty-server/src/modules/connected-account/email-alias-manager/drivers/microsoft/microsoft-email-alias-manager.service.ts b/packages/twenty-server/src/modules/connected-account/email-alias-manager/drivers/microsoft/services/microsoft-email-alias-manager.service.ts similarity index 100% rename from packages/twenty-server/src/modules/connected-account/email-alias-manager/drivers/microsoft/microsoft-email-alias-manager.service.ts rename to packages/twenty-server/src/modules/connected-account/email-alias-manager/drivers/microsoft/services/microsoft-email-alias-manager.service.ts diff --git a/packages/twenty-server/src/modules/connected-account/email-alias-manager/email-alias-manager.module.ts b/packages/twenty-server/src/modules/connected-account/email-alias-manager/email-alias-manager.module.ts index fa69131387..32dc0d436b 100644 --- a/packages/twenty-server/src/modules/connected-account/email-alias-manager/email-alias-manager.module.ts +++ b/packages/twenty-server/src/modules/connected-account/email-alias-manager/email-alias-manager.module.ts @@ -1,7 +1,8 @@ import { Module } from '@nestjs/common'; -import { GoogleEmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/drivers/google/google-email-alias-manager.service'; -import { MicrosoftEmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/drivers/microsoft/microsoft-email-alias-manager.service'; +import { GmailEmailAliasErrorHandlerService } from 'src/modules/connected-account/email-alias-manager/drivers/google/services/google-email-alias-error-handler.service'; +import { GoogleEmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/drivers/google/services/google-email-alias-manager.service'; +import { MicrosoftEmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/drivers/microsoft/services/microsoft-email-alias-manager.service'; import { EmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/services/email-alias-manager.service'; import { OAuth2ClientManagerModule } from 'src/modules/connected-account/oauth2-client-manager/oauth2-client-manager.module'; @@ -10,6 +11,7 @@ import { OAuth2ClientManagerModule } from 'src/modules/connected-account/oauth2- providers: [ EmailAliasManagerService, GoogleEmailAliasManagerService, + GmailEmailAliasErrorHandlerService, MicrosoftEmailAliasManagerService, ], exports: [EmailAliasManagerService], diff --git a/packages/twenty-server/src/modules/connected-account/email-alias-manager/services/email-alias-manager.service.spec.ts b/packages/twenty-server/src/modules/connected-account/email-alias-manager/services/email-alias-manager.service.spec.ts index 18104d5ba3..32491c1a9d 100644 --- a/packages/twenty-server/src/modules/connected-account/email-alias-manager/services/email-alias-manager.service.spec.ts +++ b/packages/twenty-server/src/modules/connected-account/email-alias-manager/services/email-alias-manager.service.spec.ts @@ -4,9 +4,9 @@ import { ConnectedAccountProvider } from 'twenty-shared/types'; import { type Repository } from 'typeorm'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; -import { GoogleEmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/drivers/google/google-email-alias-manager.service'; -import { MicrosoftEmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/drivers/microsoft/microsoft-email-alias-manager.service'; +import { GoogleEmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/drivers/google/services/google-email-alias-manager.service'; import { microsoftGraphMeResponseWithProxyAddresses } from 'src/modules/connected-account/email-alias-manager/drivers/microsoft/mocks/microsoft-api-examples'; +import { MicrosoftEmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/drivers/microsoft/services/microsoft-email-alias-manager.service'; import { OAuth2ClientManagerService } from 'src/modules/connected-account/oauth2-client-manager/services/oauth2-client-manager.service'; import { type ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; diff --git a/packages/twenty-server/src/modules/connected-account/email-alias-manager/services/email-alias-manager.service.ts b/packages/twenty-server/src/modules/connected-account/email-alias-manager/services/email-alias-manager.service.ts index b5b7cc78e7..eaeeff0511 100644 --- a/packages/twenty-server/src/modules/connected-account/email-alias-manager/services/email-alias-manager.service.ts +++ b/packages/twenty-server/src/modules/connected-account/email-alias-manager/services/email-alias-manager.service.ts @@ -4,8 +4,8 @@ import { ConnectedAccountProvider } from 'twenty-shared/types'; import { assertUnreachable } from 'twenty-shared/utils'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; -import { GoogleEmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/drivers/google/google-email-alias-manager.service'; -import { MicrosoftEmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/drivers/microsoft/microsoft-email-alias-manager.service'; +import { GoogleEmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/drivers/google/services/google-email-alias-manager.service'; +import { MicrosoftEmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/drivers/microsoft/services/microsoft-email-alias-manager.service'; import { type ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; @Injectable() diff --git a/packages/twenty-server/src/modules/connected-account/refresh-tokens-manager/services/connected-account-refresh-tokens.service.ts b/packages/twenty-server/src/modules/connected-account/refresh-tokens-manager/services/connected-account-refresh-tokens.service.ts index 484ceb0c08..5f9bc8d9b5 100644 --- a/packages/twenty-server/src/modules/connected-account/refresh-tokens-manager/services/connected-account-refresh-tokens.service.ts +++ b/packages/twenty-server/src/modules/connected-account/refresh-tokens-manager/services/connected-account-refresh-tokens.service.ts @@ -11,7 +11,7 @@ import { ConnectedAccountRefreshAccessTokenExceptionCode, } from 'src/modules/connected-account/refresh-tokens-manager/exceptions/connected-account-refresh-tokens.exception'; import { type ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; -import { isAxiosTemporaryError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/is-axios-gaxios-error.util'; +import { isGmailNetworkError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-network-error.util'; export type ConnectedAccountTokens = { accessToken: string; @@ -142,7 +142,7 @@ export class ConnectedAccountRefreshTokensService { ); } } catch (error) { - if (isAxiosTemporaryError(error)) { + if (isGmailNetworkError(error)) { throw new ConnectedAccountRefreshAccessTokenException( `Error refreshing tokens for connected account ${connectedAccount.id.slice(0, 7)} in workspace ${workspaceId.slice(0, 7)}: ${error.code}`, ConnectedAccountRefreshAccessTokenExceptionCode.TEMPORARY_NETWORK_ERROR, diff --git a/packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/gmail/services/gmail-folders-error-handler.service.ts b/packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/gmail/services/gmail-folders-error-handler.service.ts new file mode 100644 index 0000000000..bd541ddc7f --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/gmail/services/gmail-folders-error-handler.service.ts @@ -0,0 +1,33 @@ +import { Injectable, Logger } from '@nestjs/common'; + +import { + MessageImportDriverException, + MessageImportDriverExceptionCode, +} from 'src/modules/messaging/message-import-manager/drivers/exceptions/message-import-driver.exception'; +import { isGmailApiError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-api-error-error.util'; +import { isGmailNetworkError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-network-error.util'; +import { parseGmailApiError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-api-error.util'; +import { parseGmailNetworkError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-network-error.util'; + +@Injectable() +export class GmailFoldersErrorHandlerService { + private readonly logger = new Logger(GmailFoldersErrorHandlerService.name); + + constructor() {} + + public handleError(error: unknown): void { + this.logger.error(`Gmail: Error fetching folders: ${error}`); + if (isGmailNetworkError(error)) { + throw parseGmailNetworkError(error); + } + + if (isGmailApiError(error)) { + throw parseGmailApiError(error); + } + + throw new MessageImportDriverException( + 'Unknown error', + MessageImportDriverExceptionCode.UNKNOWN, + ); + } +} diff --git a/packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/gmail/gmail-get-all-folders.service.ts b/packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/gmail/services/gmail-get-all-folders.service.ts similarity index 91% rename from packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/gmail/gmail-get-all-folders.service.ts rename to packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/gmail/services/gmail-get-all-folders.service.ts index 60b8af7b9e..9d7d1745f5 100644 --- a/packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/gmail/gmail-get-all-folders.service.ts +++ b/packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/gmail/services/gmail-get-all-folders.service.ts @@ -10,11 +10,11 @@ import { import { OAuth2ClientManagerService } from 'src/modules/connected-account/oauth2-client-manager/services/oauth2-client-manager.service'; import { type ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; +import { GmailFoldersErrorHandlerService } from 'src/modules/messaging/message-folder-manager/drivers/gmail/services/gmail-folders-error-handler.service'; import { extractGmailFolderName } from 'src/modules/messaging/message-folder-manager/drivers/gmail/utils/extract-gmail-folder-name.util'; import { getGmailFolderParentId } from 'src/modules/messaging/message-folder-manager/drivers/gmail/utils/get-gmail-folder-parent-id.util'; import { shouldSyncFolderByDefault } from 'src/modules/messaging/message-folder-manager/utils/should-sync-folder-by-default.util'; import { MESSAGING_GMAIL_DEFAULT_NOT_SYNCED_LABELS } from 'src/modules/messaging/message-import-manager/drivers/gmail/constants/messaging-gmail-default-not-synced-labels'; -import { GmailMessageListFetchErrorHandler } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/gmail-message-list-fetch-error-handler.service'; @Injectable() export class GmailGetAllFoldersService implements MessageFolderDriver { @@ -22,7 +22,7 @@ export class GmailGetAllFoldersService implements MessageFolderDriver { constructor( private readonly oAuth2ClientManagerService: OAuth2ClientManagerService, - private readonly gmailMessageListFetchErrorHandler: GmailMessageListFetchErrorHandler, + private readonly gmailFoldersErrorHandlerService: GmailFoldersErrorHandlerService, ) {} async getAllMessageFolders( @@ -53,7 +53,7 @@ export class GmailGetAllFoldersService implements MessageFolderDriver { `Connected account ${connectedAccount.id}: Error fetching labels: ${error.message}`, ); - this.gmailMessageListFetchErrorHandler.handleError(error); + this.gmailFoldersErrorHandlerService.handleError(error); return { data: { labels: [] } }; }); diff --git a/packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/imap/imap-get-all-folders.service.ts b/packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/imap/services/imap-get-all-folders.service.ts similarity index 100% rename from packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/imap/imap-get-all-folders.service.ts rename to packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/imap/services/imap-get-all-folders.service.ts diff --git a/packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/microsoft/microsoft-get-all-folders.service.ts b/packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/microsoft/services/microsoft-get-all-folders.service.ts similarity index 100% rename from packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/microsoft/microsoft-get-all-folders.service.ts rename to packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/microsoft/services/microsoft-get-all-folders.service.ts diff --git a/packages/twenty-server/src/modules/messaging/message-folder-manager/messaging-folder-sync-manager.module.ts b/packages/twenty-server/src/modules/messaging/message-folder-manager/messaging-folder-sync-manager.module.ts index d4dd634fbb..0955aadd20 100644 --- a/packages/twenty-server/src/modules/messaging/message-folder-manager/messaging-folder-sync-manager.module.ts +++ b/packages/twenty-server/src/modules/messaging/message-folder-manager/messaging-folder-sync-manager.module.ts @@ -6,9 +6,10 @@ import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.ent import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; import { OAuth2ClientManagerModule } from 'src/modules/connected-account/oauth2-client-manager/oauth2-client-manager.module'; -import { GmailGetAllFoldersService } from 'src/modules/messaging/message-folder-manager/drivers/gmail/gmail-get-all-folders.service'; -import { ImapGetAllFoldersService } from 'src/modules/messaging/message-folder-manager/drivers/imap/imap-get-all-folders.service'; -import { MicrosoftGetAllFoldersService } from 'src/modules/messaging/message-folder-manager/drivers/microsoft/microsoft-get-all-folders.service'; +import { GmailFoldersErrorHandlerService } from 'src/modules/messaging/message-folder-manager/drivers/gmail/services/gmail-folders-error-handler.service'; +import { GmailGetAllFoldersService } from 'src/modules/messaging/message-folder-manager/drivers/gmail/services/gmail-get-all-folders.service'; +import { ImapGetAllFoldersService } from 'src/modules/messaging/message-folder-manager/drivers/imap/services/imap-get-all-folders.service'; +import { MicrosoftGetAllFoldersService } from 'src/modules/messaging/message-folder-manager/drivers/microsoft/services/microsoft-get-all-folders.service'; import { SyncMessageFoldersService } from 'src/modules/messaging/message-folder-manager/services/sync-message-folders.service'; import { MessagingGmailDriverModule } from 'src/modules/messaging/message-import-manager/drivers/gmail/messaging-gmail-driver.module'; import { MessagingIMAPDriverModule } from 'src/modules/messaging/message-import-manager/drivers/imap/messaging-imap-driver.module'; @@ -28,6 +29,7 @@ import { MessagingMicrosoftDriverModule } from 'src/modules/messaging/message-im providers: [ SyncMessageFoldersService, GmailGetAllFoldersService, + GmailFoldersErrorHandlerService, ImapGetAllFoldersService, MicrosoftGetAllFoldersService, ], diff --git a/packages/twenty-server/src/modules/messaging/message-folder-manager/services/sync-message-folders.service.ts b/packages/twenty-server/src/modules/messaging/message-folder-manager/services/sync-message-folders.service.ts index 909e650475..1efd1816a6 100644 --- a/packages/twenty-server/src/modules/messaging/message-folder-manager/services/sync-message-folders.service.ts +++ b/packages/twenty-server/src/modules/messaging/message-folder-manager/services/sync-message-folders.service.ts @@ -14,9 +14,9 @@ import { MessageFolderPendingSyncAction, type MessageFolderWorkspaceEntity, } from 'src/modules/messaging/common/standard-objects/message-folder.workspace-entity'; -import { GmailGetAllFoldersService } from 'src/modules/messaging/message-folder-manager/drivers/gmail/gmail-get-all-folders.service'; -import { ImapGetAllFoldersService } from 'src/modules/messaging/message-folder-manager/drivers/imap/imap-get-all-folders.service'; -import { MicrosoftGetAllFoldersService } from 'src/modules/messaging/message-folder-manager/drivers/microsoft/microsoft-get-all-folders.service'; +import { GmailGetAllFoldersService } from 'src/modules/messaging/message-folder-manager/drivers/gmail/services/gmail-get-all-folders.service'; +import { ImapGetAllFoldersService } from 'src/modules/messaging/message-folder-manager/drivers/imap/services/imap-get-all-folders.service'; +import { MicrosoftGetAllFoldersService } from 'src/modules/messaging/message-folder-manager/drivers/microsoft/services/microsoft-get-all-folders.service'; import { MessageFolderName } from 'src/modules/messaging/message-import-manager/drivers/microsoft/types/folders'; type SyncMessageFoldersInput = { diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/messaging-gmail-driver.module.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/messaging-gmail-driver.module.ts index 780fcb4d8c..3a7346b741 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/messaging-gmail-driver.module.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/messaging-gmail-driver.module.ts @@ -17,7 +17,6 @@ import { GmailGetMessageListService } from 'src/modules/messaging/message-import import { GmailGetMessagesService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/gmail-get-messages.service'; import { GmailMessageListFetchErrorHandler } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/gmail-message-list-fetch-error-handler.service'; import { GmailMessagesImportErrorHandler } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/gmail-messages-import-error-handler.service'; -import { GmailNetworkErrorHandler } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/gmail-network-error-handler.service'; import { MessageParticipantManagerModule } from 'src/modules/messaging/message-participant-manager/message-participant-manager.module'; @Module({ @@ -40,14 +39,12 @@ import { MessageParticipantManagerModule } from 'src/modules/messaging/message-p GmailFetchByBatchService, GmailGetMessagesService, GmailGetMessageListService, - GmailNetworkErrorHandler, GmailMessageListFetchErrorHandler, GmailMessagesImportErrorHandler, ], exports: [ GmailGetMessagesService, GmailGetMessageListService, - GmailNetworkErrorHandler, GmailMessageListFetchErrorHandler, GmailMessagesImportErrorHandler, ], diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/mocks/gmail-api-error-mocks.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/mocks/gmail-api-error-mocks.ts index 7b5ac94278..6f2efa7bfc 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/mocks/gmail-api-error-mocks.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/mocks/gmail-api-error-mocks.ts @@ -1,196 +1,70 @@ -// Gmail API Error Response Mocks for users.messages.list +import { type GmailApiError } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-api-error.type'; + const gmailApiErrorMocks = { // 400 Bad Request - Invalid query parameters badRequest: { - error: { - code: 400, - errors: [ - { - domain: 'global', - location: 'orderBy', - locationType: 'parameter', - message: - 'Sorting is not supported for queries with fullText terms. Results are always in descending relevance order.', - reason: 'badRequest', - }, - ], - message: - 'Sorting is not supported for queries with fullText terms. Results are always in descending relevance order.', - }, + code: '400', + message: 'badRequest', }, // 400 Invalid Grant invalidGrant: { - error: { - code: 400, - errors: [ - { - domain: 'global', - reason: 'invalid_grant', - message: 'Invalid Credentials', - }, - ], - message: 'Invalid Credentials', - }, + code: '400', + message: 'invalid_grant', }, // 400 Failed Precondition failedPrecondition: { - error: { - code: 400, - errors: [ - { - domain: 'global', - reason: 'failedPrecondition', - message: 'Failed Precondition', - }, - ], - message: 'Failed Precondition', - }, + code: '400', + message: 'failedPrecondition', }, - // 401 Invalid Credentials invalidCredentials: { - error: { - errors: [ - { - domain: 'global', - reason: 'authError', - message: 'Invalid Credentials', - locationType: 'header', - location: 'Authorization', - }, - ], - code: 401, - message: 'Invalid Credentials', - }, + code: '401', + message: 'authError', }, - // 404 Not Found notFound: { - error: { - errors: [ - { - domain: 'global', - reason: 'notFound', - message: 'Resource not found: userId', - location: 'userId', - locationType: 'parameter', - }, - ], - code: 404, - message: 'Resource not found: userId', - }, + code: '404', + message: 'notFound', }, - // 410 Gone gone: { - error: { - errors: [ - { - domain: 'global', - reason: 'resourceGone', - message: 'Resource has been deleted', - location: 'messageId', - locationType: 'parameter', - }, - ], - code: 410, - message: 'Resource has been deleted', - }, + code: '410', + message: 'resourceGone', }, - // 403 Daily Limit Exceeded dailyLimitExceeded: { - error: { - errors: [ - { - domain: 'usageLimits', - reason: 'dailyLimitExceeded', - message: 'Daily Limit Exceeded', - }, - ], - code: 403, - message: 'Daily Limit Exceeded', - }, + code: '403', + message: 'dailyLimitExceeded', }, - // 403 User Rate Limit Exceeded userRateLimitExceeded: { - error: { - errors: [ - { - domain: 'usageLimits', - reason: 'userRateLimitExceeded', - message: 'User Rate Limit Exceeded', - }, - ], - code: 403, - message: 'User Rate Limit Exceeded', - }, + code: '403', + message: 'userRateLimitExceeded', }, - // 403 Rate Limit Exceeded rateLimitExceeded: { - error: { - errors: [ - { - domain: 'usageLimits', - reason: 'rateLimitExceeded', - message: 'Rate Limit Exceeded', - }, - ], - code: 403, - message: 'Rate Limit Exceeded', - }, + code: '403', + message: 'rateLimitExceeded', }, - // 403 Domain Policy Error domainPolicyError: { - error: { - errors: [ - { - domain: 'global', - reason: 'domainPolicy', - message: 'The domain administrators have disabled Gmail apps.', - }, - ], - code: 403, - message: 'The domain administrators have disabled Gmail apps.', - }, + code: '403', + message: 'domainPolicy', }, - // 429 Too Many Requests (Concurrent Requests) tooManyConcurrentRequests: { - error: { - errors: [ - { - domain: 'global', - reason: 'rateLimitExceeded', - message: 'Too many concurrent requests for user', - }, - ], - code: 429, - message: 'Too many concurrent requests for user', - }, + code: '429', + message: 'tooManyConcurrentRequests', }, - // 500 Backend Error backendError: { - error: { - errors: [ - { - domain: 'global', - reason: 'backendError', - message: 'Backend Error', - }, - ], - code: 500, - message: 'Backend Error', - }, + code: '500', + message: 'backendError', }, - getError: function (code: number, type?: string) { + getError: function (code: number, type?: string): GmailApiError { switch (code) { case 400: switch (type) { diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/mocks/gmail-batch-api-error-mocks.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/mocks/gmail-batch-api-error-mocks.ts new file mode 100644 index 0000000000..336987e321 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/mocks/gmail-batch-api-error-mocks.ts @@ -0,0 +1,217 @@ +import { type GmailApiBatchError } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-api-batch-error.type'; + +const gmailBatchApiErrorMocks = { + // 400 Bad Request - Invalid query parameters + badRequest: { + code: 400, + errors: [ + { + domain: 'global', + location: 'orderBy', + locationType: 'parameter', + message: + 'Sorting is not supported for queries with fullText terms. Results are always in descending relevance order.', + reason: 'badRequest', + }, + ], + message: + 'Sorting is not supported for queries with fullText terms. Results are always in descending relevance order.', + }, + + // 400 Invalid Grant + invalidGrant: { + code: 400, + errors: [ + { + domain: 'global', + reason: 'invalid_grant', + message: 'Invalid Credentials', + }, + ], + message: 'Invalid Credentials', + }, + + // 400 Failed Precondition + failedPrecondition: { + code: 400, + errors: [ + { + domain: 'global', + reason: 'failedPrecondition', + message: 'Failed Precondition', + }, + ], + message: 'Failed Precondition', + }, + + // 401 Invalid Credentials + invalidCredentials: { + errors: [ + { + domain: 'global', + reason: 'authError', + message: 'Invalid Credentials', + locationType: 'header', + location: 'Authorization', + }, + ], + code: 401, + message: 'Invalid Credentials', + }, + + // 404 Not Found + notFound: { + errors: [ + { + domain: 'global', + reason: 'notFound', + message: 'Resource not found: userId', + location: 'userId', + locationType: 'parameter', + }, + ], + code: 404, + message: 'Resource not found: userId', + }, + + // 410 Gone + gone: { + errors: [ + { + domain: 'global', + reason: 'resourceGone', + message: 'Resource has been deleted', + location: 'messageId', + locationType: 'parameter', + }, + ], + code: 410, + message: 'Resource has been deleted', + }, + + // 403 Daily Limit Exceeded + dailyLimitExceeded: { + errors: [ + { + domain: 'usageLimits', + reason: 'dailyLimitExceeded', + message: 'Daily Limit Exceeded', + }, + ], + code: 403, + message: 'Daily Limit Exceeded', + }, + + // 403 User Rate Limit Exceeded + userRateLimitExceeded: { + errors: [ + { + domain: 'usageLimits', + reason: 'userRateLimitExceeded', + message: 'User Rate Limit Exceeded', + }, + ], + code: 403, + message: 'User Rate Limit Exceeded', + }, + + // 403 Rate Limit Exceeded + rateLimitExceeded: { + errors: [ + { + domain: 'usageLimits', + reason: 'rateLimitExceeded', + message: 'Rate Limit Exceeded', + }, + ], + code: 403, + message: 'Rate Limit Exceeded', + }, + + // 403 Domain Policy Error + domainPolicyError: { + errors: [ + { + domain: 'global', + reason: 'domainPolicy', + message: 'The domain administrators have disabled Gmail apps.', + }, + ], + code: 403, + message: 'The domain administrators have disabled Gmail apps.', + }, + + // 429 Too Many Requests (Concurrent Requests) + tooManyConcurrentRequests: { + errors: [ + { + domain: 'global', + reason: 'rateLimitExceeded', + message: 'Too many concurrent requests for user', + }, + ], + code: 429, + message: 'Too many concurrent requests for user', + }, + + // 500 Backend Error + backendError: { + errors: [ + { + domain: 'global', + reason: 'backendError', + message: 'Backend Error', + }, + ], + code: 500, + message: 'Backend Error', + }, + + getError: function (code: number, type?: string): GmailApiBatchError { + switch (code) { + case 400: + switch (type) { + case 'invalid_grant': + return this.invalidGrant; + case 'failedPrecondition': + return this.failedPrecondition; + default: + return this.badRequest; + } + case 401: + return this.invalidCredentials; + case 403: + switch (type) { + case 'dailyLimit': + return this.dailyLimitExceeded; + case 'userRateLimit': + return this.userRateLimitExceeded; + case 'rateLimit': + return this.rateLimitExceeded; + case 'domainPolicy': + return this.domainPolicyError; + default: + return this.rateLimitExceeded; + } + case 404: + return this.notFound; + case 410: + return this.gone; + case 429: + switch (type) { + case 'concurrent': + return this.tooManyConcurrentRequests; + case 'mailSending': + return this.mailSendingLimitExceeded; + default: + return this.tooManyConcurrentRequests; + } + case 500: + return this.backendError; + default: + throw new Error(`Unknown error code: ${code}`); + } + }, +}; + +export default gmailBatchApiErrorMocks; diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/gmail-message-list-fetch-error-handler.service.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/gmail-message-list-fetch-error-handler.service.ts index 7b71e88404..0077092709 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/gmail-message-list-fetch-error-handler.service.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/gmail-message-list-fetch-error-handler.service.ts @@ -1,26 +1,33 @@ import { Injectable, Logger } from '@nestjs/common'; -import { GmailNetworkErrorHandler } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/gmail-network-error-handler.service'; -import { parseGmailMessageListFetchError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-message-list-fetch-error.util'; +import { + MessageImportDriverException, + MessageImportDriverExceptionCode, +} from 'src/modules/messaging/message-import-manager/drivers/exceptions/message-import-driver.exception'; +import { isGmailApiError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-api-error-error.util'; +import { isGmailNetworkError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-network-error.util'; +import { parseGmailApiError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-api-error.util'; +import { parseGmailNetworkError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-network-error.util'; @Injectable() export class GmailMessageListFetchErrorHandler { private readonly logger = new Logger(GmailMessageListFetchErrorHandler.name); - constructor( - private readonly gmailNetworkErrorHandler: GmailNetworkErrorHandler, - ) {} + constructor() {} - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public handleError(error: any): void { - this.logger.log(`Error fetching message list`, error); - - const networkError = this.gmailNetworkErrorHandler.handleError(error); - - if (networkError) { - throw networkError; + public handleError(error: unknown): void { + this.logger.error(`Gmail: Error fetching message list: ${error}`); + if (isGmailNetworkError(error)) { + throw parseGmailNetworkError(error); } - throw parseGmailMessageListFetchError(error, { cause: error }); + if (isGmailApiError(error)) { + throw parseGmailApiError(error); + } + + throw new MessageImportDriverException( + 'Unknown error', + MessageImportDriverExceptionCode.UNKNOWN, + ); } } diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/gmail-messages-import-error-handler.service.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/gmail-messages-import-error-handler.service.ts index a9dd74e150..9ab22c6817 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/gmail-messages-import-error-handler.service.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/gmail-messages-import-error-handler.service.ts @@ -1,32 +1,34 @@ import { Injectable, Logger } from '@nestjs/common'; -import { GmailNetworkErrorHandler } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/gmail-network-error-handler.service'; -import { parseGmailMessagesImportError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-messages-import-error.util'; +import { + MessageImportDriverException, + MessageImportDriverExceptionCode, +} from 'src/modules/messaging/message-import-manager/drivers/exceptions/message-import-driver.exception'; +import { isGmailApiBatchError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-api-batch-error.util'; +import { isGmailNetworkError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-network-error.util'; +import { parseGmailApiBatchError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-api-batch-error.util'; +import { parseGmailNetworkError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-network-error.util'; @Injectable() export class GmailMessagesImportErrorHandler { private readonly logger = new Logger(GmailMessagesImportErrorHandler.name); - constructor( - private readonly gmailNetworkErrorHandler: GmailNetworkErrorHandler, - ) {} + constructor() {} - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public handleError(error: any, messageExternalId: string): void { - this.logger.log(`Error fetching messages`, error); + public handleError(error: unknown, messageExternalId: string): void { + this.logger.error(`Gmail: Error importing messages: ${error}`); - const networkError = this.gmailNetworkErrorHandler.handleError(error); - - if (networkError) { - throw networkError; + if (isGmailNetworkError(error)) { + throw parseGmailNetworkError(error); } - const gmailError = parseGmailMessagesImportError(error, messageExternalId, { - cause: error, - }); - - if (gmailError) { - throw gmailError; + if (isGmailApiBatchError(error)) { + throw parseGmailApiBatchError(error, messageExternalId); } + + throw new MessageImportDriverException( + 'Unknown error', + MessageImportDriverExceptionCode.UNKNOWN, + ); } } diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/gmail-network-error-handler.service.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/gmail-network-error-handler.service.ts deleted file mode 100644 index 36b55d6127..0000000000 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/gmail-network-error-handler.service.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -import { - MessageImportDriverException, - MessageImportDriverExceptionCode, -} from 'src/modules/messaging/message-import-manager/drivers/exceptions/message-import-driver.exception'; -import { isAxiosTemporaryError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/is-axios-gaxios-error.util'; - -@Injectable() -export class GmailNetworkErrorHandler { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public handleError(error: any): MessageImportDriverException | null { - if (isAxiosTemporaryError(error)) { - return new MessageImportDriverException( - error.message, - MessageImportDriverExceptionCode.TEMPORARY_ERROR, - { cause: error }, - ); - } - - return null; - } -} diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-api-batch-error.type.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-api-batch-error.type.ts new file mode 100644 index 0000000000..95490c4f17 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-api-batch-error.type.ts @@ -0,0 +1,7 @@ +export type GmailApiBatchError = { + code: number; + errors: { + reason: string; + message: string; + }[]; +}; diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-api-error.type.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-api-error.type.ts new file mode 100644 index 0000000000..efe35f0757 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-api-error.type.ts @@ -0,0 +1,4 @@ +export type GmailApiError = { + code: string; + message: string; +}; diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/__tests__/parse-gaxios-error.spec.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/__tests__/parse-gaxios-error.spec.ts index 7ee2cb3669..3ac412324d 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/__tests__/parse-gaxios-error.spec.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/__tests__/parse-gaxios-error.spec.ts @@ -1,45 +1,45 @@ import gaxiosErrorMocks from 'src/modules/messaging/message-import-manager/drivers/gmail/mocks/gaxios-error-mocks'; -import { isAxiosTemporaryError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/is-axios-gaxios-error.util'; +import { isGmailNetworkError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-network-error.util'; -describe('parseGaxiosError', () => { +describe('isGmailNetworkError', () => { it('should return a MessageImportDriverException for ECONNRESET', () => { const error = gaxiosErrorMocks.getError('ECONNRESET'); - const result = isAxiosTemporaryError(error); + const result = isGmailNetworkError(error); expect(result).toBe(true); }); it('should return a MessageImportDriverException for ENOTFOUND', () => { const error = gaxiosErrorMocks.getError('ENOTFOUND'); - const result = isAxiosTemporaryError(error); + const result = isGmailNetworkError(error); expect(result).toBe(true); }); it('should return a MessageImportDriverException for ECONNABORTED', () => { const error = gaxiosErrorMocks.getError('ECONNABORTED'); - const result = isAxiosTemporaryError(error); + const result = isGmailNetworkError(error); expect(result).toBe(true); }); it('should return a MessageImportDriverException for ETIMEDOUT', () => { const error = gaxiosErrorMocks.getError('ETIMEDOUT'); - const result = isAxiosTemporaryError(error); + const result = isGmailNetworkError(error); expect(result).toBe(true); }); it('should return a MessageImportDriverException for ERR_NETWORK', () => { const error = gaxiosErrorMocks.getError('ERR_NETWORK'); - const result = isAxiosTemporaryError(error); + const result = isGmailNetworkError(error); expect(result).toBe(true); }); it('should return undefined for unknown error codes', () => { const error = { code: 'UNKNOWN_ERROR' } as any; - const result = isAxiosTemporaryError(error); + const result = isGmailNetworkError(error); expect(result).toBe(false); }); diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/__tests__/parse-gmail-message-list-fetch-error.spec.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/__tests__/parse-gmail-message-list-fetch-error.spec.ts index 07e78c864c..08d16fffb4 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/__tests__/parse-gmail-message-list-fetch-error.spec.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/__tests__/parse-gmail-message-list-fetch-error.spec.ts @@ -3,12 +3,12 @@ import { MessageImportDriverExceptionCode, } from 'src/modules/messaging/message-import-manager/drivers/exceptions/message-import-driver.exception'; import gmailApiErrorMocks from 'src/modules/messaging/message-import-manager/drivers/gmail/mocks/gmail-api-error-mocks'; -import { parseGmailMessageListFetchError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-message-list-fetch-error.util'; +import { parseGmailApiError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-api-error.util'; -describe('parseGmailMessageListFetchError', () => { +describe('parseGmailApiError', () => { it('should handle 400 Bad Request', () => { const error = gmailApiErrorMocks.getError(400); - const exception = parseGmailMessageListFetchError(error.error); + const exception = parseGmailApiError(error); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception.code).toBe(MessageImportDriverExceptionCode.UNKNOWN); @@ -16,7 +16,7 @@ describe('parseGmailMessageListFetchError', () => { it('should handle 400 Invalid Grant', () => { const error = gmailApiErrorMocks.getError(400, 'invalid_grant'); - const exception = parseGmailMessageListFetchError(error.error); + const exception = parseGmailApiError(error); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception.code).toBe( @@ -26,7 +26,7 @@ describe('parseGmailMessageListFetchError', () => { it('should handle 400 Failed Precondition', () => { const error = gmailApiErrorMocks.getError(400, 'failedPrecondition'); - const exception = parseGmailMessageListFetchError(error.error); + const exception = parseGmailApiError(error); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception.code).toBe( @@ -36,7 +36,7 @@ describe('parseGmailMessageListFetchError', () => { it('should handle 401 Invalid Credentials', () => { const error = gmailApiErrorMocks.getError(401); - const exception = parseGmailMessageListFetchError(error.error); + const exception = parseGmailApiError(error); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception.code).toBe( @@ -46,7 +46,7 @@ describe('parseGmailMessageListFetchError', () => { it('should handle 403 Daily Limit Exceeded', () => { const error = gmailApiErrorMocks.getError(403, 'dailyLimit'); - const exception = parseGmailMessageListFetchError(error.error); + const exception = parseGmailApiError(error); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception.code).toBe( @@ -56,7 +56,7 @@ describe('parseGmailMessageListFetchError', () => { it('should handle 403 User Rate Limit Exceeded', () => { const error = gmailApiErrorMocks.getError(403, 'userRateLimit'); - const exception = parseGmailMessageListFetchError(error.error); + const exception = parseGmailApiError(error); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception.code).toBe( @@ -66,7 +66,7 @@ describe('parseGmailMessageListFetchError', () => { it('should handle 403 Rate Limit Exceeded', () => { const error = gmailApiErrorMocks.getError(403, 'rateLimit'); - const exception = parseGmailMessageListFetchError(error.error); + const exception = parseGmailApiError(error); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception.code).toBe( @@ -76,7 +76,7 @@ describe('parseGmailMessageListFetchError', () => { it('should handle 403 Domain Policy Error', () => { const error = gmailApiErrorMocks.getError(403, 'domainPolicy'); - const exception = parseGmailMessageListFetchError(error.error); + const exception = parseGmailApiError(error); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception.code).toBe( @@ -86,7 +86,7 @@ describe('parseGmailMessageListFetchError', () => { it('should handle 404 as sync cursor error', () => { const error = gmailApiErrorMocks.getError(404); - const exception = parseGmailMessageListFetchError(error.error); + const exception = parseGmailApiError(error); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception.code).toBe( @@ -96,7 +96,7 @@ describe('parseGmailMessageListFetchError', () => { it('should handle 410 Gone', () => { const error = gmailApiErrorMocks.getError(410); - const exception = parseGmailMessageListFetchError(error.error); + const exception = parseGmailApiError(error); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception.code).toBe(MessageImportDriverExceptionCode.UNKNOWN); @@ -104,7 +104,7 @@ describe('parseGmailMessageListFetchError', () => { it('should handle 429 Too Many Requests', () => { const error = gmailApiErrorMocks.getError(429, 'concurrent'); - const exception = parseGmailMessageListFetchError(error.error); + const exception = parseGmailApiError(error); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception.code).toBe( @@ -114,7 +114,7 @@ describe('parseGmailMessageListFetchError', () => { it('should handle 500 Backend Error', () => { const error = gmailApiErrorMocks.getError(500); - const exception = parseGmailMessageListFetchError(error.error); + const exception = parseGmailApiError(error); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception.code).toBe( diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/__tests__/parse-gmail-messages-import-error.spec.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/__tests__/parse-gmail-messages-import-error.spec.ts index b6acda5490..6f2b99524b 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/__tests__/parse-gmail-messages-import-error.spec.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/__tests__/parse-gmail-messages-import-error.spec.ts @@ -2,48 +2,39 @@ import { MessageImportDriverException, MessageImportDriverExceptionCode, } from 'src/modules/messaging/message-import-manager/drivers/exceptions/message-import-driver.exception'; -import gmailApiErrorMocks from 'src/modules/messaging/message-import-manager/drivers/gmail/mocks/gmail-api-error-mocks'; -import { parseGmailMessagesImportError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-messages-import-error.util'; +import { default as gmailBatchApiErrorMocks } from 'src/modules/messaging/message-import-manager/drivers/gmail/mocks/gmail-batch-api-error-mocks'; +import { parseGmailApiBatchError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-api-batch-error.util'; const messageExternalId = '123'; -describe('parseGmailMessagesImportError', () => { +describe('parseGmailApiBatchError', () => { it('should handle 400 Bad Request', () => { - const error = gmailApiErrorMocks.getError(400); - const exception = parseGmailMessagesImportError( - error.error, - messageExternalId, - ); + const error = gmailBatchApiErrorMocks.getError(400); + const exception = parseGmailApiBatchError(error, messageExternalId); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception?.code).toBe(MessageImportDriverExceptionCode.UNKNOWN); expect(exception?.message).toBe( - `${error.error.errors[0].message} for message with externalId: ${messageExternalId}`, + `${error.errors[0].message} for message with externalId: ${messageExternalId}`, ); }); it('should handle 400 Invalid Grant', () => { - const error = gmailApiErrorMocks.getError(400, 'invalid_grant'); - const exception = parseGmailMessagesImportError( - error.error, - messageExternalId, - ); + const error = gmailBatchApiErrorMocks.getError(400, 'invalid_grant'); + const exception = parseGmailApiBatchError(error, messageExternalId); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception?.code).toBe( MessageImportDriverExceptionCode.INSUFFICIENT_PERMISSIONS, ); expect(exception?.message).toBe( - `${error.error.errors[0].message} for message with externalId: ${messageExternalId}`, + `${error.errors[0].message} for message with externalId: ${messageExternalId}`, ); }); it('should handle 400 Failed Precondition', () => { - const error = gmailApiErrorMocks.getError(400, 'failedPrecondition'); - const exception = parseGmailMessagesImportError( - error.error, - messageExternalId, - ); + const error = gmailBatchApiErrorMocks.getError(400, 'failedPrecondition'); + const exception = parseGmailApiBatchError(error, messageExternalId); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception?.code).toBe( @@ -52,146 +43,119 @@ describe('parseGmailMessagesImportError', () => { }); it('should handle 401 Invalid Credentials', () => { - const error = gmailApiErrorMocks.getError(401); - const exception = parseGmailMessagesImportError( - error.error, - messageExternalId, - ); + const error = gmailBatchApiErrorMocks.getError(401); + const exception = parseGmailApiBatchError(error, messageExternalId); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception?.code).toBe( MessageImportDriverExceptionCode.INSUFFICIENT_PERMISSIONS, ); expect(exception?.message).toBe( - `${error.error.errors[0].message} for message with externalId: ${messageExternalId}`, + `${error.errors[0].message} for message with externalId: ${messageExternalId}`, ); }); it('should handle 403 Daily Limit Exceeded', () => { - const error = gmailApiErrorMocks.getError(403, 'dailyLimit'); - const exception = parseGmailMessagesImportError( - error.error, - messageExternalId, - ); + const error = gmailBatchApiErrorMocks.getError(403, 'dailyLimit'); + const exception = parseGmailApiBatchError(error, messageExternalId); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception?.code).toBe( MessageImportDriverExceptionCode.TEMPORARY_ERROR, ); expect(exception?.message).toBe( - `${error.error.errors[0].message} for message with externalId: ${messageExternalId}`, + `${error.errors[0].message} for message with externalId: ${messageExternalId}`, ); }); it('should handle 403 User Rate Limit Exceeded', () => { - const error = gmailApiErrorMocks.getError(403, 'userRateLimit'); - const exception = parseGmailMessagesImportError( - error.error, - messageExternalId, - ); + const error = gmailBatchApiErrorMocks.getError(403, 'userRateLimit'); + const exception = parseGmailApiBatchError(error, messageExternalId); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception?.code).toBe( MessageImportDriverExceptionCode.TEMPORARY_ERROR, ); expect(exception?.message).toBe( - `${error.error.errors[0].message} for message with externalId: ${messageExternalId}`, + `${error.errors[0].message} for message with externalId: ${messageExternalId}`, ); }); it('should handle 403 Rate Limit Exceeded', () => { - const error = gmailApiErrorMocks.getError(403, 'rateLimit'); - const exception = parseGmailMessagesImportError( - error.error, - messageExternalId, - ); + const error = gmailBatchApiErrorMocks.getError(403, 'rateLimit'); + const exception = parseGmailApiBatchError(error, messageExternalId); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception?.code).toBe( MessageImportDriverExceptionCode.TEMPORARY_ERROR, ); expect(exception?.message).toBe( - `${error.error.errors[0].message} for message with externalId: ${messageExternalId}`, + `${error.errors[0].message} for message with externalId: ${messageExternalId}`, ); }); it('should handle 403 Domain Policy Error', () => { - const error = gmailApiErrorMocks.getError(403, 'domainPolicy'); - const exception = parseGmailMessagesImportError( - error.error, - messageExternalId, - ); + const error = gmailBatchApiErrorMocks.getError(403, 'domainPolicy'); + const exception = parseGmailApiBatchError(error, messageExternalId); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception?.code).toBe( MessageImportDriverExceptionCode.INSUFFICIENT_PERMISSIONS, ); expect(exception?.message).toBe( - `${error.error.errors[0].message} for message with externalId: ${messageExternalId}`, + `${error.errors[0].message} for message with externalId: ${messageExternalId}`, ); }); it('should handle 404 Not Found', () => { - const error = gmailApiErrorMocks.getError(404); - const exception = parseGmailMessagesImportError( - error.error, - messageExternalId, - ); + const error = gmailBatchApiErrorMocks.getError(404); + const exception = parseGmailApiBatchError(error, messageExternalId); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception?.code).toBe( MessageImportDriverExceptionCode.SYNC_CURSOR_ERROR, ); expect(exception?.message).toBe( - `${error.error.errors[0].message} for message with externalId: ${messageExternalId}`, + `${error.errors[0].message} for message with externalId: ${messageExternalId}`, ); }); it('should handle 410 Gone', () => { - const error = gmailApiErrorMocks.getError(410); - const exception = parseGmailMessagesImportError( - error.error, - messageExternalId, - ); + const error = gmailBatchApiErrorMocks.getError(410); + const exception = parseGmailApiBatchError(error, messageExternalId); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception?.code).toBe( MessageImportDriverExceptionCode.SYNC_CURSOR_ERROR, ); expect(exception?.message).toBe( - `${error.error.errors[0].message} for message with externalId: ${messageExternalId}`, + `${error.errors[0].message} for message with externalId: ${messageExternalId}`, ); }); it('should handle 429 Too Many Requests', () => { - const error = gmailApiErrorMocks.getError(429, 'concurrent'); - const exception = parseGmailMessagesImportError( - error.error, - messageExternalId, - ); + const error = gmailBatchApiErrorMocks.getError(429, 'concurrent'); + const exception = parseGmailApiBatchError(error, messageExternalId); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception?.code).toBe( MessageImportDriverExceptionCode.TEMPORARY_ERROR, ); expect(exception?.message).toBe( - `${error.error.errors[0].message} for message with externalId: ${messageExternalId}`, + `${error.errors[0].message} for message with externalId: ${messageExternalId}`, ); }); it('should handle 500 Backend Error', () => { - const error = gmailApiErrorMocks.getError(500); - const exception = parseGmailMessagesImportError( - error.error, - messageExternalId, - ); + const error = gmailBatchApiErrorMocks.getError(500); + const exception = parseGmailApiBatchError(error, messageExternalId); expect(exception).toBeInstanceOf(MessageImportDriverException); expect(exception?.code).toBe( MessageImportDriverExceptionCode.TEMPORARY_ERROR, ); expect(exception?.message).toBe( - `${error.error.errors[0].message} for message with externalId: ${messageExternalId}`, + `${error.errors[0].message} for message with externalId: ${messageExternalId}`, ); }); }); diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-api-batch-error.util.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-api-batch-error.util.ts new file mode 100644 index 0000000000..324652a21a --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-api-batch-error.util.ts @@ -0,0 +1,21 @@ +import { type GmailApiBatchError } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-api-batch-error.type'; + +export const isGmailApiBatchError = ( + error: unknown, +): error is GmailApiBatchError => { + if (error === null || typeof error !== 'object') { + return false; + } + + if ( + !('code' in error) || + !('errors' in error) || + !Array.isArray(error.errors) || + error.errors.length === 0 || + error.errors.some((error) => !('reason' in error) || !('message' in error)) + ) { + return false; + } + + return true; +}; diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-api-error-error.util.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-api-error-error.util.ts new file mode 100644 index 0000000000..5e675532f3 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-api-error-error.util.ts @@ -0,0 +1,18 @@ +import { type GmailApiError } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-api-error.type'; + +export const isGmailApiError = (error: unknown): error is GmailApiError => { + if (error === null || typeof error !== 'object') { + return false; + } + + if ( + !('code' in error) || + typeof error.code !== 'string' || + !('message' in error) || + typeof error.message !== 'string' + ) { + return false; + } + + return true; +}; diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/is-axios-gaxios-error.util.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-network-error.util.ts similarity index 70% rename from packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/is-axios-gaxios-error.util.ts rename to packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-network-error.util.ts index f1b99fed48..0c20aed2ab 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/is-axios-gaxios-error.util.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-network-error.util.ts @@ -2,10 +2,16 @@ import { type GaxiosError } from 'gaxios'; import { MessageNetworkExceptionCode } from 'src/modules/messaging/message-import-manager/drivers/exceptions/message-network.exception'; -export const isAxiosTemporaryError = (error: GaxiosError): boolean => { - const { code } = error; +export const isGmailNetworkError = (error: unknown): error is GaxiosError => { + if (error === null || typeof error !== 'object') { + return false; + } - switch (code) { + if (!('code' in error)) { + return false; + } + + switch (error.code) { case MessageNetworkExceptionCode.ECONNRESET: case MessageNetworkExceptionCode.ENOTFOUND: case MessageNetworkExceptionCode.ECONNABORTED: @@ -13,7 +19,6 @@ export const isAxiosTemporaryError = (error: GaxiosError): boolean => { case MessageNetworkExceptionCode.ERR_NETWORK: case MessageNetworkExceptionCode.EHOSTUNREACH: return true; - default: return false; } diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-messages-import-error.util.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-api-batch-error.util.ts similarity index 81% rename from packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-messages-import-error.util.ts rename to packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-api-batch-error.util.ts index 9030df14af..1314e8e72a 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-messages-import-error.util.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-api-batch-error.util.ts @@ -2,17 +2,11 @@ import { MessageImportDriverException, MessageImportDriverExceptionCode, } from 'src/modules/messaging/message-import-manager/drivers/exceptions/message-import-driver.exception'; +import { type GmailApiBatchError } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-api-batch-error.type'; -export const parseGmailMessagesImportError = ( - error: { - code?: number; - errors: { - reason: string; - message: string; - }[]; - }, - messageExternalId: string, - options?: { cause?: Error }, +export const parseGmailApiBatchError = ( + error: GmailApiBatchError, + messageExternalId?: string, ): MessageImportDriverException | undefined => { const { code, errors } = error; @@ -26,7 +20,6 @@ export const parseGmailMessagesImportError = ( return new MessageImportDriverException( message, MessageImportDriverExceptionCode.INSUFFICIENT_PERMISSIONS, - { cause: options?.cause }, ); } if (reason === 'failedPrecondition') { @@ -34,21 +27,18 @@ export const parseGmailMessagesImportError = ( return new MessageImportDriverException( message, MessageImportDriverExceptionCode.INSUFFICIENT_PERMISSIONS, - { cause: options?.cause }, ); } return new MessageImportDriverException( message, MessageImportDriverExceptionCode.TEMPORARY_ERROR, - { cause: options?.cause }, ); } return new MessageImportDriverException( message, MessageImportDriverExceptionCode.UNKNOWN, - { cause: options?.cause }, ); case 404: @@ -56,14 +46,12 @@ export const parseGmailMessagesImportError = ( return new MessageImportDriverException( message, MessageImportDriverExceptionCode.SYNC_CURSOR_ERROR, - { cause: options?.cause }, ); case 429: return new MessageImportDriverException( message, MessageImportDriverExceptionCode.TEMPORARY_ERROR, - { cause: options?.cause }, ); case 403: @@ -75,14 +63,12 @@ export const parseGmailMessagesImportError = ( return new MessageImportDriverException( message, MessageImportDriverExceptionCode.TEMPORARY_ERROR, - { cause: options?.cause }, ); } if (reason === 'domainPolicy') { return new MessageImportDriverException( message, MessageImportDriverExceptionCode.INSUFFICIENT_PERMISSIONS, - { cause: options?.cause }, ); } @@ -92,14 +78,12 @@ export const parseGmailMessagesImportError = ( return new MessageImportDriverException( message, MessageImportDriverExceptionCode.INSUFFICIENT_PERMISSIONS, - { cause: options?.cause }, ); case 503: return new MessageImportDriverException( message, MessageImportDriverExceptionCode.TEMPORARY_ERROR, - { cause: options?.cause }, ); case 500: @@ -109,7 +93,6 @@ export const parseGmailMessagesImportError = ( return new MessageImportDriverException( message, MessageImportDriverExceptionCode.TEMPORARY_ERROR, - { cause: options?.cause }, ); } @@ -117,7 +100,6 @@ export const parseGmailMessagesImportError = ( return new MessageImportDriverException( `${code} - ${reason} - ${message}`, MessageImportDriverExceptionCode.TEMPORARY_ERROR, - { cause: options?.cause }, ); } break; @@ -129,6 +111,5 @@ export const parseGmailMessagesImportError = ( return new MessageImportDriverException( message, MessageImportDriverExceptionCode.UNKNOWN, - { cause: options?.cause }, ); }; diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-message-list-fetch-error.util.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-api-error.util.ts similarity index 62% rename from packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-message-list-fetch-error.util.ts rename to packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-api-error.util.ts index c0b8ec1390..6721e39423 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-message-list-fetch-error.util.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-api-error.util.ts @@ -2,119 +2,98 @@ import { MessageImportDriverException, MessageImportDriverExceptionCode, } from 'src/modules/messaging/message-import-manager/drivers/exceptions/message-import-driver.exception'; +import { type GmailApiError } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-api-error.type'; -export const parseGmailMessageListFetchError = ( - error: { - code?: number; - errors: { - reason: string; - message: string; - }[]; - }, - options?: { cause?: Error }, +export const parseGmailApiError = ( + error: GmailApiError, ): MessageImportDriverException => { - const { code, errors } = error; - - const reason = errors?.[0]?.reason; - const message = errors?.[0]?.message; + const { code, message } = error; switch (code) { - case 400: - if (reason === 'invalid_grant') { + case '400': + if (message === 'invalid_grant') { return new MessageImportDriverException( message, MessageImportDriverExceptionCode.INSUFFICIENT_PERMISSIONS, - { cause: options?.cause }, ); } - if (reason === 'failedPrecondition') { + if (message === 'failedPrecondition') { if (message.includes('Mail service not enabled')) { return new MessageImportDriverException( message, MessageImportDriverExceptionCode.INSUFFICIENT_PERMISSIONS, - { cause: options?.cause }, ); } return new MessageImportDriverException( message, MessageImportDriverExceptionCode.TEMPORARY_ERROR, - { cause: options?.cause }, ); } return new MessageImportDriverException( message, MessageImportDriverExceptionCode.UNKNOWN, - { cause: options?.cause }, ); - case 404: + case '404': return new MessageImportDriverException( message, MessageImportDriverExceptionCode.SYNC_CURSOR_ERROR, - { cause: options?.cause }, ); - case 429: + case '429': return new MessageImportDriverException( message, MessageImportDriverExceptionCode.TEMPORARY_ERROR, - { cause: options?.cause }, ); - case 403: + case '403': if ( - reason === 'rateLimitExceeded' || - reason === 'userRateLimitExceeded' || - reason === 'dailyLimitExceeded' + message === 'rateLimitExceeded' || + message === 'userRateLimitExceeded' || + message === 'dailyLimitExceeded' ) { return new MessageImportDriverException( message, MessageImportDriverExceptionCode.TEMPORARY_ERROR, - { cause: options?.cause }, ); } - if (reason === 'domainPolicy') { + if (message === 'domainPolicy') { return new MessageImportDriverException( message, MessageImportDriverExceptionCode.INSUFFICIENT_PERMISSIONS, - { cause: options?.cause }, ); } break; - case 401: + case '401': return new MessageImportDriverException( message, MessageImportDriverExceptionCode.INSUFFICIENT_PERMISSIONS, - { cause: options?.cause }, ); - case 503: + case '503': return new MessageImportDriverException( message, MessageImportDriverExceptionCode.TEMPORARY_ERROR, - { cause: options?.cause }, ); - case 500: - case 502: - case 504: - if (reason === 'backendError') { + case '500': + case '502': + case '504': + if (message === 'backendError') { return new MessageImportDriverException( message, MessageImportDriverExceptionCode.TEMPORARY_ERROR, - { cause: options?.cause }, ); } - if (errors?.[0]?.message.includes(`Authentication backend unavailable`)) { + if (message.includes(`Authentication backend unavailable`)) { return new MessageImportDriverException( - `${code} - ${reason} - ${message}`, + `${code} - ${message}`, MessageImportDriverExceptionCode.TEMPORARY_ERROR, - { cause: options?.cause }, ); } break; @@ -126,6 +105,5 @@ export const parseGmailMessageListFetchError = ( return new MessageImportDriverException( message, MessageImportDriverExceptionCode.UNKNOWN, - { cause: options?.cause }, ); }; diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-network-error.util.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-network-error.util.ts new file mode 100644 index 0000000000..fcf8e4a21b --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-network-error.util.ts @@ -0,0 +1,16 @@ +import { type GaxiosError } from 'gaxios'; + +import { + MessageImportDriverException, + MessageImportDriverExceptionCode, +} from 'src/modules/messaging/message-import-manager/drivers/exceptions/message-import-driver.exception'; + +export const parseGmailNetworkError = ( + error: GaxiosError, +): MessageImportDriverException | null => { + return new MessageImportDriverException( + error.message, + MessageImportDriverExceptionCode.TEMPORARY_ERROR, + { cause: error }, + ); +}; diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-message-list-fetch.service.spec.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/services/__tests__/messaging-message-list-fetch.service.spec.ts similarity index 100% rename from packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-message-list-fetch.service.spec.ts rename to packages/twenty-server/src/modules/messaging/message-import-manager/services/__tests__/messaging-message-list-fetch.service.spec.ts diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-messages-import.service.spec.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/services/__tests__/messaging-messages-import.service.spec.ts similarity index 100% rename from packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-messages-import.service.spec.ts rename to packages/twenty-server/src/modules/messaging/message-import-manager/services/__tests__/messaging-messages-import.service.spec.ts