Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

import Foundation
import Domain

/// Keychain + UserDefaults를 감싼 세션 저장소
public final class SessionStoreRepository: SessionStoreRepositoryProtocol, @unchecked Sendable {
Expand All @@ -17,7 +18,7 @@ public final class SessionStoreRepository: SessionStoreRepositoryProtocol, @unch

public init() {}

public func save(tokens: AuthTokens, socialType: SocialType?, userId: String?) {
public func save(tokens: AuthTokens, socialType: SocialType?, userId: String?) async {
KeychainManager.shared.saveTokens(
accessToken: tokens.accessToken,
refreshToken: tokens.refreshToken
Expand All @@ -35,7 +36,7 @@ public final class SessionStoreRepository: SessionStoreRepositoryProtocol, @unch
}
}

public func loadTokens() -> AuthTokens? {
public func loadTokens() async -> AuthTokens? {
let tokens = KeychainManager.shared.loadTokens()
guard let access = tokens.accessToken,
let refresh = tokens.refreshToken
Expand All @@ -50,16 +51,16 @@ public final class SessionStoreRepository: SessionStoreRepositoryProtocol, @unch
)
}

public func loadSocialType() -> SocialType? {
public func loadSocialType() async -> SocialType? {
guard let raw = UserDefaults.standard.string(forKey: Keys.socialType) else { return nil }
return SocialType(rawValue: raw)
}

public func loadUserId() -> String? {
public func loadUserId() async -> String? {
UserDefaults.standard.string(forKey: Keys.userId)
}

public func clearAll() {
public func clearAll() async {
KeychainManager.shared.clearAll()
UserDefaults.standard.removeObject(forKey: Keys.sessionId)
UserDefaults.standard.removeObject(forKey: Keys.socialType)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// MockSessionStoreRepository.swift
// DomainTests
//
// Created by Wonji Suh on 12/17/25.
//

import Foundation

final class MockSessionStoreRepository: SessionStoreRepositoryProtocol, @unchecked Sendable {
private var savedTokens: AuthTokens?
private var savedSocialType: SocialType?
private var savedUserId: String?
private(set) var didClear = false

func save(tokens: AuthTokens, socialType: SocialType?, userId: String?) async {
savedTokens = tokens
savedSocialType = socialType
savedUserId = userId
}

func loadTokens() async -> AuthTokens? { savedTokens }
func loadSocialType() async -> SocialType? { savedSocialType }
func loadUserId() async -> String? { savedUserId }

func clearAll() async {
didClear = true
savedTokens = nil
savedSocialType = nil
savedUserId = nil
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// SessionStoreRepositoryProtocol.swift
// Domain
//
// Created by Wonji Suh on 12/11/25.
//

import Foundation
import ComposableArchitecture

public protocol SessionStoreRepositoryProtocol: Sendable {
func save(tokens: AuthTokens, socialType: SocialType?, userId: String?) async
func loadTokens() async -> AuthTokens?
func loadSocialType() async -> SocialType?
func loadUserId() async -> String?
func clearAll() async
}


public struct SessionStoreRepositoryDependency: DependencyKey {
public static var liveValue: SessionStoreRepositoryProtocol {
fatalError("AuthRepositoryDependency liveValue not implemented")
}
public static var previewValue: SessionStoreRepositoryProtocol = MockSessionStoreRepository()
public static var testValue: SessionStoreRepositoryProtocol = MockSessionStoreRepository()
}

public extension DependencyValues {
var sessionStoreRepository: SessionStoreRepositoryProtocol {
get { self[SessionStoreRepositoryDependency.self] }
set { self[SessionStoreRepositoryDependency.self] = newValue }
}
}
30 changes: 30 additions & 0 deletions Domain/Sources/UseCase/Auth/AuthUseCase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,26 @@ public struct AuthUseCase: AuthUseCaseProtocol {
@Shared(.appStorage("sessionId")) var sessionId: String? = ""

@Dependency(\.authRepository) private var repository: AuthRepositoryProtocol
@Dependency(\.authRepository) private var authRepository: AuthRepositoryProtocol
@Dependency(\.tokenStorageUseCase) private var tokenStorageUseCase: TokenStorageUseCase


public init() {}

// MARK: - 로그인
public func login(_ authData: AuthData) async -> Result<AuthResult, AuthError> {
do {
let input = makeOAuthInput(from: authData)
var authResult = try await authRepository.login(input: input)
authResult.token.authToken = authData.authToken
await tokenStorageUseCase.save(auth: authResult)
return .success(authResult)
} catch {
let authError = error as? AuthError ?? .unknownError(error.localizedDescription)
return .failure(authError)
}
}

// MARK: - 로그아웃
public func logout() async throws -> LogoutStatus {
let sessionId = self.sessionId ?? ""
Expand All @@ -28,6 +46,18 @@ public struct AuthUseCase: AuthUseCaseProtocol {
}
}

private extension AuthUseCase {
func makeOAuthInput(from authData: AuthData) -> OAuthUserInput {
OAuthUserInput(
accessToken: authData.authToken,
socialType: authData.socialType,
authorizationCode: authData.authorizationCode,
codeVerifier: authData.codeVerifier,
redirectUri: authData.redirectUri
)
}
}


extension AuthUseCase: DependencyKey {
public static let liveValue: AuthUseCaseProtocol = AuthUseCase()
Expand Down
1 change: 1 addition & 0 deletions Domain/Sources/UseCase/Auth/AuthUseCaseProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ import Foundation
public protocol AuthUseCaseProtocol {
func logout() async throws -> LogoutStatus
func deleteUser() async throws -> AuthDeleteStatus
func login(_ authData: AuthData) async -> Result<AuthResult, AuthError>
}
Loading
Loading