From 24430df0b2b9f1ee10c45ac70bfbed822f17dbbc Mon Sep 17 00:00:00 2001 From: Sokratis Vidros Date: Mon, 14 Feb 2022 12:37:15 +0200 Subject: [PATCH 01/24] chore(repo): Update package-lock.json --- package-lock.json | 66 +++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/package-lock.json b/package-lock.json index 07a61da90fc..06c76d31b55 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23910,7 +23910,7 @@ }, "packages/backend-core": { "name": "@clerk/backend-core", - "version": "0.4.1-staging.0", + "version": "0.4.1", "license": "MIT", "dependencies": { "camelcase-keys": "^7.0.1", @@ -23938,10 +23938,10 @@ }, "packages/clerk-js": { "name": "@clerk/clerk-js", - "version": "2.13.1-staging.0", + "version": "2.13.1", "license": "MIT", "dependencies": { - "@clerk/types": "^1.25.1-staging.0", + "@clerk/types": "^1.25.1", "@popperjs/core": "^2.4.4", "browser-tabs-lock": "^1.2.15", "classnames": "^2.3.1", @@ -23961,7 +23961,7 @@ "@babel/preset-env": "^7.12.1", "@babel/preset-react": "^7.12.5", "@babel/preset-typescript": "^7.12.1", - "@clerk/shared": "^0.0.2-staging.0", + "@clerk/shared": "^0.0.2", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.2", "@svgr/webpack": "^5.5.0", "@testing-library/dom": "^7.28.1", @@ -24009,10 +24009,10 @@ }, "packages/edge": { "name": "@clerk/edge", - "version": "0.3.1-staging.0", + "version": "0.3.1", "license": "MIT", "dependencies": { - "@clerk/backend-core": "^0.4.1-staging.0", + "@clerk/backend-core": "^0.4.1", "@peculiar/webcrypto": "^1.2.3", "next": "^12.0.7" }, @@ -24035,15 +24035,15 @@ }, "packages/expo": { "name": "@clerk/clerk-expo", - "version": "0.8.1-staging.0", + "version": "0.8.1", "license": "MIT", "dependencies": { - "@clerk/clerk-js": "^2.13.1-staging.0", - "@clerk/clerk-react": "^2.11.1-staging.0", + "@clerk/clerk-js": "^2.13.1", + "@clerk/clerk-react": "^2.11.1", "base-64": "^1.0.0" }, "devDependencies": { - "@clerk/types": "^1.25.1-staging.0", + "@clerk/types": "^1.25.1", "@types/jest": "^27.4.0", "@types/node": "^16.11.9", "@types/react": "^17.0.39", @@ -24070,12 +24070,12 @@ }, "packages/nextjs": { "name": "@clerk/nextjs", - "version": "2.11.1-staging.0", + "version": "2.11.1", "license": "MIT", "dependencies": { - "@clerk/clerk-react": "^2.11.1-staging.0", - "@clerk/clerk-sdk-node": "^2.9.1-staging.0", - "@clerk/types": "^1.25.1-staging.0", + "@clerk/clerk-react": "^2.11.1", + "@clerk/clerk-sdk-node": "^2.9.1", + "@clerk/types": "^1.25.1", "tslib": "^2.3.1" }, "devDependencies": { @@ -24574,10 +24574,10 @@ }, "packages/react": { "name": "@clerk/clerk-react", - "version": "2.11.1-staging.0", + "version": "2.11.1", "license": "MIT", "dependencies": { - "@clerk/types": "^1.25.1-staging.0", + "@clerk/types": "^1.25.1", "tslib": "^2.3.1" }, "devDependencies": { @@ -24614,10 +24614,10 @@ }, "packages/sdk-node": { "name": "@clerk/clerk-sdk-node", - "version": "2.9.1-staging.0", + "version": "2.9.1", "license": "MIT", "dependencies": { - "@clerk/backend-core": "^0.4.1-staging.0", + "@clerk/backend-core": "^0.4.1", "@peculiar/webcrypto": "^1.2.3", "camelcase-keys": "^6.2.2", "cookies": "^0.8.0", @@ -24891,12 +24891,12 @@ }, "packages/shared": { "name": "@clerk/shared", - "version": "0.0.2-staging.0", + "version": "0.0.2", "devDependencies": { "@babel/core": "^7.13.14", "@babel/preset-env": "^7.13.12", "@babel/preset-react": "^7.13.13", - "@clerk/types": "^1.25.1-staging.0", + "@clerk/types": "^1.25.1", "@popperjs/core": "^2.5.4", "@sentry/browser": "^6.3.0", "@svgr/webpack": "^5.5.0", @@ -24950,7 +24950,7 @@ }, "packages/types": { "name": "@clerk/types", - "version": "1.25.1-staging.0", + "version": "1.25.1", "license": "MIT", "devDependencies": { "@types/jest": "^27.4.0", @@ -26223,9 +26223,9 @@ "@clerk/clerk-expo": { "version": "file:packages/expo", "requires": { - "@clerk/clerk-js": "^2.13.1-staging.0", - "@clerk/clerk-react": "^2.11.1-staging.0", - "@clerk/types": "^1.25.1-staging.0", + "@clerk/clerk-js": "^2.13.1", + "@clerk/clerk-react": "^2.11.1", + "@clerk/types": "^1.25.1", "@types/jest": "^27.4.0", "@types/node": "^16.11.9", "@types/react": "^17.0.39", @@ -26256,8 +26256,8 @@ "@babel/preset-env": "^7.12.1", "@babel/preset-react": "^7.12.5", "@babel/preset-typescript": "^7.12.1", - "@clerk/shared": "^0.0.2-staging.0", - "@clerk/types": "^1.25.1-staging.0", + "@clerk/shared": "^0.0.2", + "@clerk/types": "^1.25.1", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.2", "@popperjs/core": "^2.4.4", "@svgr/webpack": "^5.5.0", @@ -26317,7 +26317,7 @@ "@clerk/clerk-react": { "version": "file:packages/react", "requires": { - "@clerk/types": "^1.25.1-staging.0", + "@clerk/types": "^1.25.1", "@testing-library/dom": "^7.28.1", "@testing-library/jest-dom": "^5.11.6", "@testing-library/react": "^11.2.1", @@ -26349,7 +26349,7 @@ "@clerk/clerk-sdk-node": { "version": "file:packages/sdk-node", "requires": { - "@clerk/backend-core": "^0.4.1-staging.0", + "@clerk/backend-core": "^0.4.1", "@peculiar/webcrypto": "^1.2.3", "@types/cookies": "^0.7.7", "@types/express": "^4.17.11", @@ -26550,7 +26550,7 @@ "@clerk/edge": { "version": "file:packages/edge", "requires": { - "@clerk/backend-core": "^0.4.1-staging.0", + "@clerk/backend-core": "^0.4.1", "@peculiar/webcrypto": "^1.2.3", "@types/jest": "^27.4.0", "@types/node": "^16.11.12", @@ -26571,9 +26571,9 @@ "@clerk/nextjs": { "version": "file:packages/nextjs", "requires": { - "@clerk/clerk-react": "^2.11.1-staging.0", - "@clerk/clerk-sdk-node": "^2.9.1-staging.0", - "@clerk/types": "^1.25.1-staging.0", + "@clerk/clerk-react": "^2.11.1", + "@clerk/clerk-sdk-node": "^2.9.1", + "@clerk/types": "^1.25.1", "@types/jest": "^27.4.0", "@types/node": "^16.11.9", "@types/react": "^17.0.39", @@ -26952,7 +26952,7 @@ "@babel/core": "^7.13.14", "@babel/preset-env": "^7.13.12", "@babel/preset-react": "^7.13.13", - "@clerk/types": "^1.25.1-staging.0", + "@clerk/types": "^1.25.1", "@popperjs/core": "^2.5.4", "@sentry/browser": "^6.3.0", "@svgr/webpack": "^5.5.0", From f580d4aebfc3938ca152e7cbc529a8c948e0c311 Mon Sep 17 00:00:00 2001 From: Sokratis Vidros Date: Mon, 14 Feb 2022 12:44:10 +0200 Subject: [PATCH 02/24] fix(clerk-js): Remove unnecessary type assertions --- packages/clerk-js/src/core/clerk.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index dec5ce5fce6..714aabd9252 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -684,11 +684,11 @@ export default class Clerk implements ClerkInterface { s => s.id === client.lastActiveSessionId, ); if (lastActiveSession) { - return lastActiveSession as ActiveSessionResource; + return lastActiveSession; } } const session = client.activeSessions[0]; - return session ? (session as ActiveSessionResource) : null; + return session || null; }; #setupListeners = (): void => { From 199643fe517e628615b5fc81802b444ff54c4550 Mon Sep 17 00:00:00 2001 From: Sokratis Vidros Date: Mon, 14 Feb 2022 12:44:26 +0200 Subject: [PATCH 03/24] chore(release): Publish - @clerk/clerk-js@2.13.2 - @clerk/clerk-expo@0.8.2 --- packages/clerk-js/CHANGELOG.md | 9 +++++++++ packages/clerk-js/package.json | 2 +- packages/expo/CHANGELOG.md | 8 ++++++++ packages/expo/package.json | 4 ++-- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/clerk-js/CHANGELOG.md b/packages/clerk-js/CHANGELOG.md index e7658260c61..f70734248db 100644 --- a/packages/clerk-js/CHANGELOG.md +++ b/packages/clerk-js/CHANGELOG.md @@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +### [2.13.2](https://github.com/clerkinc/javascript/compare/@clerk/clerk-js@2.13.1...@clerk/clerk-js@2.13.2) (2022-02-14) + + +### Bug Fixes + +* **clerk-js:** Remove unnecessary type assertions ([f580d4a](https://github.com/clerkinc/javascript/commit/f580d4aebfc3938ca152e7cbc529a8c948e0c311)) + + + ### [2.13.1](https://github.com/clerkinc/javascript/compare/@clerk/clerk-js@2.13.1-staging.0...@clerk/clerk-js@2.13.1) (2022-02-14) **Note:** Version bump only for package @clerk/clerk-js diff --git a/packages/clerk-js/package.json b/packages/clerk-js/package.json index 513b7746433..ec211270602 100644 --- a/packages/clerk-js/package.json +++ b/packages/clerk-js/package.json @@ -1,6 +1,6 @@ { "name": "@clerk/clerk-js", - "version": "2.13.1", + "version": "2.13.2", "license": "MIT", "description": "Clerk.dev JS library", "keywords": [ diff --git a/packages/expo/CHANGELOG.md b/packages/expo/CHANGELOG.md index e94d765e3ba..e62b20bd764 100644 --- a/packages/expo/CHANGELOG.md +++ b/packages/expo/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +### [0.8.2](https://github.com/clerkinc/javascript/compare/@clerk/clerk-expo@0.8.1...@clerk/clerk-expo@0.8.2) (2022-02-14) + +**Note:** Version bump only for package @clerk/clerk-expo + + + + + ### [0.8.1](https://github.com/clerkinc/javascript/compare/@clerk/clerk-expo@0.8.1-staging.0...@clerk/clerk-expo@0.8.1) (2022-02-14) **Note:** Version bump only for package @clerk/clerk-expo diff --git a/packages/expo/package.json b/packages/expo/package.json index 553e0d7382c..58aa46e0727 100644 --- a/packages/expo/package.json +++ b/packages/expo/package.json @@ -1,6 +1,6 @@ { "name": "@clerk/clerk-expo", - "version": "0.8.1", + "version": "0.8.2", "license": "MIT", "description": "Clerk.dev React Native/Expo library", "keywords": [ @@ -26,7 +26,7 @@ "dev": "tsc -p tsconfig.build.json --watch" }, "dependencies": { - "@clerk/clerk-js": "^2.13.1", + "@clerk/clerk-js": "^2.13.2", "@clerk/clerk-react": "^2.11.1", "base-64": "^1.0.0" }, From e52e416b51d38b31d6008c8c592e7fe4cfa245ca Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Tue, 8 Feb 2022 23:45:49 +0200 Subject: [PATCH 04/24] chore(repo): Open source `@clerk/types` v3 --- packages/types/package.json | 2 +- packages/types/src/clerk.ts | 74 ++++----------------------- packages/types/src/externalAccount.ts | 8 +-- packages/types/src/index.ts | 1 + packages/types/src/json.ts | 47 +++++------------ packages/types/src/oauth.ts | 51 +++++------------- packages/types/src/session.ts | 4 -- packages/types/src/ssr.ts | 36 +++++++++++++ packages/types/src/user.ts | 5 -- packages/types/src/verification.ts | 7 +-- 10 files changed, 79 insertions(+), 156 deletions(-) create mode 100644 packages/types/src/ssr.ts diff --git a/packages/types/package.json b/packages/types/package.json index 3a69338a255..8c065de0aec 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@clerk/types", - "version": "1.25.1", + "version": "2.0.0-alpha.5", "license": "MIT", "description": "Clerk.dev Types", "keywords": [ diff --git a/packages/types/src/clerk.ts b/packages/types/src/clerk.ts index 82df8ea0589..eea1175370d 100644 --- a/packages/types/src/clerk.ts +++ b/packages/types/src/clerk.ts @@ -1,3 +1,4 @@ +import { EnvironmentResource } from '.'; import { ClientResource } from './client'; import { DisplayThemeJSON } from './json'; import { ActiveSessionResource } from './session'; @@ -32,6 +33,9 @@ export interface Clerk { /** Current User. */ user?: UserResource | null; + /** Clerk environment. */ + __unstable__environment?: EnvironmentResource | null; + /** * Signs out the current user on single-session instances, or all users on multi-session instances. * @@ -171,33 +175,19 @@ export interface Clerk { */ navigate: CustomNavigation; - /** - * Redirects to the configured sign in URL. Retrieved from {@link environment}. - * @deprecated Use the new {@link Clerk.redirectToSignIn} instead; - * @param returnBack will appends a query string parameter to the sign in URL so the user can be redirected back to the current page. Defaults to false. - */ - redirectToSignIn(returnBack?: boolean): Promise; - /** * Redirects to the configured sign in URL. Retrieved from {@link environment}. * * @param opts A {@link RedirectOptions} object */ - redirectToSignIn(opts: RedirectOptions): Promise; - - /** - * Redirects to the configured sign up URL. Retrieved from {@link environment}. - * @deprecated Use the new {@link Clerk.redirectToSignIn} instead; - * @param returnBack will appends a query string parameter to the sign in URL so the user can be redirected back to the current page. Defaults to false. - */ - redirectToSignUp(returnBack?: boolean): Promise; + redirectToSignIn(opts?: RedirectOptions): Promise; /** * Redirects to the configured sign up URL. Retrieved from {@link environment}. * * @param opts A {@link RedirectOptions} object */ - redirectToSignUp(opts: RedirectOptions): Promise; + redirectToSignUp(opts?: RedirectOptions): Promise; /** * Redirects to the configured user profile URL. Retrieved from {@link environment}. @@ -272,12 +262,12 @@ export type CustomNavigation = (to: string) => Promise | void; export type ClerkThemeOptions = DeepSnakeToCamel>; export interface ClerkOptions { + authVersion?: 1 | 2; + navigate?: (to: string) => Promise | unknown; + polling?: boolean; selectInitialSession?: ( client: ClientResource, ) => ActiveSessionResource | null; - navigate?: (to: string) => Promise | unknown; - polling?: boolean; - authVersion?: 1 | 2; theme?: ClerkThemeOptions; } @@ -327,16 +317,6 @@ export type SignInProps = { * Used to fill the "Sign up" link in the SignUp component. */ signUpUrl?: string; - - /** - * @deprecated Use {@link SignInProps.afterSignInUrl} instead; - */ - afterSignIn?: string | null; - - /** - * @deprecated Use {@link SignInProps.signUpUrl} instead; - */ - signUpURL?: string; } & RedirectOptions; export type SignUpProps = { @@ -355,16 +335,6 @@ export type SignUpProps = { * Used to fill the "Sign in" link in the SignUp component. */ signInUrl?: string; - - /** - * @deprecated Use {@link SignUpProps.afterSignUpUrl} instead; - */ - afterSignUp?: string | null; - - /** - * @deprecated Use {@link SignUpProps.signInUrl} instead; - */ - signInURL?: string; } & RedirectOptions; export type UserProfileProps = { @@ -423,30 +393,6 @@ export type UserButtonProps = { * Multi-session mode only. */ afterSwitchSessionUrl?: string; - - /** - * @deprecated Use {@link UserButtonProps.afterSwitchSessionUrl} instead; - */ - afterSwitchSession?: string; - - /** - * @deprecated Use {@link UserButtonProps.userProfileUrl} instead; - */ - userProfileURL?: string; - - /** - * @deprecated Use {@link UserButtonProps.signInUrl} instead; - */ signInURL?: string; - - /** - * @deprecated Use {@link UserButtonProps.afterSignOutAllUrl} instead; - */ - afterSignOutAll?: string; - - /** - * @deprecated Use {@link UserButtonProps.afterSignOutOneUrl} instead; - */ - afterSignOutOne?: string; }; export interface HandleMagicLinkVerificationParams { @@ -464,7 +410,7 @@ export interface HandleMagicLinkVerificationParams { * Callback function to be executed after successful magic link * verification on another device. */ - onVerifiedOnOtherDevice?: Function; + onVerifiedOnOtherDevice?: () => void; } export interface AuthenticateWithMetamaskParams { diff --git a/packages/types/src/externalAccount.ts b/packages/types/src/externalAccount.ts index 80b3b9ab55f..7cc10def859 100644 --- a/packages/types/src/externalAccount.ts +++ b/packages/types/src/externalAccount.ts @@ -1,14 +1,16 @@ -import { OAuthProvider } from './oauth'; +import { OAuthProvider } from '.'; export interface ExternalAccountResource { id: string; + identificationId: string; provider: OAuthProvider; - externalId: string; + providerUserId: string; emailAddress: string; approvedScopes: string; firstName: string; lastName: string; - picture: string; + avatarUrl: string; + providerSlug: () => OAuthProvider; providerTitle: () => string; } diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 57129c35cc3..6d81f2f4a9c 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -21,5 +21,6 @@ export * from './token'; export * from './user'; export * from './utils'; export * from './verification'; +export * from './ssr'; export * from './web3'; export * from './web3Wallet'; diff --git a/packages/types/src/json.ts b/packages/types/src/json.ts index 1340daf328c..3f7689d5e3d 100644 --- a/packages/types/src/json.ts +++ b/packages/types/src/json.ts @@ -5,6 +5,7 @@ import { ToggleType, ToggleTypeWithRequire } from './authConfig'; import { EmailAddressVerificationStrategy } from './emailAddress'; import { OAuthStrategy } from './oauth'; +import { OAuthProvider } from './oauth'; import { SessionStatus } from './session'; import { IdentificationStrategy, @@ -181,6 +182,18 @@ export interface Web3WalletJSON extends ClerkResourceJSON { verification: VerificationJSON | null; } +export interface ExternalAccountJSON extends ClerkResourceJSON { + object: 'external_account'; + provider: OAuthProvider; + identification_id: string; + provider_user_id: string; + approved_scopes: string; + email_address: string; + first_name: string; + last_name: string; + avatar_url: string; +} + export interface UserJSON extends ClerkResourceJSON { object: 'user'; id: string; @@ -283,37 +296,3 @@ export interface SessionActivityJSON extends ClerkResourceJSON { country?: string; is_mobile?: boolean; } - -// TODO: Generalize external account JSON payload to simplify type declarations -export type ExternalAccountJSON = - | { - object: 'google_account'; - id: string; - google_id: string; - approved_scopes: string; - email_address: string; - given_name: string; - family_name: string; - picture: string; - } - | { - object: 'facebook_account'; - id: string; - facebook_id: string; - approved_scopes: string; - email_address: string; - first_name: string; - last_name: string; - picture: string; - } - | { - object: 'external_account'; - provider: string; - identification_id: string; - provider_user_id: string; - approved_scopes: string; - email_address: string; - first_name: string; - last_name: string; - avatar_url: string; - }; diff --git a/packages/types/src/oauth.ts b/packages/types/src/oauth.ts index 315e33412db..017d815da42 100644 --- a/packages/types/src/oauth.ts +++ b/packages/types/src/oauth.ts @@ -14,47 +14,20 @@ export type OAuthProvider = export type OAuthStrategy = `oauth_${OAuthProvider}`; -/** - * @deprecated `OAuthCallbacks` has been deprecated and will be removed soon. - * Use {@link AuthenticateWithRedirectParams}, SignIn.authenticateWithRedirect() or SignUp.authenticateWithRedirect() instead. - */ -export type OAuthCallbacks = { - callbackUrl: string; - callbackUrlComplete: string; -}; - export type AuthenticateWithRedirectParams = { /** * One of the supported OAuth providers you can use to authenticate with, eg 'oauth_google'. */ strategy: OAuthStrategy; -} & ( - | { - /** - * Full URL or path to the route that will complete the OAuth flow. - * Typically, this will be a simple `/sso-callback` route that calls `Clerk.handleRedirectCallback` - * or mounts the component. - */ - redirectUrl: string; - /** - * Full URL or path to navigate after the OAuth flow completes. - */ - redirectUrlComplete: string; - callbackUrl?: never; - callbackUrlComplete?: never; - } - | { - /** - * @deprecated `callbackUrl` has been deprecated and will be removed soon. - * Use {@link AuthenticateWithRedirectParams.redirectUrl} instead. - */ - callbackUrl: string; - /** - * @deprecated `callbackUrlComplete` has been deprecated and will be removed soon. - * Use {@link AuthenticateWithRedirectParams.redirectUrlComplete} instead. - */ - callbackUrlComplete: string; - redirectUrl?: never; - redirectUrlComplete?: never; - } -); +} & { + /** + * Full URL or path to the route that will complete the OAuth flow. + * Typically, this will be a simple `/sso-callback` route that calls `Clerk.handleRedirectCallback` + * or mounts the component. + */ + redirectUrl: string; + /** + * Full URL or path to navigate after the OAuth flow completes. + */ + redirectUrlComplete: string; +}; diff --git a/packages/types/src/session.ts b/packages/types/src/session.ts index 804af7e4f61..83d4517cf31 100644 --- a/packages/types/src/session.ts +++ b/packages/types/src/session.ts @@ -12,10 +12,6 @@ export interface SessionResource extends ClerkResource { publicUserData: PublicUserData; end: () => Promise; remove: () => Promise; - /** - * `revoke` has been deprecated and will be removed soon. - */ - revoke: () => Promise; touch: () => Promise; getToken: (options?: GetSessionTokenOptions) => Promise; createdAt: Date; diff --git a/packages/types/src/ssr.ts b/packages/types/src/ssr.ts new file mode 100644 index 00000000000..f4ad6567aef --- /dev/null +++ b/packages/types/src/ssr.ts @@ -0,0 +1,36 @@ +import { SessionJSON, UserJSON } from './json'; +import { SessionResource } from './session'; +import { UserResource } from './user'; + +type SsrSessionState = + | { + sessionId: null; + session: null; + } + | { + sessionId: string; + session: SessionType | undefined; + }; + +type SsrUserState = + | { + userId: null; + user: null; + } + | { + userId: string; + user: UserType | undefined; + }; + +export type SsrAuthData = SsrSessionState & + SsrUserState; +export type ClerkSsrState = SsrSessionState & + SsrUserState; +export type InitialState = + | { + user: undefined; + userId: undefined; + session: undefined; + sessionId: undefined; + } + | (SsrSessionState & SsrUserState); diff --git a/packages/types/src/user.ts b/packages/types/src/user.ts index dc4bb08a0ae..01488263c38 100644 --- a/packages/types/src/user.ts +++ b/packages/types/src/user.ts @@ -5,7 +5,6 @@ import { UserJSON } from './json'; import { PhoneNumberResource } from './phoneNumber'; import { ClerkResource } from './resource'; import { SessionWithActivitiesResource } from './session'; -import { GetUserTokenOptions,JWTService } from './token'; import { SnakeToCamel } from './utils'; import { Web3WalletResource } from './web3Wallet'; @@ -39,10 +38,6 @@ export interface UserResource extends ClerkResource { isPrimaryIdentification: ( ident: EmailAddressResource | PhoneNumberResource, ) => boolean; - getToken: ( - service: JWTService, - options?: GetUserTokenOptions, - ) => Promise; getSessions: () => Promise; setProfileImage: (file: Blob | File) => Promise; } diff --git a/packages/types/src/verification.ts b/packages/types/src/verification.ts index ba812675fca..87092f904cb 100644 --- a/packages/types/src/verification.ts +++ b/packages/types/src/verification.ts @@ -34,12 +34,7 @@ export type VerificationAttemptParams = | SignatureVerificationAttemptParam; export interface StartMagicLinkFlowParams { - redirectUrl?: string; - // DX: Deprecated v2.4.4 - /** - * @deprecated Use {@link StartMagicLinkFlowParams.redirectUrl} instead. - */ - callbackUrl?: string; + redirectUrl: string; } export type CreateMagicLinkFlowReturn = { From 8b1c7d05d94282ce95f148c993b6c9a954f6fa8b Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Tue, 8 Feb 2022 23:46:39 +0200 Subject: [PATCH 05/24] chore(repo): Open source `@clerk/clerk-expo` v3 --- packages/expo/package.json | 4 ++-- packages/expo/src/index.ts | 1 + packages/expo/src/singleton.ts | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/expo/package.json b/packages/expo/package.json index 58aa46e0727..a5654ab3953 100644 --- a/packages/expo/package.json +++ b/packages/expo/package.json @@ -26,8 +26,8 @@ "dev": "tsc -p tsconfig.build.json --watch" }, "dependencies": { - "@clerk/clerk-js": "^2.13.2", - "@clerk/clerk-react": "^2.11.1", + "@clerk/clerk-js": "^3.0.0-alpha.5", + "@clerk/clerk-react": "^3.0.0-alpha.6", "base-64": "^1.0.0" }, "devDependencies": { diff --git a/packages/expo/src/index.ts b/packages/expo/src/index.ts index 1bdaf3d65c0..44da01dd3f7 100644 --- a/packages/expo/src/index.ts +++ b/packages/expo/src/index.ts @@ -5,6 +5,7 @@ export { useSignIn, useSignUp, useUser, + useAuth, withClerk, withSession, withUser, diff --git a/packages/expo/src/singleton.ts b/packages/expo/src/singleton.ts index a5962113c40..7d269a7bd61 100644 --- a/packages/expo/src/singleton.ts +++ b/packages/expo/src/singleton.ts @@ -1,5 +1,5 @@ // @ts-ignore -import Clerk from '@clerk/clerk-js/dist/clerk.nocomponents'; +import Clerk from '@clerk/clerk-js/dist/clerk.headless'; import type { FapiRequestInit, FapiResponse, From c864f95313191251e1f4f3a1c79ff667b049141e Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Tue, 8 Feb 2022 23:47:45 +0200 Subject: [PATCH 06/24] chore(repo): Open source `@clerk/clerk-react` v3 --- packages/react/package.json | 4 +- .../src/components/SignInButton.test.tsx | 9 +- .../react/src/components/SignInButton.tsx | 11 +- .../SignInWithMetamaskButton.test.tsx | 7 +- .../components/SignInWithMetamaskButton.tsx | 2 +- .../src/components/SignOutButton.test.tsx | 10 +- .../react/src/components/SignOutButton.tsx | 2 +- .../src/components/SignUpButton.test.tsx | 10 +- .../react/src/components/SignUpButton.tsx | 11 +- .../src/components/controlComponents.tsx | 73 +++++---- packages/react/src/components/index.ts | 5 + .../react/src/components/uiComponents.tsx | 2 +- packages/react/src/components/withClerk.tsx | 50 ++++++ packages/react/src/components/withSession.tsx | 42 +++++ packages/react/src/components/withUser.tsx | 42 +++++ packages/react/src/contexts/AuthContext.ts | 6 + .../src/contexts/ClerkContextProvider.tsx | 109 +++++++++++++ .../src/contexts/ClerkContextWrapper.tsx | 54 ------- packages/react/src/contexts/ClerkProvider.tsx | 32 ++-- packages/react/src/contexts/ClientContext.tsx | 27 ++-- .../src/contexts/IsomorphicClerkContext.tsx | 121 +-------------- .../react/src/contexts/SessionContext.tsx | 146 +----------------- .../react/src/contexts/StructureContext.tsx | 30 ++-- packages/react/src/contexts/UserContext.tsx | 144 +---------------- packages/react/src/contexts/assertHelpers.ts | 15 +- packages/react/src/contexts/index.ts | 3 - packages/react/src/errors.ts | 3 + packages/react/src/hooks/index.ts | 4 + packages/react/src/hooks/useAuth.ts | 119 ++++++++++++++ packages/react/src/hooks/useClerk.ts | 10 ++ packages/react/src/hooks/useSession.ts | 63 ++++++++ packages/react/src/hooks/useUser.ts | 80 ++++++++++ packages/react/src/index.ts | 8 + packages/react/src/info.ts | 4 +- packages/react/src/isomorphicClerk.ts | 68 ++++---- packages/react/src/types.ts | 10 +- packages/react/src/useMagicLink.ts | 2 +- packages/react/src/utils/childrenUtils.tsx | 42 ++--- packages/react/src/utils/inBrowser.ts | 3 - packages/react/src/utils/inClientSide.ts | 3 + packages/react/src/utils/index.ts | 2 +- .../react/src/utils/makeContextAndHook.ts | 17 ++ packages/react/src/utils/scriptLoader.ts | 35 +++-- .../src/utils/useMaxAllowedInstancesGuard.tsx | 2 +- 44 files changed, 801 insertions(+), 641 deletions(-) create mode 100644 packages/react/src/components/withClerk.tsx create mode 100644 packages/react/src/components/withSession.tsx create mode 100644 packages/react/src/components/withUser.tsx create mode 100644 packages/react/src/contexts/AuthContext.ts create mode 100644 packages/react/src/contexts/ClerkContextProvider.tsx delete mode 100644 packages/react/src/contexts/ClerkContextWrapper.tsx create mode 100644 packages/react/src/hooks/index.ts create mode 100644 packages/react/src/hooks/useAuth.ts create mode 100644 packages/react/src/hooks/useClerk.ts create mode 100644 packages/react/src/hooks/useSession.ts create mode 100644 packages/react/src/hooks/useUser.ts delete mode 100644 packages/react/src/utils/inBrowser.ts create mode 100644 packages/react/src/utils/inClientSide.ts create mode 100644 packages/react/src/utils/makeContextAndHook.ts diff --git a/packages/react/package.json b/packages/react/package.json index 1c8eaeeebe1..4e935d54837 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@clerk/clerk-react", - "version": "2.11.1", + "version": "3.0.0-alpha.6", "license": "MIT", "description": "Clerk.dev React library", "keywords": [ @@ -28,7 +28,7 @@ "test": "jest" }, "dependencies": { - "@clerk/types": "^1.25.1", + "@clerk/types": "^2.0.0-alpha.5", "tslib": "^2.3.1" }, "devDependencies": { diff --git a/packages/react/src/components/SignInButton.test.tsx b/packages/react/src/components/SignInButton.test.tsx index da48881df50..8e1b1d8b9dd 100644 --- a/packages/react/src/components/SignInButton.test.tsx +++ b/packages/react/src/components/SignInButton.test.tsx @@ -1,4 +1,9 @@ -import { render, screen, userEvent, waitFor } from '@clerk/shared/testUtils'; +import { + render, + screen, + userEvent, + waitFor, +} from '@clerk/shared/utils/testUtils'; import React from 'react'; import { SignInButton } from './SignInButton'; @@ -10,7 +15,7 @@ const mockClerk = { redirectToSignIn: mockRedirectToSignIn, } as any; -jest.mock('../contexts', () => { +jest.mock('./withClerk', () => { return { withClerk: (Component: any) => (props: any) => { return ; diff --git a/packages/react/src/components/SignInButton.tsx b/packages/react/src/components/SignInButton.tsx index 2f3d0d9a1dc..001635239b8 100644 --- a/packages/react/src/components/SignInButton.tsx +++ b/packages/react/src/components/SignInButton.tsx @@ -1,22 +1,17 @@ import React from 'react'; -import { withClerk } from '../contexts'; import { SignInButtonProps, WithClerkProp } from '../types'; import { assertSingleChild, normalizeWithDefaultValue, safeExecute, } from '../utils'; +import { withClerk } from './withClerk'; export const SignInButton = withClerk( ({ clerk, children, ...props }: WithClerkProp) => { - const { - afterSignInUrl, - afterSignUpUrl, - redirectUrl, - mode, - ...rest - } = props; + const { afterSignInUrl, afterSignUpUrl, redirectUrl, mode, ...rest } = + props; children = normalizeWithDefaultValue(children, 'Sign in'); const child = assertSingleChild(children)('SignInButton'); diff --git a/packages/react/src/components/SignInWithMetamaskButton.test.tsx b/packages/react/src/components/SignInWithMetamaskButton.test.tsx index 4d2cfb6b22e..aca11ea0ca6 100644 --- a/packages/react/src/components/SignInWithMetamaskButton.test.tsx +++ b/packages/react/src/components/SignInWithMetamaskButton.test.tsx @@ -17,11 +17,10 @@ const mockClerk = { authenticateWithMetamask: mockAuthenticatewithMetamask, } as any; -jest.mock('../contexts', () => { +jest.mock('./withClerk', () => { return { - withClerk: (Component: any) => (props: any) => ( - - ), + withClerk: (Component: any) => (props: any) => + , }; }); diff --git a/packages/react/src/components/SignInWithMetamaskButton.tsx b/packages/react/src/components/SignInWithMetamaskButton.tsx index c13a2ffe0a8..5fa87d0caf7 100644 --- a/packages/react/src/components/SignInWithMetamaskButton.tsx +++ b/packages/react/src/components/SignInWithMetamaskButton.tsx @@ -1,12 +1,12 @@ import React from 'react'; -import { withClerk } from '../contexts'; import { SignInWithMetamaskButtonProps, WithClerkProp } from '../types'; import { assertSingleChild, normalizeWithDefaultValue, safeExecute, } from '../utils'; +import { withClerk } from './withClerk'; export const SignInWithMetamaskButton = withClerk( ({ diff --git a/packages/react/src/components/SignOutButton.test.tsx b/packages/react/src/components/SignOutButton.test.tsx index 194332cd37c..c618eae1720 100644 --- a/packages/react/src/components/SignOutButton.test.tsx +++ b/packages/react/src/components/SignOutButton.test.tsx @@ -1,5 +1,9 @@ -import { render, screen, waitFor } from '@clerk/shared/testUtils'; -import { userEvent } from '@clerk/shared/utils/testUtils'; +import { + render, + screen, + userEvent, + waitFor, +} from '@clerk/shared/utils/testUtils'; import React from 'react'; import { SignOutButton } from './SignOutButton'; @@ -11,7 +15,7 @@ const mockClerk = { signOutOne: mockSignOutOne, } as any; -jest.mock('../contexts', () => { +jest.mock('./withClerk', () => { return { withClerk: (Component: any) => (props: any) => { return ; diff --git a/packages/react/src/components/SignOutButton.tsx b/packages/react/src/components/SignOutButton.tsx index 38c1b740d7c..0b2cd134046 100644 --- a/packages/react/src/components/SignOutButton.tsx +++ b/packages/react/src/components/SignOutButton.tsx @@ -1,12 +1,12 @@ import React from 'react'; -import { withClerk } from '../contexts'; import { SignOutButtonProps, WithClerkProp } from '../types'; import { assertSingleChild, normalizeWithDefaultValue, safeExecute, } from '../utils'; +import { withClerk } from './withClerk'; export const SignOutButton = withClerk( ({ diff --git a/packages/react/src/components/SignUpButton.test.tsx b/packages/react/src/components/SignUpButton.test.tsx index 19f601fa5ae..9a2af3bf66a 100644 --- a/packages/react/src/components/SignUpButton.test.tsx +++ b/packages/react/src/components/SignUpButton.test.tsx @@ -1,5 +1,9 @@ -import { render, screen, waitFor } from '@clerk/shared/testUtils'; -import { userEvent } from '@clerk/shared/utils/testUtils'; +import { + render, + screen, + userEvent, + waitFor, +} from '@clerk/shared/utils/testUtils'; import React from 'react'; import { SignUpButton } from './SignUpButton'; @@ -11,7 +15,7 @@ const mockClerk = { redirectToSignUp: mockRedirectToSignUp, } as any; -jest.mock('../contexts', () => { +jest.mock('./withClerk', () => { return { withClerk: (Component: any) => (props: any) => { return ; diff --git a/packages/react/src/components/SignUpButton.tsx b/packages/react/src/components/SignUpButton.tsx index b2118182334..878c1e52bc8 100644 --- a/packages/react/src/components/SignUpButton.tsx +++ b/packages/react/src/components/SignUpButton.tsx @@ -1,22 +1,17 @@ import React from 'react'; -import { withClerk } from '../contexts'; import { SignUpButtonProps, WithClerkProp } from '../types'; import { assertSingleChild, normalizeWithDefaultValue, safeExecute, } from '../utils'; +import { withClerk } from './withClerk'; export const SignUpButton = withClerk( ({ clerk, children, ...props }: WithClerkProp) => { - const { - afterSignInUrl, - afterSignUpUrl, - redirectUrl, - mode, - ...rest - } = props; + const { afterSignInUrl, afterSignUpUrl, redirectUrl, mode, ...rest } = + props; children = normalizeWithDefaultValue(children, 'Sign up'); const child = assertSingleChild(children)('SignUpButton'); diff --git a/packages/react/src/components/controlComponents.tsx b/packages/react/src/components/controlComponents.tsx index 08c22e6c0ee..2b11b5137f6 100644 --- a/packages/react/src/components/controlComponents.tsx +++ b/packages/react/src/components/controlComponents.tsx @@ -1,64 +1,74 @@ import { HandleOAuthCallbackParams } from '@clerk/types'; import React from 'react'; -import { withClerk, withUser } from '../contexts'; -import { useUserContext } from '../contexts/UserContext'; +import { useAuthContext } from '../contexts/AuthContext'; +import { useIsomorphicClerkContext } from '../contexts/IsomorphicClerkContext'; +import { useSessionContext } from '../contexts/SessionContext'; +import { LoadedGuarantee } from '../contexts/StructureContext'; import type { RedirectToProps, WithClerkProp } from '../types'; +import { withClerk } from './withClerk'; -export const SignedIn: React.FC = withUser(({ children }) => { - return <>{children}; -}, 'SignedIn'); +export const SignedIn: React.FC = ({ children }) => { + const { userId } = useAuthContext(); + if (userId) { + return <>{children}; + } + return null; +}; -export const SignedOut: React.FC = withClerk(({ children }) => { - const userCtx = useUserContext(); - return userCtx.value === null ? <>{children} : null; -}, 'SignedOut'); +export const SignedOut: React.FC = ({ children }) => { + const { userId } = useAuthContext(); + if (userId === null) { + return <>{children}; + } + return null; +}; -export const ClerkLoaded: React.FC = withClerk(({ children }) => { - return <>{children}; -}, 'ClerkLoaded'); +export const ClerkLoaded: React.FC = ({ children }) => { + const isomorphicClerk = useIsomorphicClerkContext(); + if (!isomorphicClerk.loaded) { + return null; + } + return {children}; +}; export const ClerkLoading: React.FC = ({ children }) => { - const userCtx = useUserContext(); - return userCtx.value === undefined ? <>{children} : null; + const isomorphicClerk = useIsomorphicClerkContext(); + if (isomorphicClerk.loaded) { + return null; + } + return <>{children}; }; -// DX: returnBack deprecated <=2.4.2 -// Deprecate the boolean type before removing returnBack export const RedirectToSignIn = withClerk( ({ clerk, ...props }: WithClerkProp) => { - const { returnBack, afterSignUpUrl, redirectUrl, afterSignInUrl } = props; - const redirectOptions = { afterSignUpUrl, redirectUrl, afterSignInUrl }; - const { client, session } = clerk; // TODO: Remove temp use of __unstable__environment const { __unstable__environment } = clerk as any; const hasActiveSessions = client.activeSessions && client.activeSessions.length > 0; + React.useEffect(() => { if (session === null && hasActiveSessions && __unstable__environment) { const { afterSignOutOneUrl } = __unstable__environment.displayConfig; void clerk.navigate(afterSignOutOneUrl); } else { - void clerk.redirectToSignIn((returnBack || redirectOptions) as any); + void clerk.redirectToSignIn(props); } }, []); + return null; }, 'RedirectToSignIn', ); -// DX: returnBack deprecated <=2.4.2 -// Deprecate the boolean type before removing returnBack export const RedirectToSignUp = withClerk( ({ clerk, ...props }: WithClerkProp) => { - const { returnBack, afterSignUpUrl, redirectUrl, afterSignInUrl } = props; - const redirectOptions = { afterSignUpUrl, redirectUrl, afterSignInUrl }; - React.useEffect(() => { - void clerk.redirectToSignUp((returnBack || redirectOptions) as any); + void clerk.redirectToSignUp(props); }, []); + return null; }, 'RedirectToSignUp', @@ -68,6 +78,7 @@ export const RedirectToUserProfile = withClerk(({ clerk }) => { React.useEffect(() => { clerk.redirectToUserProfile(); }, []); + return null; }, 'RedirectToUserProfile'); @@ -79,7 +90,17 @@ export const AuthenticateWithRedirectCallback = withClerk( React.useEffect(() => { void clerk.handleRedirectCallback(handleRedirectCallbackParams); }, []); + return null; }, 'AuthenticateWithRedirectCallback', ); + +export const MultisessionAppSupport: React.FC = ({ children }) => { + const session = useSessionContext(); + return ( + + {children} + + ); +}; diff --git a/packages/react/src/components/index.ts b/packages/react/src/components/index.ts index 4c84a1d05f2..2b88eb4a74f 100644 --- a/packages/react/src/components/index.ts +++ b/packages/react/src/components/index.ts @@ -9,8 +9,13 @@ export { RedirectToSignUp, RedirectToUserProfile, AuthenticateWithRedirectCallback, + MultisessionAppSupport, } from './controlComponents'; +export * from './withClerk'; +export * from './withUser'; +export * from './withSession'; + export * from './SignInButton'; export * from './SignUpButton'; export * from './SignOutButton'; diff --git a/packages/react/src/components/uiComponents.tsx b/packages/react/src/components/uiComponents.tsx index 4f13571f538..141de232376 100644 --- a/packages/react/src/components/uiComponents.tsx +++ b/packages/react/src/components/uiComponents.tsx @@ -6,8 +6,8 @@ import { } from '@clerk/types'; import React from 'react'; -import { withClerk } from '../contexts'; import { MountProps, WithClerkProp } from '../types'; +import { withClerk } from './withClerk'; // README: should be a class pure component in order for mount and unmount // lifecycle props to be invoked correctly. Replacing the class component with a diff --git a/packages/react/src/components/withClerk.tsx b/packages/react/src/components/withClerk.tsx new file mode 100644 index 00000000000..d411ef987da --- /dev/null +++ b/packages/react/src/components/withClerk.tsx @@ -0,0 +1,50 @@ +import { LoadedClerk } from '@clerk/types'; +import React from 'react'; + +import { useIsomorphicClerkContext } from '../contexts/IsomorphicClerkContext'; +import { LoadedGuarantee } from '../contexts/StructureContext'; +import { hocChildrenNotAFunctionError } from '../errors'; + +export const withClerk =

( + Component: React.ComponentType

, + displayName?: string, +) => { + displayName = + displayName || Component.displayName || Component.name || 'Component'; + Component.displayName = displayName; + const HOC = (props: Omit) => { + const clerk = useIsomorphicClerkContext(); + + if (!clerk.loaded) { + return null; + } + + return ( + + + + ); + }; + HOC.displayName = `withClerk(${displayName})`; + return HOC; +}; + +export const WithClerk: React.FC<{ + children: (clerk: LoadedClerk) => React.ReactNode; +}> = ({ children }) => { + const clerk = useIsomorphicClerkContext(); + + if (typeof children !== 'function') { + throw new Error(hocChildrenNotAFunctionError); + } + + if (!clerk.loaded) { + return null; + } + + return ( + + {children(clerk as unknown as LoadedClerk)} + + ); +}; diff --git a/packages/react/src/components/withSession.tsx b/packages/react/src/components/withSession.tsx new file mode 100644 index 00000000000..80dad74e062 --- /dev/null +++ b/packages/react/src/components/withSession.tsx @@ -0,0 +1,42 @@ +import { SessionResource } from '@clerk/types'; +import React from 'react'; + +import { useSessionContext } from '../contexts/SessionContext'; +import { hocChildrenNotAFunctionError } from '../errors'; + +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') { + throw new Error(hocChildrenNotAFunctionError); + } + + if (!session) { + return null; + } + + return <>{children(session)}; +}; diff --git a/packages/react/src/components/withUser.tsx b/packages/react/src/components/withUser.tsx new file mode 100644 index 00000000000..817d8916bf2 --- /dev/null +++ b/packages/react/src/components/withUser.tsx @@ -0,0 +1,42 @@ +import { UserResource } from '@clerk/types'; +import React from 'react'; + +import { useUserContext } from '../contexts/UserContext'; +import { hocChildrenNotAFunctionError } from '../errors'; + +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') { + throw new Error(hocChildrenNotAFunctionError); + } + + if (!user) { + return null; + } + + return <>{children(user)}; +}; diff --git a/packages/react/src/contexts/AuthContext.ts b/packages/react/src/contexts/AuthContext.ts new file mode 100644 index 00000000000..dfdc1ef57a5 --- /dev/null +++ b/packages/react/src/contexts/AuthContext.ts @@ -0,0 +1,6 @@ +import { makeContextAndHook } from '../utils/makeContextAndHook'; + +export const [AuthContext, useAuthContext] = makeContextAndHook<{ + userId: string | null | undefined; + sessionId: string | null | undefined; +}>('AuthContext'); diff --git a/packages/react/src/contexts/ClerkContextProvider.tsx b/packages/react/src/contexts/ClerkContextProvider.tsx new file mode 100644 index 00000000000..9e396313529 --- /dev/null +++ b/packages/react/src/contexts/ClerkContextProvider.tsx @@ -0,0 +1,109 @@ +import { + ActiveSessionResource, + ClientResource, + InitialState, + Resources, + UserResource, +} from '@clerk/types'; +import React from 'react'; + +import IsomorphicClerk from '../isomorphicClerk'; +import { AuthContext } from './AuthContext'; +import { ClientContext } from './ClientContext'; +import { IsomorphicClerkContext } from './IsomorphicClerkContext'; +import { SessionContext } from './SessionContext'; +import { UserContext } from './UserContext'; + +type ClerkContextWrapperProps = { + isomorphicClerk: IsomorphicClerk; + children: React.ReactNode; + clerkLoaded: boolean; +}; + +type ClerkContextProviderState = Resources; + +export function ClerkContextProvider({ + isomorphicClerk, + children, + clerkLoaded, +}: ClerkContextWrapperProps): JSX.Element | null { + const clerk = isomorphicClerk; + + const initialState = clerk.initialState; + const [state, setState] = React.useState({ + client: clerk.client as ClientResource, + session: clerk.session, + user: clerk.user, + }); + const derivedState = deriveState(clerkLoaded, state, initialState); + + React.useEffect(() => { + return clerk.addListener(e => setState({ ...e })); + }, []); + + const clerkCtx = React.useMemo(() => ({ value: clerk }), [clerkLoaded]); + const clientCtx = React.useMemo( + () => ({ value: state.client }), + [state.client], + ); + + const authCtx = React.useMemo(() => { + return { + value: { sessionId: derivedState.sessionId, userId: derivedState.userId }, + }; + }, [derivedState.sessionId, derivedState.userId]); + + const userCtx = React.useMemo(() => { + return { value: derivedState.user }; + }, [derivedState.userId, derivedState.user]); + + const sessionCtx = React.useMemo(() => { + return { value: derivedState.session }; + }, [derivedState.sessionId, derivedState.session]); + + return ( + + + + + + {children} + + + + + + ); +} + +// This should be provided from isomorphicClerk +// TODO: move inside isomorphicClerk +function deriveState( + clerkLoaded: boolean, + state: ClerkContextProviderState, + initialState: InitialState | undefined, +): { + userId: string | null | undefined; + sessionId: string | null | undefined; + session: ActiveSessionResource | null | undefined; + user: UserResource | null | undefined; +} { + if (!clerkLoaded && initialState) { + const userId = initialState.userId; + // TODO: Instantiate an actual user resource + const user = initialState.user as any as UserResource; + const sessionId = initialState.sessionId; + // TODO: Instantiate an actual session resource + const session = initialState.session as any as ActiveSessionResource; + return { sessionId, session, userId, user }; + } + const userId: string | null | undefined = state.user + ? state.user.id + : state.user; + const user = state.user; + const sessionId: string | null | undefined = state.session + ? state.session.id + : state.session; + const session = state.session; + return { sessionId, session, userId, user }; +} diff --git a/packages/react/src/contexts/ClerkContextWrapper.tsx b/packages/react/src/contexts/ClerkContextWrapper.tsx deleted file mode 100644 index 88a8cddc06c..00000000000 --- a/packages/react/src/contexts/ClerkContextWrapper.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { ClientResource, Resources } from '@clerk/types'; -import React from 'react'; - -import IsomorphicClerk from '../isomorphicClerk'; -import { ClientContext } from './ClientContext'; -import { IsomorphicClerkContext } from './IsomorphicClerkContext'; -import { SessionContext } from './SessionContext'; -import { UserContext } from './UserContext'; - -type ClerkContextWrapperProps = { - isomorphicClerk: IsomorphicClerk; - children: React.ReactNode; - clerkLoaded: boolean; -}; - -type ClerkContextProviderState = Resources; - -export function ClerkContextWrapper({ - isomorphicClerk, - children, - clerkLoaded, -}: ClerkContextWrapperProps): JSX.Element | null { - const clerk = isomorphicClerk; - - const [state, setState] = React.useState({ - client: clerk.client as ClientResource, - session: clerk.session, - user: clerk.user, - }); - - React.useEffect(() => { - return clerk.addListener(e => setState({ ...e })); - }, []); - - const { client, session, user } = state; - const clerkCtx = React.useMemo(() => ({ value: clerk }), [clerkLoaded]); - const clientCtx = React.useMemo(() => ({ value: client }), [client]); - const sessionCtx = React.useMemo(() => ({ value: session }), [session]); - const userCtx = React.useMemo(() => ({ value: user }), [user]); - - return ( - - - - - - {children} - - - - - - ); -} diff --git a/packages/react/src/contexts/ClerkProvider.tsx b/packages/react/src/contexts/ClerkProvider.tsx index 61c51afffdb..ff31f06268d 100644 --- a/packages/react/src/contexts/ClerkProvider.tsx +++ b/packages/react/src/contexts/ClerkProvider.tsx @@ -1,41 +1,45 @@ +import { InitialState } from '@clerk/types'; import React, { useEffect, useMemo, useState } from 'react'; import { multipleClerkProvidersError } from '../errors'; import IsomorphicClerk from '../isomorphicClerk'; import type { ClerkProp, IsomorphicClerkOptions } from '../types'; import { withMaxAllowedInstancesGuard } from '../utils'; -import { ClerkContextWrapper } from './ClerkContextWrapper'; +import { ClerkContextProvider } from './ClerkContextProvider'; import { StructureContext, StructureContextStates } from './StructureContext'; export interface ClerkProviderProps extends IsomorphicClerkOptions { frontendApi?: string; Clerk?: ClerkProp; + initialState?: InitialState; } function ClerkProviderBase(props: React.PropsWithChildren) { + const [clerkLoaded, setClerkLoaded] = useState(false); const clerk = useMemo(() => { - const { frontendApi = '', Clerk: ClerkConstructor, ...rest } = props; - return new IsomorphicClerk(frontendApi, rest, ClerkConstructor); + const { + frontendApi = '', + Clerk: ClerkConstructor, + initialState, + ...rest + } = props; + return new IsomorphicClerk( + frontendApi, + rest, + ClerkConstructor, + initialState, + ); }, []); - const [clerkLoaded, setClerkLoaded] = useState(false); - useEffect(() => { void clerk.loadClerkJS().then(() => setClerkLoaded(true)); }, []); return ( - {clerk instanceof IsomorphicClerk && clerk.ssrData && ( -