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
10 changes: 5 additions & 5 deletions Sources/Core/NXCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@

import Foundation

/// Response cache behavior for successful GET responses and in-flight identical requests.
/// 성공한 GET 응답과 진행 중인 동일 요청에 대한 응답 캐시 동작입니다.
public enum NXCache: Sendable, Equatable {
/// Does not cache responses and executes identical requests separately.
/// 응답을 캐시하지 않고 동일한 요청을 각각 별도로 실행합니다.
case disabled
/// Stores successful GET responses in memory for the specified TTL and reuses in-flight identical GET request results without validator revalidation.
/// 지정된 TTL 동안 성공한 GET 응답을 메모리에 저장하고, 검증자 재검증 없이 진행 중인 동일 GET 요청 결과를 재사용합니다.
case memory(ttl: TimeInterval)
/// Stores successful GET responses in memory for the specified TTL and revalidates expired validator-backed `200` responses.
/// 지정된 TTL 동안 성공한 GET 응답을 메모리에 저장하고, 만료된 검증자 기반 `200` 응답을 재검증합니다.
///
/// The cache belongs to the `NXAPIClient` instance that receives this policy. Recreating the client creates an independent cache.
/// 캐시는 이 정책을 받는 `NXAPIClient` 인스턴스에 속합니다. 클라이언트를 다시 생성하면 독립적인 캐시가 생깁니다.
case revalidatingMemory(ttl: TimeInterval)
}
48 changes: 24 additions & 24 deletions Sources/Core/NXClientConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@

import Foundation

