@@ -131,6 +131,37 @@ struct LicenseAPIErrorResponse: Codable {
131131 let message : String
132132}
133133
134+ /// Information about a single license activation (machine)
135+ internal struct LicenseActivationInfo : Codable , Identifiable {
136+ var id : String { machineId }
137+ let machineId : String
138+ let machineName : String
139+ let appVersion : String
140+ let osVersion : String
141+ let lastValidatedAt : String ?
142+ let createdAt : String
143+
144+ private enum CodingKeys : String , CodingKey {
145+ case machineId = " machine_id "
146+ case machineName = " machine_name "
147+ case appVersion = " app_version "
148+ case osVersion = " os_version "
149+ case lastValidatedAt = " last_validated_at "
150+ case createdAt = " created_at "
151+ }
152+ }
153+
154+ /// Response from the list activations endpoint
155+ internal struct ListActivationsResponse : Codable {
156+ let activations : [ LicenseActivationInfo ]
157+ let maxActivations : Int
158+
159+ private enum CodingKeys : String , CodingKey {
160+ case activations
161+ case maxActivations = " max_activations "
162+ }
163+ }
164+
134165// MARK: - Cached License
135166
136167/// Local cached license with metadata for offline use
@@ -151,6 +182,12 @@ struct License: Codable, Equatable {
151182 return expiresAt < Date ( )
152183 }
153184
185+ /// Days until the license expires (nil for lifetime licenses)
186+ var daysUntilExpiry : Int ? {
187+ guard let expiresAt else { return nil }
188+ return Calendar . current. dateComponents ( [ . day] , from: Date ( ) , to: expiresAt) . day
189+ }
190+
154191 /// Days since last successful server validation
155192 var daysSinceLastValidation : Int {
156193 Calendar . current. dateComponents ( [ . day] , from: lastValidatedAt, to: Date ( ) ) . day ?? 0
0 commit comments