diff --git a/.changeset/mighty-bulldogs-try.md b/.changeset/mighty-bulldogs-try.md new file mode 100644 index 00000000000..eb9d1bbbb01 --- /dev/null +++ b/.changeset/mighty-bulldogs-try.md @@ -0,0 +1,34 @@ +--- +'gatsby-plugin-clerk': major +'@clerk/chrome-extension': major +'@clerk/nextjs': major +'@clerk/clerk-react': major +'@clerk/remix': major +'@clerk/clerk-expo': major +--- + +- Introduce `@clerk/clerk-react/errors` and `@clerk/clerk-react/internal` subpath exports to expose some internal utilities. Eg + ```typescript + // Before + import { __internal__setErrorThrowerOptions } from '@clerk/clerk-react'; + // After + import { setErrorThrowerOptions } from '@clerk/clerk-react/internal'; + + // Before + import { isClerkAPIResponseError, isEmailLinkError, isKnownError, isMetamaskError } from '@clerk/clerk-react'; + // After + import { isClerkAPIResponseError, isEmailLinkError, isKnownError, isMetamaskError } from '@clerk/clerk-react/errors'; + + // Before + import { MultisessionAppSupport } from '@clerk/clerk-react'; + // After + import { MultisessionAppSupport } from '@clerk/clerk-react/internal'; + ``` +- Drop from the `@clerk/clerk-react` and all other clerk-react wrapper packages: + - `__internal__setErrorThrowerOptions` internal utility (moved to /internal subpath) + - `WithClerkProp` type + - `MultisessionAppSupport` component (moved to /internal subpath) + - `EmailLinkErrorCode` enum +- Drop `StructureContext` and related errors to reduce to reduce code complexity since it seems that it was not being used. +- Drop `withUser`, `WithUser`, `withClerk` HOFs and `WithClerk`, `withSession`, `WithSession` HOCs from the `@clerk/clerk-react` + to reduce the export surface since it's trivial to implement if needed. diff --git a/packages/chrome-extension/src/ClerkProvider.tsx b/packages/chrome-extension/src/ClerkProvider.tsx index a243a34b622..01d27ce92f5 100644 --- a/packages/chrome-extension/src/ClerkProvider.tsx +++ b/packages/chrome-extension/src/ClerkProvider.tsx @@ -1,6 +1,6 @@ import { Clerk } from '@clerk/clerk-js'; import type { ClerkProp, ClerkProviderProps as ClerkReactProviderProps } from '@clerk/clerk-react'; -import { __internal__setErrorThrowerOptions, ClerkProvider as ClerkReactProvider } from '@clerk/clerk-react'; +import { ClerkProvider as ClerkReactProvider } from '@clerk/clerk-react'; import React from 'react'; import { buildClerk } from './singleton'; @@ -11,10 +11,6 @@ Clerk.sdkMetadata = { version: PACKAGE_VERSION, }; -__internal__setErrorThrowerOptions({ - packageName: '@clerk/chrome-extension', -}); - type WebSSOClerkProviderCustomProps = | { syncSessionWithTab?: false; diff --git a/packages/chrome-extension/src/__snapshots__/exports.test.ts.snap b/packages/chrome-extension/src/__snapshots__/exports.test.ts.snap index a8554f210c6..41c4f086171 100644 --- a/packages/chrome-extension/src/__snapshots__/exports.test.ts.snap +++ b/packages/chrome-extension/src/__snapshots__/exports.test.ts.snap @@ -7,8 +7,6 @@ exports[`public exports should not include a breaking change 1`] = ` "ClerkLoading", "ClerkProvider", "CreateOrganization", - "EmailLinkErrorCode", - "MultisessionAppSupport", "OrganizationList", "OrganizationProfile", "OrganizationSwitcher", @@ -29,13 +27,6 @@ exports[`public exports should not include a breaking change 1`] = ` "UserButton", "UserProfile", "WithClerk", - "WithSession", - "WithUser", - "__internal__setErrorThrowerOptions", - "isClerkAPIResponseError", - "isEmailLinkError", - "isKnownError", - "isMetamaskError", "useAuth", "useClerk", "useEmailLink", @@ -47,7 +38,5 @@ exports[`public exports should not include a breaking change 1`] = ` "useSignUp", "useUser", "withClerk", - "withSession", - "withUser", ] `; diff --git a/packages/chrome-extension/src/index.ts b/packages/chrome-extension/src/index.ts index da7fbe97acb..1a134cf1f5f 100644 --- a/packages/chrome-extension/src/index.ts +++ b/packages/chrome-extension/src/index.ts @@ -3,3 +3,7 @@ export type { StorageCache } from './utils/storage'; // The order matters since we want override @clerk/clerk-react ClerkProvider export { ClerkProvider } from './ClerkProvider'; + +// Override Clerk React error thrower to show that errors come from @clerk/chrome-extension +import { setErrorThrowerOptions } from '@clerk/clerk-react/internal'; +setErrorThrowerOptions({ packageName: PACKAGE_NAME }); diff --git a/packages/expo/src/ClerkProvider.tsx b/packages/expo/src/ClerkProvider.tsx index 0802497a1dc..c7a5e3fef8d 100644 --- a/packages/expo/src/ClerkProvider.tsx +++ b/packages/expo/src/ClerkProvider.tsx @@ -1,7 +1,7 @@ import './polyfills'; import type { ClerkProviderProps as ClerkReactProviderProps } from '@clerk/clerk-react'; -import { __internal__setErrorThrowerOptions, ClerkProvider as ClerkReactProvider } from '@clerk/clerk-react'; +import { ClerkProvider as ClerkReactProvider } from '@clerk/clerk-react'; import React from 'react'; import type { TokenCache } from './cache'; @@ -9,10 +9,6 @@ import { MemoryTokenCache } from './cache'; import { isReactNative } from './runtime'; import { buildClerk } from './singleton'; -__internal__setErrorThrowerOptions({ - packageName: '@clerk/expo', -}); - export type ClerkProviderProps = ClerkReactProviderProps & { tokenCache?: TokenCache; }; diff --git a/packages/expo/src/index.ts b/packages/expo/src/index.ts index 187f187982c..3e3eeb04815 100644 --- a/packages/expo/src/index.ts +++ b/packages/expo/src/index.ts @@ -1,17 +1,8 @@ export { ClerkLoaded, ClerkLoading, - EmailLinkErrorCode, - MultisessionAppSupport, SignedIn, SignedOut, - WithClerk, - WithSession, - WithUser, - isClerkAPIResponseError, - isEmailLinkError, - isKnownError, - isMetamaskError, useAuth, useClerk, useEmailLink, @@ -22,12 +13,16 @@ export { useSignIn, useSignUp, useUser, - withClerk, - withSession, - withUser, } from '@clerk/clerk-react'; +export { isClerkAPIResponseError, isEmailLinkError, isKnownError, isMetamaskError } from '@clerk/clerk-react/errors'; + export { clerk as Clerk } from './singleton'; export * from './ClerkProvider'; export * from './useOAuth'; + +// Override Clerk React error thrower to show that errors come from @clerk/clerk-expo +import { setErrorThrowerOptions } from '@clerk/clerk-react/internal'; + +setErrorThrowerOptions({ packageName: PACKAGE_NAME }); diff --git a/packages/gatsby-plugin-clerk/src/GatsbyClerkProvider.tsx b/packages/gatsby-plugin-clerk/src/GatsbyClerkProvider.tsx index 50de7845722..6f0c6a4b33f 100644 --- a/packages/gatsby-plugin-clerk/src/GatsbyClerkProvider.tsx +++ b/packages/gatsby-plugin-clerk/src/GatsbyClerkProvider.tsx @@ -1,12 +1,10 @@ import type { ClerkProviderProps } from '@clerk/clerk-react'; -import { __internal__setErrorThrowerOptions, ClerkProvider as ReactClerkProvider } from '@clerk/clerk-react'; +import { ClerkProvider as ReactClerkProvider } from '@clerk/clerk-react'; import { navigate } from 'gatsby'; import React from 'react'; import { SDK_METADATA, TELEMETRY_DEBUG, TELEMETRY_DISABLED } from './constants'; -__internal__setErrorThrowerOptions({ packageName: 'gatsby-plugin-clerk' }); - export type GatsbyClerkProviderProps = { clerkState: any; } & ClerkProviderProps; diff --git a/packages/gatsby-plugin-clerk/src/index.ts b/packages/gatsby-plugin-clerk/src/index.ts index db76ee4c692..e75d696c860 100644 --- a/packages/gatsby-plugin-clerk/src/index.ts +++ b/packages/gatsby-plugin-clerk/src/index.ts @@ -1 +1,5 @@ export * from '@clerk/clerk-react'; + +// Override Clerk React error thrower to show that errors come from gatsby-plugin-clerk +import { setErrorThrowerOptions } from '@clerk/clerk-react/internal'; +setErrorThrowerOptions({ packageName: PACKAGE_NAME }); diff --git a/packages/nextjs/src/client-boundary/controlComponents.ts b/packages/nextjs/src/client-boundary/controlComponents.ts index 58eec00a1fa..9cf3881e2f3 100644 --- a/packages/nextjs/src/client-boundary/controlComponents.ts +++ b/packages/nextjs/src/client-boundary/controlComponents.ts @@ -10,7 +10,6 @@ export { RedirectToSignUp, RedirectToUserProfile, AuthenticateWithRedirectCallback, - MultisessionAppSupport, RedirectToCreateOrganization, RedirectToOrganizationProfile, } from '@clerk/clerk-react'; diff --git a/packages/nextjs/src/client-boundary/hooks.ts b/packages/nextjs/src/client-boundary/hooks.ts index 3384164c893..7d5283fbcac 100644 --- a/packages/nextjs/src/client-boundary/hooks.ts +++ b/packages/nextjs/src/client-boundary/hooks.ts @@ -1,9 +1,6 @@ 'use client'; export { - WithClerk, - WithSession, - WithUser, useAuth, useClerk, useEmailLink, @@ -14,17 +11,6 @@ export { useSignIn, useSignUp, useUser, - withClerk, - withSession, - withUser, } from '@clerk/clerk-react'; -export type { WithClerkProp, WithSessionProp, WithUserProp } from '@clerk/clerk-react'; - -export { - EmailLinkErrorCode, - isClerkAPIResponseError, - isEmailLinkError, - isKnownError, - isMetamaskError, -} from '@clerk/clerk-react'; +export { isClerkAPIResponseError, isEmailLinkError, isKnownError, isMetamaskError } from '@clerk/clerk-react/errors'; diff --git a/packages/nextjs/src/index.ts b/packages/nextjs/src/index.ts index 038b6e2f519..ba69ff2efa7 100644 --- a/packages/nextjs/src/index.ts +++ b/packages/nextjs/src/index.ts @@ -6,7 +6,6 @@ export { AuthenticateWithRedirectCallback, ClerkLoaded, ClerkLoading, - MultisessionAppSupport, RedirectToCreateOrganization, RedirectToOrganizationProfile, RedirectToSignIn, @@ -38,10 +37,6 @@ export { * If you do, app router will break. */ export { - EmailLinkErrorCode, - WithClerk, - WithSession, - WithUser, isClerkAPIResponseError, isEmailLinkError, isKnownError, @@ -56,13 +51,8 @@ export { useSignIn, useSignUp, useUser, - withClerk, - withSession, - withUser, } from './client-boundary/hooks'; -export type { WithClerkProp, WithSessionProp, WithUserProp } from './client-boundary/hooks'; - /** * Conditionally export components that exhibit different behavior * when used in /app vs /pages. @@ -89,7 +79,7 @@ export const ClerkProvider = ComponentsModule.ClerkProvider as ServerComponentsS export const SignedIn = ComponentsModule.SignedIn as ServerComponentsServerModuleTypes['SignedIn']; export const SignedOut = ComponentsModule.SignedOut as ServerComponentsServerModuleTypes['SignedOut']; -export const Protect = ComponentsModule.Protect as ServerComponentsServerModuleTypes['Protect']; +export const Protect = ComponentsModule.Protect; export const auth = ServerHelperModule.auth as ServerHelpersServerModuleTypes['auth']; export const currentUser = ServerHelperModule.currentUser as ServerHelpersServerModuleTypes['currentUser']; diff --git a/packages/nextjs/src/pages/ClerkProvider.tsx b/packages/nextjs/src/pages/ClerkProvider.tsx index 78444777c2c..d8624455162 100644 --- a/packages/nextjs/src/pages/ClerkProvider.tsx +++ b/packages/nextjs/src/pages/ClerkProvider.tsx @@ -1,4 +1,6 @@ -import { __internal__setErrorThrowerOptions, ClerkProvider as ReactClerkProvider } from '@clerk/clerk-react'; +import { ClerkProvider as ReactClerkProvider } from '@clerk/clerk-react'; +// Override Clerk React error thrower to show that errors come from @clerk/nextjs +import { setErrorThrowerOptions } from '@clerk/clerk-react/internal'; import { useRouter } from 'next/router'; import React from 'react'; @@ -7,8 +9,7 @@ import { useSafeLayoutEffect } from '../client-boundary/useSafeLayoutEffect'; import type { NextClerkProviderProps } from '../types'; import { invalidateNextRouterCache } from '../utils/invalidateNextRouterCache'; import { mergeNextClerkPropsWithEnv } from '../utils/mergeNextClerkPropsWithEnv'; - -__internal__setErrorThrowerOptions({ packageName: '@clerk/nextjs' }); +setErrorThrowerOptions({ packageName: PACKAGE_NAME }); export function ClerkProvider({ children, ...props }: NextClerkProviderProps): JSX.Element { const { __unstable_invokeMiddlewareOnAuthStateChange = true } = props; @@ -40,7 +41,6 @@ export function ClerkProvider({ children, ...props }: NextClerkProviderProps): J return ( - {/*@ts-expect-error*/} ) => { +// @ts-ignore - https://github.com/microsoft/TypeScript/issues/47663 +export const mergeNextClerkPropsWithEnv = (props: Omit): any => { return { ...props, publishableKey: props.publishableKey || process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY || '', diff --git a/packages/react/.gitignore b/packages/react/.gitignore new file mode 100644 index 00000000000..5b45b89ce31 --- /dev/null +++ b/packages/react/.gitignore @@ -0,0 +1,2 @@ +/*/ +!/src/ diff --git a/packages/react/jest.config.js b/packages/react/jest.config.js index 383e9448c5a..0b8ddf1fa50 100644 --- a/packages/react/jest.config.js +++ b/packages/react/jest.config.js @@ -1,4 +1,4 @@ -const { name } = require('./package.json'); +const { name, version } = require('./package.json'); module.exports = { displayName: name.replace('@clerk', ''), @@ -15,4 +15,10 @@ module.exports = { testRegex: ['/ui/.*/__tests__/.*.test.[jt]sx?$', '/.*.test.[jt]sx?$'], testPathIgnorePatterns: ['/node_modules/'], + + globals: { + __DEV__: true, + PACKAGE_NAME: name, + PACKAGE_VERSION: version, + }, }; diff --git a/packages/react/package.json b/packages/react/package.json index cb8d40f24f7..1099c63bc38 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -33,15 +33,37 @@ "default": "./dist/index.js" } }, + "./internal": { + "import": { + "types": "./dist/internal.d.mts", + "default": "./dist/internal.mjs" + }, + "require": { + "types": "./dist/internal.d.ts", + "default": "./dist/internal.js" + } + }, + "./errors": { + "import": { + "types": "./dist/errors.d.mts", + "default": "./dist/errors.mjs" + }, + "require": { + "types": "./dist/errors.d.ts", + "default": "./dist/errors.js" + } + }, "./package.json": "./package.json" }, "main": "./dist/index.js", - "types": "./dist/index.d.ts", "files": [ - "dist" + "dist", + "internal", + "errors" ], "scripts": { "build": "tsup", + "postbuild": "node ../../scripts/subpath-workaround.mjs react", "clean": "rimraf ./dist", "dev": "tsup --watch", "dev:publish": "npm run dev -- --env.publish", diff --git a/packages/react/src/components/controlComponents.tsx b/packages/react/src/components/controlComponents.tsx index de4111bb3fa..900b00cc574 100644 --- a/packages/react/src/components/controlComponents.tsx +++ b/packages/react/src/components/controlComponents.tsx @@ -9,7 +9,6 @@ import React from 'react'; import { useAuthContext } from '../contexts/AuthContext'; 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'; @@ -42,7 +41,7 @@ export const ClerkLoaded = ({ children }: React.PropsWithChildren): JSX if (!isomorphicClerk.loaded) { return null; } - return {children}; + return <>{children}; }; export const ClerkLoading = ({ children }: React.PropsWithChildren): JSX.Element | null => { diff --git a/packages/react/src/components/index.ts b/packages/react/src/components/index.ts index 439452bb52f..3f143d35dd4 100644 --- a/packages/react/src/components/index.ts +++ b/packages/react/src/components/index.ts @@ -19,14 +19,11 @@ export { RedirectToSignUp, RedirectToUserProfile, AuthenticateWithRedirectCallback, - MultisessionAppSupport, RedirectToCreateOrganization, RedirectToOrganizationProfile, } from './controlComponents'; export * from './withClerk'; -export * from './withUser'; -export * from './withSession'; export * from './SignInButton'; export * from './SignUpButton'; diff --git a/packages/react/src/components/uiComponents.tsx b/packages/react/src/components/uiComponents.tsx index 2a8f23165d7..ce9033f9014 100644 --- a/packages/react/src/components/uiComponents.tsx +++ b/packages/react/src/components/uiComponents.tsx @@ -18,7 +18,7 @@ import { organizationProfilePageRenderedError, userProfileLinkRenderedError, userProfilePageRenderedError, -} from '../errors'; +} from '../errors/messages'; import type { MountProps, OrganizationProfileLinkProps, diff --git a/packages/react/src/components/withClerk.tsx b/packages/react/src/components/withClerk.tsx index c8f0a0f5668..54ff7be47cc 100644 --- a/packages/react/src/components/withClerk.tsx +++ b/packages/react/src/components/withClerk.tsx @@ -2,10 +2,9 @@ import type { LoadedClerk, Without } from '@clerk/types'; import React from 'react'; import { useIsomorphicClerkContext } from '../contexts/IsomorphicClerkContext'; -import { LoadedGuarantee } from '../contexts/StructureContext'; -import { hocChildrenNotAFunctionError } from '../errors'; +import { errorThrower } from '../errors/errorThrower'; +import { hocChildrenNotAFunctionError } from '../errors/messages'; import { useAssertWrappedByClerkProvider } from '../hooks/useAssertWrappedByClerkProvider'; -import { errorThrower } from '../utils'; export const withClerk =

( Component: React.ComponentType

, @@ -23,12 +22,10 @@ export const withClerk =

( } return ( - - - + ); }; HOC.displayName = `withClerk(${displayName})`; @@ -48,5 +45,5 @@ export const WithClerk: React.FC<{ return null; } - return {children(clerk as unknown as LoadedClerk)}; + return <>{children(clerk as unknown as LoadedClerk)}; }; diff --git a/packages/react/src/components/withSession.tsx b/packages/react/src/components/withSession.tsx deleted file mode 100644 index 276269beb5f..00000000000 --- a/packages/react/src/components/withSession.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import type { SessionResource } from '@clerk/types'; -import React from 'react'; - -import { useSessionContext } from '../contexts/SessionContext'; -import { hocChildrenNotAFunctionError } from '../errors'; -import { errorThrower } from '../utils'; - -export const withSession =

