diff --git a/CHANGELOG.md b/CHANGELOG.md index debf5ca..9eea076 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log +## 18.0.0 + +* Breaking: `avatars.getScreenshot` `theme` parameter now uses the `BrowserTheme` enum +* Breaking: Removed generic type parameters from `presences` service methods +* Added: `BrowserTheme` enum +* Updated: `Presence` model is now concrete and adds a `metadata` field + ## 17.1.1 * Fixed: Removed `Advisor` service and `Insight`, `InsightCTA`, `InsightList`, `Report`, `ReportList` models (admin-only endpoints, not intended for client SDKs) diff --git a/README.md b/README.md index c5f324e..e262c07 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Add the package to your `Package.swift` dependencies: ```swift dependencies: [ - .package(url: "git@github.com:appwrite/sdk-for-apple.git", from: "17.2.0"), + .package(url: "git@github.com:appwrite/sdk-for-apple.git", from: "18.0.0"), ], ``` diff --git a/Sources/Appwrite/Client.swift b/Sources/Appwrite/Client.swift index e3f4419..17f521f 100644 --- a/Sources/Appwrite/Client.swift +++ b/Sources/Appwrite/Client.swift @@ -27,7 +27,7 @@ open class Client { "x-sdk-name": "Apple", "x-sdk-platform": "client", "x-sdk-language": "apple", - "x-sdk-version": "17.2.0", + "x-sdk-version": "18.0.0", "x-appwrite-response-format": "1.9.5" ] diff --git a/Sources/Appwrite/Services/Avatars.swift b/Sources/Appwrite/Services/Avatars.swift index 8601e22..b673f44 100644 --- a/Sources/Appwrite/Services/Avatars.swift +++ b/Sources/Appwrite/Services/Avatars.swift @@ -308,7 +308,7 @@ open class Avatars: Service { /// - viewportWidth: Int (optional) /// - viewportHeight: Int (optional) /// - scale: Double (optional) - /// - theme: AppwriteEnums.Theme (optional) + /// - theme: AppwriteEnums.BrowserTheme (optional) /// - userAgent: String (optional) /// - fullpage: Bool (optional) /// - locale: String (optional) @@ -332,7 +332,7 @@ open class Avatars: Service { viewportWidth: Int? = nil, viewportHeight: Int? = nil, scale: Double? = nil, - theme: AppwriteEnums.Theme? = nil, + theme: AppwriteEnums.BrowserTheme? = nil, userAgent: String? = nil, fullpage: Bool? = nil, locale: String? = nil, diff --git a/Sources/Appwrite/Services/Presences.swift b/Sources/Appwrite/Services/Presences.swift index 803a3c6..715e963 100644 --- a/Sources/Appwrite/Services/Presences.swift +++ b/Sources/Appwrite/Services/Presences.swift @@ -17,14 +17,13 @@ open class Presences: Service { /// - total: Bool (optional) /// - ttl: Int (optional) /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.PresenceList + /// - Returns: AppwriteModels.PresenceList /// - open func list( + open func list( queries: [String]? = nil, total: Bool? = nil, - ttl: Int? = nil, - nestedType: T.Type - ) async throws -> AppwriteModels.PresenceList { + ttl: Int? = nil + ) async throws -> AppwriteModels.PresenceList { let apiPath: String = "/presences" let apiParams: [String: Any?] = [ @@ -35,7 +34,7 @@ open class Presences: Service { let apiHeaders: [String: String] = [:] - let converter: (Any) throws -> AppwriteModels.PresenceList = { response in + let converter: (Any) throws -> AppwriteModels.PresenceList = { response in return AppwriteModels.PresenceList.from(map: response as! [String: Any]) } @@ -48,30 +47,6 @@ open class Presences: Service { ) } - /// - /// List presence logs. Expired entries are filtered out automatically. - /// - /// - /// - Parameters: - /// - queries: [String] (optional) - /// - total: Bool (optional) - /// - ttl: Int (optional) - /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.PresenceList - /// - open func list( - queries: [String]? = nil, - total: Bool? = nil, - ttl: Int? = nil - ) async throws -> AppwriteModels.PresenceList<[String: AnyCodable]> { - return try await list( - queries: queries, - total: total, - ttl: ttl, - nestedType: [String: AnyCodable].self - ) - } - /// /// Get a presence log by its unique ID. Entries whose `expiresAt` is in the /// past are treated as not found. @@ -80,12 +55,11 @@ open class Presences: Service { /// - Parameters: /// - presenceId: String /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.Presence + /// - Returns: AppwriteModels.Presence /// - open func get( - presenceId: String, - nestedType: T.Type - ) async throws -> AppwriteModels.Presence { + open func get( + presenceId: String + ) async throws -> AppwriteModels.Presence { let apiPath: String = "/presences/{presenceId}" .replacingOccurrences(of: "{presenceId}", with: presenceId) @@ -93,7 +67,7 @@ open class Presences: Service { let apiHeaders: [String: String] = [:] - let converter: (Any) throws -> AppwriteModels.Presence = { response in + let converter: (Any) throws -> AppwriteModels.Presence = { response in return AppwriteModels.Presence.from(map: response as! [String: Any]) } @@ -106,25 +80,6 @@ open class Presences: Service { ) } - /// - /// Get a presence log by its unique ID. Entries whose `expiresAt` is in the - /// past are treated as not found. - /// - /// - /// - Parameters: - /// - presenceId: String - /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.Presence - /// - open func get( - presenceId: String - ) async throws -> AppwriteModels.Presence<[String: AnyCodable]> { - return try await get( - presenceId: presenceId, - nestedType: [String: AnyCodable].self - ) - } - /// /// Create or update a presence log by its user ID. /// @@ -136,16 +91,15 @@ open class Presences: Service { /// - expiresAt: String (optional) /// - metadata: Any (optional) /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.Presence + /// - Returns: AppwriteModels.Presence /// - open func upsert( + open func upsert( presenceId: String, status: String, permissions: [String]? = nil, expiresAt: String? = nil, - metadata: Any? = nil, - nestedType: T.Type - ) async throws -> AppwriteModels.Presence { + metadata: Any? = nil + ) async throws -> AppwriteModels.Presence { let apiPath: String = "/presences/{presenceId}" .replacingOccurrences(of: "{presenceId}", with: presenceId) @@ -160,7 +114,7 @@ open class Presences: Service { "content-type": "application/json" ] - let converter: (Any) throws -> AppwriteModels.Presence = { response in + let converter: (Any) throws -> AppwriteModels.Presence = { response in return AppwriteModels.Presence.from(map: response as! [String: Any]) } @@ -173,36 +127,6 @@ open class Presences: Service { ) } - /// - /// Create or update a presence log by its user ID. - /// - /// - /// - Parameters: - /// - presenceId: String - /// - status: String - /// - permissions: [String] (optional) - /// - expiresAt: String (optional) - /// - metadata: Any (optional) - /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.Presence - /// - open func upsert( - presenceId: String, - status: String, - permissions: [String]? = nil, - expiresAt: String? = nil, - metadata: Any? = nil - ) async throws -> AppwriteModels.Presence<[String: AnyCodable]> { - return try await upsert( - presenceId: presenceId, - status: status, - permissions: permissions, - expiresAt: expiresAt, - metadata: metadata, - nestedType: [String: AnyCodable].self - ) - } - /// /// Update a presence log by its unique ID. Using the patch method you can pass /// only specific fields that will get updated. @@ -216,17 +140,16 @@ open class Presences: Service { /// - permissions: [String] (optional) /// - purge: Bool (optional) /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.Presence + /// - Returns: AppwriteModels.Presence /// - open func update( + open func update( presenceId: String, status: String? = nil, expiresAt: String? = nil, metadata: Any? = nil, permissions: [String]? = nil, - purge: Bool? = nil, - nestedType: T.Type - ) async throws -> AppwriteModels.Presence { + purge: Bool? = nil + ) async throws -> AppwriteModels.Presence { let apiPath: String = "/presences/{presenceId}" .replacingOccurrences(of: "{presenceId}", with: presenceId) @@ -242,7 +165,7 @@ open class Presences: Service { "content-type": "application/json" ] - let converter: (Any) throws -> AppwriteModels.Presence = { response in + let converter: (Any) throws -> AppwriteModels.Presence = { response in return AppwriteModels.Presence.from(map: response as! [String: Any]) } @@ -255,40 +178,6 @@ open class Presences: Service { ) } - /// - /// Update a presence log by its unique ID. Using the patch method you can pass - /// only specific fields that will get updated. - /// - /// - /// - Parameters: - /// - presenceId: String - /// - status: String (optional) - /// - expiresAt: String (optional) - /// - metadata: Any (optional) - /// - permissions: [String] (optional) - /// - purge: Bool (optional) - /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.Presence - /// - open func update( - presenceId: String, - status: String? = nil, - expiresAt: String? = nil, - metadata: Any? = nil, - permissions: [String]? = nil, - purge: Bool? = nil - ) async throws -> AppwriteModels.Presence<[String: AnyCodable]> { - return try await update( - presenceId: presenceId, - status: status, - expiresAt: expiresAt, - metadata: metadata, - permissions: permissions, - purge: purge, - nestedType: [String: AnyCodable].self - ) - } - /// /// Delete a presence log by its unique ID. /// diff --git a/Sources/AppwriteEnums/Theme.swift b/Sources/AppwriteEnums/BrowserTheme.swift similarity index 66% rename from Sources/AppwriteEnums/Theme.swift rename to Sources/AppwriteEnums/BrowserTheme.swift index f81a4b2..ac273b1 100644 --- a/Sources/AppwriteEnums/Theme.swift +++ b/Sources/AppwriteEnums/BrowserTheme.swift @@ -1,6 +1,6 @@ import Foundation -public enum Theme: String, Codable, CustomStringConvertible { +public enum BrowserTheme: String, Codable, CustomStringConvertible { case light = "light" case dark = "dark" diff --git a/Sources/AppwriteModels/Document.swift b/Sources/AppwriteModels/Document.swift index bd83adb..a3cba78 100644 --- a/Sources/AppwriteModels/Document.swift +++ b/Sources/AppwriteModels/Document.swift @@ -100,16 +100,7 @@ open class Document: Codable { createdAt: map["$createdAt"] as? String ?? "", updatedAt: map["$updatedAt"] as? String ?? "", permissions: map["$permissions"] as? [String] ?? [], - data: try! JSONDecoder().decode(T.self, from: { - let raw = map["data"] - if let dict = raw as? [String: Any] { - return try! JSONSerialization.data(withJSONObject: dict, options: []) - } else if let raw = raw, JSONSerialization.isValidJSONObject(raw) { - return try! JSONSerialization.data(withJSONObject: raw, options: []) - } else { - return try! JSONSerialization.data(withJSONObject: [:] as [String: Any], options: []) - } - }()) + data: try! JSONDecoder().decode(T.self, from: JSONSerialization.data(withJSONObject: map["data"] as? [String: Any] ?? map, options: [])) ) } } diff --git a/Sources/AppwriteModels/Presence.swift b/Sources/AppwriteModels/Presence.swift index d60c69b..da34ff0 100644 --- a/Sources/AppwriteModels/Presence.swift +++ b/Sources/AppwriteModels/Presence.swift @@ -2,7 +2,7 @@ import Foundation import JSONCodable /// Presence -open class Presence: Codable { +open class Presence: Codable { enum CodingKeys: String, CodingKey { case id = "$id" @@ -32,8 +32,8 @@ open class Presence: Codable { public let source: String /// Presence expiry date in ISO 8601 format. public let expiresAt: String? - /// Additional properties - public let metadata: T + /// Presence metadata. + public let metadata: [String: AnyCodable]? init( id: String, @@ -44,7 +44,7 @@ open class Presence: Codable { status: String?, source: String, expiresAt: String?, - metadata: T + metadata: [String: AnyCodable]? ) { self.id = id self.createdAt = createdAt @@ -68,7 +68,7 @@ open class Presence: Codable { self.status = try container.decodeIfPresent(String.self, forKey: .status) self.source = try container.decode(String.self, forKey: .source) self.expiresAt = try container.decodeIfPresent(String.self, forKey: .expiresAt) - self.metadata = try container.decode(T.self, forKey: .metadata) + self.metadata = try container.decodeIfPresent([String: AnyCodable].self, forKey: .metadata) } public func encode(to encoder: Encoder) throws { @@ -82,7 +82,7 @@ open class Presence: Codable { try container.encodeIfPresent(status, forKey: .status) try container.encode(source, forKey: .source) try container.encodeIfPresent(expiresAt, forKey: .expiresAt) - try container.encode(metadata, forKey: .metadata) + try container.encodeIfPresent(metadata, forKey: .metadata) } public func toMap() -> [String: Any] { @@ -95,7 +95,7 @@ open class Presence: Codable { "status": status as Any, "source": source as Any, "expiresAt": expiresAt as Any, - "metadata": (try! JSONSerialization.jsonObject(with: JSONEncoder().encode(metadata))) as? [String: Any] ?? [:] + "metadata": metadata as Any ] } @@ -109,16 +109,7 @@ open class Presence: Codable { status: map["status"] as? String, source: map["source"] as! String, expiresAt: map["expiresAt"] as? String, - metadata: try! JSONDecoder().decode(T.self, from: { - let raw = map["metadata"] - if let dict = raw as? [String: Any] { - return try! JSONSerialization.data(withJSONObject: dict, options: []) - } else if let raw = raw, JSONSerialization.isValidJSONObject(raw) { - return try! JSONSerialization.data(withJSONObject: raw, options: []) - } else { - return try! JSONSerialization.data(withJSONObject: [:] as [String: Any], options: []) - } - }()) + metadata: (map["metadata"] as? [String: Any] ?? [:]).mapValues { AnyCodable($0) } ) } } diff --git a/Sources/AppwriteModels/PresenceList.swift b/Sources/AppwriteModels/PresenceList.swift index 97548f6..6d149fb 100644 --- a/Sources/AppwriteModels/PresenceList.swift +++ b/Sources/AppwriteModels/PresenceList.swift @@ -2,7 +2,7 @@ import Foundation import JSONCodable /// Presences List -open class PresenceList: Codable { +open class PresenceList: Codable { enum CodingKeys: String, CodingKey { case total = "total" @@ -12,11 +12,11 @@ open class PresenceList: Codable { /// Total number of presences that matched your query. public let total: Int /// List of presences. - public let presences: [Presence] + public let presences: [Presence] init( total: Int, - presences: [Presence] + presences: [Presence] ) { self.total = total self.presences = presences @@ -26,7 +26,7 @@ open class PresenceList: Codable { let container = try decoder.container(keyedBy: CodingKeys.self) self.total = try container.decode(Int.self, forKey: .total) - self.presences = try container.decode([Presence].self, forKey: .presences) + self.presences = try container.decode([Presence].self, forKey: .presences) } public func encode(to encoder: Encoder) throws { diff --git a/Sources/AppwriteModels/Row.swift b/Sources/AppwriteModels/Row.swift index 331af18..2ee0565 100644 --- a/Sources/AppwriteModels/Row.swift +++ b/Sources/AppwriteModels/Row.swift @@ -100,16 +100,7 @@ open class Row: Codable { createdAt: map["$createdAt"] as! String, updatedAt: map["$updatedAt"] as! String, permissions: map["$permissions"] as! [String], - data: try! JSONDecoder().decode(T.self, from: { - let raw = map["data"] - if let dict = raw as? [String: Any] { - return try! JSONSerialization.data(withJSONObject: dict, options: []) - } else if let raw = raw, JSONSerialization.isValidJSONObject(raw) { - return try! JSONSerialization.data(withJSONObject: raw, options: []) - } else { - return try! JSONSerialization.data(withJSONObject: [:] as [String: Any], options: []) - } - }()) + data: try! JSONDecoder().decode(T.self, from: JSONSerialization.data(withJSONObject: map["data"] as? [String: Any] ?? map, options: [])) ) } }