79 lines
2.2 KiB
Swift
79 lines
2.2 KiB
Swift
//
|
|
// AuthService.swift
|
|
// Snail
|
|
//
|
|
|
|
import Foundation
|
|
|
|
nonisolated struct User: Codable, Identifiable, Hashable, Sendable {
|
|
let id: String
|
|
let name: String
|
|
let email: String
|
|
let emailVerified: Bool
|
|
let image: String?
|
|
let createdAt: Date
|
|
|
|
/// При входе по коду better-auth создаёт пользователя с пустым именем.
|
|
var displayName: String {
|
|
name.trimmingCharacters(in: .whitespaces).isEmpty ? email : name
|
|
}
|
|
|
|
var initials: String {
|
|
let source = name.trimmingCharacters(in: .whitespaces).isEmpty ? email : name
|
|
let letters = source
|
|
.split(whereSeparator: { $0 == " " || $0 == "@" || $0 == "." })
|
|
.prefix(2)
|
|
.compactMap(\.first)
|
|
return String(letters).uppercased()
|
|
}
|
|
}
|
|
|
|
/// Эндпоинты better-auth (плагин emailOTP) и профиля.
|
|
nonisolated struct AuthService: Sendable {
|
|
private let client: APIClient
|
|
|
|
init(client: APIClient = APIClient()) {
|
|
self.client = client
|
|
}
|
|
|
|
func sendSignInCode(to email: String) async throws {
|
|
let _: SuccessResponse = try await client.send(
|
|
"POST",
|
|
"auth/email-otp/send-verification-otp",
|
|
body: ["email": email, "type": "sign-in"]
|
|
)
|
|
}
|
|
|
|
func signIn(email: String, code: String) async throws -> User {
|
|
let response: UserResponse = try await client.send(
|
|
"POST",
|
|
"auth/sign-in/email-otp",
|
|
body: ["email": email, "otp": code]
|
|
)
|
|
return response.user
|
|
}
|
|
|
|
/// Текущий пользователь или nil, если сессии нет.
|
|
func currentUser() async throws -> User? {
|
|
do {
|
|
let response: Envelope<UserResponse> = try await client.send("GET", "users/me")
|
|
return response.data.user
|
|
} catch APIError.unauthorized {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func signOut() async {
|
|
let _: SuccessResponse? = try? await client.send("POST", "auth/sign-out", body: [:])
|
|
client.clearCookies()
|
|
}
|
|
}
|
|
|
|
private nonisolated struct SuccessResponse: Decodable {
|
|
let success: Bool
|
|
}
|
|
|
|
private nonisolated struct UserResponse: Decodable {
|
|
let user: User
|
|
}
|