1+ import { inBrowser } from '@clerk/shared/browser' ;
12import { type ClerkError , ClerkRuntimeError , isCaptchaError , isClerkAPIResponseError } from '@clerk/shared/error' ;
23import { createValidatePassword } from '@clerk/shared/internal/clerk-js/passwords/password' ;
34import { windowNavigate } from '@clerk/shared/internal/clerk-js/windowNavigate' ;
@@ -24,6 +25,7 @@ import type {
2425 SignUpField ,
2526 SignUpFutureCreateParams ,
2627 SignUpFutureEmailCodeVerifyParams ,
28+ SignUpFutureEmailLinkSendParams ,
2729 SignUpFutureFinalizeParams ,
2830 SignUpFuturePasswordParams ,
2931 SignUpFuturePhoneCodeSendParams ,
@@ -591,21 +593,30 @@ export class SignUp extends BaseResource implements SignUpResource {
591593
592594type SignUpFutureVerificationsMethods = Pick <
593595 SignUpFutureVerifications ,
594- 'sendEmailCode' | 'verifyEmailCode' | 'sendPhoneCode' | 'verifyPhoneCode'
596+ | 'sendEmailCode'
597+ | 'verifyEmailCode'
598+ | 'sendEmailLink'
599+ | 'waitForEmailLinkVerification'
600+ | 'sendPhoneCode'
601+ | 'verifyPhoneCode'
595602> ;
596603
597604class SignUpFutureVerifications implements SignUpFutureVerificationsType {
598605 #resource: SignUp ;
599606
600607 sendEmailCode : SignUpFutureVerificationsType [ 'sendEmailCode' ] ;
601608 verifyEmailCode : SignUpFutureVerificationsType [ 'verifyEmailCode' ] ;
609+ sendEmailLink : SignUpFutureVerificationsType [ 'sendEmailLink' ] ;
610+ waitForEmailLinkVerification : SignUpFutureVerificationsType [ 'waitForEmailLinkVerification' ] ;
602611 sendPhoneCode : SignUpFutureVerificationsType [ 'sendPhoneCode' ] ;
603612 verifyPhoneCode : SignUpFutureVerificationsType [ 'verifyPhoneCode' ] ;
604613
605614 constructor ( resource : SignUp , methods : SignUpFutureVerificationsMethods ) {
606615 this . #resource = resource ;
607616 this . sendEmailCode = methods . sendEmailCode ;
608617 this . verifyEmailCode = methods . verifyEmailCode ;
618+ this . sendEmailLink = methods . sendEmailLink ;
619+ this . waitForEmailLinkVerification = methods . waitForEmailLinkVerification ;
609620 this . sendPhoneCode = methods . sendPhoneCode ;
610621 this . verifyPhoneCode = methods . verifyPhoneCode ;
611622 }
@@ -625,6 +636,30 @@ class SignUpFutureVerifications implements SignUpFutureVerificationsType {
625636 get externalAccount ( ) {
626637 return this . #resource. verifications . externalAccount ;
627638 }
639+
640+ get emailLinkVerification ( ) {
641+ if ( ! inBrowser ( ) ) {
642+ return null ;
643+ }
644+
645+ const status = getClerkQueryParam ( '__clerk_status' ) as 'verified' | 'expired' | 'failed' | 'client_mismatch' ;
646+ const createdSessionId = getClerkQueryParam ( '__clerk_created_session' ) ;
647+
648+ if ( ! status || ! createdSessionId ) {
649+ return null ;
650+ }
651+
652+ const verifiedFromTheSameClient =
653+ status === 'verified' &&
654+ typeof SignUp . clerk . client !== 'undefined' &&
655+ SignUp . clerk . client . sessions . some ( s => s . id === createdSessionId ) ;
656+
657+ return {
658+ status,
659+ createdSessionId,
660+ verifiedFromTheSameClient,
661+ } ;
662+ }
628663}
629664
630665class SignUpFuture implements SignUpFutureResource {
@@ -638,6 +673,8 @@ class SignUpFuture implements SignUpFutureResource {
638673 this . verifications = new SignUpFutureVerifications ( this . #resource, {
639674 sendEmailCode : this . sendEmailCode . bind ( this ) ,
640675 verifyEmailCode : this . verifyEmailCode . bind ( this ) ,
676+ sendEmailLink : this . sendEmailLink . bind ( this ) ,
677+ waitForEmailLinkVerification : this . waitForEmailLinkVerification . bind ( this ) ,
641678 sendPhoneCode : this . sendPhoneCode . bind ( this ) ,
642679 verifyPhoneCode : this . verifyPhoneCode . bind ( this ) ,
643680 } ) ;
@@ -833,6 +870,46 @@ class SignUpFuture implements SignUpFutureResource {
833870 } ) ;
834871 }
835872
873+ async sendEmailLink ( params : SignUpFutureEmailLinkSendParams ) : Promise < { error : ClerkError | null } > {
874+ const { verificationUrl } = params ;
875+ return runAsyncResourceTask ( this . #resource, async ( ) => {
876+ let absoluteVerificationUrl = verificationUrl ;
877+ try {
878+ new URL ( verificationUrl ) ;
879+ } catch {
880+ absoluteVerificationUrl = window . location . origin + verificationUrl ;
881+ }
882+
883+ await this . #resource. __internal_basePost ( {
884+ body : { strategy : 'email_link' , redirectUrl : absoluteVerificationUrl } ,
885+ action : 'prepare_verification' ,
886+ } ) ;
887+ } ) ;
888+ }
889+
890+ async waitForEmailLinkVerification ( ) : Promise < { error : ClerkError | null } > {
891+ return runAsyncResourceTask ( this . #resource, async ( ) => {
892+ const { run, stop } = Poller ( ) ;
893+ await new Promise ( ( resolve , reject ) => {
894+ void run ( ( ) => {
895+ return this . #resource
896+ . reload ( )
897+ . then ( res => {
898+ const status = res . verifications . emailAddress . status ;
899+ if ( status === 'verified' || status === 'expired' ) {
900+ stop ( ) ;
901+ resolve ( res ) ;
902+ }
903+ } )
904+ . catch ( err => {
905+ stop ( ) ;
906+ reject ( err ) ;
907+ } ) ;
908+ } ) ;
909+ } ) ;
910+ } ) ;
911+ }
912+
836913 async sendPhoneCode ( params : SignUpFuturePhoneCodeSendParams ) : Promise < { error : ClerkError | null } > {
837914 const { phoneNumber, channel = 'sms' } = params ;
838915 return runAsyncResourceTask ( this . #resource, async ( ) => {
0 commit comments