diff --git a/src/core/net/interceptor/auth_refresh_interceptor.ts b/src/core/net/interceptor/auth_refresh_interceptor.ts index 72a7a025..bf0e5fa1 100644 --- a/src/core/net/interceptor/auth_refresh_interceptor.ts +++ b/src/core/net/interceptor/auth_refresh_interceptor.ts @@ -8,7 +8,7 @@ import type { FetchHook } from "ofetch"; import { ApiPath } from "../../../data/services/api/api_path"; import { ApiError, ErrorCode } from "../../../data/services/api/api_result"; import { AuthStorage } from "@/data/storage/auth/auth_storage"; -import { deviceIdentifier, Result } from "@/utils"; +import { AppEnvUtil, deviceIdentifier, Result } from "@/utils"; /** * 不需要 auth token 刷新的路径 @@ -105,7 +105,7 @@ async function refreshGuestToken(baseUrl: string): Promise { const response = await fetch(`${baseUrl}${ApiPath.guestLogin}`, { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ deviceId }), + body: JSON.stringify(withTestAccountFlag({ deviceId })), }); if (!response.ok) { @@ -125,6 +125,12 @@ async function refreshGuestToken(baseUrl: string): Promise { } } +function withTestAccountFlag>( + payload: T, +): T & { isTestAccount: boolean } { + return { ...payload, isTestAccount: !AppEnvUtil.isProduction() }; +} + /** * 401 → 刷新 token 并重试 */ diff --git a/src/data/dto/auth/apple_login_request.ts b/src/data/dto/auth/apple_login_request.ts index 218a38ad..7416506e 100644 --- a/src/data/dto/auth/apple_login_request.ts +++ b/src/data/dto/auth/apple_login_request.ts @@ -10,6 +10,7 @@ import { export class AppleLoginRequest { declare readonly identityToken: string; declare readonly platform: string; + declare readonly isTestAccount: boolean; private constructor(input: AppleLoginRequestInput) { const data = AppleLoginRequestSchema.parse(input); diff --git a/src/data/dto/auth/facebook_login_request.ts b/src/data/dto/auth/facebook_login_request.ts index 2a96eb59..fdff17ad 100644 --- a/src/data/dto/auth/facebook_login_request.ts +++ b/src/data/dto/auth/facebook_login_request.ts @@ -11,6 +11,7 @@ export class FacebookLoginRequest { declare readonly accessToken: string; declare readonly platform: string; declare readonly guestId: string; + declare readonly isTestAccount: boolean; private constructor(input: FacebookLoginRequestInput) { const data = FacebookLoginRequestSchema.parse(input); diff --git a/src/data/dto/auth/fb_id_login_request.ts b/src/data/dto/auth/fb_id_login_request.ts index f0f26430..82642114 100644 --- a/src/data/dto/auth/fb_id_login_request.ts +++ b/src/data/dto/auth/fb_id_login_request.ts @@ -10,6 +10,7 @@ import { export class FbIdLoginRequest { declare readonly fbId: string; declare readonly avatarUrl: string; + declare readonly isTestAccount: boolean; private constructor(input: FbIdLoginRequestInput) { const data = FbIdLoginRequestSchema.parse(input); diff --git a/src/data/dto/auth/google_login_request.ts b/src/data/dto/auth/google_login_request.ts index 0dbcba5b..964f72a3 100644 --- a/src/data/dto/auth/google_login_request.ts +++ b/src/data/dto/auth/google_login_request.ts @@ -11,6 +11,7 @@ export class GoogleLoginRequest { declare readonly idToken: string; declare readonly platform: string; declare readonly guestId: string; + declare readonly isTestAccount: boolean; private constructor(input: GoogleLoginRequestInput) { const data = GoogleLoginRequestSchema.parse(input); diff --git a/src/data/dto/auth/guest_login_request.ts b/src/data/dto/auth/guest_login_request.ts index d01274cd..28d98341 100644 --- a/src/data/dto/auth/guest_login_request.ts +++ b/src/data/dto/auth/guest_login_request.ts @@ -9,6 +9,7 @@ import { export class GuestLoginRequest { declare readonly deviceId: string; + declare readonly isTestAccount: boolean; private constructor(input: GuestLoginRequestInput) { const data = GuestLoginRequestSchema.parse(input); diff --git a/src/data/dto/auth/login_request.ts b/src/data/dto/auth/login_request.ts index 4c69cba4..a5f84a74 100644 --- a/src/data/dto/auth/login_request.ts +++ b/src/data/dto/auth/login_request.ts @@ -13,6 +13,7 @@ export class LoginRequest { declare readonly password: string; declare readonly platform: string; declare readonly guestId: string; + declare readonly isTestAccount: boolean; private constructor(input: LoginRequestInput) { const data = LoginRequestSchema.parse(input); diff --git a/src/data/dto/auth/register_request.ts b/src/data/dto/auth/register_request.ts index 856ed5a3..dc8c4236 100644 --- a/src/data/dto/auth/register_request.ts +++ b/src/data/dto/auth/register_request.ts @@ -13,6 +13,7 @@ export class RegisterRequest { declare readonly password: string; declare readonly platform: string; declare readonly guestId: string; + declare readonly isTestAccount: boolean; private constructor(input: RegisterRequestInput) { const data = RegisterRequestSchema.parse(input); diff --git a/src/data/repositories/auth_repository.ts b/src/data/repositories/auth_repository.ts index 409604bb..a228e10d 100644 --- a/src/data/repositories/auth_repository.ts +++ b/src/data/repositories/auth_repository.ts @@ -28,7 +28,7 @@ import { SendCodeRequest, } from "@/data/dto/auth"; import { User } from "@/data/dto/user"; -import { Result, Logger } from "@/utils"; +import { AppEnvUtil, Result, Logger } from "@/utils"; import type { IAuthRepository } from "@/data/repositories/interfaces"; import { AuthStorage, type IAuthStorage } from "@/data/storage/auth"; import { UserStorage, type IUserStorage } from "@/data/storage/user"; @@ -37,6 +37,7 @@ const log = new Logger("DataRepositoriesAuthRepository"); /** 硬编码平台名,对齐 Dart `PlatformUtil.platformName.toLowerCase()`(Web 平台)。 */ const WEB_PLATFORM = "web"; +const TEST_ACCOUNT_FLAG = "isTestAccount"; export class AuthRepository implements IAuthRepository { constructor( @@ -59,13 +60,15 @@ export class AuthRepository implements IAuthRepository { }): Promise> { return Result.wrap(async () => { await this.api.register( - RegisterRequest.from({ - username: input.username, - email: input.email, - password: input.password, - platform: WEB_PLATFORM, - guestId: input.guestId ?? "", - }), + RegisterRequest.from( + withTestAccountFlag({ + username: input.username, + email: input.email, + password: input.password, + platform: WEB_PLATFORM, + guestId: input.guestId ?? "", + }), + ), ); }); } @@ -79,13 +82,15 @@ export class AuthRepository implements IAuthRepository { }): Promise> { return Result.wrap(async () => { const response = await this.api.emailLogin( - LoginRequest.from({ - email: input.email ?? "", - username: input.username ?? "", - password: input.password, - platform: WEB_PLATFORM, - guestId: input.guestId ?? "", - }), + LoginRequest.from( + withTestAccountFlag({ + email: input.email ?? "", + username: input.username ?? "", + password: input.password, + platform: WEB_PLATFORM, + guestId: input.guestId ?? "", + }), + ), ); await this._saveLoginData(response); return response; @@ -131,7 +136,7 @@ export class AuthRepository implements IAuthRepository { }); return Result.wrap(async () => { const response = await this.api.guestLogin( - GuestLoginRequest.from({ deviceId }), + GuestLoginRequest.from(withTestAccountFlag({ deviceId })), ); log.debug("[AuthRepository.guestLogin] API call SUCCESS (Zod parsed)", { hasToken: !!response.token, @@ -160,11 +165,13 @@ export class AuthRepository implements IAuthRepository { }): Promise> { return this._socialLogin(() => this.api.googleLogin( - GoogleLoginRequest.from({ - idToken: input.idToken, - platform: WEB_PLATFORM, - guestId: input.guestId ?? "", - }), + GoogleLoginRequest.from( + withTestAccountFlag({ + idToken: input.idToken, + platform: WEB_PLATFORM, + guestId: input.guestId ?? "", + }), + ), ), ); } @@ -176,11 +183,13 @@ export class AuthRepository implements IAuthRepository { }): Promise> { return this._socialLogin(() => this.api.facebookLogin( - FacebookLoginRequest.from({ - accessToken: input.accessToken, - platform: WEB_PLATFORM, - guestId: input.guestId ?? "", - }), + FacebookLoginRequest.from( + withTestAccountFlag({ + accessToken: input.accessToken, + platform: WEB_PLATFORM, + guestId: input.guestId ?? "", + }), + ), ), ); } @@ -192,10 +201,12 @@ export class AuthRepository implements IAuthRepository { }): Promise> { return this._socialLogin(() => this.api.facebookIdLogin( - FbIdLoginRequest.from({ - fbId: input.fbId, - avatarUrl: input.avatarUrl ?? "", - }), + FbIdLoginRequest.from( + withTestAccountFlag({ + fbId: input.fbId, + avatarUrl: input.avatarUrl ?? "", + }), + ), ), ); } @@ -208,10 +219,12 @@ export class AuthRepository implements IAuthRepository { async appleLogin(identityToken: string): Promise> { return this._socialLogin(() => this.api.appleLogin( - AppleLoginRequest.from({ - identityToken, - platform: WEB_PLATFORM, - }), + AppleLoginRequest.from( + withTestAccountFlag({ + identityToken, + platform: WEB_PLATFORM, + }), + ), ), ); } @@ -305,3 +318,12 @@ export const authRepository = new AuthRepository( AuthStorage.getInstance(), UserStorage.getInstance(), ); + +function withTestAccountFlag>( + payload: T, +): T & { isTestAccount: boolean } { + return { + ...payload, + [TEST_ACCOUNT_FLAG]: !AppEnvUtil.isProduction(), + }; +} diff --git a/src/data/schemas/auth/apple_login_request.ts b/src/data/schemas/auth/apple_login_request.ts index 09da28e1..7edbb09c 100644 --- a/src/data/schemas/auth/apple_login_request.ts +++ b/src/data/schemas/auth/apple_login_request.ts @@ -7,6 +7,7 @@ import { z } from "zod"; export const AppleLoginRequestSchema = z.object({ identityToken: z.string(), platform: z.string(), + isTestAccount: z.boolean().default(false), }); export type AppleLoginRequestInput = z.input; diff --git a/src/data/schemas/auth/facebook_login_request.ts b/src/data/schemas/auth/facebook_login_request.ts index 074014ac..48af4794 100644 --- a/src/data/schemas/auth/facebook_login_request.ts +++ b/src/data/schemas/auth/facebook_login_request.ts @@ -8,6 +8,7 @@ export const FacebookLoginRequestSchema = z.object({ accessToken: z.string(), platform: z.string(), guestId: z.string().default(""), + isTestAccount: z.boolean().default(false), }); export type FacebookLoginRequestInput = z.input; diff --git a/src/data/schemas/auth/fb_id_login_request.ts b/src/data/schemas/auth/fb_id_login_request.ts index d9207346..3efcf151 100644 --- a/src/data/schemas/auth/fb_id_login_request.ts +++ b/src/data/schemas/auth/fb_id_login_request.ts @@ -7,6 +7,7 @@ import { z } from "zod"; export const FbIdLoginRequestSchema = z.object({ fbId: z.string(), avatarUrl: z.string().default(""), + isTestAccount: z.boolean().default(false), }); export type FbIdLoginRequestInput = z.input; diff --git a/src/data/schemas/auth/google_login_request.ts b/src/data/schemas/auth/google_login_request.ts index d39cd0dd..b3d81947 100644 --- a/src/data/schemas/auth/google_login_request.ts +++ b/src/data/schemas/auth/google_login_request.ts @@ -8,6 +8,7 @@ export const GoogleLoginRequestSchema = z.object({ idToken: z.string(), platform: z.string(), guestId: z.string().default(""), + isTestAccount: z.boolean().default(false), }); export type GoogleLoginRequestInput = z.input; diff --git a/src/data/schemas/auth/guest_login_request.ts b/src/data/schemas/auth/guest_login_request.ts index 09bba9d9..d67bf0d5 100644 --- a/src/data/schemas/auth/guest_login_request.ts +++ b/src/data/schemas/auth/guest_login_request.ts @@ -6,6 +6,7 @@ import { z } from "zod"; export const GuestLoginRequestSchema = z.object({ deviceId: z.string(), + isTestAccount: z.boolean().default(false), }); export type GuestLoginRequestInput = z.input; diff --git a/src/data/schemas/auth/login_request.ts b/src/data/schemas/auth/login_request.ts index bcea9aa6..bdbcc324 100644 --- a/src/data/schemas/auth/login_request.ts +++ b/src/data/schemas/auth/login_request.ts @@ -10,6 +10,7 @@ export const LoginRequestSchema = z.object({ password: z.string(), platform: z.string(), guestId: z.string().default(""), + isTestAccount: z.boolean().default(false), }); export type LoginRequestInput = z.input; diff --git a/src/data/schemas/auth/register_request.ts b/src/data/schemas/auth/register_request.ts index 7ed90574..7afec37b 100644 --- a/src/data/schemas/auth/register_request.ts +++ b/src/data/schemas/auth/register_request.ts @@ -10,6 +10,7 @@ export const RegisterRequestSchema = z.object({ password: z.string(), platform: z.string(), guestId: z.string().default(""), + isTestAccount: z.boolean().default(false), }); export type RegisterRequestInput = z.input;