c6d9bbe
ZhenYi
feat(voice): integrate LiveKit for voice channel functionality and add voice-related APIs
c6d9bbe
import Apis from '@/shared/api'
import type {
AppResponseData_ForgotPasswordResp,
AppResponseData_LoginResp,
AppResponseData_PowChallengeResp,
AppResponseData_RegisterResp,
AppResponseData_ResendCodeResp,
AppResponseData_VerifyEmailResp,
EmailVerificationPurpose,
ForgotPasswordCmd,
LoginCmd,
RegisterCmd,
ResendCodeCmd,
ResetPasswordCmd,
TwoFactorLoginCmd,
VerifyEmailCmd,
} from '@/shared/api'
export type { EmailVerificationPurpose }
interface Envelope<T> {
code: number
message: string
data?: T | null
error?: string | null
error_code?: string | null
}
export class ApiError extends Error {
readonly code: number
readonly errorCode?: string | null
constructor(message: string, code: number, errorCode?: string | null) {
super(message)
this.name = 'ApiError'
this.code = code
this.errorCode = errorCode
}
}
export function toUserError(err: unknown): string {
if (err instanceof ApiError) return err.message
if (err instanceof TypeError) return 'Network error — check your connection and retry.'
return 'Something went wrong. Please try again.'
}
async function unwrap<T>(method: PromiseLike<Envelope<T>>): Promise<T | null> {
const res = await method
if (res.code !== 200) {
throw new ApiError(res.error || res.message || 'Request failed', res.code, res.error_code)
}
return res.data ?? null
}
// Challenges are single-use server-side, but alova caches GET responses for
// 5 min by default: a retried submit would replay the already-consumed nonce
// and fail with "pow challenge missing". A cache controller that always
// returns undefined skips both the cache read (even entries stored by older
// builds) and the cache write, so every submit fetches a fresh challenge.
export const powChallenge = () =>
unwrap(Apis.auth.pow_challenge({ cacheFor: () => undefined }))
export const login = (cmd: LoginCmd) => unwrap(Apis.auth.login({ data: cmd }))
export const login2fa = (cmd: TwoFactorLoginCmd) => unwrap(Apis.auth.login_2fa({ data: cmd }))
export const register = (cmd: RegisterCmd) => unwrap(Apis.auth.register({ data: cmd }))
export const forgotPassword = (cmd: ForgotPasswordCmd) =>
unwrap(Apis.auth.forgot_password({ data: cmd }))
export const resetPassword = (cmd: ResetPasswordCmd) =>
unwrap(Apis.auth.reset_password({ data: cmd }))
export const verifyEmail = (cmd: VerifyEmailCmd) => unwrap(Apis.auth.verify_email({ data: cmd }))
export const resendCode = (cmd: ResendCodeCmd) => unwrap(Apis.auth.resend_code({ data: cmd }))
export type PowChallenge = NonNullable<AppResponseData_PowChallengeResp['data']>
export type LoginResult = NonNullable<AppResponseData_LoginResp['data']>
export type RegisterResult = NonNullable<AppResponseData_RegisterResp['data']>
export type ForgotPasswordResult = NonNullable<AppResponseData_ForgotPasswordResp['data']>
export type VerifyEmailResult = NonNullable<AppResponseData_VerifyEmailResp['data']>
export type ResendCodeResult = NonNullable<AppResponseData_ResendCodeResp['data']>