From 88f0aaef2ff493b38c2b8de6d364add5441b13dd Mon Sep 17 00:00:00 2001 From: Tom Milewski Date: Thu, 7 Dec 2023 21:39:04 -0500 Subject: [PATCH 1/7] chore(clerk-js,shared): Add hook to assert the presence of ClerkProvider --- .../contexts/CoreClerkContextWrapper.tsx | 27 ++++++++++--------- .../ui/contexts/CoreClerkContextWrapper.tsx | 27 ++++++++++--------- .../src/components/controlComponents.tsx | 14 ++++++++++ packages/react/src/components/withClerk.tsx | 3 +++ packages/react/src/contexts/ClerkProvider.tsx | 19 +++++++------ .../hooks/useAssertWrappedByClerkProvider.ts | 9 +++++++ packages/react/src/hooks/useAuth.ts | 3 +++ packages/react/src/hooks/useSignIn.ts | 3 +++ packages/react/src/hooks/useSignUp.ts | 3 +++ packages/shared/src/error.ts | 8 ++++++ packages/shared/src/react/contexts.tsx | 21 +++++++++++++++ packages/shared/src/react/hooks/useClerk.ts | 7 +++-- .../src/react/hooks/useOrganization.tsx | 10 ++++++- .../src/react/hooks/useOrganizationList.tsx | 4 ++- packages/shared/src/react/hooks/useSession.ts | 4 ++- .../shared/src/react/hooks/useSessionList.ts | 4 ++- packages/shared/src/react/hooks/useUser.ts | 4 ++- packages/shared/src/react/index.ts | 2 ++ 18 files changed, 133 insertions(+), 39 deletions(-) create mode 100644 packages/react/src/hooks/useAssertWrappedByClerkProvider.ts diff --git a/packages/clerk-js/src/ui.retheme/contexts/CoreClerkContextWrapper.tsx b/packages/clerk-js/src/ui.retheme/contexts/CoreClerkContextWrapper.tsx index 78b186bba95..99f995693d0 100644 --- a/packages/clerk-js/src/ui.retheme/contexts/CoreClerkContextWrapper.tsx +++ b/packages/clerk-js/src/ui.retheme/contexts/CoreClerkContextWrapper.tsx @@ -1,5 +1,6 @@ import { ClerkInstanceContext, + ClerkProviderAssertionContext, ClientContext, OrganizationProvider, SessionContext, @@ -47,17 +48,19 @@ export function CoreClerkContextWrapper(props: CoreClerkContextWrapperProps): JS ); return ( - - - - - {props.children} - - - - + + + + + + {props.children} + + + + + ); } diff --git a/packages/clerk-js/src/ui/contexts/CoreClerkContextWrapper.tsx b/packages/clerk-js/src/ui/contexts/CoreClerkContextWrapper.tsx index 78b186bba95..99f995693d0 100644 --- a/packages/clerk-js/src/ui/contexts/CoreClerkContextWrapper.tsx +++ b/packages/clerk-js/src/ui/contexts/CoreClerkContextWrapper.tsx @@ -1,5 +1,6 @@ import { ClerkInstanceContext, + ClerkProviderAssertionContext, ClientContext, OrganizationProvider, SessionContext, @@ -47,17 +48,19 @@ export function CoreClerkContextWrapper(props: CoreClerkContextWrapperProps): JS ); return ( - - - - - {props.children} - - - - + + + + + + {props.children} + + + + + ); } diff --git a/packages/react/src/components/controlComponents.tsx b/packages/react/src/components/controlComponents.tsx index 4b05c0cfd31..7a0c5ccfe1d 100644 --- a/packages/react/src/components/controlComponents.tsx +++ b/packages/react/src/components/controlComponents.tsx @@ -11,10 +11,13 @@ import { useIsomorphicClerkContext } from '../contexts/IsomorphicClerkContext'; import { useSessionContext } from '../contexts/SessionContext'; import { LoadedGuarantee } from '../contexts/StructureContext'; import { useAuth } from '../hooks'; +import { useAssertWrappedByClerkProvider } from '../hooks/useAssertWrappedByClerkProvider'; import type { RedirectToSignInProps, RedirectToSignUpProps, WithClerkProp } from '../types'; import { withClerk } from './withClerk'; export const SignedIn = ({ children }: React.PropsWithChildren): JSX.Element | null => { + useAssertWrappedByClerkProvider('SignedIn'); + const { userId } = useAuthContext(); if (userId) { return <>{children}; @@ -23,6 +26,8 @@ export const SignedIn = ({ children }: React.PropsWithChildren): JSX.El }; export const SignedOut = ({ children }: React.PropsWithChildren): JSX.Element | null => { + useAssertWrappedByClerkProvider('SignedOut'); + const { userId } = useAuthContext(); if (userId === null) { return <>{children}; @@ -31,6 +36,8 @@ export const SignedOut = ({ children }: React.PropsWithChildren): JSX.E }; export const ClerkLoaded = ({ children }: React.PropsWithChildren): JSX.Element | null => { + useAssertWrappedByClerkProvider('ClerkLoaded'); + const isomorphicClerk = useIsomorphicClerkContext(); if (!isomorphicClerk.loaded) { return null; @@ -39,6 +46,8 @@ export const ClerkLoaded = ({ children }: React.PropsWithChildren): JSX }; export const ClerkLoading = ({ children }: React.PropsWithChildren): JSX.Element | null => { + useAssertWrappedByClerkProvider('ClerkLoading'); + const isomorphicClerk = useIsomorphicClerkContext(); if (isomorphicClerk.loaded) { return null; @@ -86,6 +95,8 @@ type ProtectProps = React.PropsWithChildren< * ``` */ export const Protect = ({ children, fallback, ...restAuthorizedParams }: ProtectProps) => { + useAssertWrappedByClerkProvider('Protect'); + const { isLoaded, has, userId } = useAuth(); /** @@ -129,6 +140,7 @@ export const Protect = ({ children, fallback, ...restAuthorizedParams }: Protect */ return authorized; }; +/* eslint-enable react-hooks/rules-of-hooks */ export const RedirectToSignIn = withClerk(({ clerk, ...props }: WithClerkProp) => { const { client, session } = clerk; @@ -193,6 +205,8 @@ export const AuthenticateWithRedirectCallback = withClerk( ); export const MultisessionAppSupport = ({ children }: React.PropsWithChildren): JSX.Element => { + useAssertWrappedByClerkProvider('MultisessionAppSupport'); + const session = useSessionContext(); return {children}; }; diff --git a/packages/react/src/components/withClerk.tsx b/packages/react/src/components/withClerk.tsx index 1048b154d82..c8f0a0f5668 100644 --- a/packages/react/src/components/withClerk.tsx +++ b/packages/react/src/components/withClerk.tsx @@ -4,6 +4,7 @@ import React from 'react'; import { useIsomorphicClerkContext } from '../contexts/IsomorphicClerkContext'; import { LoadedGuarantee } from '../contexts/StructureContext'; import { hocChildrenNotAFunctionError } from '../errors'; +import { useAssertWrappedByClerkProvider } from '../hooks/useAssertWrappedByClerkProvider'; import { errorThrower } from '../utils'; export const withClerk =

( @@ -13,6 +14,8 @@ export const withClerk =

( displayName = displayName || Component.displayName || Component.name || 'Component'; Component.displayName = displayName; const HOC = (props: Without) => { + useAssertWrappedByClerkProvider(displayName || 'withClerk'); + const clerk = useIsomorphicClerkContext(); if (!clerk.loaded) { diff --git a/packages/react/src/contexts/ClerkProvider.tsx b/packages/react/src/contexts/ClerkProvider.tsx index 0867ce47437..4da025b6f33 100644 --- a/packages/react/src/contexts/ClerkProvider.tsx +++ b/packages/react/src/contexts/ClerkProvider.tsx @@ -1,4 +1,5 @@ import { isPublishableKey } from '@clerk/shared/keys'; +import { ClerkProviderAssertionContext } from '@clerk/shared/react'; import React from 'react'; import { multipleClerkProvidersError } from '../errors'; @@ -24,14 +25,16 @@ function ClerkProviderBase(props: ClerkProviderProps): JSX.Element { } return ( - - - {children} - - + + + + {children} + + + ); } diff --git a/packages/react/src/hooks/useAssertWrappedByClerkProvider.ts b/packages/react/src/hooks/useAssertWrappedByClerkProvider.ts new file mode 100644 index 00000000000..1fad233ec66 --- /dev/null +++ b/packages/react/src/hooks/useAssertWrappedByClerkProvider.ts @@ -0,0 +1,9 @@ +import { useAssertWrappedByClerkProvider as useSharedAssertWrappedByClerkProvider } from '@clerk/shared/react'; + +import { errorThrower } from '../utils'; + +export const useAssertWrappedByClerkProvider = (source: string): void => { + useSharedAssertWrappedByClerkProvider(() => { + errorThrower.throwMissingClerkProviderError({ source }); + }); +}; diff --git a/packages/react/src/hooks/useAuth.ts b/packages/react/src/hooks/useAuth.ts index b8e60b3d1e6..661d69b5778 100644 --- a/packages/react/src/hooks/useAuth.ts +++ b/packages/react/src/hooks/useAuth.ts @@ -11,6 +11,7 @@ import { useAuthContext } from '../contexts/AuthContext'; import { useIsomorphicClerkContext } from '../contexts/IsomorphicClerkContext'; import { invalidStateError, useAuthHasRequiresRoleOrPermission } from '../errors'; import { errorThrower } from '../utils'; +import { useAssertWrappedByClerkProvider } from './useAssertWrappedByClerkProvider'; import { createGetToken, createSignOut } from './utils'; type CheckAuthorizationSignedOut = undefined; @@ -109,6 +110,8 @@ type UseAuth = () => UseAuthReturn; * } */ export const useAuth: UseAuth = () => { + useAssertWrappedByClerkProvider('useAuth'); + const { sessionId, userId, actor, orgId, orgRole, orgSlug, orgPermissions } = useAuthContext(); const isomorphicClerk = useIsomorphicClerkContext(); diff --git a/packages/react/src/hooks/useSignIn.ts b/packages/react/src/hooks/useSignIn.ts index 73885d47cc5..d666940dd84 100644 --- a/packages/react/src/hooks/useSignIn.ts +++ b/packages/react/src/hooks/useSignIn.ts @@ -2,6 +2,7 @@ import { useClientContext } from '@clerk/shared/react'; import type { SetActive, SignInResource } from '@clerk/types'; import { useIsomorphicClerkContext } from '../contexts/IsomorphicClerkContext'; +import { useAssertWrappedByClerkProvider } from './useAssertWrappedByClerkProvider'; type UseSignInReturn = | { @@ -18,6 +19,8 @@ type UseSignInReturn = type UseSignIn = () => UseSignInReturn; export const useSignIn: UseSignIn = () => { + useAssertWrappedByClerkProvider('useSignIn'); + const isomorphicClerk = useIsomorphicClerkContext(); const client = useClientContext(); diff --git a/packages/react/src/hooks/useSignUp.ts b/packages/react/src/hooks/useSignUp.ts index 1398773b2a9..5b169c2779a 100644 --- a/packages/react/src/hooks/useSignUp.ts +++ b/packages/react/src/hooks/useSignUp.ts @@ -2,6 +2,7 @@ import { useClientContext } from '@clerk/shared/react'; import type { SetActive, SignUpResource } from '@clerk/types'; import { useIsomorphicClerkContext } from '../contexts/IsomorphicClerkContext'; +import { useAssertWrappedByClerkProvider } from './useAssertWrappedByClerkProvider'; type UseSignUpReturn = | { @@ -18,6 +19,8 @@ type UseSignUpReturn = type UseSignUp = () => UseSignUpReturn; export const useSignUp: UseSignUp = () => { + useAssertWrappedByClerkProvider('useSignUp'); + const isomorphicClerk = useIsomorphicClerkContext(); const client = useClientContext(); diff --git a/packages/shared/src/error.ts b/packages/shared/src/error.ts index 8f35f232a63..f520bbc82e4 100644 --- a/packages/shared/src/error.ts +++ b/packages/shared/src/error.ts @@ -190,6 +190,7 @@ const DefaultMessages = Object.freeze({ InvalidProxyUrlErrorMessage: `The proxyUrl passed to Clerk is invalid. The expected value for proxyUrl is an absolute URL or a relative path with a leading '/'. (key={{url}})`, InvalidPublishableKeyErrorMessage: `The publishableKey passed to Clerk is invalid. You can get your Publishable key at https://dashboard.clerk.com/last-active?path=api-keys. (key={{key}})`, MissingPublishableKeyErrorMessage: `Missing publishableKey. You can get your key at https://dashboard.clerk.com/last-active?path=api-keys.`, + MissingClerkProvider: `{{source}} must be wrapped within the component. Please see: https://clerk.com/docs/quickstarts/react#configure-clerk-provider`, }); type MessageKeys = keyof typeof DefaultMessages; @@ -213,6 +214,9 @@ export interface ErrorThrower { throwInvalidProxyUrl(params: { url?: string }): never; throwMissingPublishableKeyError(): never; + + throwMissingClerkProviderError(params: { source?: string }): never; + throw(message: string): never; } @@ -265,6 +269,10 @@ export function buildErrorThrower({ packageName, customMessages }: ErrorThrowerO throw new Error(buildMessage(messages.MissingPublishableKeyErrorMessage)); }, + throwMissingClerkProviderError(params: { source?: string }): never { + throw new Error(buildMessage(messages.MissingClerkProvider, params)); + }, + throw(message: string): never { throw new Error(buildMessage(message)); }, diff --git a/packages/shared/src/react/contexts.tsx b/packages/shared/src/react/contexts.tsx index de372140a89..eb06a5342db 100644 --- a/packages/shared/src/react/contexts.tsx +++ b/packages/shared/src/react/contexts.tsx @@ -50,6 +50,25 @@ const OrganizationProvider = ({ ); }; +const ClerkProviderAssertionContext = React.createContext<{ inTree: true } | undefined>(undefined); +ClerkProviderAssertionContext.displayName = 'ClerkProviderAssertionContext'; + +function useAssertWrappedByClerkProvider(displayNameOrCustomHandler?: string | (() => void)): void { + const assertionCtx = React.useContext(ClerkProviderAssertionContext); + + if (!assertionCtx) { + if (typeof displayNameOrCustomHandler === 'function') { + displayNameOrCustomHandler(); + return; + } + + throw new Error( + `${displayNameOrCustomHandler || 'Clerk components'} must be wrapped within the component. + Please see: https://clerk.com/docs/components/clerk-provider`, + ); + } +} + export { ClientContext, useClientContext, @@ -61,4 +80,6 @@ export { useSessionContext, ClerkInstanceContext, useClerkInstanceContext, + ClerkProviderAssertionContext, + useAssertWrappedByClerkProvider, }; diff --git a/packages/shared/src/react/hooks/useClerk.ts b/packages/shared/src/react/hooks/useClerk.ts index 505cab5e80a..c65bd45a0e9 100644 --- a/packages/shared/src/react/hooks/useClerk.ts +++ b/packages/shared/src/react/hooks/useClerk.ts @@ -1,5 +1,8 @@ import type { LoadedClerk } from '@clerk/types'; -import { useClerkInstanceContext } from '../contexts'; +import { useAssertWrappedByClerkProvider, useClerkInstanceContext } from '../contexts'; -export const useClerk: () => LoadedClerk = useClerkInstanceContext; +export const useClerk = (): LoadedClerk => { + useAssertWrappedByClerkProvider('useClerk'); + return useClerkInstanceContext(); +}; diff --git a/packages/shared/src/react/hooks/useOrganization.tsx b/packages/shared/src/react/hooks/useOrganization.tsx index 483fb158458..044f1461859 100644 --- a/packages/shared/src/react/hooks/useOrganization.tsx +++ b/packages/shared/src/react/hooks/useOrganization.tsx @@ -11,7 +11,12 @@ import type { OrganizationResource, } from '@clerk/types'; -import { useClerkInstanceContext, useOrganizationContext, useSessionContext } from '../contexts'; +import { + useAssertWrappedByClerkProvider, + useClerkInstanceContext, + useOrganizationContext, + useSessionContext, +} from '../contexts'; import type { PaginatedResources, PaginatedResourcesWithDefault } from '../types'; import { usePagesOrInfinite, useWithSafeValues } from './usePagesOrInfinite'; @@ -110,6 +115,9 @@ export const useOrganization: UseOrganization = params => { memberships: membersListParams, invitations: invitationsListParams, } = params || {}; + + useAssertWrappedByClerkProvider('useOrganization'); + const { organization } = useOrganizationContext(); const session = useSessionContext(); diff --git a/packages/shared/src/react/hooks/useOrganizationList.tsx b/packages/shared/src/react/hooks/useOrganizationList.tsx index 80dc52e0af4..2f879a92d38 100644 --- a/packages/shared/src/react/hooks/useOrganizationList.tsx +++ b/packages/shared/src/react/hooks/useOrganizationList.tsx @@ -11,7 +11,7 @@ import type { UserOrganizationInvitationResource, } from '@clerk/types'; -import { useClerkInstanceContext, useUserContext } from '../contexts'; +import { useAssertWrappedByClerkProvider, useClerkInstanceContext, useUserContext } from '../contexts'; import type { PaginatedResources, PaginatedResourcesWithDefault } from '../types'; import { usePagesOrInfinite, useWithSafeValues } from './usePagesOrInfinite'; @@ -85,6 +85,8 @@ type UseOrganizationList = ( export const useOrganizationList: UseOrganizationList = params => { const { userMemberships, userInvitations, userSuggestions } = params || {}; + useAssertWrappedByClerkProvider('useOrganizationList'); + const userMembershipsSafeValues = useWithSafeValues(userMemberships, { initialPage: 1, pageSize: 10, diff --git a/packages/shared/src/react/hooks/useSession.ts b/packages/shared/src/react/hooks/useSession.ts index db27bbbaf34..6f9544483ec 100644 --- a/packages/shared/src/react/hooks/useSession.ts +++ b/packages/shared/src/react/hooks/useSession.ts @@ -1,6 +1,6 @@ import type { ActiveSessionResource } from '@clerk/types'; -import { useSessionContext } from '../contexts'; +import { useAssertWrappedByClerkProvider, useSessionContext } from '../contexts'; type UseSessionReturn = | { isLoaded: false; isSignedIn: undefined; session: undefined } @@ -30,6 +30,8 @@ type UseSession = () => UseSessionReturn; * } */ export const useSession: UseSession = () => { + useAssertWrappedByClerkProvider('useSession'); + const session = useSessionContext(); if (session === undefined) { diff --git a/packages/shared/src/react/hooks/useSessionList.ts b/packages/shared/src/react/hooks/useSessionList.ts index 03f2cdcdbf4..32e9c3718d7 100644 --- a/packages/shared/src/react/hooks/useSessionList.ts +++ b/packages/shared/src/react/hooks/useSessionList.ts @@ -1,6 +1,6 @@ import type { SessionResource, SetActive } from '@clerk/types'; -import { useClerkInstanceContext, useClientContext } from '../contexts'; +import { useAssertWrappedByClerkProvider, useClerkInstanceContext, useClientContext } from '../contexts'; type UseSessionListReturn = | { @@ -17,6 +17,8 @@ type UseSessionListReturn = type UseSessionList = () => UseSessionListReturn; export const useSessionList: UseSessionList = () => { + useAssertWrappedByClerkProvider('useSessionList'); + const isomorphicClerk = useClerkInstanceContext(); const client = useClientContext(); diff --git a/packages/shared/src/react/hooks/useUser.ts b/packages/shared/src/react/hooks/useUser.ts index 89a0934de1b..a1bc3686738 100644 --- a/packages/shared/src/react/hooks/useUser.ts +++ b/packages/shared/src/react/hooks/useUser.ts @@ -1,6 +1,6 @@ import type { UserResource } from '@clerk/types'; -import { useUserContext } from '../contexts'; +import { useAssertWrappedByClerkProvider, useUserContext } from '../contexts'; type UseUserReturn = | { isLoaded: false; isSignedIn: undefined; user: undefined } @@ -28,6 +28,8 @@ type UseUserReturn = * } */ export function useUser(): UseUserReturn { + useAssertWrappedByClerkProvider('useUser'); + const user = useUserContext(); if (user === undefined) { diff --git a/packages/shared/src/react/index.ts b/packages/shared/src/react/index.ts index 1a4c5968064..6f63b8333bd 100644 --- a/packages/shared/src/react/index.ts +++ b/packages/shared/src/react/index.ts @@ -11,4 +11,6 @@ export { UserContext, useSessionContext, useUserContext, + ClerkProviderAssertionContext, + useAssertWrappedByClerkProvider, } from './contexts'; From 355500a6bec900be4685ad8b45b80ed36ecd21d3 Mon Sep 17 00:00:00 2001 From: Tom Milewski Date: Fri, 8 Dec 2023 15:39:51 -0500 Subject: [PATCH 2/7] chore(clerk-js,clerk-react,shared): Add changeset --- .changeset/slow-bugs-exist.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/slow-bugs-exist.md diff --git a/.changeset/slow-bugs-exist.md b/.changeset/slow-bugs-exist.md new file mode 100644 index 00000000000..c7a929862b8 --- /dev/null +++ b/.changeset/slow-bugs-exist.md @@ -0,0 +1,7 @@ +--- +'@clerk/clerk-js': patch +'@clerk/shared': patch +'@clerk/clerk-react': patch +--- + +Adds useAssertWrappedByClerkProvider to assert the presence of ClerkProvider From 110ac9ca747b40daef2b28e6cf6cd4cfd450ef40 Mon Sep 17 00:00:00 2001 From: Tom Milewski Date: Mon, 11 Dec 2023 10:12:50 -0500 Subject: [PATCH 3/7] chore(shared): Update messaging --- .changeset/slow-bugs-exist.md | 6 +++++- packages/shared/src/error.ts | 2 +- packages/shared/src/react/contexts.tsx | 5 +++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.changeset/slow-bugs-exist.md b/.changeset/slow-bugs-exist.md index c7a929862b8..2d9c84d6976 100644 --- a/.changeset/slow-bugs-exist.md +++ b/.changeset/slow-bugs-exist.md @@ -4,4 +4,8 @@ '@clerk/clerk-react': patch --- -Adds useAssertWrappedByClerkProvider to assert the presence of ClerkProvider +Add `useAssertWrappedByClerkProvider` to internal code. If you use hooks like `useAuth` outside of the `` context an error will be thrown. For example: + + ```shell + @clerk/clerk-react: useAuth must be used within the component + ``` diff --git a/packages/shared/src/error.ts b/packages/shared/src/error.ts index f520bbc82e4..bfc9c9e2487 100644 --- a/packages/shared/src/error.ts +++ b/packages/shared/src/error.ts @@ -190,7 +190,7 @@ const DefaultMessages = Object.freeze({ InvalidProxyUrlErrorMessage: `The proxyUrl passed to Clerk is invalid. The expected value for proxyUrl is an absolute URL or a relative path with a leading '/'. (key={{url}})`, InvalidPublishableKeyErrorMessage: `The publishableKey passed to Clerk is invalid. You can get your Publishable key at https://dashboard.clerk.com/last-active?path=api-keys. (key={{key}})`, MissingPublishableKeyErrorMessage: `Missing publishableKey. You can get your key at https://dashboard.clerk.com/last-active?path=api-keys.`, - MissingClerkProvider: `{{source}} must be wrapped within the component. Please see: https://clerk.com/docs/quickstarts/react#configure-clerk-provider`, + MissingClerkProvider: `{{source}} must be wrapped within the component. Learn more: https://clerk.com/docs/components/clerk-provider`, }); type MessageKeys = keyof typeof DefaultMessages; diff --git a/packages/shared/src/react/contexts.tsx b/packages/shared/src/react/contexts.tsx index eb06a5342db..698d63d0a0b 100644 --- a/packages/shared/src/react/contexts.tsx +++ b/packages/shared/src/react/contexts.tsx @@ -63,8 +63,9 @@ function useAssertWrappedByClerkProvider(displayNameOrCustomHandler?: string | ( } throw new Error( - `${displayNameOrCustomHandler || 'Clerk components'} must be wrapped within the component. - Please see: https://clerk.com/docs/components/clerk-provider`, + `${ + displayNameOrCustomHandler || 'Clerk components' + } must be wrapped within the component. Learn more: https://clerk.com/docs/components/clerk-provider`, ); } } From dba908180f1a6b9a096d72d9d94de28b98e886fd Mon Sep 17 00:00:00 2001 From: Tom Milewski Date: Mon, 11 Dec 2023 10:25:31 -0500 Subject: [PATCH 4/7] chore(clerk-js,shared): Re-used existing context --- .../contexts/CoreClerkContextWrapper.tsx | 27 +++++++++---------- .../ui/contexts/CoreClerkContextWrapper.tsx | 27 +++++++++---------- packages/react/src/contexts/ClerkProvider.tsx | 19 ++++++------- packages/shared/src/react/contexts.tsx | 8 ++---- packages/shared/src/react/index.ts | 1 - 5 files changed, 34 insertions(+), 48 deletions(-) diff --git a/packages/clerk-js/src/ui.retheme/contexts/CoreClerkContextWrapper.tsx b/packages/clerk-js/src/ui.retheme/contexts/CoreClerkContextWrapper.tsx index 99f995693d0..78b186bba95 100644 --- a/packages/clerk-js/src/ui.retheme/contexts/CoreClerkContextWrapper.tsx +++ b/packages/clerk-js/src/ui.retheme/contexts/CoreClerkContextWrapper.tsx @@ -1,6 +1,5 @@ import { ClerkInstanceContext, - ClerkProviderAssertionContext, ClientContext, OrganizationProvider, SessionContext, @@ -48,19 +47,17 @@ export function CoreClerkContextWrapper(props: CoreClerkContextWrapperProps): JS ); return ( - - - - - - {props.children} - - - - - + + + + + {props.children} + + + + ); } diff --git a/packages/clerk-js/src/ui/contexts/CoreClerkContextWrapper.tsx b/packages/clerk-js/src/ui/contexts/CoreClerkContextWrapper.tsx index 99f995693d0..78b186bba95 100644 --- a/packages/clerk-js/src/ui/contexts/CoreClerkContextWrapper.tsx +++ b/packages/clerk-js/src/ui/contexts/CoreClerkContextWrapper.tsx @@ -1,6 +1,5 @@ import { ClerkInstanceContext, - ClerkProviderAssertionContext, ClientContext, OrganizationProvider, SessionContext, @@ -48,19 +47,17 @@ export function CoreClerkContextWrapper(props: CoreClerkContextWrapperProps): JS ); return ( - - - - - - {props.children} - - - - - + + + + + {props.children} + + + + ); } diff --git a/packages/react/src/contexts/ClerkProvider.tsx b/packages/react/src/contexts/ClerkProvider.tsx index 4da025b6f33..0867ce47437 100644 --- a/packages/react/src/contexts/ClerkProvider.tsx +++ b/packages/react/src/contexts/ClerkProvider.tsx @@ -1,5 +1,4 @@ import { isPublishableKey } from '@clerk/shared/keys'; -import { ClerkProviderAssertionContext } from '@clerk/shared/react'; import React from 'react'; import { multipleClerkProvidersError } from '../errors'; @@ -25,16 +24,14 @@ function ClerkProviderBase(props: ClerkProviderProps): JSX.Element { } return ( - - - - {children} - - - + + + {children} + + ); } diff --git a/packages/shared/src/react/contexts.tsx b/packages/shared/src/react/contexts.tsx index 698d63d0a0b..1034d10d16d 100644 --- a/packages/shared/src/react/contexts.tsx +++ b/packages/shared/src/react/contexts.tsx @@ -50,13 +50,10 @@ const OrganizationProvider = ({ ); }; -const ClerkProviderAssertionContext = React.createContext<{ inTree: true } | undefined>(undefined); -ClerkProviderAssertionContext.displayName = 'ClerkProviderAssertionContext'; - function useAssertWrappedByClerkProvider(displayNameOrCustomHandler?: string | (() => void)): void { - const assertionCtx = React.useContext(ClerkProviderAssertionContext); + const ctx = React.useContext(ClerkInstanceContext); - if (!assertionCtx) { + if (!ctx) { if (typeof displayNameOrCustomHandler === 'function') { displayNameOrCustomHandler(); return; @@ -81,6 +78,5 @@ export { useSessionContext, ClerkInstanceContext, useClerkInstanceContext, - ClerkProviderAssertionContext, useAssertWrappedByClerkProvider, }; diff --git a/packages/shared/src/react/index.ts b/packages/shared/src/react/index.ts index 6f63b8333bd..40735d10f2d 100644 --- a/packages/shared/src/react/index.ts +++ b/packages/shared/src/react/index.ts @@ -11,6 +11,5 @@ export { UserContext, useSessionContext, useUserContext, - ClerkProviderAssertionContext, useAssertWrappedByClerkProvider, } from './contexts'; From 49e6d014a2145b10d3c1fa15fc99f9755d76e273 Mon Sep 17 00:00:00 2001 From: Tom Milewski Date: Mon, 11 Dec 2023 19:09:21 -0500 Subject: [PATCH 5/7] chore(shared): Require useAssertWrappedByClerkProvider param --- packages/shared/src/react/contexts.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/shared/src/react/contexts.tsx b/packages/shared/src/react/contexts.tsx index 1034d10d16d..142779ddf1a 100644 --- a/packages/shared/src/react/contexts.tsx +++ b/packages/shared/src/react/contexts.tsx @@ -50,19 +50,17 @@ const OrganizationProvider = ({ ); }; -function useAssertWrappedByClerkProvider(displayNameOrCustomHandler?: string | (() => void)): void { +function useAssertWrappedByClerkProvider(displayNameOrFn: string | (() => void)): void { const ctx = React.useContext(ClerkInstanceContext); if (!ctx) { - if (typeof displayNameOrCustomHandler === 'function') { - displayNameOrCustomHandler(); + if (typeof displayNameOrFn === 'function') { + displayNameOrFn(); return; } throw new Error( - `${ - displayNameOrCustomHandler || 'Clerk components' - } must be wrapped within the component. Learn more: https://clerk.com/docs/components/clerk-provider`, + `${displayNameOrFn} must be wrapped within the component. Learn more: https://clerk.com/docs/components/clerk-provider`, ); } } From df5108661baec849c07b8f91707c19e9eede1c25 Mon Sep 17 00:00:00 2001 From: Lennart Date: Tue, 12 Dec 2023 09:43:10 +0100 Subject: [PATCH 6/7] Update .changeset/slow-bugs-exist.md --- .changeset/slow-bugs-exist.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.changeset/slow-bugs-exist.md b/.changeset/slow-bugs-exist.md index 2d9c84d6976..a55662b0ef7 100644 --- a/.changeset/slow-bugs-exist.md +++ b/.changeset/slow-bugs-exist.md @@ -6,6 +6,6 @@ Add `useAssertWrappedByClerkProvider` to internal code. If you use hooks like `useAuth` outside of the `` context an error will be thrown. For example: - ```shell - @clerk/clerk-react: useAuth must be used within the component - ``` +```shell +@clerk/clerk-react: useAuth must be used within the component +``` From 06115b23c94bc71c6e04b6255e880495273c3dfc Mon Sep 17 00:00:00 2001 From: Tom Milewski Date: Tue, 12 Dec 2023 09:48:28 -0500 Subject: [PATCH 7/7] chore(shared): Update error messaging --- .changeset/slow-bugs-exist.md | 2 +- packages/shared/src/error.ts | 2 +- packages/shared/src/react/contexts.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.changeset/slow-bugs-exist.md b/.changeset/slow-bugs-exist.md index a55662b0ef7..f9e4d57bd45 100644 --- a/.changeset/slow-bugs-exist.md +++ b/.changeset/slow-bugs-exist.md @@ -7,5 +7,5 @@ Add `useAssertWrappedByClerkProvider` to internal code. If you use hooks like `useAuth` outside of the `` context an error will be thrown. For example: ```shell -@clerk/clerk-react: useAuth must be used within the component +@clerk/clerk-react: useAuth can only be used within the component ``` diff --git a/packages/shared/src/error.ts b/packages/shared/src/error.ts index bfc9c9e2487..6cf10ef7f6e 100644 --- a/packages/shared/src/error.ts +++ b/packages/shared/src/error.ts @@ -190,7 +190,7 @@ const DefaultMessages = Object.freeze({ InvalidProxyUrlErrorMessage: `The proxyUrl passed to Clerk is invalid. The expected value for proxyUrl is an absolute URL or a relative path with a leading '/'. (key={{url}})`, InvalidPublishableKeyErrorMessage: `The publishableKey passed to Clerk is invalid. You can get your Publishable key at https://dashboard.clerk.com/last-active?path=api-keys. (key={{key}})`, MissingPublishableKeyErrorMessage: `Missing publishableKey. You can get your key at https://dashboard.clerk.com/last-active?path=api-keys.`, - MissingClerkProvider: `{{source}} must be wrapped within the component. Learn more: https://clerk.com/docs/components/clerk-provider`, + MissingClerkProvider: `{{source}} can only be used within the component. Learn more: https://clerk.com/docs/components/clerk-provider`, }); type MessageKeys = keyof typeof DefaultMessages; diff --git a/packages/shared/src/react/contexts.tsx b/packages/shared/src/react/contexts.tsx index 142779ddf1a..51b9bab76db 100644 --- a/packages/shared/src/react/contexts.tsx +++ b/packages/shared/src/react/contexts.tsx @@ -60,7 +60,7 @@ function useAssertWrappedByClerkProvider(displayNameOrFn: string | (() => void)) } throw new Error( - `${displayNameOrFn} must be wrapped within the component. Learn more: https://clerk.com/docs/components/clerk-provider`, + `${displayNameOrFn} can only be used within the component. Learn more: https://clerk.com/docs/components/clerk-provider`, ); } }