( - Component: React.ComponentType

, - displayName?: string, -) => { - displayName = displayName || Component.displayName || Component.name || 'Component'; - Component.displayName = displayName; - const HOC: React.FC> = (props: Omit) => { - const session = useSessionContext(); - - if (!session) { - return null; - } - - return ( - - ); - }; - - HOC.displayName = `withSession(${displayName})`; - return HOC; -}; - -export const WithSession: React.FC<{ - children: (session: SessionResource) => React.ReactNode; -}> = ({ children }) => { - const session = useSessionContext(); - - if (typeof children !== 'function') { - errorThrower.throw(hocChildrenNotAFunctionError); - } - - if (!session) { - return null; - } - - return <>{children(session)}; -}; diff --git a/packages/react/src/components/withUser.tsx b/packages/react/src/components/withUser.tsx deleted file mode 100644 index 87d3aeece79..00000000000 --- a/packages/react/src/components/withUser.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { UserResource } from '@clerk/types'; -import React from 'react'; - -import { useUserContext } from '../contexts/UserContext'; -import { hocChildrenNotAFunctionError } from '../errors'; -import { errorThrower } from '../utils'; - -export const withUser =

(Component: React.ComponentType

, displayName?: string) => { - displayName = displayName || Component.displayName || Component.name || 'Component'; - Component.displayName = displayName; - const HOC: React.FC> = (props: Omit) => { - const user = useUserContext(); - - if (!user) { - return null; - } - - return ( - - ); - }; - - HOC.displayName = `withUser(${displayName})`; - return HOC; -}; - -export const WithUser: React.FC<{ - children: (user: UserResource) => React.ReactNode; -}> = ({ children }) => { - const user = useUserContext(); - - if (typeof children !== 'function') { - errorThrower.throw(hocChildrenNotAFunctionError); - } - - if (!user) { - return null; - } - - return <>{children(user)}; -}; diff --git a/packages/react/src/contexts/ClerkProvider.tsx b/packages/react/src/contexts/ClerkProvider.tsx index 0867ce47437..62262d8e8ce 100644 --- a/packages/react/src/contexts/ClerkProvider.tsx +++ b/packages/react/src/contexts/ClerkProvider.tsx @@ -1,15 +1,11 @@ import { isPublishableKey } from '@clerk/shared/keys'; import React from 'react'; -import { multipleClerkProvidersError } from '../errors'; +import { errorThrower } from '../errors/errorThrower'; +import { multipleClerkProvidersError } from '../errors/messages'; import type { ClerkProviderProps } from '../types'; -import { __internal__setErrorThrowerOptions, errorThrower, withMaxAllowedInstancesGuard } from '../utils'; +import { withMaxAllowedInstancesGuard } from '../utils'; import { ClerkContextProvider } from './ClerkContextProvider'; -import { StructureContext, StructureContextStates } from './StructureContext'; - -__internal__setErrorThrowerOptions({ - packageName: '@clerk/clerk-react', -}); function ClerkProviderBase(props: ClerkProviderProps): JSX.Element { const { initialState, children, ...restIsomorphicClerkOptions } = props; @@ -24,14 +20,12 @@ function ClerkProviderBase(props: ClerkProviderProps): JSX.Element { } return ( - - - {children} - - + + {children} + ); } @@ -39,4 +33,4 @@ const ClerkProvider = withMaxAllowedInstancesGuard(ClerkProviderBase, 'ClerkProv ClerkProvider.displayName = 'ClerkProvider'; -export { ClerkProvider, __internal__setErrorThrowerOptions }; +export { ClerkProvider }; diff --git a/packages/react/src/contexts/StructureContext.tsx b/packages/react/src/contexts/StructureContext.tsx deleted file mode 100644 index 4a3923d9e23..00000000000 --- a/packages/react/src/contexts/StructureContext.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; - -import { assertWrappedByClerkProvider } from './assertHelpers'; - -export interface StructureContextValue { - guaranteedLoaded: boolean; -} - -export const StructureContextStates = Object.freeze({ - noGuarantees: Object.freeze({ - guaranteedLoaded: false, - }), - guaranteedLoaded: Object.freeze({ - guaranteedLoaded: true, - }), -}); - -export const StructureContext = React.createContext(undefined); - -StructureContext.displayName = 'StructureContext'; - -const useStructureContext = (): StructureContextValue => { - const structureCtx = React.useContext(StructureContext); - assertWrappedByClerkProvider(structureCtx); - return structureCtx; -}; - -export const LoadedGuarantee: React.FC> = ({ children }) => { - const structure = useStructureContext(); - if (structure.guaranteedLoaded) { - return <>{children}; - } - return ( - {children} - ); -}; diff --git a/packages/react/src/contexts/assertHelpers.ts b/packages/react/src/contexts/assertHelpers.ts index 3d5d4ae6127..0c02aae05b8 100644 --- a/packages/react/src/contexts/assertHelpers.ts +++ b/packages/react/src/contexts/assertHelpers.ts @@ -1,14 +1,8 @@ -import { noClerkProviderError, noGuaranteedLoadedError } from '../errors'; -import { errorThrower } from '../utils'; +import { errorThrower } from '../errors/errorThrower'; +import { noClerkProviderError } from '../errors/messages'; export function assertWrappedByClerkProvider(contextVal: unknown): asserts contextVal { if (!contextVal) { errorThrower.throw(noClerkProviderError); } } - -export function assertClerkLoadedGuarantee(guarantee: unknown, hookName: string): asserts guarantee { - if (!guarantee) { - errorThrower.throw(noGuaranteedLoadedError(hookName)); - } -} diff --git a/packages/react/src/contexts/index.ts b/packages/react/src/contexts/index.ts index 29e060d3843..aebcfc5ad9b 100644 --- a/packages/react/src/contexts/index.ts +++ b/packages/react/src/contexts/index.ts @@ -1 +1 @@ -export { ClerkProvider, __internal__setErrorThrowerOptions } from './ClerkProvider'; +export { ClerkProvider } from './ClerkProvider'; diff --git a/packages/react/src/errors.ts b/packages/react/src/errors.ts index 6f94acf99b9..e5f95a3b9c0 100644 --- a/packages/react/src/errors.ts +++ b/packages/react/src/errors.ts @@ -1,48 +1 @@ -export { - EmailLinkErrorCode, - isClerkAPIResponseError, - isEmailLinkError, - isKnownError, - isMetamaskError, -} from '@clerk/shared/error'; - -export const noClerkProviderError = 'You must wrap your application in a component.'; - -export const noGuaranteedLoadedError = (hookName: string) => - `You're calling ${hookName} before there's a guarantee the client has been loaded. Call ${hookName} from a child of , , or , or use the withClerk() HOC.`; - -export const multipleClerkProvidersError = - "You've added multiple components in your React component tree. Wrap your components in a single ."; - -export const hocChildrenNotAFunctionError = 'Child of WithClerk must be a function.'; - -export const multipleChildrenInButtonComponent = (name: string) => - `You've passed multiple children components to <${name}/>. You can only pass a single child component or text.`; - -export const invalidStateError = - 'Invalid state. Feel free to submit a bug or reach out to support here: https://clerk.com/support'; - -export const unsupportedNonBrowserDomainOrProxyUrlFunction = - 'Unsupported usage of isSatellite, domain or proxyUrl. The usage of isSatellite, domain or proxyUrl as function is not supported in non-browser environments.'; - -export const userProfilePageRenderedError = - ' component needs to be a direct child of `` or ``.'; -export const userProfileLinkRenderedError = - ' component needs to be a direct child of `` or ``.'; - -export const organizationProfilePageRenderedError = - ' component needs to be a direct child of `` or ``.'; -export const organizationProfileLinkRenderedError = - ' component needs to be a direct child of `` or ``.'; - -export const customPagesIgnoredComponent = (componentName: string) => - `<${componentName} /> can only accept <${componentName}.Page /> and <${componentName}.Link /> as its children. Any other provided component will be ignored.`; - -export const customPageWrongProps = (componentName: string) => - `Missing props. <${componentName}.Page /> component requires the following props: url, label, labelIcon, alongside with children to be rendered inside the page.`; - -export const customLinkWrongProps = (componentName: string) => - `Missing props. <${componentName}.Link /> component requires the following props: url, label and labelIcon.`; - -export const useAuthHasRequiresRoleOrPermission = - 'Missing parameters. `has` from `useAuth` requires a permission or role key to be passed. Example usage: `has({permission: "org:posts:edit"`'; +export { isClerkAPIResponseError, isEmailLinkError, isKnownError, isMetamaskError } from '@clerk/shared/error'; diff --git a/packages/react/src/utils/errorThrower.ts b/packages/react/src/errors/errorThrower.ts similarity index 56% rename from packages/react/src/utils/errorThrower.ts rename to packages/react/src/errors/errorThrower.ts index c3c328d1cbf..5fdf015d52c 100644 --- a/packages/react/src/utils/errorThrower.ts +++ b/packages/react/src/errors/errorThrower.ts @@ -3,8 +3,13 @@ import { buildErrorThrower } from '@clerk/shared/error'; const errorThrower = buildErrorThrower({ packageName: '@clerk/clerk-react' }); -function __internal__setErrorThrowerOptions(options: ErrorThrowerOptions) { +export { errorThrower }; + +/** + * Overrides options of the internal errorThrower (eg setting packageName prefix). + * + * @internal + */ +export function setErrorThrowerOptions(options: ErrorThrowerOptions) { errorThrower.setMessages(options).setPackageName(options); } - -export { errorThrower, __internal__setErrorThrowerOptions }; diff --git a/packages/react/src/errors/messages.ts b/packages/react/src/errors/messages.ts new file mode 100644 index 00000000000..42e2ac81368 --- /dev/null +++ b/packages/react/src/errors/messages.ts @@ -0,0 +1,37 @@ +export const noClerkProviderError = 'You must wrap your application in a component.'; + +export const multipleClerkProvidersError = + "You've added multiple components in your React component tree. Wrap your components in a single ."; + +export const hocChildrenNotAFunctionError = 'Child of WithClerk must be a function.'; + +export const multipleChildrenInButtonComponent = (name: string) => + `You've passed multiple children components to <${name}/>. You can only pass a single child component or text.`; + +export const invalidStateError = + 'Invalid state. Feel free to submit a bug or reach out to support here: https://clerk.com/support'; + +export const unsupportedNonBrowserDomainOrProxyUrlFunction = + 'Unsupported usage of isSatellite, domain or proxyUrl. The usage of isSatellite, domain or proxyUrl as function is not supported in non-browser environments.'; + +export const userProfilePageRenderedError = + ' component needs to be a direct child of `` or ``.'; +export const userProfileLinkRenderedError = + ' component needs to be a direct child of `` or ``.'; + +export const organizationProfilePageRenderedError = + ' component needs to be a direct child of `` or ``.'; +export const organizationProfileLinkRenderedError = + ' component needs to be a direct child of `` or ``.'; + +export const customPagesIgnoredComponent = (componentName: string) => + `<${componentName} /> can only accept <${componentName}.Page /> and <${componentName}.Link /> as its children. Any other provided component will be ignored.`; + +export const customPageWrongProps = (componentName: string) => + `Missing props. <${componentName}.Page /> component requires the following props: url, label, labelIcon, alongside with children to be rendered inside the page.`; + +export const customLinkWrongProps = (componentName: string) => + `Missing props. <${componentName}.Link /> component requires the following props: url, label and labelIcon.`; + +export const useAuthHasRequiresRoleOrPermission = + 'Missing parameters. `has` from `useAuth` requires a permission or role key to be passed. Example usage: `has({permission: "org:posts:edit"`'; diff --git a/packages/react/src/hooks/useAssertWrappedByClerkProvider.ts b/packages/react/src/hooks/useAssertWrappedByClerkProvider.ts index 1fad233ec66..1781a1c8ed4 100644 --- a/packages/react/src/hooks/useAssertWrappedByClerkProvider.ts +++ b/packages/react/src/hooks/useAssertWrappedByClerkProvider.ts @@ -1,6 +1,6 @@ import { useAssertWrappedByClerkProvider as useSharedAssertWrappedByClerkProvider } from '@clerk/shared/react'; -import { errorThrower } from '../utils'; +import { errorThrower } from '../errors/errorThrower'; export const useAssertWrappedByClerkProvider = (source: string): void => { useSharedAssertWrappedByClerkProvider(() => { diff --git a/packages/react/src/hooks/useAuth.ts b/packages/react/src/hooks/useAuth.ts index 661d69b5778..3a0ff00ea96 100644 --- a/packages/react/src/hooks/useAuth.ts +++ b/packages/react/src/hooks/useAuth.ts @@ -9,8 +9,8 @@ import { useCallback } from 'react'; import { useAuthContext } from '../contexts/AuthContext'; import { useIsomorphicClerkContext } from '../contexts/IsomorphicClerkContext'; -import { invalidStateError, useAuthHasRequiresRoleOrPermission } from '../errors'; -import { errorThrower } from '../utils'; +import { errorThrower } from '../errors/errorThrower'; +import { invalidStateError, useAuthHasRequiresRoleOrPermission } from '../errors/messages'; import { useAssertWrappedByClerkProvider } from './useAssertWrappedByClerkProvider'; import { createGetToken, createSignOut } from './utils'; diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index 2af4a3a6cea..3d900e88ad5 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -1,8 +1,10 @@ import './polyfills'; +import { setErrorThrowerOptions } from './errors/errorThrower'; + export * from './components'; export * from './contexts'; -export { EmailLinkErrorCode, isClerkAPIResponseError, isEmailLinkError, isKnownError, isMetamaskError } from './errors'; + export * from './hooks'; export { useEmailLink } from './hooks/useEmailLink'; export type { @@ -11,7 +13,6 @@ export type { HeadlessBrowserClerk, ClerkProviderOptionsWrapper, ClerkProviderProps, - WithClerkProp, - WithSessionProp, - WithUserProp, } from './types'; + +setErrorThrowerOptions({ packageName: PACKAGE_NAME }); diff --git a/packages/react/src/internal.ts b/packages/react/src/internal.ts new file mode 100644 index 00000000000..618de019b63 --- /dev/null +++ b/packages/react/src/internal.ts @@ -0,0 +1,2 @@ +export { setErrorThrowerOptions } from './errors/errorThrower'; +export { MultisessionAppSupport } from './components/controlComponents'; diff --git a/packages/react/src/isomorphicClerk.ts b/packages/react/src/isomorphicClerk.ts index 98c2a29cb5c..c5cbb5ebdfb 100644 --- a/packages/react/src/isomorphicClerk.ts +++ b/packages/react/src/isomorphicClerk.ts @@ -36,7 +36,8 @@ import type { Without, } from '@clerk/types'; -import { unsupportedNonBrowserDomainOrProxyUrlFunction } from './errors'; +import { errorThrower } from './errors/errorThrower'; +import { unsupportedNonBrowserDomainOrProxyUrlFunction } from './errors/messages'; import type { BrowserClerk, BrowserClerkConstructor, @@ -45,7 +46,7 @@ import type { HeadlessBrowserClerkConstructor, IsomorphicClerkOptions, } from './types'; -import { errorThrower, isConstructor, loadClerkJsScript } from './utils'; +import { isConstructor, loadClerkJsScript } from './utils'; const SDK_METADATA = { name: PACKAGE_NAME, version: PACKAGE_VERSION }; diff --git a/packages/react/src/types.ts b/packages/react/src/types.ts index d88e9fe0f37..fa52248638a 100644 --- a/packages/react/src/types.ts +++ b/packages/react/src/types.ts @@ -7,10 +7,8 @@ import type { LoadedClerk, MultiDomainAndOrProxy, SDKMetadata, - SessionResource, SignInRedirectOptions, SignUpRedirectOptions, - UserResource, Without, } from '@clerk/types'; import type React from 'react'; @@ -53,10 +51,6 @@ export interface HeadlessBrowserClerkConstructor { export type WithClerkProp = T & { clerk: LoadedClerk }; -export type WithUserProp = T & { user: UserResource }; - -export type WithSessionProp = T & { session: SessionResource }; - // Clerk object export interface MountProps { mount: (node: HTMLDivElement, props: any) => void; diff --git a/packages/react/src/utils/childrenUtils.tsx b/packages/react/src/utils/childrenUtils.tsx index 1afc87fc7e6..7207ac23290 100644 --- a/packages/react/src/utils/childrenUtils.tsx +++ b/packages/react/src/utils/childrenUtils.tsx @@ -1,7 +1,7 @@ import React from 'react'; -import { multipleChildrenInButtonComponent } from '../errors'; -import { errorThrower } from './errorThrower'; +import { errorThrower } from '../errors/errorThrower'; +import { multipleChildrenInButtonComponent } from '../errors/messages'; export const assertSingleChild = (children: React.ReactNode) => diff --git a/packages/react/src/utils/index.ts b/packages/react/src/utils/index.ts index 04a02b30856..c65c5835502 100644 --- a/packages/react/src/utils/index.ts +++ b/packages/react/src/utils/index.ts @@ -1,5 +1,4 @@ export * from './childrenUtils'; -export * from './errorThrower'; export * from './isConstructor'; export { loadClerkJsScript } from './loadClerkJsScript'; export * from './useMaxAllowedInstancesGuard'; diff --git a/packages/react/src/utils/loadClerkJsScript.ts b/packages/react/src/utils/loadClerkJsScript.ts index c6dab5f282b..2c7113e65b3 100644 --- a/packages/react/src/utils/loadClerkJsScript.ts +++ b/packages/react/src/utils/loadClerkJsScript.ts @@ -3,8 +3,8 @@ import { loadScript } from '@clerk/shared/loadScript'; import { isValidProxyUrl, proxyUrlToAbsoluteURL } from '@clerk/shared/proxy'; import { addClerkPrefix } from '@clerk/shared/url'; +import { errorThrower } from '../errors/errorThrower'; import type { IsomorphicClerkOptions } from '../types'; -import { errorThrower } from './errorThrower'; import { isDevOrStagingUrl } from './isDevOrStageUrl'; import { versionSelector } from './versionSelector'; diff --git a/packages/react/src/utils/useCustomPages.tsx b/packages/react/src/utils/useCustomPages.tsx index 7037a4751c0..cdc7de795ff 100644 --- a/packages/react/src/utils/useCustomPages.tsx +++ b/packages/react/src/utils/useCustomPages.tsx @@ -9,7 +9,7 @@ import { UserProfileLink, UserProfilePage, } from '../components/uiComponents'; -import { customLinkWrongProps, customPagesIgnoredComponent, customPageWrongProps } from '../errors'; +import { customLinkWrongProps, customPagesIgnoredComponent, customPageWrongProps } from '../errors/messages'; import type { UserProfilePageProps } from '../types'; import type { UseCustomElementPortalParams, UseCustomElementPortalReturn } from './useCustomElementPortal'; import { useCustomElementPortal } from './useCustomElementPortal'; diff --git a/packages/react/src/utils/useMaxAllowedInstancesGuard.tsx b/packages/react/src/utils/useMaxAllowedInstancesGuard.tsx index 5e3c7161058..bc78e8496f0 100644 --- a/packages/react/src/utils/useMaxAllowedInstancesGuard.tsx +++ b/packages/react/src/utils/useMaxAllowedInstancesGuard.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { errorThrower } from './errorThrower'; +import { errorThrower } from '../errors/errorThrower'; const counts = new Map(); diff --git a/packages/react/subpaths.mjs b/packages/react/subpaths.mjs new file mode 100644 index 00000000000..a9b97cb58ff --- /dev/null +++ b/packages/react/subpaths.mjs @@ -0,0 +1,11 @@ +import packageJson from './package.json' assert { type: 'json' }; +// This file is a helper for the "subpath-workaround.mjs" script +// We have to polyfill our "exports" subpaths :cry: + +export const subpathNames = Object.keys(packageJson.exports) + .filter(k => k.startsWith('./') && k !== './' && k !== './package.json') + .map(k => k.replace('./', '')); + +export const subpathFoldersBarrel = []; + +export const ignoredFolders = []; diff --git a/packages/react/tsconfig.json b/packages/react/tsconfig.json index be04afbdc58..01630db0209 100644 --- a/packages/react/tsconfig.json +++ b/packages/react/tsconfig.json @@ -4,6 +4,7 @@ "declaration": true, "declarationMap": false, "esModuleInterop": true, + "emitDeclarationOnly": true, "importHelpers": true, "isolatedModules": true, "jsx": "react", diff --git a/packages/react/tsup.config.ts b/packages/react/tsup.config.ts index e2b4da48307..6ed467a3bcf 100644 --- a/packages/react/tsup.config.ts +++ b/packages/react/tsup.config.ts @@ -12,14 +12,16 @@ export default defineConfig(overrideOptions => { return { entry: { index: 'src/index.ts', + internal: 'src/internal.ts', + errors: 'src/errors.ts', }, + dts: true, onSuccess: shouldPublish ? 'npm run publish:local' : undefined, format: ['cjs', 'esm'], bundle: true, clean: true, minify: false, sourcemap: true, - dts: true, external: ['react', 'react-dom'], define: { PACKAGE_NAME: `"${name}"`, diff --git a/packages/remix/src/client/RemixOptionsContext.tsx b/packages/remix/src/client/RemixOptionsContext.tsx index 93defa3f62b..4e4f39b7550 100644 --- a/packages/remix/src/client/RemixOptionsContext.tsx +++ b/packages/remix/src/client/RemixOptionsContext.tsx @@ -7,7 +7,7 @@ type ClerkRemixContextValue = Partial> const ClerkRemixOptionsCtx = React.createContext<{ value: ClerkRemixContextValue } | undefined>(undefined); ClerkRemixOptionsCtx.displayName = 'ClerkRemixOptionsCtx'; -const useClerkRemixOptions = () => { +const useClerkRemixOptions = (): ClerkRemixContextValue => { const ctx = React.useContext(ClerkRemixOptionsCtx) as { value: ClerkRemixContextValue }; return ctx.value; }; diff --git a/packages/remix/src/errorThrower.ts b/packages/remix/src/errorThrower.ts index a7f17471d05..339b52dc6e3 100644 --- a/packages/remix/src/errorThrower.ts +++ b/packages/remix/src/errorThrower.ts @@ -1,10 +1,5 @@ -import type { ErrorThrowerOptions } from '@clerk/shared/error'; import { buildErrorThrower } from '@clerk/shared/error'; -const errorThrower = buildErrorThrower({ packageName: '@clerk/remix' }); +const errorThrower = buildErrorThrower({ packageName: PACKAGE_NAME }); -function __internal__setErrorThrowerOptions(options: ErrorThrowerOptions) { - errorThrower.setMessages(options).setPackageName(options); -} - -export { errorThrower, __internal__setErrorThrowerOptions }; +export { errorThrower }; diff --git a/packages/remix/src/index.ts b/packages/remix/src/index.ts index c1c5739ae89..d2afdeedcba 100644 --- a/packages/remix/src/index.ts +++ b/packages/remix/src/index.ts @@ -1,3 +1,7 @@ import './globalPolyfill'; export * from './client'; + +// Override Clerk React error thrower to show that errors come from @clerk/remix +import { setErrorThrowerOptions } from '@clerk/clerk-react/internal'; +setErrorThrowerOptions({ packageName: PACKAGE_NAME });