template_0205
This commit is contained in:
878
RN_TEMPLATE/app/services/api/authApi.ts
Normal file
878
RN_TEMPLATE/app/services/api/authApi.ts
Normal file
@@ -0,0 +1,878 @@
|
||||
/**
|
||||
* Authentication API Service
|
||||
*
|
||||
* Handles all authentication-related API calls:
|
||||
* - Pre-login (password verification + send verification code)
|
||||
* - Resend verification code
|
||||
* - Verify login (code verification + get tokens)
|
||||
* - Google login
|
||||
*/
|
||||
import { ApiResponse, ApisauceInstance, create } from "apisauce"
|
||||
|
||||
import Config from "@/config"
|
||||
|
||||
import { getGeneralApiProblem, GeneralApiProblem } from "./apiProblem"
|
||||
import type {
|
||||
BindNewEmailRequest,
|
||||
BindNewEmailResponse,
|
||||
ChangePasswordRequest,
|
||||
ChangePasswordResponse,
|
||||
ForgotPasswordRequest,
|
||||
ForgotPasswordResponse,
|
||||
GetLoginHistoryParams,
|
||||
GetLoginHistoryResponse,
|
||||
GetProfileResponse,
|
||||
GetSessionCountResponse,
|
||||
GetSessionsParams,
|
||||
GetSessionsResponse,
|
||||
GoogleLoginRequest,
|
||||
GoogleLoginResponse,
|
||||
LogoutResponse,
|
||||
PreLoginRequest,
|
||||
PreLoginResponse,
|
||||
PreRegisterRequest,
|
||||
PreRegisterResponse,
|
||||
RefreshTokenRequest,
|
||||
RefreshTokenResponse,
|
||||
ResendCodeRequest,
|
||||
ResendCodeResponse,
|
||||
ResendForgotPasswordRequest,
|
||||
ResendForgotPasswordResponse,
|
||||
ResendRegisterCodeRequest,
|
||||
ResendRegisterCodeResponse,
|
||||
ResetPasswordRequest,
|
||||
ResetPasswordResponse,
|
||||
RevokeOtherSessionsResponse,
|
||||
RevokeSessionResponse,
|
||||
SendEmailCodeRequest,
|
||||
SendEmailCodeResponse,
|
||||
UpdateProfileRequest,
|
||||
UpdateProfileResponse,
|
||||
VerifyCurrentEmailRequest,
|
||||
VerifyCurrentEmailResponse,
|
||||
VerifyLoginRequest,
|
||||
VerifyLoginResponse,
|
||||
VerifyRegisterRequest,
|
||||
VerifyRegisterResponse,
|
||||
} from "./authTypes"
|
||||
|
||||
const AUTH_API_CONFIG = {
|
||||
url: Config.AUTH_API_URL || "https://auth.upay01.com",
|
||||
timeout: 15000,
|
||||
}
|
||||
|
||||
/**
|
||||
* Auth API class for handling authentication requests
|
||||
*/
|
||||
export class AuthApi {
|
||||
apisauce: ApisauceInstance
|
||||
|
||||
constructor() {
|
||||
this.apisauce = create({
|
||||
baseURL: AUTH_API_CONFIG.url,
|
||||
timeout: AUTH_API_CONFIG.timeout,
|
||||
headers: {
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-login: Verify password and send verification code
|
||||
*/
|
||||
async preLogin(
|
||||
email: string,
|
||||
password: string,
|
||||
language?: string,
|
||||
): Promise<{ kind: "ok"; data: PreLoginResponse } | GeneralApiProblem> {
|
||||
const payload: PreLoginRequest = { email, password }
|
||||
if (language) payload.language = language
|
||||
|
||||
const response: ApiResponse<PreLoginResponse> = await this.apisauce.post(
|
||||
"/api/auth/pre-login",
|
||||
payload,
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth preLogin error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resend verification code
|
||||
*/
|
||||
async resendCode(
|
||||
email: string,
|
||||
language?: string,
|
||||
): Promise<{ kind: "ok"; data: ResendCodeResponse } | GeneralApiProblem> {
|
||||
const payload: ResendCodeRequest = { email }
|
||||
if (language) payload.language = language
|
||||
|
||||
const response: ApiResponse<ResendCodeResponse> = await this.apisauce.post(
|
||||
"/api/auth/pre-login/resend",
|
||||
payload,
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth resendCode error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify login: Verify code and get tokens
|
||||
*/
|
||||
async verifyLogin(
|
||||
email: string,
|
||||
code: string,
|
||||
): Promise<{ kind: "ok"; data: VerifyLoginResponse } | GeneralApiProblem> {
|
||||
const payload: VerifyLoginRequest = { email, code }
|
||||
|
||||
const response: ApiResponse<VerifyLoginResponse> = await this.apisauce.post(
|
||||
"/api/auth/login/verify",
|
||||
payload,
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth verifyLogin error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Google login
|
||||
*/
|
||||
async googleLogin(
|
||||
idToken: string,
|
||||
referralCode?: string,
|
||||
): Promise<{ kind: "ok"; data: GoogleLoginResponse } | GeneralApiProblem> {
|
||||
const payload: GoogleLoginRequest = { idToken }
|
||||
if (referralCode) payload.referralCode = referralCode
|
||||
|
||||
const response: ApiResponse<GoogleLoginResponse> = await this.apisauce.post(
|
||||
"/api/auth/google-login",
|
||||
payload,
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth googleLogin error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-register: Validate data and send verification code
|
||||
*/
|
||||
async preRegister(
|
||||
username: string,
|
||||
password: string,
|
||||
email: string,
|
||||
nickname?: string,
|
||||
referralCode?: string,
|
||||
language?: string,
|
||||
): Promise<{ kind: "ok"; data: PreRegisterResponse } | GeneralApiProblem> {
|
||||
const payload: PreRegisterRequest = { username, password, email }
|
||||
if (nickname) payload.nickname = nickname
|
||||
if (referralCode) payload.referralCode = referralCode
|
||||
if (language) payload.language = language
|
||||
|
||||
const response: ApiResponse<PreRegisterResponse> = await this.apisauce.post(
|
||||
"/api/auth/pre-register",
|
||||
payload,
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth preRegister error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resend register verification code
|
||||
*/
|
||||
async resendRegisterCode(
|
||||
email: string,
|
||||
language?: string,
|
||||
): Promise<{ kind: "ok"; data: ResendRegisterCodeResponse } | GeneralApiProblem> {
|
||||
const payload: ResendRegisterCodeRequest = { email }
|
||||
if (language) payload.language = language
|
||||
|
||||
const response: ApiResponse<ResendRegisterCodeResponse> = await this.apisauce.post(
|
||||
"/api/auth/pre-register/resend",
|
||||
payload,
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth resendRegisterCode error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify register: Verify code and create user
|
||||
*/
|
||||
async verifyRegister(
|
||||
email: string,
|
||||
code: string,
|
||||
): Promise<{ kind: "ok"; data: VerifyRegisterResponse } | GeneralApiProblem> {
|
||||
const payload: VerifyRegisterRequest = { email, code }
|
||||
|
||||
const response: ApiResponse<VerifyRegisterResponse> = await this.apisauce.post(
|
||||
"/api/auth/register/verify",
|
||||
payload,
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth verifyRegister error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forgot password: Send verification code
|
||||
*/
|
||||
async forgotPassword(
|
||||
email: string,
|
||||
language?: string,
|
||||
): Promise<{ kind: "ok"; data: ForgotPasswordResponse } | GeneralApiProblem> {
|
||||
const payload: ForgotPasswordRequest = { email }
|
||||
if (language) payload.language = language
|
||||
|
||||
const response: ApiResponse<ForgotPasswordResponse> = await this.apisauce.post(
|
||||
"/api/auth/forgot-password",
|
||||
payload,
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth forgotPassword error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resend forgot password verification code
|
||||
*/
|
||||
async resendForgotPasswordCode(
|
||||
email: string,
|
||||
language?: string,
|
||||
): Promise<{ kind: "ok"; data: ResendForgotPasswordResponse } | GeneralApiProblem> {
|
||||
const payload: ResendForgotPasswordRequest = { email }
|
||||
if (language) payload.language = language
|
||||
|
||||
const response: ApiResponse<ResendForgotPasswordResponse> = await this.apisauce.post(
|
||||
"/api/auth/forgot-password/resend",
|
||||
payload,
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth resendForgotPasswordCode error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset password: Verify code and set new password
|
||||
*/
|
||||
async resetPassword(
|
||||
email: string,
|
||||
code: string,
|
||||
newPassword: string,
|
||||
): Promise<{ kind: "ok"; data: ResetPasswordResponse } | GeneralApiProblem> {
|
||||
const payload: ResetPasswordRequest = { email, code, newPassword }
|
||||
|
||||
const response: ApiResponse<ResetPasswordResponse> = await this.apisauce.post(
|
||||
"/api/auth/reset-password",
|
||||
payload,
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth resetPassword error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout: Revoke token
|
||||
*/
|
||||
async logoutApi(
|
||||
accessToken: string,
|
||||
): Promise<{ kind: "ok"; data: LogoutResponse } | GeneralApiProblem> {
|
||||
const response: ApiResponse<LogoutResponse> = await this.apisauce.post(
|
||||
"/api/auth/logout",
|
||||
{},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth logout error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Profile APIs
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* Get user profile
|
||||
*/
|
||||
async getProfile(
|
||||
accessToken: string,
|
||||
): Promise<{ kind: "ok"; data: GetProfileResponse } | GeneralApiProblem> {
|
||||
const response: ApiResponse<GetProfileResponse> = await this.apisauce.get(
|
||||
"/api/auth/profile",
|
||||
{},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth getProfile error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user profile
|
||||
*/
|
||||
async updateProfile(
|
||||
accessToken: string,
|
||||
payload: UpdateProfileRequest,
|
||||
): Promise<{ kind: "ok"; data: UpdateProfileResponse } | GeneralApiProblem> {
|
||||
const response: ApiResponse<UpdateProfileResponse> = await this.apisauce.put(
|
||||
"/api/auth/profile",
|
||||
payload,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth updateProfile error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Password APIs
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* Change password
|
||||
*/
|
||||
async changePassword(
|
||||
accessToken: string,
|
||||
payload: ChangePasswordRequest,
|
||||
): Promise<{ kind: "ok"; data: ChangePasswordResponse } | GeneralApiProblem> {
|
||||
const response: ApiResponse<ChangePasswordResponse> = await this.apisauce.post(
|
||||
"/api/auth/change-password",
|
||||
payload,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth changePassword error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Token APIs
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* Refresh access token
|
||||
*/
|
||||
async refreshToken(
|
||||
refreshToken: string,
|
||||
): Promise<{ kind: "ok"; data: RefreshTokenResponse } | GeneralApiProblem> {
|
||||
const payload: RefreshTokenRequest = { refreshToken }
|
||||
|
||||
const response: ApiResponse<RefreshTokenResponse> = await this.apisauce.post(
|
||||
"/api/auth/refresh-token",
|
||||
payload,
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth refreshToken error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Email APIs
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* Send email verification code (for changing email)
|
||||
*/
|
||||
async sendEmailCode(
|
||||
accessToken: string,
|
||||
email: string,
|
||||
language?: string,
|
||||
): Promise<{ kind: "ok"; data: SendEmailCodeResponse } | GeneralApiProblem> {
|
||||
const payload: SendEmailCodeRequest = { email }
|
||||
if (language) payload.language = language
|
||||
|
||||
const response: ApiResponse<SendEmailCodeResponse> = await this.apisauce.post(
|
||||
"/api/email/send-verification-code",
|
||||
payload,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth sendEmailCode error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify current email (Step 1 of email change)
|
||||
*/
|
||||
async verifyCurrentEmail(
|
||||
accessToken: string,
|
||||
currentCode: string,
|
||||
): Promise<{ kind: "ok"; data: VerifyCurrentEmailResponse } | GeneralApiProblem> {
|
||||
const payload: VerifyCurrentEmailRequest = {
|
||||
action: "verify-current",
|
||||
currentCode,
|
||||
}
|
||||
|
||||
const response: ApiResponse<VerifyCurrentEmailResponse> = await this.apisauce.post(
|
||||
"/api/email/change",
|
||||
payload,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth verifyCurrentEmail error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind new email (Step 2 of email change)
|
||||
*/
|
||||
async bindNewEmail(
|
||||
accessToken: string,
|
||||
newEmail: string,
|
||||
newCode: string,
|
||||
): Promise<{ kind: "ok"; data: BindNewEmailResponse } | GeneralApiProblem> {
|
||||
const payload: BindNewEmailRequest = {
|
||||
action: "bind-new",
|
||||
newEmail,
|
||||
newCode,
|
||||
}
|
||||
|
||||
const response: ApiResponse<BindNewEmailResponse> = await this.apisauce.post(
|
||||
"/api/email/change",
|
||||
payload,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth bindNewEmail error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Session Management APIs
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* Get sessions/devices list
|
||||
*/
|
||||
async getSessions(
|
||||
accessToken: string,
|
||||
params?: GetSessionsParams,
|
||||
): Promise<{ kind: "ok"; data: GetSessionsResponse } | GeneralApiProblem> {
|
||||
const response: ApiResponse<GetSessionsResponse> = await this.apisauce.get(
|
||||
"/api/sessions",
|
||||
params,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth getSessions error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get active session count
|
||||
*/
|
||||
async getSessionCount(
|
||||
accessToken: string,
|
||||
): Promise<{ kind: "ok"; data: GetSessionCountResponse } | GeneralApiProblem> {
|
||||
const response: ApiResponse<GetSessionCountResponse> = await this.apisauce.get(
|
||||
"/api/sessions/count",
|
||||
{},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth getSessionCount error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get login history
|
||||
*/
|
||||
async getLoginHistory(
|
||||
accessToken: string,
|
||||
params?: GetLoginHistoryParams,
|
||||
): Promise<{ kind: "ok"; data: GetLoginHistoryResponse } | GeneralApiProblem> {
|
||||
const response: ApiResponse<GetLoginHistoryResponse> = await this.apisauce.get(
|
||||
"/api/sessions/history",
|
||||
params,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth getLoginHistory error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke a specific session (remote logout device)
|
||||
*/
|
||||
async revokeSession(
|
||||
accessToken: string,
|
||||
sessionId: string,
|
||||
): Promise<{ kind: "ok"; data: RevokeSessionResponse } | GeneralApiProblem> {
|
||||
const response: ApiResponse<RevokeSessionResponse> = await this.apisauce.delete(
|
||||
`/api/sessions/${sessionId}`,
|
||||
{},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth revokeSession error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke all other sessions (logout all other devices)
|
||||
*/
|
||||
async revokeOtherSessions(
|
||||
accessToken: string,
|
||||
): Promise<{ kind: "ok"; data: RevokeOtherSessionsResponse } | GeneralApiProblem> {
|
||||
const response: ApiResponse<RevokeOtherSessionsResponse> = await this.apisauce.post(
|
||||
"/api/sessions/revoke-others",
|
||||
{},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const problem = getGeneralApiProblem(response)
|
||||
if (problem) return problem
|
||||
}
|
||||
|
||||
try {
|
||||
const data = response.data
|
||||
if (!data) return { kind: "bad-data" }
|
||||
return { kind: "ok", data }
|
||||
} catch (e) {
|
||||
if (__DEV__ && e instanceof Error) {
|
||||
console.error(`Auth revokeOtherSessions error: ${e.message}`)
|
||||
}
|
||||
return { kind: "bad-data" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Singleton instance
|
||||
export const authApi = new AuthApi()
|
||||
Reference in New Issue
Block a user