diff --git a/packages/twenty-front/src/modules/sse-db-event/components/SSEQuerySubscribeEffect.tsx b/packages/twenty-front/src/modules/sse-db-event/components/SSEQuerySubscribeEffect.tsx index 802ca8b205..aa1a31751b 100644 --- a/packages/twenty-front/src/modules/sse-db-event/components/SSEQuerySubscribeEffect.tsx +++ b/packages/twenty-front/src/modules/sse-db-event/components/SSEQuerySubscribeEffect.tsx @@ -5,10 +5,12 @@ import { requiredQueryListenersState } from '@/sse-db-event/states/requiredQuery import { shouldDestroyEventStreamState } from '@/sse-db-event/states/shouldDestroyEventStreamState'; import { sseEventStreamIdState } from '@/sse-db-event/states/sseEventStreamIdState'; import { sseEventStreamReadyState } from '@/sse-db-event/states/sseEventStreamReadyState'; +import { isGracefullyHandledEventStreamError } from '@/sse-db-event/utils/isGracefullyHandledEventStreamError'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import { useMutation } from '@apollo/client/react'; import { CombinedGraphQLErrors } from '@apollo/client/errors'; +import { useMutation } from '@apollo/client/react'; import { isNonEmptyString } from '@sniptt/guards'; +import { useStore } from 'jotai'; import { useCallback, useEffect } from 'react'; import { compareArraysOfObjectsByProperty, @@ -19,7 +21,6 @@ import { type AddQuerySubscriptionInput, type RemoveQueryFromEventStreamInput, } from '~/generated-metadata/graphql'; -import { useStore } from 'jotai'; export const SSEQuerySubscribeEffect = () => { const store = useStore(); @@ -90,14 +91,7 @@ export const SSEQuerySubscribeEffect = () => { const subCode = error.errors[0]?.extensions?.subCode; const code = error.errors[0]?.extensions?.code; - const isRecoverable = - subCode === 'EVENT_STREAM_DOES_NOT_EXIST' || - subCode === 'EVENT_STREAM_ALREADY_EXISTS' || - subCode === 'NOT_AUTHORIZED' || - code === 'UNAUTHENTICATED' || - code === 'FORBIDDEN'; - - if (isRecoverable) { + if (isGracefullyHandledEventStreamError({ subCode, code })) { store.set(activeQueryListenersState.atom, []); store.set(shouldDestroyEventStreamState.atom, true); return; diff --git a/packages/twenty-front/src/modules/sse-db-event/hooks/useTriggerEventStreamCreation.ts b/packages/twenty-front/src/modules/sse-db-event/hooks/useTriggerEventStreamCreation.ts index 697d20ef92..80aed5f1c0 100644 --- a/packages/twenty-front/src/modules/sse-db-event/hooks/useTriggerEventStreamCreation.ts +++ b/packages/twenty-front/src/modules/sse-db-event/hooks/useTriggerEventStreamCreation.ts @@ -9,6 +9,7 @@ import { shouldDestroyEventStreamState } from '@/sse-db-event/states/shouldDestr import { sseClientState } from '@/sse-db-event/states/sseClientState'; import { sseEventStreamIdState } from '@/sse-db-event/states/sseEventStreamIdState'; import { sseEventStreamReadyState } from '@/sse-db-event/states/sseEventStreamReadyState'; +import { isGracefullyHandledEventStreamError } from '@/sse-db-event/utils/isGracefullyHandledEventStreamError'; import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; import { captureException } from '@sentry/react'; import { isNonEmptyString } from '@sniptt/guards'; @@ -80,9 +81,17 @@ export const useTriggerEventStreamCreation = () => { }>, ) => { if (isDefined(value?.errors) && Array.isArray(value.errors)) { - captureException( - new Error(`SSE subscription error: ${value.errors[0]?.message}`), - ); + const subCode = value.errors[0]?.extensions?.subCode; + const code = value.errors[0]?.extensions?.code; + + if (!isGracefullyHandledEventStreamError({ subCode, code })) { + captureException( + new Error( + `SSE subscription error: ${value.errors[0]?.message}`, + ), + ); + } + store.set(shouldDestroyEventStreamState.atom, true); return; @@ -129,16 +138,11 @@ export const useTriggerEventStreamCreation = () => { if (event === 'next') { if (isDefined(result?.errors)) { const subCode = result.errors[0]?.extensions?.subCode; + const code = result.errors[0]?.extensions?.code; - switch (subCode) { - case 'EVENT_STREAM_ALREADY_EXISTS': { - store.set(shouldDestroyEventStreamState.atom, true); - break; - } - default: { - for (const error of result.errors) { - captureException(error); - } + if (!isGracefullyHandledEventStreamError({ subCode, code })) { + for (const error of result.errors) { + captureException(error); } } diff --git a/packages/twenty-front/src/modules/sse-db-event/utils/isGracefullyHandledEventStreamError.ts b/packages/twenty-front/src/modules/sse-db-event/utils/isGracefullyHandledEventStreamError.ts new file mode 100644 index 0000000000..a272170c11 --- /dev/null +++ b/packages/twenty-front/src/modules/sse-db-event/utils/isGracefullyHandledEventStreamError.ts @@ -0,0 +1,21 @@ +import { isNonEmptyString } from '@sniptt/guards'; + +export const isGracefullyHandledEventStreamError = ({ + subCode, + code, +}: { + subCode?: unknown; + code?: unknown; +}) => { + if (!isNonEmptyString(subCode) && !isNonEmptyString(code)) { + return false; + } + + return ( + subCode === 'EVENT_STREAM_DOES_NOT_EXIST' || + subCode === 'EVENT_STREAM_ALREADY_EXISTS' || + subCode === 'NOT_AUTHORIZED' || + code === 'UNAUTHENTICATED' || + code === 'FORBIDDEN' + ); +};