refactor(auth): unify Facebook and Google login into AuthPlatform class

Replace the separate FacebookLogin and GoogleLogin classes with a single
AuthPlatform class that takes a provider name ("facebook" | "google") as a
constructor argument. This consolidates duplicate OAuth sign-in logic behind
one entry point while preserving the existing NextAuth flow.

- Add new src/lib/auth/auth_platform.ts exporting AuthPlatform and
  AuthProvider type
- Update auth-facebook-panel.tsx and splash-button.tsx to use the new API
- Rename initialContext → initialState in the auth machine for consistency
- Update inline docs and comments to reference AuthPlatform

No behavioral change for end users; both providers still route through
NextAuth's signIn() with the same callbacks and cookies.
This commit is contained in:
2026-06-10 18:58:15 +08:00
parent 744e23fc29
commit 47591be41c
30 changed files with 111 additions and 117 deletions
-189
View File
@@ -1,189 +0,0 @@
/**
* Auth 状态机(XState v5
*
* 原始 Dart: lib/ui/auth/bloc/auth_bloc.dart + auth_state.dart + auth_event.dart
*
* 本轮迁移:社交登录改由 NextAuth 处理(`@/lib/auth/nextauth`),状态机仅保留
* 邮箱注册/登录 + 通用 reset 事件。社交登录走 `new GoogleLogin().signIn()` /
* `new FacebookLogin().signIn()`。
*/
import { setup, fromPromise, assign } from "xstate";
import type { LoginType } from "@/models/auth/login-type";
import { authRepository } from "@/data/repositories/auth_repository";
import { AuthStorage } from "@/data/storage/auth/auth_storage";
import { Result } from "@/utils/result";
import { AuthContext, initialContext } from "./auth-context";
import type { AuthEvent } from "./auth-events";
// 重新导出 Context / Event 类型,保持 machine 文件的公共 API 不变
export type { AuthContext } from "./auth-context";
export { initialContext } from "./auth-context";
export type { AuthEvent } from "./auth-events";
// ============================================================
// Helpers
// ============================================================
async function readGuestId(): Promise<string | undefined> {
const r = await AuthStorage.getInstance().getDeviceId();
if (r.success && r.data != null) {
return r.data;
}
return undefined;
}
// ============================================================
// Actors(异步服务)
// ============================================================
// 邮箱登录 actor 仅调 authRepository.emailLogin 拿业务 token。
// 本轮起不再调 /api/auth/marker 写 cookie(统一迁到 NextAuth session
// cookie 检测,邮箱登录 proxy 行为在后续轮恢复)。
const emailLoginActor = fromPromise<LoginType, { email: string; password: string }>(
async ({ input }) => {
const guestId = await readGuestId();
const result = await authRepository.emailLogin({ ...input, guestId });
if (Result.isErr(result)) throw result.error;
return "email" as LoginType;
},
);
const emailRegisterThenLoginActor = fromPromise<
LoginType,
{ email: string; password: string; username: string; confirmPassword: string }
>(async ({ input }) => {
const guestId = await readGuestId();
const registerResult = await authRepository.register({ ...input, guestId });
if (Result.isErr(registerResult)) throw registerResult.error;
// 注册后自动登录(对齐 Dart 行为)
const loginResult = await authRepository.emailLogin({
email: input.email,
password: input.password,
guestId,
});
if (Result.isErr(loginResult)) throw loginResult.error;
return "email" as LoginType;
});
// ============================================================
// Machine
// ============================================================
export const authMachine = setup({
types: {
context: {} as AuthContext,
events: {} as AuthEvent,
},
actors: {
emailLogin: emailLoginActor,
emailRegisterThenLogin: emailRegisterThenLoginActor,
},
}).createMachine({
id: "auth",
initial: "idle",
context: initialContext,
states: {
idle: {
on: {
AuthPanelModeChanged: {
actions: assign({
authPanelMode: ({ event }) => event.mode,
errorMessage: null,
}),
},
AuthModeChanged: {
actions: assign({
authMode: ({ event }) => event.mode,
errorMessage: null,
}),
},
AuthFormCleared: {
actions: assign({
email: "",
password: "",
username: "",
confirmPassword: "",
errorMessage: null,
}),
},
AuthReset: {
actions: assign(() => initialContext),
},
AuthEmailLoginSubmitted: "loadingEmailLogin",
AuthEmailRegisterSubmitted: "loadingEmailRegister",
// 社交登录已迁移到 NextAuth + GoogleLogin / FacebookLogin 类
// 状态机保留事件以兼容旧调用方(实际不再触发)
AuthGoogleLoginSubmitted: {},
AuthFacebookLoginSubmitted: {},
AuthAppleLoginSubmitted: {
actions: assign({
errorMessage: "Apple login not implemented",
}),
},
},
},
loadingEmailLogin: {
invoke: {
src: "emailLogin",
input: ({ event }) => {
if (event.type !== "AuthEmailLoginSubmitted")
return { email: "", password: "" };
return { email: event.email, password: event.password };
},
onDone: {
target: "success",
actions: assign({
loginType: ({ event }) => event.output,
errorMessage: null,
}),
},
onError: {
target: "idle",
actions: assign({
errorMessage: ({ event }) =>
event.error instanceof Error ? event.error.message : String(event.error),
}),
},
},
},
loadingEmailRegister: {
invoke: {
src: "emailRegisterThenLogin",
input: ({ event }) => {
if (event.type !== "AuthEmailRegisterSubmitted")
return { email: "", password: "", username: "", confirmPassword: "" };
return {
email: event.email,
password: event.password,
username: event.username,
confirmPassword: event.confirmPassword,
};
},
onDone: {
target: "success",
actions: assign({
loginType: ({ event }) => event.output,
errorMessage: null,
}),
},
onError: {
target: "idle",
actions: assign({
errorMessage: ({ event }) =>
event.error instanceof Error ? event.error.message : String(event.error),
}),
},
},
},
success: {
// 终态:业务层通过 state.matches("success") 判断
},
},
});
export type AuthMachine = typeof authMachine;