All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.com.supertokens.sdk.recipes.passwordless.PasswordlessRecipe.kt Maven / Gradle / Ivy

The newest version!
package com.supertokens.sdk.recipes.passwordless

import com.supertokens.sdk.SuperTokensClient
import com.supertokens.sdk.common.RECIPE_PASSWORDLESS
import com.supertokens.sdk.common.models.PasswordlessMode
import com.supertokens.sdk.handlers.SignInProvider
import com.supertokens.sdk.handlers.SignInProviderConfig
import com.supertokens.sdk.handlers.SignUpProvider
import com.supertokens.sdk.handlers.SignUpProviderConfig
import com.supertokens.sdk.models.SignInData
import com.supertokens.sdk.recipes.Recipe
import com.supertokens.sdk.recipes.RecipeBuilder
import com.supertokens.sdk.recipes.RecipeConfig
import com.supertokens.sdk.recipes.core.usecases.CheckEmailExistsUseCase
import com.supertokens.sdk.recipes.passwordless.usecases.CheckPhoneNumberExistsUseCase
import com.supertokens.sdk.recipes.passwordless.usecases.PasswordlessEmailSignUpUseCase
import com.supertokens.sdk.recipes.passwordless.usecases.PasswordlessInputCodeSignInUseCase
import com.supertokens.sdk.recipes.passwordless.usecases.PasswordlessLinkCodeSignInUseCase
import com.supertokens.sdk.recipes.passwordless.usecases.PasswordlessPhoneNumberSignUpUseCase

class PasswordlessConfig : RecipeConfig

class PasswordlessRecipe(
    private val superTokens: SuperTokensClient,
    private val config: PasswordlessConfig,
) : Recipe {

  private val passwordlessEmailSignUpUseCase by lazy {
    PasswordlessEmailSignUpUseCase(
        client = superTokens.apiClient,
        tenantId = superTokens.tenantId,
    )
  }

  private val passwordlessPhoneNumberSignUpUseCase by lazy {
    PasswordlessPhoneNumberSignUpUseCase(
        client = superTokens.apiClient,
        tenantId = superTokens.tenantId,
    )
  }

  private val passwordlessLinkCodeSignInUseCase by lazy {
    PasswordlessLinkCodeSignInUseCase(
        client = superTokens.apiClient,
        tenantId = superTokens.tenantId,
        userRepository = superTokens.userRepository,
    )
  }

  private val passwordlessInputCodeSignInUseCase by lazy {
    PasswordlessInputCodeSignInUseCase(
        client = superTokens.apiClient,
        tenantId = superTokens.tenantId,
        userRepository = superTokens.userRepository,
    )
  }

  private val checkEmailExistsUseCase by lazy {
    CheckEmailExistsUseCase(
        client = superTokens.apiClient,
        tenantId = superTokens.tenantId,
        recipeId = RECIPE_PASSWORDLESS,
    )
  }

  private val checkPhoneNumberExistsUseCase by lazy {
    CheckPhoneNumberExistsUseCase(
        client = superTokens.apiClient,
        tenantId = superTokens.tenantId,
    )
  }

  suspend fun signUpEmail(email: String) = passwordlessEmailSignUpUseCase.signUp(email)

  suspend fun signUpPhoneNumber(phoneNumber: String) =
      passwordlessPhoneNumberSignUpUseCase.signUp(phoneNumber)

  suspend fun signInLinkCode(preAuthSessionId: String, linkCode: String) =
      passwordlessLinkCodeSignInUseCase.signIn(
          preAuthSessionId = preAuthSessionId,
          linkCode = linkCode,
      )

  suspend fun signInInputCode(preAuthSessionId: String, deviceId: String, userInputCode: String) =
      passwordlessInputCodeSignInUseCase.signIn(
          preAuthSessionId = preAuthSessionId,
          deviceId = deviceId,
          userInputCode = userInputCode,
      )

  suspend fun checkEmailExists(email: String) = checkEmailExistsUseCase.checkEmailExists(email)

  suspend fun checkPhoneNumberExists(phoneNumber: String) =
      checkPhoneNumberExistsUseCase.checkPhoneNumberExists(phoneNumber)
}

data class PasswordlessSignUpData(
    val deviceId: String,
    val preAuthSessionId: String,
    val flowType: PasswordlessMode,
)

object Passwordless :
    RecipeBuilder(),
    SignUpProvider {

  override fun install(
      configure: PasswordlessConfig.() -> Unit
  ): (SuperTokensClient) -> PasswordlessRecipe {
    val config = PasswordlessConfig().apply(configure)

    return { PasswordlessRecipe(it, config) }
  }

  data class SignUpConfig(var email: String? = null, var phoneNumber: String? = null) :
      SignUpProviderConfig

  override suspend fun signUp(
      superTokensClient: SuperTokensClient,
      configure: SignUpConfig.() -> Unit
  ): PasswordlessSignUpData {
    val config = SignUpConfig().apply(configure)

    return config.email?.let { superTokensClient.getRecipe().signUpEmail(it) }
        ?: config.phoneNumber?.let {
          superTokensClient.getRecipe().signUpPhoneNumber(it)
        }
        ?: throw IllegalStateException("Either 'email' or 'phoneNumber' must be provided")
  }
}

object PasswordlessLinkCode : SignInProvider {

  data class SignInConfig(
      var preAuthSessionId: String? = null,
      var linkCode: String? = null,
  ) : SignInProviderConfig

  override suspend fun signIn(
      superTokensClient: SuperTokensClient,
      configure: SignInConfig.() -> Unit
  ): SignInData {
    val config = SignInConfig().apply(configure)

    return superTokensClient
        .getRecipe()
        .signInLinkCode(
            preAuthSessionId =
                checkNotNull(config.preAuthSessionId) { "preAuthSessionId is required" },
            linkCode = checkNotNull(config.linkCode) { "linkCode is required" },
        )
  }
}

object PasswordlessInputCode : SignInProvider {

  data class SignInConfig(
      var preAuthSessionId: String? = null,
      var deviceId: String? = null,
      var userInputCode: String? = null,
  ) : SignInProviderConfig

  override suspend fun signIn(
      superTokensClient: SuperTokensClient,
      configure: SignInConfig.() -> Unit
  ): SignInData {
    val config = SignInConfig().apply(configure)

    return superTokensClient
        .getRecipe()
        .signInInputCode(
            preAuthSessionId =
                checkNotNull(config.preAuthSessionId) { "preAuthSessionId is required" },
            deviceId = checkNotNull(config.deviceId) { "deviceId is required" },
            userInputCode = checkNotNull(config.userInputCode) { "userInputCode is required" },
        )
  }
}

suspend fun SuperTokensClient.checkPhoneNumberExists(phoneNumber: String): Boolean {
  return getRecipe().checkPhoneNumberExists(phoneNumber)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy