From 6e8ffb0412b4bc5a15de81fdcf34f55209097194 Mon Sep 17 00:00:00 2001 From: laurenashpole Date: Wed, 1 Oct 2025 10:42:48 -0400 Subject: [PATCH 1/5] refactor: remove unused cors error code --- packages/core/src/_exports/index.ts | 2 -- packages/core/src/query/queryStore.ts | 36 ------------------- .../src/components/auth/AuthBoundary.tsx | 19 ++-------- .../src/hooks/errors/useCorsOriginError.ts | 22 ------------ 4 files changed, 2 insertions(+), 77 deletions(-) delete mode 100644 packages/react/src/hooks/errors/useCorsOriginError.ts diff --git a/packages/core/src/_exports/index.ts b/packages/core/src/_exports/index.ts index 758df273e..2b3426647 100644 --- a/packages/core/src/_exports/index.ts +++ b/packages/core/src/_exports/index.ts @@ -123,8 +123,6 @@ export {resolveProjection} from '../projection/resolveProjection' export {type ProjectionValuePending, type ValidProjection} from '../projection/types' export {getProjectsState, resolveProjects} from '../projects/projects' export { - clearQueryError, - getQueryErrorState, getQueryKey, getQueryState, parseQueryKey, diff --git a/packages/core/src/query/queryStore.ts b/packages/core/src/query/queryStore.ts index 4b59677ea..995bfec2f 100644 --- a/packages/core/src/query/queryStore.ts +++ b/packages/core/src/query/queryStore.ts @@ -317,29 +317,6 @@ const _getQueryState = bindActionByDataset( }), ) -/** - * Returns a state source for the top-level query store error (if any). - * - * Unlike {@link getQueryState}, this selector does not throw; it simply returns the error value. - * Subscribe to this to be notified when a global query error occurs (e.g., CORS failures). - * - * @beta - */ -export function getQueryErrorState(instance: SanityInstance): StateSource { - return _getQueryErrorState(instance) -} - -const _getQueryErrorState = bindActionByDataset( - queryStore, - createStateSourceAction({ - selector: ({state}: SelectorContext) => state.error, - onSubscribe: () => { - // No-op subscription as we don't track per-query subscribers here - return () => {} - }, - }), -) - /** * Resolves the result of a query without registering a lasting subscriber. * @@ -413,16 +390,3 @@ const _resolveQuery = bindActionByDataset( return firstValueFrom(race([resolved$, aborted$])) }, ) - -/** - * Clears the top-level query store error. - * @beta - */ -export function clearQueryError(instance: SanityInstance): void -export function clearQueryError(...args: Parameters): void { - return _clearQueryError(...args) -} - -const _clearQueryError = bindActionByDataset(queryStore, ({state}) => { - state.set('setError', {error: undefined}) -}) diff --git a/packages/react/src/components/auth/AuthBoundary.tsx b/packages/react/src/components/auth/AuthBoundary.tsx index efb1df0d1..cc6c817fc 100644 --- a/packages/react/src/components/auth/AuthBoundary.tsx +++ b/packages/react/src/components/auth/AuthBoundary.tsx @@ -7,7 +7,6 @@ import {ComlinkTokenRefreshProvider} from '../../context/ComlinkTokenRefresh' import {useAuthState} from '../../hooks/auth/useAuthState' import {useLoginUrl} from '../../hooks/auth/useLoginUrl' import {useVerifyOrgProjects} from '../../hooks/auth/useVerifyOrgProjects' -import {useCorsOriginError} from '../../hooks/errors/useCorsOriginError' import {CorsErrorComponent} from '../errors/CorsErrorComponent' import {isInIframe} from '../utils' import {AuthError} from './AuthError' @@ -108,8 +107,6 @@ export function AuthBoundary({ LoginErrorComponent = LoginError, ...props }: AuthBoundaryProps): React.ReactNode { - const {error: corsError, projectId, clear: clearCorsError} = useCorsOriginError() - const FallbackComponent = useMemo(() => { return function LoginComponentWithLayoutProps(fallbackProps: FallbackProps) { if (fallbackProps.error instanceof CorsOriginError) { @@ -117,29 +114,17 @@ export function AuthBoundary({ { - clearCorsError() - fallbackProps.resetErrorBoundary() - }} /> ) } return } - }, [LoginErrorComponent, clearCorsError]) + }, [LoginErrorComponent]) return ( - {corsError ? ( - clearCorsError()} - projectId={projectId} - /> - ) : ( - - )} + ) diff --git a/packages/react/src/hooks/errors/useCorsOriginError.ts b/packages/react/src/hooks/errors/useCorsOriginError.ts deleted file mode 100644 index 93397a99d..000000000 --- a/packages/react/src/hooks/errors/useCorsOriginError.ts +++ /dev/null @@ -1,22 +0,0 @@ -import {CorsOriginError} from '@sanity/client' -import {clearQueryError, getCorsErrorProjectId, getQueryErrorState} from '@sanity/sdk' -import {useCallback, useMemo, useSyncExternalStore} from 'react' - -import {useSanityInstance} from '../context/useSanityInstance' - -export function useCorsOriginError(): { - error: Error | null - projectId: string | null - clear: () => void -} { - const instance = useSanityInstance() - const {getCurrent, subscribe} = useMemo(() => getQueryErrorState(instance), [instance]) - const error = useSyncExternalStore(subscribe, getCurrent) - const clear = useCallback(() => clearQueryError(instance), [instance]) - const value = useMemo(() => { - if (!(error instanceof CorsOriginError)) return {error: null, projectId: null} - - return {error: error as unknown as Error, projectId: getCorsErrorProjectId(error)} - }, [error]) - return useMemo(() => ({...value, clear}), [value, clear]) -} From 65368b87befeb482bef25a850161d4828a3c48fd Mon Sep 17 00:00:00 2001 From: laurenashpole Date: Thu, 2 Oct 2025 12:04:58 -0400 Subject: [PATCH 2/5] fix: styling for error messaging --- .../react/src/components/auth/LoginError.tsx | 21 ++++----- .../components/errors/CorsErrorComponent.tsx | 33 ++++++-------- .../src/components/errors/Error.styles.ts | 35 +++++++++++++++ .../react/src/components/errors/Error.tsx | 43 +++++++++++++++++++ 4 files changed, 99 insertions(+), 33 deletions(-) create mode 100644 packages/react/src/components/errors/Error.styles.ts create mode 100644 packages/react/src/components/errors/Error.tsx diff --git a/packages/react/src/components/auth/LoginError.tsx b/packages/react/src/components/auth/LoginError.tsx index 3213dd8b2..455028ca8 100644 --- a/packages/react/src/components/auth/LoginError.tsx +++ b/packages/react/src/components/auth/LoginError.tsx @@ -5,6 +5,7 @@ import {type FallbackProps} from 'react-error-boundary' import {useAuthState} from '../../hooks/auth/useAuthState' import {useLogOut} from '../../hooks/auth/useLogOut' +import {Error} from '../errors/Error' import {AuthError} from './AuthError' import {ConfigurationError} from './ConfigurationError' /** @@ -59,17 +60,13 @@ export function LoginError({error, resetErrorBoundary}: LoginErrorProps): React. }, [authState, handleRetry, error]) return ( -
-
-

- {error instanceof AuthError ? 'Authentication Error' : 'Configuration Error'} -

-

{authErrorMessage}

-
- - -
+ ) } diff --git a/packages/react/src/components/errors/CorsErrorComponent.tsx b/packages/react/src/components/errors/CorsErrorComponent.tsx index 22b6de77a..d6a4d2bde 100644 --- a/packages/react/src/components/errors/CorsErrorComponent.tsx +++ b/packages/react/src/components/errors/CorsErrorComponent.tsx @@ -1,6 +1,8 @@ import {useMemo} from 'react' import {type FallbackProps} from 'react-error-boundary' +import {Error} from './Error' + type CorsErrorComponentProps = FallbackProps & { projectId: string | null } @@ -15,26 +17,15 @@ export function CorsErrorComponent({projectId, error}: CorsErrorComponentProps): return url.toString() }, [origin, projectId]) return ( -
-
-

Before you continue...

-

- To access your content, you need to add the following URL as a CORS origin to your - Sanity project. -

-

- {origin} -

- {projectId ? ( -

- - Manage CORS configuration - -

- ) : ( -

{error?.message}

- )} -
-
+ ) } diff --git a/packages/react/src/components/errors/Error.styles.ts b/packages/react/src/components/errors/Error.styles.ts new file mode 100644 index 000000000..ea867dc39 --- /dev/null +++ b/packages/react/src/components/errors/Error.styles.ts @@ -0,0 +1,35 @@ +const FONT_SANS_SERIF = `-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Helvetica, Arial, system-ui, sans-serif` +const FONT_MONOSPACE = `-apple-system-ui-monospace, 'SF Mono', Menlo, Monaco, Consolas, monospace` + +const styles: Record = { + container: { + padding: '28px', + fontFamily: FONT_SANS_SERIF, + display: 'flex', + flexDirection: 'column', + gap: '21px', + fontSize: '14px', + }, + heading: { + margin: 0, + fontSize: '28px', + fontWeight: 700, + }, + paragraph: { + margin: 0, + }, + link: { + appearance: 'none', + background: 'transparent', + border: 0, + padding: 0, + font: 'inherit', + textDecoration: 'underline', + cursor: 'pointer', + }, + code: { + fontFamily: FONT_MONOSPACE, + }, +} + +export default styles diff --git a/packages/react/src/components/errors/Error.tsx b/packages/react/src/components/errors/Error.tsx new file mode 100644 index 000000000..834fb1274 --- /dev/null +++ b/packages/react/src/components/errors/Error.tsx @@ -0,0 +1,43 @@ +import styles from './Error.styles' + +type ErrorProps = { + heading: string + description?: string + code?: string + cta?: { + text: string + href?: string + onClick?: () => void + } + message?: string +} + +export function Error({heading, description, code, cta, message}: ErrorProps): React.ReactNode { + return ( +
+

{heading}

+ + {description && ( +

+ )} + + {code && {code}} + + {cta && (cta.href || cta.onClick) && ( +

+ {cta.href ? ( + + {cta.text} + + ) : ( + + )} +

+ )} + + {message &&

{message}

} +
+ ) +} From 5bcf108334a59c28b2a6cfb7e1b2cc0da1fd805a Mon Sep 17 00:00:00 2001 From: laurenashpole Date: Thu, 2 Oct 2025 13:20:53 -0400 Subject: [PATCH 3/5] chore: fix tests --- .../src/components/errors/CorsErrorComponent.tsx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/react/src/components/errors/CorsErrorComponent.tsx b/packages/react/src/components/errors/CorsErrorComponent.tsx index d6a4d2bde..027bd755f 100644 --- a/packages/react/src/components/errors/CorsErrorComponent.tsx +++ b/packages/react/src/components/errors/CorsErrorComponent.tsx @@ -21,11 +21,15 @@ export function CorsErrorComponent({projectId, error}: CorsErrorComponentProps): heading="Before you continue..." description="To access your content, you need to add the following URL as a CORS origin to your Sanity project." code={origin} - cta={{ - text: 'Manage CORS configuration', - href: corsUrl, - }} - message={projectId ? null : error?.message} + cta={ + projectId + ? { + text: 'Manage CORS configuration', + href: corsUrl, + } + : undefined + } + message={projectId ? undefined : error?.message} /> ) } From c0908c001d7cc7a692b3df05d3c871ab67f870f8 Mon Sep 17 00:00:00 2001 From: laurenashpole Date: Thu, 2 Oct 2025 16:26:44 -0400 Subject: [PATCH 4/5] chore: code review updates --- .../components/errors/CorsErrorComponent.tsx | 22 ++++++++++--------- .../react/src/components/errors/Error.tsx | 5 +---- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/packages/react/src/components/errors/CorsErrorComponent.tsx b/packages/react/src/components/errors/CorsErrorComponent.tsx index 027bd755f..a3edbfe4c 100644 --- a/packages/react/src/components/errors/CorsErrorComponent.tsx +++ b/packages/react/src/components/errors/CorsErrorComponent.tsx @@ -18,18 +18,20 @@ export function CorsErrorComponent({projectId, error}: CorsErrorComponentProps): }, [origin, projectId]) return ( add the following URL as a CORS origin to your Sanity project.', + code: origin, + cta: { text: 'Manage CORS configuration', href: corsUrl, - } - : undefined - } - message={projectId ? undefined : error?.message} + }, + } + : { + description: error?.message, + })} /> ) } diff --git a/packages/react/src/components/errors/Error.tsx b/packages/react/src/components/errors/Error.tsx index 834fb1274..ab1b770e4 100644 --- a/packages/react/src/components/errors/Error.tsx +++ b/packages/react/src/components/errors/Error.tsx @@ -9,10 +9,9 @@ type ErrorProps = { href?: string onClick?: () => void } - message?: string } -export function Error({heading, description, code, cta, message}: ErrorProps): React.ReactNode { +export function Error({heading, description, code, cta}: ErrorProps): React.ReactNode { return (

{heading}

@@ -36,8 +35,6 @@ export function Error({heading, description, code, cta, message}: ErrorProps): R )}

)} - - {message &&

{message}

}
) } From de293bb0e3ac0aee23daaa333b923a4077303468 Mon Sep 17 00:00:00 2001 From: laurenashpole Date: Thu, 2 Oct 2025 16:31:33 -0400 Subject: [PATCH 5/5] chore: fix tests --- .../react/src/components/errors/CorsErrorComponent.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react/src/components/errors/CorsErrorComponent.test.tsx b/packages/react/src/components/errors/CorsErrorComponent.test.tsx index 4f2420e7b..01f90f941 100644 --- a/packages/react/src/components/errors/CorsErrorComponent.test.tsx +++ b/packages/react/src/components/errors/CorsErrorComponent.test.tsx @@ -21,7 +21,7 @@ describe('CorsErrorComponent', () => { />, ) - expect(screen.getByText('Before you continue...')).toBeInTheDocument() + expect(screen.getByText('Before you continue…')).toBeInTheDocument() expect(screen.getByText(origin)).toBeInTheDocument() const link = screen.getByRole('link', {name: 'Manage CORS configuration'}) as HTMLAnchorElement @@ -41,7 +41,7 @@ describe('CorsErrorComponent', () => { const error = new Error('some error message') render( {}} />) - expect(screen.getByText('Before you continue...')).toBeInTheDocument() + expect(screen.getByText('Before you continue…')).toBeInTheDocument() expect(screen.getByText('some error message')).toBeInTheDocument() expect(screen.queryByRole('link', {name: 'Manage CORS configuration'})).toBeNull() })