Skip to content

Commit b3f994f

Browse files
authored
Merge pull request #108 from appwrite/dev
2 parents e2ba30c + cf788ff commit b3f994f

11 files changed

Lines changed: 118 additions & 44 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Change Log
22

3+
## 16.0.0
4+
5+
* [BREAKING] Changed `$sequence` type from `Int` to `String` for `Row` and `Document` models
6+
* Added impersonation support: `setImpersonateUserId()`, `setImpersonateUserEmail()`, `setImpersonateUserPhone()` on `Client`
7+
* Added `impersonator` and `impersonatorUserId` optional fields to `User` model
8+
* Updated `Log` model field descriptions to clarify impersonation behavior for `userId`, `userEmail`, `userName`
9+
* Fixed `NIOFoundationCompat` import to be conditional with `#if canImport` for platform compatibility
10+
* Fixed `ByteBuffer` to `Data` conversion to use `readableBytesView` throughout (Client and WebSocket handler)
11+
* Fixed `ByteBuffer(data:)` calls replaced with `ByteBuffer(bytes:)` for file/data loading
12+
* Updated `X-Appwrite-Response-Format` header to `1.9.0`
13+
* Updated API version badge to `1.9.0` and compatibility note to server version `1.9.x` in README
14+
315
## 15.0.0
416

