refactor(auth): funnel OAuth signIn into auth state machine

Move new AuthPlatform(provider).signIn() out of UI components and into
the auth state machine. UI now dispatches AuthGoogle/FacebookLoginSubmitted
events; a new oauthSignIn actor inside the machine calls next-auth/react's
signIn(provider). Errors and the OAuth redirect window are exposed via
the existing state.isLoading / state.errorMessage surface, removing the
local busy / error state in auth-facebook-panel.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
kanban
2026-06-11 10:05:14 +08:00
committed by chenhang
parent d4cb40a74b
commit e2a57386e7
6 changed files with 274 additions and 54 deletions
+40 -7
View File
@@ -3,12 +3,14 @@
*
* 原始 Dart: lib/ui/auth/bloc/auth_bloc.dart + auth_state.dart + auth_event.dart
*
* 本轮迁移:社交登录改由 NextAuth 处理(`@/lib/auth/nextauth`),状态机仅保留
* 邮箱注册/登录 + 通用 reset 事件。社交登录走 `new AuthPlatform("google").signIn()` /
* `new AuthPlatform("facebook").signIn()`
* 本轮迁移:所有认证登录调用(含 OAuth 社交登录)统一收口到状态机内。
* 业务层只派发事件(`AuthEmailLoginSubmitted` / `AuthGoogleLoginSubmitted` / 等),
* 状态机通过 actors 调 `authRepository`(邮箱)或 `next-auth/react.signIn`OAuth
*/
import { setup, fromPromise, assign } from "xstate";
import { signIn } from "next-auth/react";
import type { AuthProvider } from "@/lib/auth/auth_platform";
import type { LoginType } from "@/models/auth/login-type";
import { authRepository } from "@/data/repositories/auth_repository";
import { AuthStorage } from "@/data/storage/auth/auth_storage";
@@ -68,6 +70,13 @@ const emailRegisterThenLoginActor = fromPromise<
return "email" as LoginType;
});
// OAuth 登录 actor:调 next-auth/react 的 signIn(provider) 触发 OAuth 跳转。
// 成功路径下 NextAuth 会重定向离开本应用,actor 通常不会 resolve
// onDone 仍保留以处理 SDK 同步返回(极少见)。
const oauthSignInActor = fromPromise<void, AuthProvider>(async ({ input }) => {
await signIn(input);
});
// ============================================================
// Machine
// ============================================================
@@ -79,6 +88,7 @@ export const authMachine = setup({
actors: {
emailLogin: emailLoginActor,
emailRegisterThenLogin: emailRegisterThenLoginActor,
oauthSignIn: oauthSignInActor,
},
}).createMachine({
id: "auth",
@@ -113,10 +123,8 @@ export const authMachine = setup({
},
AuthEmailLoginSubmitted: "loadingEmailLogin",
AuthEmailRegisterSubmitted: "loadingEmailRegister",
// 社交登录已迁移到 NextAuth + AuthPlatform 类
// 状态机保留事件以兼容旧调用方(实际不再触发)
AuthGoogleLoginSubmitted: {},
AuthFacebookLoginSubmitted: {},
AuthGoogleLoginSubmitted: "loadingOAuth",
AuthFacebookLoginSubmitted: "loadingOAuth",
AuthAppleLoginSubmitted: {
actions: assign({
errorMessage: "Apple login not implemented",
@@ -180,6 +188,31 @@ export const authMachine = setup({
},
},
loadingOAuth: {
entry: assign({ errorMessage: null }),
invoke: {
src: "oauthSignIn",
input: ({ event }) => {
// event 来自 idle 跳转(AuthGoogle/FacebookLoginSubmitted
if (event.type === "AuthGoogleLoginSubmitted") return event.provider;
if (event.type === "AuthFacebookLoginSubmitted") return event.provider;
return "google" as AuthProvider;
},
onDone: {
// 罕见分支:NextAuth 同步 resolve(实际几乎不会发生,
// OAuth 流程会通过重定向离开本应用)。
target: "idle",
},
onError: {
target: "idle",
actions: assign({
errorMessage: ({ event }) =>
event.error instanceof Error ? event.error.message : String(event.error),
}),
},
},
},
success: {
// 终态:业务层通过 state.matches("success") 判断
},