@@ -16,6 +16,7 @@ import type {
1616 EmailCodeConfig ,
1717 EmailLinkConfig ,
1818 EnterpriseSSOConfig ,
19+ OAuthStrategy ,
1920 PassKeyConfig ,
2021 PasskeyFactor ,
2122 PhoneCodeConfig ,
@@ -27,6 +28,7 @@ import type {
2728 SamlConfig ,
2829 SignInCreateParams ,
2930 SignInFirstFactor ,
31+ SignInFutureResource ,
3032 SignInIdentifier ,
3133 SignInJSON ,
3234 SignInJSONSnapshot ,
@@ -66,6 +68,7 @@ import {
6668 clerkVerifyPasskeyCalledBeforeCreate ,
6769 clerkVerifyWeb3WalletCalledBeforeCreate ,
6870} from '../errors' ;
71+ import { eventBus } from '../events' ;
6972import { BaseResource , UserData , Verification } from './internal' ;
7073
7174export class SignIn extends BaseResource implements SignInResource {
@@ -82,6 +85,21 @@ export class SignIn extends BaseResource implements SignInResource {
8285 createdSessionId : string | null = null ;
8386 userData : UserData = new UserData ( null ) ;
8487
88+ /**
89+ * @experimental This experimental API is subject to change.
90+ *
91+ * An instance of `SignInFuture`, which has a different API than `SignIn`, intended to be used in custom flows.
92+ */
93+ __internal_future : SignInFuture | null = new SignInFuture ( this ) ;
94+
95+ /**
96+ * @internal Only used for internal purposes, and is not intended to be used directly.
97+ *
98+ * This property is used to provide access to underlying Client methods to `SignInFuture`, which wraps an instance
99+ * of `SignIn`.
100+ */
101+ __internal_basePost = this . _basePost . bind ( this ) ;
102+
85103 constructor ( data : SignInJSON | SignInJSONSnapshot | null = null ) {
86104 super ( ) ;
87105 this . fromJSON ( data ) ;
@@ -451,6 +469,8 @@ export class SignIn extends BaseResource implements SignInResource {
451469 this . createdSessionId = data . created_session_id ;
452470 this . userData = new UserData ( data . user_data ) ;
453471 }
472+
473+ eventBus . emit ( 'resource:update' , { resource : this } ) ;
454474 return this ;
455475 }
456476
@@ -470,3 +490,132 @@ export class SignIn extends BaseResource implements SignInResource {
470490 } ;
471491 }
472492}
493+
494+ class SignInFuture implements SignInFutureResource {
495+ emailCode = {
496+ sendCode : this . sendEmailCode . bind ( this ) ,
497+ verifyCode : this . verifyEmailCode . bind ( this ) ,
498+ } ;
499+
500+ constructor ( readonly resource : SignIn ) { }
501+
502+ get status ( ) {
503+ return this . resource . status ;
504+ }
505+
506+ async create ( params : {
507+ identifier ?: string ;
508+ strategy ?: OAuthStrategy | 'saml' | 'enterprise_sso' ;
509+ redirectUrl ?: string ;
510+ actionCompleteRedirectUrl ?: string ;
511+ } ) : Promise < { error : unknown } > {
512+ eventBus . emit ( 'resource:error' , { resource : this . resource , error : null } ) ;
513+ try {
514+ await this . resource . __internal_basePost ( {
515+ path : this . resource . pathRoot ,
516+ body : params ,
517+ } ) ;
518+
519+ return { error : null } ;
520+ } catch ( err ) {
521+ eventBus . emit ( 'resource:error' , { resource : this . resource , error : err } ) ;
522+ return { error : err } ;
523+ }
524+ }
525+
526+ async password ( { identifier, password } : { identifier : string ; password : string } ) : Promise < { error : unknown } > {
527+ eventBus . emit ( 'resource:error' , { resource : this . resource , error : null } ) ;
528+ try {
529+ await this . resource . __internal_basePost ( {
530+ path : this . resource . pathRoot ,
531+ body : { identifier, password } ,
532+ } ) ;
533+ } catch ( err ) {
534+ eventBus . emit ( 'resource:error' , { resource : this . resource , error : err } ) ;
535+ return { error : err } ;
536+ }
537+
538+ return { error : null } ;
539+ }
540+
541+ async sendEmailCode ( { email } : { email : string } ) : Promise < { error : unknown } > {
542+ eventBus . emit ( 'resource:error' , { resource : this . resource , error : null } ) ;
543+ try {
544+ if ( ! this . resource . id ) {
545+ await this . create ( { identifier : email } ) ;
546+ }
547+
548+ const emailCodeFactor = this . resource . supportedFirstFactors ?. find ( f => f . strategy === 'email_code' ) ;
549+
550+ if ( ! emailCodeFactor ) {
551+ throw new Error ( 'Email code factor not found' ) ;
552+ }
553+
554+ const { emailAddressId } = emailCodeFactor ;
555+ await this . resource . __internal_basePost ( {
556+ body : { emailAddressId, strategy : 'email_code' } ,
557+ action : 'prepare_first_factor' ,
558+ } ) ;
559+ } catch ( err : unknown ) {
560+ eventBus . emit ( 'resource:error' , { resource : this . resource , error : err } ) ;
561+ return { error : err } ;
562+ }
563+
564+ return { error : null } ;
565+ }
566+
567+ async verifyEmailCode ( { code } : { code : string } ) : Promise < { error : unknown } > {
568+ eventBus . emit ( 'resource:error' , { resource : this . resource , error : null } ) ;
569+ try {
570+ await this . resource . __internal_basePost ( {
571+ body : { code, strategy : 'email_code' } ,
572+ action : 'attempt_first_factor' ,
573+ } ) ;
574+ } catch ( err : unknown ) {
575+ eventBus . emit ( 'resource:error' , { resource : this . resource , error : err } ) ;
576+ return { error : err } ;
577+ }
578+
579+ return { error : null } ;
580+ }
581+
582+ async sso ( {
583+ flow = 'auto' ,
584+ strategy,
585+ redirectUrl,
586+ redirectUrlComplete,
587+ } : {
588+ flow ?: 'auto' | 'modal' ;
589+ strategy : OAuthStrategy | 'saml' | 'enterprise_sso' ;
590+ redirectUrl : string ;
591+ redirectUrlComplete : string ;
592+ } ) : Promise < { error : unknown } > {
593+ eventBus . emit ( 'resource:error' , { resource : this . resource , error : null } ) ;
594+ try {
595+ if ( flow !== 'auto' ) {
596+ throw new Error ( 'modal flow is not supported yet' ) ;
597+ }
598+
599+ const redirectUrlWithAuthToken = SignIn . clerk . buildUrlWithAuth ( redirectUrl ) ;
600+
601+ if ( ! this . resource . id ) {
602+ await this . create ( {
603+ strategy,
604+ redirectUrl : redirectUrlWithAuthToken ,
605+ actionCompleteRedirectUrl : redirectUrlComplete ,
606+ } ) ;
607+ }
608+
609+ const { status, externalVerificationRedirectURL } = this . resource . firstFactorVerification ;
610+
611+ if ( status === 'unverified' && externalVerificationRedirectURL ) {
612+ windowNavigate ( externalVerificationRedirectURL ) ;
613+ }
614+ } catch ( err : unknown ) {
615+ eventBus . emit ( 'resource:error' , { resource : this . resource , error : err } ) ;
616+ return { error : err } ;
617+ }
618+
619+ return { error : null } ;
620+ }
621+ }
0 commit comments