- 添加 AuthCoinAmount 类型和 AuthWithdrawAccount 接口 - 在 AuthUser 和相关 DTO 中增加余额和提款账户字段 - 将获取用户资料的请求方法从 POST 改为 GET - 实现提款账户信息的默认值设置和状态管理 - 添加 JackpotPoolTicker 组件并在状态栏中显示 - 更新多语言文件中的游戏规则说明 - 实现提款表单的预填充和状态重置功能
234 lines
5.3 KiB
TypeScript
234 lines
5.3 KiB
TypeScript
import {
|
|
API_SUCCESS_CODE,
|
|
AUTH_ENDPOINTS,
|
|
AUTH_SKIP_REFRESH_CONTEXT_KEY,
|
|
SMS_SEND_EVENT_REGISTER,
|
|
} from '@/constants'
|
|
import { api } from '@/lib/api/api-client'
|
|
import { ApiError } from '@/lib/api/api-error'
|
|
import {
|
|
mergeAuthUsers,
|
|
normalizeAuthSession,
|
|
normalizeAuthUserProfile,
|
|
normalizeRefreshAuthSession,
|
|
} from '@/lib/auth/auth-normalizers'
|
|
import { getAuthDeviceId } from '@/store/auth'
|
|
import type {
|
|
ApiResponse,
|
|
AuthSessionDto,
|
|
AuthSessionInput,
|
|
AuthUserProfileDto,
|
|
LoginPayload,
|
|
LoginRequestDto,
|
|
LogoutPayload,
|
|
LogoutRequestDto,
|
|
RefreshTokenDto,
|
|
RefreshTokenRequestDto,
|
|
RegisterPayload,
|
|
RegisterRequestDto,
|
|
SendSmsCodeDto,
|
|
SendSmsCodePayload,
|
|
SendSmsCodeRequestDto,
|
|
SendSmsCodeResult,
|
|
} from '@/type'
|
|
|
|
const shouldLogAuthLifecycle =
|
|
import.meta.env.VITE_ENABLE_REQUEST_LOG === 'true'
|
|
|
|
function unwrapEnvelope<T>(
|
|
response: ApiResponse<T>,
|
|
fallbackErrorKey = 'auth.errors.requestFailed',
|
|
) {
|
|
if (response.code === API_SUCCESS_CODE) {
|
|
return response.data
|
|
}
|
|
|
|
throw new ApiError({
|
|
data: response,
|
|
message:
|
|
typeof response.msg === 'string' && response.msg.length > 0
|
|
? response.msg
|
|
: typeof response.message === 'string' && response.message.length > 0
|
|
? response.message
|
|
: fallbackErrorKey,
|
|
})
|
|
}
|
|
|
|
function logAuthSessionExpiry(action: string, session: AuthSessionInput) {
|
|
if (!shouldLogAuthLifecycle || !session.accessTokenExpiresAt) {
|
|
return
|
|
}
|
|
|
|
console.info(
|
|
`[auth] ${action} user-token expires at ${new Date(
|
|
session.accessTokenExpiresAt,
|
|
).toISOString()} (${session.accessTokenExpiresAt})`,
|
|
)
|
|
}
|
|
|
|
async function getCurrentUserProfileByToken(userToken: string) {
|
|
const response = await api.get<AuthUserProfileDto>(AUTH_ENDPOINTS.profile, {
|
|
headers: {
|
|
Authorization: `Bearer ${userToken}`,
|
|
'user-token': userToken,
|
|
},
|
|
})
|
|
|
|
return normalizeAuthUserProfile(
|
|
unwrapEnvelope(
|
|
response as ApiResponse<AuthUserProfileDto>,
|
|
'auth.errors.requestFailed',
|
|
),
|
|
)
|
|
}
|
|
|
|
async function buildEnrichedAuthSession(dto: AuthSessionDto) {
|
|
const session = normalizeAuthSession(dto)
|
|
|
|
try {
|
|
const profileUser = await getCurrentUserProfileByToken(session.accessToken)
|
|
|
|
return {
|
|
...session,
|
|
currentUser: mergeAuthUsers(session.currentUser, profileUser),
|
|
} satisfies AuthSessionInput
|
|
} catch {
|
|
return session
|
|
}
|
|
}
|
|
|
|
export async function loginWithPassword(
|
|
payload: LoginPayload,
|
|
): Promise<AuthSessionInput> {
|
|
const response = await api.post<AuthSessionDto, LoginRequestDto>(
|
|
AUTH_ENDPOINTS.login,
|
|
{
|
|
json: {
|
|
device_id: getAuthDeviceId(),
|
|
password: payload.password,
|
|
username: payload.username,
|
|
},
|
|
},
|
|
)
|
|
|
|
const session = await buildEnrichedAuthSession(
|
|
unwrapEnvelope(
|
|
response as ApiResponse<AuthSessionDto>,
|
|
'auth.login.errors.submitFailed',
|
|
),
|
|
)
|
|
|
|
logAuthSessionExpiry('login', session)
|
|
|
|
return session
|
|
}
|
|
|
|
export async function logoutWithPassword(
|
|
payload: LogoutPayload,
|
|
): Promise<void> {
|
|
const response = await api.post<null, LogoutRequestDto>(
|
|
AUTH_ENDPOINTS.logout,
|
|
{
|
|
json: {
|
|
password: payload.password,
|
|
username: payload.username,
|
|
},
|
|
},
|
|
)
|
|
|
|
unwrapEnvelope(
|
|
response as ApiResponse<null>,
|
|
'auth.logout.errors.submitFailed',
|
|
)
|
|
}
|
|
|
|
export async function registerWithPassword(
|
|
payload: RegisterPayload,
|
|
): Promise<AuthSessionInput> {
|
|
const response = await api.post<AuthSessionDto, RegisterRequestDto>(
|
|
AUTH_ENDPOINTS.register,
|
|
{
|
|
json: {
|
|
captcha: payload.captcha,
|
|
device_id: getAuthDeviceId(),
|
|
invite_code: payload.inviteCode,
|
|
password: payload.password,
|
|
username: payload.mobile,
|
|
},
|
|
},
|
|
)
|
|
|
|
const session = await buildEnrichedAuthSession(
|
|
unwrapEnvelope(
|
|
response as ApiResponse<AuthSessionDto>,
|
|
'auth.register.errors.submitFailed',
|
|
),
|
|
)
|
|
|
|
logAuthSessionExpiry('register', session)
|
|
|
|
return session
|
|
}
|
|
|
|
export async function sendSmsCode(
|
|
payload: SendSmsCodePayload,
|
|
): Promise<SendSmsCodeResult> {
|
|
const response = await api.post<SendSmsCodeDto, SendSmsCodeRequestDto>(
|
|
AUTH_ENDPOINTS.sendSmsCode,
|
|
{
|
|
json: {
|
|
event: SMS_SEND_EVENT_REGISTER,
|
|
mobile: payload.mobile,
|
|
},
|
|
},
|
|
)
|
|
|
|
const data = unwrapEnvelope(
|
|
response as ApiResponse<SendSmsCodeDto>,
|
|
'auth.register.sms.errors.submitFailed',
|
|
)
|
|
|
|
return {
|
|
expiresIn: data.expires_in,
|
|
messageId: data.message_id,
|
|
}
|
|
}
|
|
|
|
export async function getCurrentUserProfile() {
|
|
const response = await api.get<AuthUserProfileDto>(AUTH_ENDPOINTS.profile)
|
|
|
|
return normalizeAuthUserProfile(
|
|
unwrapEnvelope(
|
|
response as ApiResponse<AuthUserProfileDto>,
|
|
'auth.errors.requestFailed',
|
|
),
|
|
)
|
|
}
|
|
|
|
export async function refreshAuthSession(
|
|
refreshToken: string,
|
|
): Promise<AuthSessionInput | null> {
|
|
const response = await api.post<RefreshTokenDto, RefreshTokenRequestDto>(
|
|
AUTH_ENDPOINTS.refreshToken,
|
|
{
|
|
context: {
|
|
[AUTH_SKIP_REFRESH_CONTEXT_KEY]: true,
|
|
},
|
|
json: {
|
|
refresh_token: refreshToken,
|
|
},
|
|
},
|
|
)
|
|
|
|
const session = normalizeRefreshAuthSession(
|
|
unwrapEnvelope(
|
|
response as ApiResponse<RefreshTokenDto>,
|
|
'auth.errors.requestFailed',
|
|
),
|
|
)
|
|
|
|
logAuthSessionExpiry('refresh', session)
|
|
|
|
return session
|
|
}
|