diff --git a/.changeset/cool-cars-float.md b/.changeset/cool-cars-float.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/cool-cars-float.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/package-lock.json b/package-lock.json index b3b97d4b917..2010ee7c936 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33419,7 +33419,9 @@ "version": "0.0.2-alpha-v5.1", "license": "MIT", "dependencies": { - "@clerk/nextjs": "^5.0.0-alpha-v5.12", + "@clerk/clerk-react": "5.0.0-alpha-v5.12", + "@clerk/nextjs": "5.0.0-alpha-v5.13", + "@clerk/shared": "2.0.0-alpha-v5.7", "@radix-ui/react-form": "^0.0.3", "@radix-ui/react-slot": "^1.0.2", "@xstate/react": "^4.0.1", diff --git a/packages/elements/examples/nextjs/app/layout.tsx b/packages/elements/examples/nextjs/app/layout.tsx index 71865a5a957..c493eb59c82 100644 --- a/packages/elements/examples/nextjs/app/layout.tsx +++ b/packages/elements/examples/nextjs/app/layout.tsx @@ -14,10 +14,7 @@ export const metadata: Metadata = { export default function RootLayout({ children }: { children: React.ReactNode }) { return ( - + {children} diff --git a/packages/elements/examples/nextjs/app/sign-in/[[...sign-in]]/page.tsx b/packages/elements/examples/nextjs/app/sign-in/[[...sign-in]]/page.tsx index e598afa5cb9..c2f3ffc4b50 100644 --- a/packages/elements/examples/nextjs/app/sign-in/[[...sign-in]]/page.tsx +++ b/packages/elements/examples/nextjs/app/sign-in/[[...sign-in]]/page.tsx @@ -30,6 +30,9 @@ export default function SignInPage() { type='identifier' className='bg-tertiary rounded-sm px-2 py-1 border border-foreground' /> + + {/* */} + {/* */} new Promise(resolve => clerk.addOnLoaded(resolve)), +); diff --git a/packages/elements/src/internals/machines/sign-in.actors.ts b/packages/elements/src/internals/machines/sign-in.actors.ts index e46be2306fe..331deec4386 100644 --- a/packages/elements/src/internals/machines/sign-in.actors.ts +++ b/packages/elements/src/internals/machines/sign-in.actors.ts @@ -1,24 +1,39 @@ import type { AttemptFirstFactorParams, AttemptSecondFactorParams, + LoadedClerk, PrepareFirstFactorParams, PrepareSecondFactorParams, - SignInCreateParams, SignInResource, } from '@clerk/types'; import { fromPromise } from 'xstate'; +import type { SignInMachineContext } from './sign-in.machine'; import type { SignInResourceParams } from './sign-in.types'; -export const createSignIn = fromPromise>( - async ({ input: { client, params } }) => { - if (!client.signIn) { - throw new Error('signIn not available'); // TODO: better error - } +export const createSignIn = fromPromise< + SignInResource, + { client: LoadedClerk['client']; fields: SignInMachineContext['fields'] } +>(({ input: { client, fields } }) => { + const password = fields.get('password'); + const identifier = fields.get('identifier'); - return client.signIn.create(params); - }, -); + if (!identifier) { + throw new Error('Identifier field not present'); // TODO: better error + } + + const passwordParams = password + ? { + password: password.value, + strategy: 'password', + } + : {}; + + return client.signIn.create({ + identifier: identifier.value as string, + ...passwordParams, + }); +}); export const prepareFirstFactor = fromPromise>( async ({ input: { client, params } }) => { diff --git a/packages/elements/src/internals/machines/sign-in.machine.ts b/packages/elements/src/internals/machines/sign-in.machine.ts index c3ff6c97e22..9773326eb47 100644 --- a/packages/elements/src/internals/machines/sign-in.machine.ts +++ b/packages/elements/src/internals/machines/sign-in.machine.ts @@ -1,9 +1,9 @@ -import type { ClerkAPIResponseError } from '@clerk/shared/error'; -import { isClerkAPIResponseError } from '@clerk/shared/error'; -import type { SignInResource } from '@clerk/types'; +import { type ClerkAPIResponseError, isClerkAPIResponseError } from '@clerk/shared/error'; +import type { LoadedClerk, SignInResource } from '@clerk/types'; import { assign, setup } from 'xstate'; import type { ClerkHostRouter } from '../router'; +import { waitForClerk } from './shared.actors'; import { attemptFirstFactor, attemptSecondFactor, @@ -11,10 +11,10 @@ import { prepareFirstFactor, prepareSecondFactor, } from './sign-in.actors'; -import type { FieldDetails, SignInClient } from './sign-in.types'; +import type { FieldDetails } from './sign-in.types'; export interface SignInMachineContext { - client: SignInClient; + clerk: LoadedClerk; router: ClerkHostRouter; error?: Error | ClerkAPIResponseError; resource?: SignInResource; @@ -22,7 +22,7 @@ export interface SignInMachineContext { } export interface SignInMachineInput { - client: SignInClient; + clerk: LoadedClerk; router: ClerkHostRouter; } @@ -44,19 +44,23 @@ export type SignInMachineEvents = export const STATES = { Init: 'Init', + Start: 'Start', StartAttempting: 'StartAttempting', StartFailure: 'StartFailure', + FirstFactor: 'FirstFactor', FirstFactorPreparing: 'FirstFactorPreparing', FirstFactorIdle: 'FirstFactorIdle', FirstFactorAttempting: 'FirstFactorAttempting', FirstFactorFailure: 'FirstFactorFailure', + SecondFactor: 'SecondFactor', SecondFactorPreparing: 'SecondFactorPreparing', SecondFactorIdle: 'SecondFactorIdle', SecondFactorAttempting: 'SecondFactorAttempting', SecondFactorFailure: 'SecondFactorFailure', + Complete: 'Complete', } as const; @@ -67,6 +71,7 @@ function eventHasError(value: T): value is T & { error: Error } { export const SignInMachine = setup({ actors: { + waitForClerk, createSignIn, prepareFirstFactor, attemptFirstFactor, @@ -106,7 +111,7 @@ export const SignInMachine = setup({ }, }).createMachine({ context: ({ input }) => ({ - client: input.client, + clerk: input.clerk, router: input.router, currentFactor: null, fields: new Map(), @@ -164,33 +169,50 @@ export const SignInMachine = setup({ }, states: { [STATES.Init]: { - always: 'Start', + invoke: { + src: 'waitForClerk', + input: ({ context }) => context.clerk, + onDone: { + target: STATES.Start, + actions: assign({ + // @ts-expect-error -- this is really IsomorphicClerk up to this point + clerk: ({ context }) => context.clerk.clerkjs, + }), + }, + }, }, [STATES.Start]: { entry: ({ context }) => console.log('Start entry: ', context), on: { - SUBMIT: STATES.StartAttempting, + SUBMIT: { + target: STATES.StartAttempting, + }, }, }, [STATES.StartAttempting]: { entry: ({ context }) => console.log('StartAttempting entry: ', context), invoke: { - id: 'createSignIn', src: 'createSignIn', input: ({ context }) => ({ - client: context.client, - params: { - identifier: context.fields.get('identifier')?.value as string, - password: context.fields.get('identifier')?.value as string, - strategy: 'password', - }, + client: context.clerk.client, + fields: context.fields, }), - onDone: [{ actions: 'assignResourceToContext' }], + onDone: { actions: 'assignResourceToContext' }, onError: { target: STATES.StartFailure, actions: 'assignErrorMessageToContext', }, }, + always: [ + { + guard: ({ context }) => context?.resource?.status === 'complete', + target: STATES.Complete, + }, + { + guard: ({ context }) => context?.resource?.status === 'needs_first_factor', + target: STATES.FirstFactor, + }, + ], }, [STATES.StartFailure]: { entry: ({ context }) => console.log('StartFailure entry: ', context), @@ -210,14 +232,6 @@ export const SignInMachine = setup({ guard: 'hasClerkAPIError', target: STATES.Start, }, - { - actions: { - type: 'navigateTo', - params: { - path: '/sign-in/factor-one', - }, - }, - }, ], }, [STATES.FirstFactor]: { @@ -229,7 +243,7 @@ export const SignInMachine = setup({ src: 'prepareFirstFactor', // @ts-expect-error - TODO: Implement input: ({ context }) => ({ - client: context.client, + client: context.clerk.client, params: {}, }), onDone: { @@ -264,7 +278,7 @@ export const SignInMachine = setup({ src: 'prepareFirstFactor', // @ts-expect-error - TODO: Implement input: ({ context }) => ({ - client: context.client, + client: context.clerk.client, params: {}, }), onDone: { @@ -310,7 +324,7 @@ export const SignInMachine = setup({ src: 'prepareSecondFactor', // @ts-expect-error - TODO: Implement input: ({ context }) => ({ - client: context.client, + client: context.clerk.client, params: {}, }), onDone: { @@ -338,7 +352,7 @@ export const SignInMachine = setup({ src: 'prepareFirstFactor', // @ts-expect-error - TODO: Implement input: ({ context }) => ({ - client: context.client, + client: context.clerk.client, params: {}, }), onDone: { @@ -370,6 +384,10 @@ export const SignInMachine = setup({ }, [STATES.Complete]: { type: 'final', + entry: ({ context }) => { + const beforeEmit = () => context.router.push(context.clerk.buildAfterSignInUrl()); + void context.clerk.setActive({ session: context.resource?.createdSessionId, beforeEmit }); + }, }, }, }); diff --git a/packages/elements/src/internals/machines/sign-in.types.ts b/packages/elements/src/internals/machines/sign-in.types.ts index c6f873868f0..527acd16964 100644 --- a/packages/elements/src/internals/machines/sign-in.types.ts +++ b/packages/elements/src/internals/machines/sign-in.types.ts @@ -1,4 +1,4 @@ -import type { ClientResource } from '@clerk/types'; +import type { LoadedClerk } from '@clerk/types'; export type FieldDetails = { type?: string; @@ -6,9 +6,7 @@ export type FieldDetails = { error?: Error; }; -export type SignInClient = ClientResource; - export type SignInResourceParams = { - client: SignInClient; + client: LoadedClerk['client']; params: T; }; diff --git a/packages/elements/src/sign-in/index.tsx b/packages/elements/src/sign-in/index.tsx index 0b3fa247f86..6619ce940d6 100644 --- a/packages/elements/src/sign-in/index.tsx +++ b/packages/elements/src/sign-in/index.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useClerk } from '@clerk/nextjs'; +import { useClerk } from '@clerk/clerk-react'; import { useEffect } from 'react'; import { SignInFlowProvider, useSignInFlow } from '../internals/machines/sign-in.context'; @@ -12,20 +12,12 @@ export function SignIn({ children }: { children: React.ReactNode }): JSX.Element const router = useNextRouter(); const clerk = useClerk(); - // @ts-expect-error - clerk.clerkjs isn't typed - if (!router || !clerk?.clerkjs) { - return null; - } - - // @ts-expect-error - clerk.clerkjs isn't typed - const client = clerk.clerkjs.client; - return ( - {children} + {children} ); } @@ -36,6 +28,22 @@ export function SignInStartInner({ children }: { children: React.ReactNode }) { useEffect(() => ref.send({ type: 'START' }), [ref]); return children; + // return ( + //
{ + // event.preventDefault(); + + // const fields = { + // identifier: { value: event.target.elements.identifier?.value }, + // password: { value: event.target.elements.password?.value }, + // }; + + // ref.send({ type: 'SUBMIT', fields }); + // }} + // > + // {children} + //
+ // ); } export function SignInStart({ children }: { children: React.ReactNode }) {