/// Shared configuration applied to every request created by an API client.
/// API 클라이언트가 생성하는 모든 요청에 적용되는 공통 설정입니다.
///
/// ## Overview
/// ## 개요
///
/// Put shared networking behavior here once, then reuse it through `NXAPIClient`.
/// 공통 네트워킹 동작을 한 곳에 정의하고 `NXAPIClient`를 통해 재사용하세요.
///
/// ```swift
/// import Foundation
Expand All @@ -30,40 +30,40 @@ import Foundation
/// let client = NXAPIClient(configuration: configuration)
/// ```
public struct NXClientConfiguration: Sendable {
/// Base URL used to resolve relative request paths.
/// 상대 경로 요청을 해석할 때 사용하는 기본 URL입니다.
public let baseURL: URL
/// Headers added to every request. Request-level headers overwrite these if keys conflict.
/// 모든 요청에 추가되는 헤더입니다. 키가 겹치면 요청 단위 헤더가 이 헤더를 덮어씁니다.
public let headers: [String: String]
/// Transport used to execute the assembled `URLRequest`.
/// 조립된 `URLRequest` 실행에 사용하는 전송 계층입니다.
public let transport: any NXHTTPTransport
/// Logger that receives request lifecycle events.
/// 요청 라이프사이클 이벤트를 수신하는 로거입니다.
public let logger: any NXLogger
/// Interceptors applied to every request.
/// 모든 요청에 적용되는 인터셉터입니다.
public let interceptors: [any NXHTTPInterceptor]
/// Response cache behavior for successful GET responses and in-flight identical requests.
/// 성공한 GET 응답과 진행 중인 동일 요청에 대한 캐시 동작입니다.
public let cache: NXCache
/// Decoder used by typed requests to decode the response body.
/// 타입 지정 요청에서 응답 본문을 디코딩할 때 사용하는 디코더입니다.
public let decoder: JSONDecoder
/// Encoder used for JSON request bodies when no encoder is passed to `json(_:encoder:)`.
/// `json(_:encoder:)`에 인코더가 전달되지 않을 때 JSON 요청 본문을 만드는 인코더입니다.
public let encoder: JSONEncoder
/// Decoder that can map failed server responses into domain-specific errors.
/// 실패한 서버 응답을 도메인 전용 오류로 매핑할 수 있는 디코더입니다.
public let serverErrorDecoder: any NXServerErrorDecoder
/// Provider used by authenticated requests to fetch and refresh bearer tokens.
/// 인증 요청에서 베어러 토큰을 조회하고 갱신하는 데 사용하는 공급자입니다.
public let authTokenProvider: (any NXAuthTokenProvider)?

/// Creates a client configuration.
/// 클라이언트 구성을 생성합니다.
///
/// - Parameters:
/// - baseURL: Base URL used to resolve relative request paths.
/// - headers: Headers added to every request.
/// - transport: Transport used to execute requests.
/// - logger: Logger that receives request lifecycle events.
/// - interceptors: Interceptors applied to every request.
/// - cache: Response cache behavior for successful GET responses and in-flight identical requests.
/// - decoder: Decoder used for typed responses.
/// - encoder: Encoder used for JSON request bodies.
/// - serverErrorDecoder: Decoder used to map failed responses to custom errors.
/// - authTokenProvider: Provider used for authenticated requests.
/// - baseURL: 상대 경로 요청을 해석할 때 사용하는 기본 URL입니다.
/// - headers: 모든 요청에 추가되는 헤더입니다.
/// - transport: 요청 실행을 담당하는 전송 계층입니다.
/// - logger: 요청 라이프사이클 이벤트를 받는 로거입니다.
/// - interceptors: 모든 요청에 적용되는 인터셉터 목록입니다.
/// - cache: 성공한 GET 응답 및 진행 중인 동일 요청에 대한 캐시 동작입니다.
/// - decoder: 타입 지정 응답 디코딩에 사용하는 디코더입니다.
/// - encoder: JSON 요청 본문 인코딩에 사용하는 인코더입니다.
/// - serverErrorDecoder: 실패 응답을 커스텀 오류로 매핑하는 디코더입니다.
/// - authTokenProvider: 인증 요청에 사용되는 공급자입니다.
public init(
baseURL: URL,
headers: [String: String] = [:],
Expand Down
22 changes: 11 additions & 11 deletions Sources/Core/NXError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,26 @@

import Foundation

/// Errors produced by Nexa while assembling, sending, validating, or decoding requests.
/// Nexa가 요청 조립, 전송, 유효성 검사, 디코딩 과정에서 발생시키는 오류입니다.
public enum NXError: Error, Sendable {
/// Request assembly failed because the input could not produce a valid HTTP request.
/// 입력으로 유효한 HTTP 요청을 만들 수 없어 요청 조립이 실패했습니다.
case invalidRequest(String)
/// The request required authentication but no token was available.
/// 요청에 인증이 필요했지만 사용 가능한 토큰이 없습니다.
case authenticationRequired
/// The request required authentication but no auth token provider was configured.
/// 요청에 인증이 필요했지만 인증 토큰 공급자가 설정되지 않았습니다.
case authProviderUnavailable
/// The underlying transport failed with a `URLError`.
/// 전송 계층에서 `URLError`가 발생했습니다.
case transport(URLError)
/// The request timed out.
/// 요청이 시간 초과되었습니다.
case timeout
/// The request was cancelled.
/// 요청이 취소되었습니다.
case cancelled
/// Response validation failed for the received status code.
/// 수신한 상태 코드에 대한 응답 유효성 검사가 실패했습니다.
case invalidStatus(statusCode: Int, data: Data?)
/// The server returned a failing status code and a custom server error was decoded.
/// 서버가 실패 상태 코드를 반환했고 사용자 정의 서버 오류로 디코딩되었습니다.
case server(statusCode: Int, data: Data?, underlying: any Error)
/// Response decoding failed for a successful request.
/// 성공한 요청의 응답 디코딩이 실패했습니다.
case decoding(any Error, data: Data?)
/// An uncategorized error occurred.
/// 분류되지 않은 오류가 발생했습니다.
case unknown(any Error)
}
2 changes: 1 addition & 1 deletion Sources/Core/NXHTTPMethod.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import Foundation

/// HTTP methods supported by Nexa request builders.
/// Nexa 요청 빌더가 지원하는 HTTP 메서드입니다.
public enum NXHTTPMethod: String, Sendable, Hashable {
case get = "GET"
case post = "POST"
Expand Down
74 changes: 37 additions & 37 deletions Sources/Core/NXLogging.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import Foundation

/// Request lifecycle events emitted by Nexa loggers.
/// Nexa 로거가 내보내는 요청 라이프사이클 이벤트입니다.
public enum NXLogEvent: Sendable {
case requestStart(NXRequestStartLog)
case requestEnd(NXRequestEndLog)
Expand All @@ -16,20 +16,20 @@ public enum NXLogEvent: Sendable {
case authRefresh(NXAuthRefreshLog)
}

/// Structured payload emitted when a request attempt starts.
/// 요청 시도 시작 시점에 출력되는 구조화된 페이로드입니다.
public struct NXRequestStartLog: Sendable {
/// Stable identifier shared by all attempts of the same logical request.
/// 동일한 논리 요청의 모든 시도에서 공유되는 안정적 식별자입니다.
public let requestIdentifier: UUID
/// Current attempt number starting from `1`.
/// 현재 시도 번호(`1`부터 시작)입니다.
public let attemptNumber: Int
/// HTTP method string for the outgoing request.
/// 전송할 요청의 HTTP 메서드 문자열입니다.
public let method: String
/// Fully resolved request URL string.
/// 완전히 해석된 요청 URL 문자열입니다.
public let url: String
/// Final headers included in the request.
/// 요청에 포함된 최종 헤더입니다.
public let headers: [String: String]

/// Creates a request-start log payload.
/// 요청 시작 로그 페이로드를 생성합니다.
public init(
requestIdentifier: UUID,
attemptNumber: Int,
Expand All @@ -45,20 +45,20 @@ public struct NXRequestStartLog: Sendable {
}
}

/// Structured payload emitted when a request attempt ends successfully.
/// 요청 시도가 성공적으로 끝났을 때 출력되는 구조화된 페이로드입니다.
public struct NXRequestEndLog: Sendable {
/// Stable identifier shared by all attempts of the same logical request.
/// 동일한 논리 요청의 모든 시도에서 공유되는 안정적인 식별자입니다.
public let requestIdentifier: UUID
/// Current attempt number starting from `1`.
/// 현재 시도 번호(`1`부터 시작)입니다.
public let attemptNumber: Int
/// HTTP status code returned by the server.
/// 서버가 반환한 HTTP 상태 코드입니다.
public let statusCode: Int
/// Elapsed wall-clock time for the attempt.
/// 시도의 실제 경과 시간입니다.
public let elapsedTime: TimeInterval
/// Response payload size in bytes.
/// 응답 페이로드 크기(바이트)입니다.
public let payloadSize: Int

/// Creates a request-end log payload.
/// 요청 완료 로그 페이로드를 생성합니다.
public init(
requestIdentifier: UUID,
attemptNumber: Int,
Expand All @@ -74,18 +74,18 @@ public struct NXRequestEndLog: Sendable {
}
}

/// Structured payload emitted when a request attempt fails.
/// 요청 시도가 실패했을 때 출력되는 구조화된 페이로드입니다.
public struct NXRequestFailureLog: Sendable {
/// Stable identifier shared by all attempts of the same logical request.
/// 동일한 논리 요청의 모든 시도에서 공유되는 안정적인 식별자입니다.
public let requestIdentifier: UUID
/// Current attempt number starting from `1`.
/// 현재 시도 번호(`1`부터 시작)입니다.
public let attemptNumber: Int
/// Elapsed wall-clock time for the attempt.
/// 시도의 실제 경과 시간입니다.
public let elapsedTime: TimeInterval
/// Human-readable description of the failure.
/// 사람이 읽기 쉬운 실패 설명입니다.
public let errorDescription: String

/// Creates a request-failure log payload.
/// 요청 실패 로그 페이로드를 생성합니다.
public init(
requestIdentifier: UUID,
attemptNumber: Int,
Expand All @@ -99,52 +99,52 @@ public struct NXRequestFailureLog: Sendable {
}
}

/// Structured payload emitted when Nexa schedules another retry attempt.
/// Nexa가 다음 재시도를 예약할 때 출력되는 구조화된 페이로드입니다.
public struct NXRetryLog: Sendable {
/// Stable identifier shared by all attempts of the same logical request.
/// 동일한 논리 요청의 모든 시도에서 공유되는 안정적인 식별자입니다.
public let requestIdentifier: UUID
/// Attempt number that will run next.
/// 다음에 실행될 시도 번호입니다.
public let nextAttemptNumber: Int
/// Delay before the next attempt begins.
/// 다음 시도 시작 전 대기 시간입니다.
public let delay: TimeInterval

/// Creates a retry log payload.
/// 재시도 로그 페이로드를 생성합니다.
public init(requestIdentifier: UUID, nextAttemptNumber: Int, delay: TimeInterval) {
self.requestIdentifier = requestIdentifier
self.nextAttemptNumber = nextAttemptNumber
self.delay = delay
}
}

/// Structured payload emitted after an auth token refresh attempt finishes.
/// 인증 토큰 갱신 시도 종료 후 출력되는 구조화된 페이로드입니다.
public struct NXAuthRefreshLog: Sendable {
/// Identifier of the request that started the refresh.
/// 갱신을 시작한 요청의 식별자입니다.
public let requestIdentifier: UUID
/// Whether the refresh attempt succeeded.
/// 갱신 시도 성공 여부입니다.
public let succeeded: Bool

/// Creates an auth-refresh log payload.
/// 인증 갱신 로그 페이로드를 생성합니다.
public init(requestIdentifier: UUID, succeeded: Bool) {
self.requestIdentifier = requestIdentifier
self.succeeded = succeeded
}
}

/// Receives structured request lifecycle events from Nexa.
/// Nexa의 구조화된 요청 라이프사이클 이벤트를 수신합니다.
///
/// ## Overview
/// ## 개요
///
/// Adopt `NXLogger` to forward request lifecycle events into your own logging or analytics pipeline.
/// 요청 라이프사이클 이벤트를 자체 로깅 또는 분석 파이프라인으로 전달하려면 `NXLogger`를 채택하세요.
public protocol NXLogger: Sendable {
/// Handles one log event emitted by Nexa.
/// Nexa가 발행한 로그 이벤트 한 건을 처리합니다.
func log(_ event: NXLogEvent) async
}

/// Logger that ignores every emitted event.
/// 발생한 모든 이벤트를 무시하는 로거입니다.
public struct NXNoopLogger: NXLogger {
/// Creates a logger that performs no work.
/// 아무 작업도 수행하지 않는 로거를 생성합니다.
public init() {}

/// Ignores the incoming log event.
/// 전달된 로그 이벤트를 무시합니다.
public func log(_ event: NXLogEvent) async {}
}
30 changes: 15 additions & 15 deletions Sources/Core/NXNetworkMetrics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@

import Foundation

/// Value snapshot of one `URLSession` task's network activity.
/// 하나의 `URLSession` 작업에서 발생한 네트워크 활동의 값 스냅샷입니다.
///
/// `NXURLSessionTransport` creates this value before delivering it to an `NXNetworkMetricsObserver`.
/// Custom `NXHTTPTransport` implementations do not produce this value.
/// `NXURLSessionTransport`는 이 값을 `NXNetworkMetricsObserver`에 전달하기 전에 생성합니다.
/// 사용자 정의 `NXHTTPTransport` 구현은 이 값을 생성하지 않습니다.
public struct NXNetworkMetrics: Sendable, Equatable {
/// Total duration of the URL loading task.
/// URL 로딩 작업의 총 소요 시간입니다.
public let taskDuration: TimeInterval?
/// Number of redirects followed by the URL loading task.
/// URL 로딩 작업이 따라간 리다이렉트 횟수입니다.
public let redirectCount: Int
/// Number of transactions collected for the URL loading task.
/// URL 로딩 작업에서 수집한 트랜잭션 개수입니다.
public let transactionCount: Int
/// Transaction snapshots in the order reported by `URLSession`.
/// `URLSession`이 보고한 순서를 보존한 트랜잭션 스냅샷입니다.
public let transactions: [NXNetworkTransactionMetrics]

/// Creates a network metrics snapshot.
/// 네트워크 메트릭 스냅샷을 생성합니다.
public init(
taskDuration: TimeInterval?,
redirectCount: Int,
Expand All @@ -35,20 +35,20 @@ public struct NXNetworkMetrics: Sendable, Equatable {
}
}

/// Value snapshot of one URL loading transaction.
/// 하나의 URL 로딩 트랜잭션에 대한 값 스냅샷입니다.
public struct NXNetworkTransactionMetrics: Sendable, Equatable {
/// Duration of DNS lookup when URLSession reports both timestamps.
/// URLSession이 두 타임스탬프를 모두 보고한 경우의 DNS 조회 시간입니다.
public let domainLookupDuration: TimeInterval?
/// Duration from connection start through connection end when URLSession reports both timestamps.
/// URLSession이 두 타임스탬프를 모두 보고한 경우 연결 시작부터 종료까지의 시간입니다.
public let connectionDuration: TimeInterval?
/// Duration of TLS negotiation when URLSession reports both timestamps.
/// URLSession이 두 타임스탬프를 모두 보고한 경우 TLS 협상 시간입니다.
public let secureConnectionDuration: TimeInterval?
/// Duration from request start until the first response byte when URLSession reports both timestamps.
/// URLSession이 두 타임스탬프를 모두 보고한 경우 요청 시작부터 첫 바이트 응답 수신까지의 시간입니다.
public let timeToFirstByte: TimeInterval?
/// Whether URLSession reused an existing connection.
/// URLSession이 기존 연결을 재사용했는지 여부입니다.
public let isConnectionReused: Bool

/// Creates a transaction metrics snapshot.
/// 트랜잭션 메트릭 스냅샷을 생성합니다.
public init(
domainLookupDuration: TimeInterval?,
connectionDuration: TimeInterval?,
Expand Down
6 changes: 3 additions & 3 deletions Sources/Core/NXNetworkMetricsObserver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
// Created by opfic on 8/23/26.
//

/// Receives metrics snapshots collected by `NXURLSessionTransport`.
/// `NXURLSessionTransport`에서 수집한 메트릭 스냅샷을 수신합니다.
///
/// Metrics delivery is independent of request completion and logger event order.
/// 메트릭 전달은 요청 완료와 로거 이벤트 순서와 독립적으로 수행됩니다.
public protocol NXNetworkMetricsObserver: Sendable {
/// Records one network metrics snapshot.
/// 네트워크 메트릭 스냅샷을 한 건 기록합니다.
func record(_ metrics: NXNetworkMetrics) async
}
Loading