517
* Breaking: RealtimeChannel API required explicit IDs and threw errors.

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
![Swift Package Manager](https://img.shields.io/github/v/release/appwrite/sdk-for-apple.svg?color=green&style=flat-square)
44
![License](https://img.shields.io/github/license/appwrite/sdk-for-apple.svg?style=flat-square)
5-
![Version](https://img.shields.io/badge/api%20version-1.8.1-blue.svg?style=flat-square)
5+
![Version](https://img.shields.io/badge/api%20version-1.9.0-blue.svg?style=flat-square)
66
[![Build Status](https://img.shields.io/travis/com/appwrite/sdk-generator?style=flat-square)](https://travis-ci.com/appwrite/sdk-generator)
77
[![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite)
88
[![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord)
99

10-
**This SDK is compatible with Appwrite server version latest. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-apple/releases).**
10+
**This SDK is compatible with Appwrite server version 1.9.x. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-apple/releases).**
1111

1212
Appwrite is an open-source backend as a service server that abstracts and simplifies complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the Apple SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)
1313

@@ -31,7 +31,7 @@ Add the package to your `Package.swift` dependencies:
3131

3232
```swift
3333
dependencies: [
34-
.package(url: "git@github.com:appwrite/sdk-for-apple.git", from: "15.0.0"),
34+
.package(url: "git@github.com:appwrite/sdk-for-apple.git", from: "16.0.0"),
3535
],
3636
```
3737

Sources/Appwrite/Client.swift

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import NIO
22
import NIOCore
3+
#if canImport(NIOFoundationCompat)
34
import NIOFoundationCompat
5+
#endif
46
import NIOSSL
57
import Foundation
68
import AsyncHTTPClient
@@ -24,8 +26,8 @@ open class Client {
2426
"x-sdk-name": "Apple",
2527
"x-sdk-platform": "client",
2628
"x-sdk-language": "apple",
27-
"x-sdk-version": "15.0.0",
28-
"x-appwrite-response-format": "1.8.0"
29+
"x-sdk-version": "16.0.0",
30+
"x-appwrite-response-format": "1.9.0"
2931
]
3032

3133
internal var config: [String: String] = [:]
@@ -162,6 +164,51 @@ open class Client {
162164
return self
163165
}
164166

167+
///
168+
/// Set ImpersonateUserId
169+
///
170+
/// Impersonate a user by ID on an already user-authenticated request. Requires the current request to be authenticated as a user with impersonator capability; X-Appwrite-Key alone is not sufficient. Impersonator users are intentionally granted users.read so they can discover a target before impersonation begins. Internal audit logs still attribute actions to the original impersonator and record the impersonated target only in internal audit payload data.
171+
///
172+
/// @param String value
173+
///
174+
/// @return Client
175+
///
176+
open func setImpersonateUserId(_ value: String) -> Client {
177+
config["impersonateuserid"] = value
178+
_ = addHeader(key: "X-Appwrite-Impersonate-User-Id", value: value)
179+
return self
180+
}
181+
182+
///
183+
/// Set ImpersonateUserEmail
184+
///
185+
/// Impersonate a user by email on an already user-authenticated request. Requires the current request to be authenticated as a user with impersonator capability; X-Appwrite-Key alone is not sufficient. Impersonator users are intentionally granted users.read so they can discover a target before impersonation begins. Internal audit logs still attribute actions to the original impersonator and record the impersonated target only in internal audit payload data.
186+
///
187+
/// @param String value
188+
///
189+
/// @return Client
190+
///
191+
open func setImpersonateUserEmail(_ value: String) -> Client {
192+
config["impersonateuseremail"] = value
193+
_ = addHeader(key: "X-Appwrite-Impersonate-User-Email", value: value)
194+
return self
195+
}
196+
197+
///
198+
/// Set ImpersonateUserPhone
199+
///
200+
/// Impersonate a user by phone on an already user-authenticated request. Requires the current request to be authenticated as a user with impersonator capability; X-Appwrite-Key alone is not sufficient. Impersonator users are intentionally granted users.read so they can discover a target before impersonation begins. Internal audit logs still attribute actions to the original impersonator and record the impersonated target only in internal audit payload data.
201+
///
202+
/// @param String value
203+
///
204+
/// @return Client
205+
///
206+
open func setImpersonateUserPhone(_ value: String) -> Client {
207+
config["impersonateuserphone"] = value
208+
_ = addHeader(key: "X-Appwrite-Impersonate-User-Phone", value: value)
209+
return self
210+
}
211+
165212

166213
///
167214
/// Set self signed
@@ -378,7 +425,7 @@ open class Client {
378425
if data.readableBytes == 0 {
379426
return true as! T
380427
}
381-
let dict = try JSONSerialization.jsonObject(with: data) as? [String: Any]
428+
let dict = try JSONSerialization.jsonObject(with: Data(data.readableBytesView)) as? [String: Any]
382429

383430
return converter?(dict!) ?? dict! as! T
384431
}
@@ -388,7 +435,7 @@ open class Client {
388435
var responseString = ""
389436

390437
do {
391-
let dict = try JSONSerialization.jsonObject(with: data) as? [String: Any]
438+
let dict = try JSONSerialization.jsonObject(with: Data(data.readableBytesView)) as? [String: Any]
392439

393440
message = dict?["message"] as? String ?? response.status.reasonPhrase
394441
type = dict?["type"] as? String ?? ""
@@ -420,9 +467,9 @@ open class Client {
420467

421468
switch(input.sourceType) {
422469
case "path":
423-
input.data = ByteBuffer(data: try! Data(contentsOf: URL(fileURLWithPath: input.path)))
470+
input.data = ByteBuffer(bytes: try! Data(contentsOf: URL(fileURLWithPath: input.path)))
424471
case "data":
425-
input.data = ByteBuffer(data: input.data as! Data)
472+
input.data = ByteBuffer(bytes: input.data as! Data)
426473
default:
427474
break
428475
}

Sources/Appwrite/WebSockets/MessageHandler.swift

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import Foundation
22
import NIO
3+
#if canImport(NIOFoundationCompat)
4+
import NIOFoundationCompat
5+
#endif
36
import NIOHTTP1
47
import NIOWebSocket
58

@@ -18,7 +21,7 @@ class MessageHandler {
1821
self.client = client
1922
self.buffer = ByteBufferAllocator().buffer(capacity: 0)
2023
}
21-
24+
2225
private func unmaskedData(frame: WebSocketFrame) -> ByteBuffer {
2326
var frameData = frame.data
2427
if let maskingKey = frame.maskKey {
@@ -31,7 +34,7 @@ class MessageHandler {
3134
extension MessageHandler: ChannelInboundHandler, RemovableChannelHandler {
3235

3336
typealias InboundIn = WebSocketFrame
34-
37+
3538
public func channelRead(context: ChannelHandlerContext, data: NIOAny) {
3639
let frame = self.unwrapInboundIn(data)
3740
switch frame.opcode {
@@ -56,18 +59,14 @@ extension MessageHandler: ChannelInboundHandler, RemovableChannelHandler {
5659
case .binary:
5760
let data = unmaskedData(frame: frame)
5861
if frame.fin {
59-
guard let binaryData = data.getData(at: 0, length: data.readableBytes) else {
60-
return
61-
}
62+
let binaryData = Data(data.readableBytesView)
6263
if let delegate = client.delegate {
6364
try! delegate.onMessage(data: binaryData)
6465
} else {
6566
client.onBinaryMessage(binaryData)
6667
}
6768
} else {
68-
guard let binaryData = data.getData(at: 0, length: data.readableBytes) else {
69-
return
70-
}
69+
let binaryData = Data(data.readableBytesView)
7170
binaryBuffer = binaryData
7271
}
7372
case .continuation:
@@ -92,19 +91,15 @@ extension MessageHandler: ChannelInboundHandler, RemovableChannelHandler {
9291
}
9392
} else {
9493
if frame.fin {
95-
guard let binaryData = data.getData(at: 0, length: data.readableBytes) else {
96-
return
97-
}
94+
let binaryData = Data(data.readableBytesView)
9895
binaryBuffer.append(binaryData)
9996
if let delegate = client.delegate {
10097
try! delegate.onMessage(data: binaryBuffer)
10198
} else {
10299
client.onBinaryMessage(binaryBuffer)
103100
}
104101
} else {
105-
guard let binaryData = data.getData(at: 0, length: data.readableBytes) else {
106-
return
107-
}
102+
let binaryData = Data(data.readableBytesView)
108103
binaryBuffer.append(binaryData)
109104
}
110105
}
@@ -114,18 +109,18 @@ extension MessageHandler: ChannelInboundHandler, RemovableChannelHandler {
114109
}
115110
let data = frame.data
116111
if !client.closeSent {
117-
client.close(data: frame.data.getData(at: 0, length: frame.data.readableBytes) ?? Data())
112+
client.close(data: Data(frame.data.readableBytesView))
118113
}
119114
if let delegate = client.delegate {
120-
delegate.onClose(channel: context.channel, data: data.getData(at: 0, length: data.readableBytes)!)
115+
delegate.onClose(channel: context.channel, data: Data(data.readableBytesView))
121116
} else {
122-
client.onClose(context.channel, data.getData(at: 0, length: data.readableBytes)!)
117+
client.onClose(context.channel, Data(data.readableBytesView))
123118
}
124119
default:
125120
break
126121
}
127122
}
128-
123+
129124
public func errorCaught(context: ChannelHandlerContext, error: Swift.Error) {
130125
if client.delegate != nil {
131126
try! client.delegate?.onError(error: error, status: nil)

Sources/Appwrite/WebSockets/WebSocketClient.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import Foundation
22
import NIO
3+
#if canImport(NIOFoundationCompat)
4+
import NIOFoundationCompat
5+
#endif
36
import NIOHTTP1
47
import NIOWebSocket
58
import Dispatch
6-
import NIOFoundationCompat
79
import NIOSSL
810

911
public let WEBSOCKET_LOCKER_QUEUE = "SyncLocker"

Sources/AppwriteModels/Document.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ open class Document<T : Codable>: Codable {
1818
/// Document ID.
1919
public let id: String
2020
/// Document sequence ID.
21-
public let sequence: Int
21+
public let sequence: String
2222
/// Collection ID.
2323
public let collectionId: String
2424
/// Database ID.
@@ -34,7 +34,7 @@ open class Document<T : Codable>: Codable {
3434

3535
init(
3636
id: String,
37-
sequence: Int,
37+
sequence: String,
3838
collectionId: String,
3939
databaseId: String,
4040
createdAt: String,
@@ -56,7 +56,7 @@ open class Document<T : Codable>: Codable {
5656
let container = try decoder.container(keyedBy: CodingKeys.self)
5757

5858
self.id = try container.decode(String.self, forKey: .id)
59-
self.sequence = try container.decode(Int.self, forKey: .sequence)
59+
self.sequence = try container.decode(String.self, forKey: .sequence)
6060
self.collectionId = try container.decode(String.self, forKey: .collectionId)
6161
self.databaseId = try container.decode(String.self, forKey: .databaseId)
6262
self.createdAt = try container.decode(String.self, forKey: .createdAt)
@@ -94,7 +94,7 @@ open class Document<T : Codable>: Codable {
9494
public static func from(map: [String: Any] ) -> Document {
9595
return Document(
9696
id: map["$id"] as? String ?? "",
97-
sequence: map["$sequence"] as? Int ?? 0,
97+
sequence: map["$sequence"] as? String ?? "",
9898
collectionId: map["$collectionId"] as? String ?? "",
9999
databaseId: map["$databaseId"] as? String ?? "",
100100
createdAt: map["$createdAt"] as? String ?? "",

Sources/AppwriteModels/Log.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ open class Log: Codable {
3030

3131
/// Event name.
3232
public let event: String
33-
/// User ID.
33+
/// User ID of the actor recorded for this log. During impersonation, this is the original impersonator, not the impersonated target user.
3434
public let userId: String
35-
/// User Email.
35+
/// User email of the actor recorded for this log. During impersonation, this is the original impersonator.
3636
public let userEmail: String
37-
/// User Name.
37+
/// User name of the actor recorded for this log. During impersonation, this is the original impersonator.
3838
public let userName: String
3939
/// API mode when event triggered.
4040
public let mode: String

Sources/AppwriteModels/Row.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ open class Row<T : Codable>: Codable {
1818
/// Row ID.
1919
public let id: String
2020
/// Row sequence ID.
21-
public let sequence: Int
21+
public let sequence: String
2222
/// Table ID.
2323
public let tableId: String
2424
/// Database ID.
@@ -34,7 +34,7 @@ open class Row<T : Codable>: Codable {
3434

3535
init(
3636
id: String,
37-
sequence: Int,
37+
sequence: String,
3838
tableId: String,
3939
databaseId: String,
4040
createdAt: String,
@@ -56,7 +56,7 @@ open class Row<T : Codable>: Codable {
5656
let container = try decoder.container(keyedBy: CodingKeys.self)
5757

5858
self.id = try container.decode(String.self, forKey: .id)
59-
self.sequence = try container.decode(Int.self, forKey: .sequence)
59+
self.sequence = try container.decode(String.self, forKey: .sequence)
6060
self.tableId = try container.decode(String.self, forKey: .tableId)
6161
self.databaseId = try container.decode(String.self, forKey: .databaseId)
6262
self.createdAt = try container.decode(String.self, forKey: .createdAt)
@@ -94,7 +94,7 @@ open class Row<T : Codable>: Codable {
9494
public static func from(map: [String: Any] ) -> Row {
9595
return Row(
9696
id: map["$id"] as! String,
97-
sequence: map["$sequence"] as! Int,
97+
sequence: map["$sequence"] as! String,
9898
tableId: map["$tableId"] as! String,
9999
databaseId: map["$databaseId"] as! String,
100100
createdAt: map["$createdAt"] as! String,

0 commit comments

Comments
 (0)