From df22b36ca2e5dc837931a1509e7469ef17cac6bc Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Mon, 8 Jun 2026 11:20:39 +0530 Subject: [PATCH 1/5] chore: update Apple SDK to 18.1.0 --- CHANGELOG.md | 11 +- README.md | 2 +- Sources/Appwrite/Client.swift | 8 +- Sources/Appwrite/Services/Account.swift | 216 +++++++-- Sources/Appwrite/Services/Apps.swift | 431 ++++++++++++++++++ Sources/Appwrite/Services/Databases.swift | 54 ++- Sources/Appwrite/Services/Functions.swift | 14 +- Sources/Appwrite/Services/Graphql.swift | 8 +- Sources/Appwrite/Services/Locale.swift | 40 +- Sources/Appwrite/Services/Messaging.swift | 5 +- Sources/Appwrite/Services/Oauth2.swift | 253 ++++++++++ Sources/Appwrite/Services/Presences.swift | 19 +- Sources/Appwrite/Services/Storage.swift | 19 +- Sources/Appwrite/Services/TablesDB.swift | 54 ++- Sources/Appwrite/Services/Teams.swift | 51 ++- Sources/AppwriteModels/App.swift | 133 ++++++ Sources/AppwriteModels/AppSecret.swift | 115 +++++ Sources/AppwriteModels/AppSecretList.swift | 52 +++ .../AppwriteModels/AppSecretPlaintext.swift | 115 +++++ Sources/AppwriteModels/AppsList.swift | 52 +++ Sources/AppwriteModels/Membership.swift | 9 + Sources/AppwriteModels/Oauth2Approve.swift | 43 ++ Sources/AppwriteModels/Oauth2Authorize.swift | 52 +++ Sources/AppwriteModels/Oauth2Grant.swift | 133 ++++++ Sources/AppwriteModels/Oauth2Reject.swift | 43 ++ Sources/AppwriteModels/User.swift | 45 ++ docs/examples/account/update-password.md | 2 +- docs/examples/apps/create-secret.md | 14 + docs/examples/apps/create.md | 20 + docs/examples/apps/delete-secret.md | 15 + docs/examples/apps/delete-tokens.md | 14 + docs/examples/apps/delete.md | 14 + docs/examples/apps/get-secret.md | 15 + docs/examples/apps/get.md | 14 + docs/examples/apps/list-secrets.md | 16 + docs/examples/apps/list.md | 15 + docs/examples/apps/update-team.md | 15 + docs/examples/apps/update.md | 19 + docs/examples/oauth2/approve.md | 16 + docs/examples/oauth2/authorize.md | 25 + docs/examples/oauth2/create-grant.md | 15 + docs/examples/oauth2/get-grant.md | 15 + docs/examples/oauth2/reject.md | 15 + 43 files changed, 2122 insertions(+), 114 deletions(-) create mode 100644 Sources/Appwrite/Services/Apps.swift create mode 100644 Sources/Appwrite/Services/Oauth2.swift create mode 100644 Sources/AppwriteModels/App.swift create mode 100644 Sources/AppwriteModels/AppSecret.swift create mode 100644 Sources/AppwriteModels/AppSecretList.swift create mode 100644 Sources/AppwriteModels/AppSecretPlaintext.swift create mode 100644 Sources/AppwriteModels/AppsList.swift create mode 100644 Sources/AppwriteModels/Oauth2Approve.swift create mode 100644 Sources/AppwriteModels/Oauth2Authorize.swift create mode 100644 Sources/AppwriteModels/Oauth2Grant.swift create mode 100644 Sources/AppwriteModels/Oauth2Reject.swift create mode 100644 docs/examples/apps/create-secret.md create mode 100644 docs/examples/apps/create.md create mode 100644 docs/examples/apps/delete-secret.md create mode 100644 docs/examples/apps/delete-tokens.md create mode 100644 docs/examples/apps/delete.md create mode 100644 docs/examples/apps/get-secret.md create mode 100644 docs/examples/apps/get.md create mode 100644 docs/examples/apps/list-secrets.md create mode 100644 docs/examples/apps/list.md create mode 100644 docs/examples/apps/update-team.md create mode 100644 docs/examples/apps/update.md create mode 100644 docs/examples/oauth2/approve.md create mode 100644 docs/examples/oauth2/authorize.md create mode 100644 docs/examples/oauth2/create-grant.md create mode 100644 docs/examples/oauth2/get-grant.md create mode 100644 docs/examples/oauth2/reject.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 9eea076..8dedfa8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,19 @@ # Change Log +## 18.1.0 + +* Added: `apps` service with app and secret management methods. +* Added: `oauth2` service with `authorize`, `approve`, `reject`, `createGrant`, and `getGrant`. +* Added: `App`, `AppSecret`, `AppSecretPlaintext`, `AppsList`, and `AppSecretList` models. +* Added: `Oauth2Authorize`, `Oauth2Approve`, `Oauth2Reject`, and `Oauth2Grant` models. +* Added: Email metadata fields to `User` (`emailCanonical`, `emailIsFree`, `emailIsDisposable`, `emailIsCorporate`, `emailIsCanonical`). +* Added: `Membership.userAccessedAt` field. + ## 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 +* Replaced: `BrowserTheme` enum * Updated: `Presence` model is now concrete and adds a `metadata` field ## 17.1.1 diff --git a/README.md b/README.md index e262c07..ba26403 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: "18.0.0"), + .package(url: "git@github.com:appwrite/sdk-for-apple.git", from: "18.1.0"), ], ``` diff --git a/Sources/Appwrite/Client.swift b/Sources/Appwrite/Client.swift index 17f521f..ac23a0e 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": "18.0.0", + "x-sdk-version": "18.1.0", "x-appwrite-response-format": "1.9.5" ] @@ -108,7 +108,6 @@ open class Client { /// open func setProject(_ value: String) -> Client { config["project"] = value - _ = addHeader(key: "X-Appwrite-Project", value: value) return self } @@ -384,7 +383,8 @@ open class Client { let apiPath: String = "/ping" let apiHeaders: [String: String] = [ - "content-type": "application/json" + "content-type": "application/json", + "X-Appwrite-Project": config["project"] ?? "" ] return try await call( @@ -415,7 +415,7 @@ open class Client { let validParams = params.filter { $0.value != nil } let queryParameters = method == "GET" && !validParams.isEmpty - ? "?" + parametersToQueryString(params: validParams) + ? (path.contains("?") ? "&" : "?") + parametersToQueryString(params: validParams) : "" var request = HTTPClientRequest(url: endPoint + path + queryParameters) diff --git a/Sources/Appwrite/Services/Account.swift b/Sources/Appwrite/Services/Account.swift index 0f07c6f..a8f386b 100644 --- a/Sources/Appwrite/Services/Account.swift +++ b/Sources/Appwrite/Services/Account.swift @@ -21,7 +21,10 @@ open class Account: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.User = { response in return AppwriteModels.User.from(map: response as! [String: Any]) @@ -83,7 +86,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.User = { response in @@ -160,7 +165,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.User = { response in @@ -223,7 +230,10 @@ open class Account: Service { "total": total ] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.IdentityList = { response in return AppwriteModels.IdentityList.from(map: response as! [String: Any]) @@ -255,6 +265,7 @@ open class Account: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", "content-type": "application/json" ] @@ -287,7 +298,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Jwt = { response in @@ -324,7 +337,10 @@ open class Account: Service { "total": total ] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.LogList = { response in return AppwriteModels.LogList.from(map: response as! [String: Any]) @@ -358,7 +374,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.User = { response in @@ -412,7 +430,9 @@ open class Account: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.MfaType = { response in @@ -448,7 +468,9 @@ open class Account: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.MfaType = { response in @@ -489,7 +511,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.User = { response in @@ -552,7 +576,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.User = { response in @@ -608,6 +634,7 @@ open class Account: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", "content-type": "application/json" ] @@ -635,6 +662,7 @@ open class Account: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", "content-type": "application/json" ] @@ -666,7 +694,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.MfaChallenge = { response in @@ -702,7 +732,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.MfaChallenge = { response in @@ -744,7 +776,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Session = { response in @@ -785,7 +819,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Session = { response in @@ -814,7 +850,10 @@ open class Account: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.MfaFactors = { response in return AppwriteModels.MfaFactors.from(map: response as! [String: Any]) @@ -841,7 +880,10 @@ open class Account: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.MfaFactors = { response in return AppwriteModels.MfaFactors.from(map: response as! [String: Any]) @@ -872,7 +914,10 @@ open class Account: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.MfaRecoveryCodes = { response in return AppwriteModels.MfaRecoveryCodes.from(map: response as! [String: Any]) @@ -902,7 +947,10 @@ open class Account: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.MfaRecoveryCodes = { response in return AppwriteModels.MfaRecoveryCodes.from(map: response as! [String: Any]) @@ -935,7 +983,9 @@ open class Account: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.MfaRecoveryCodes = { response in @@ -968,7 +1018,9 @@ open class Account: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.MfaRecoveryCodes = { response in @@ -1001,7 +1053,9 @@ open class Account: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.MfaRecoveryCodes = { response in @@ -1033,7 +1087,9 @@ open class Account: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.MfaRecoveryCodes = { response in @@ -1068,7 +1124,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.User = { response in @@ -1125,7 +1183,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.User = { response in @@ -1189,7 +1249,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.User = { response in @@ -1242,7 +1304,10 @@ open class Account: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.Preferences = { response in return AppwriteModels.Preferences.from(map: response as! [String: Any]) @@ -1291,7 +1356,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.User = { response in @@ -1354,7 +1421,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Token = { response in @@ -1403,7 +1472,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Token = { response in @@ -1432,7 +1503,10 @@ open class Account: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.SessionList = { response in return AppwriteModels.SessionList.from(map: response as! [String: Any]) @@ -1461,6 +1535,7 @@ open class Account: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", "content-type": "application/json" ] @@ -1490,7 +1565,9 @@ open class Account: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Session = { response in @@ -1532,7 +1609,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Session = { response in @@ -1572,7 +1651,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Session = { response in @@ -1672,7 +1753,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Session = { response in @@ -1711,7 +1794,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Session = { response in @@ -1744,7 +1829,10 @@ open class Account: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.Session = { response in return AppwriteModels.Session.from(map: response as! [String: Any]) @@ -1778,7 +1866,9 @@ open class Account: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Session = { response in @@ -1815,6 +1905,7 @@ open class Account: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", "content-type": "application/json" ] @@ -1841,7 +1932,9 @@ open class Account: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.User = { response in @@ -1900,7 +1993,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Target = { response in @@ -1941,7 +2036,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Target = { response in @@ -1976,6 +2073,7 @@ open class Account: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", "content-type": "application/json" ] @@ -2023,7 +2121,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Token = { response in @@ -2079,7 +2179,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Token = { response in @@ -2183,7 +2285,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Token = { response in @@ -2231,7 +2335,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Token = { response in @@ -2280,7 +2386,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Token = { response in @@ -2320,7 +2428,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Token = { response in @@ -2361,7 +2471,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Token = { response in @@ -2397,7 +2509,9 @@ open class Account: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Token = { response in @@ -2437,7 +2551,9 @@ open class Account: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Token = { response in diff --git a/Sources/Appwrite/Services/Apps.swift b/Sources/Appwrite/Services/Apps.swift new file mode 100644 index 0000000..ab13d65 --- /dev/null +++ b/Sources/Appwrite/Services/Apps.swift @@ -0,0 +1,431 @@ +import AsyncHTTPClient +import Foundation +import NIO +import JSONCodable +import AppwriteEnums +import AppwriteModels + +/// +open class Apps: Service { + + /// + /// List applications. + /// + /// - Parameters: + /// - queries: [String] (optional) + /// - total: Bool (optional) + /// - Throws: Exception if the request fails + /// - Returns: AppwriteModels.AppsList + /// + open func list( + queries: [String]? = nil, + total: Bool? = nil + ) async throws -> AppwriteModels.AppsList { + let apiPath: String = "/apps" + + let apiParams: [String: Any?] = [ + "queries": queries, + "total": total + ] + + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] + + let converter: (Any) throws -> AppwriteModels.AppsList = { response in + return AppwriteModels.AppsList.from(map: response as! [String: Any]) + } + + return try await client.call( + method: "GET", + path: apiPath, + headers: apiHeaders, + params: apiParams, + converter: converter + ) + } + + /// + /// Create a new application. + /// + /// - Parameters: + /// - appId: String + /// - name: String + /// - redirectUris: [String] + /// - enabled: Bool (optional) + /// - type: String (optional) + /// - deviceFlow: Bool (optional) + /// - teamId: String (optional) + /// - Throws: Exception if the request fails + /// - Returns: AppwriteModels.App + /// + open func create( + appId: String, + name: String, + redirectUris: [String], + enabled: Bool? = nil, + type: String? = nil, + deviceFlow: Bool? = nil, + teamId: String? = nil + ) async throws -> AppwriteModels.App { + let apiPath: String = "/apps" + + let apiParams: [String: Any?] = [ + "appId": appId, + "name": name, + "redirectUris": redirectUris, + "enabled": enabled, + "type": type, + "deviceFlow": deviceFlow, + "teamId": teamId + ] + + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" + ] + + let converter: (Any) throws -> AppwriteModels.App = { response in + return AppwriteModels.App.from(map: response as! [String: Any]) + } + + return try await client.call( + method: "POST", + path: apiPath, + headers: apiHeaders, + params: apiParams, + converter: converter + ) + } + + /// + /// Get an application by its unique ID. + /// + /// - Parameters: + /// - appId: String + /// - Throws: Exception if the request fails + /// - Returns: AppwriteModels.App + /// + open func get( + appId: String + ) async throws -> AppwriteModels.App { + let apiPath: String = "/apps/{appId}" + .replacingOccurrences(of: "{appId}", with: appId) + + let apiParams: [String: Any] = [:] + + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] + + let converter: (Any) throws -> AppwriteModels.App = { response in + return AppwriteModels.App.from(map: response as! [String: Any]) + } + + return try await client.call( + method: "GET", + path: apiPath, + headers: apiHeaders, + params: apiParams, + converter: converter + ) + } + + /// + /// Update an application by its unique ID. + /// + /// - Parameters: + /// - appId: String + /// - name: String + /// - enabled: Bool (optional) + /// - redirectUris: [String] (optional) + /// - type: String (optional) + /// - deviceFlow: Bool (optional) + /// - Throws: Exception if the request fails + /// - Returns: AppwriteModels.App + /// + open func update( + appId: String, + name: String, + enabled: Bool? = nil, + redirectUris: [String]? = nil, + type: String? = nil, + deviceFlow: Bool? = nil + ) async throws -> AppwriteModels.App { + let apiPath: String = "/apps/{appId}" + .replacingOccurrences(of: "{appId}", with: appId) + + let apiParams: [String: Any?] = [ + "name": name, + "enabled": enabled, + "redirectUris": redirectUris, + "type": type, + "deviceFlow": deviceFlow + ] + + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" + ] + + let converter: (Any) throws -> AppwriteModels.App = { response in + return AppwriteModels.App.from(map: response as! [String: Any]) + } + + return try await client.call( + method: "PUT", + path: apiPath, + headers: apiHeaders, + params: apiParams, + converter: converter + ) + } + + /// + /// Delete an application by its unique ID. + /// + /// - Parameters: + /// - appId: String + /// - Throws: Exception if the request fails + /// - Returns: Any + /// + open func delete( + appId: String + ) async throws -> Any { + let apiPath: String = "/apps/{appId}" + .replacingOccurrences(of: "{appId}", with: appId) + + let apiParams: [String: Any] = [:] + + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" + ] + + return try await client.call( + method: "DELETE", + path: apiPath, + headers: apiHeaders, + params: apiParams ) + } + + /// + /// List client secrets for an application. + /// + /// - Parameters: + /// - appId: String + /// - queries: [String] (optional) + /// - total: Bool (optional) + /// - Throws: Exception if the request fails + /// - Returns: AppwriteModels.AppSecretList + /// + open func listSecrets( + appId: String, + queries: [String]? = nil, + total: Bool? = nil + ) async throws -> AppwriteModels.AppSecretList { + let apiPath: String = "/apps/{appId}/secrets" + .replacingOccurrences(of: "{appId}", with: appId) + + let apiParams: [String: Any?] = [ + "queries": queries, + "total": total + ] + + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] + + let converter: (Any) throws -> AppwriteModels.AppSecretList = { response in + return AppwriteModels.AppSecretList.from(map: response as! [String: Any]) + } + + return try await client.call( + method: "GET", + path: apiPath, + headers: apiHeaders, + params: apiParams, + converter: converter + ) + } + + /// + /// Create a new client secret for an application. + /// + /// - Parameters: + /// - appId: String + /// - Throws: Exception if the request fails + /// - Returns: AppwriteModels.AppSecretPlaintext + /// + open func createSecret( + appId: String + ) async throws -> AppwriteModels.AppSecretPlaintext { + let apiPath: String = "/apps/{appId}/secrets" + .replacingOccurrences(of: "{appId}", with: appId) + + let apiParams: [String: Any] = [:] + + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" + ] + + let converter: (Any) throws -> AppwriteModels.AppSecretPlaintext = { response in + return AppwriteModels.AppSecretPlaintext.from(map: response as! [String: Any]) + } + + return try await client.call( + method: "POST", + path: apiPath, + headers: apiHeaders, + params: apiParams, + converter: converter + ) + } + + /// + /// Get an application client secret by its unique ID. + /// + /// - Parameters: + /// - appId: String + /// - secretId: String + /// - Throws: Exception if the request fails + /// - Returns: AppwriteModels.AppSecret + /// + open func getSecret( + appId: String, + secretId: String + ) async throws -> AppwriteModels.AppSecret { + let apiPath: String = "/apps/{appId}/secrets/{secretId}" + .replacingOccurrences(of: "{appId}", with: appId) + .replacingOccurrences(of: "{secretId}", with: secretId) + + let apiParams: [String: Any] = [:] + + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] + + let converter: (Any) throws -> AppwriteModels.AppSecret = { response in + return AppwriteModels.AppSecret.from(map: response as! [String: Any]) + } + + return try await client.call( + method: "GET", + path: apiPath, + headers: apiHeaders, + params: apiParams, + converter: converter + ) + } + + /// + /// Delete an application client secret by its unique ID. + /// + /// - Parameters: + /// - appId: String + /// - secretId: String + /// - Throws: Exception if the request fails + /// - Returns: Any + /// + open func deleteSecret( + appId: String, + secretId: String + ) async throws -> Any { + let apiPath: String = "/apps/{appId}/secrets/{secretId}" + .replacingOccurrences(of: "{appId}", with: appId) + .replacingOccurrences(of: "{secretId}", with: secretId) + + let apiParams: [String: Any] = [:] + + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" + ] + + return try await client.call( + method: "DELETE", + path: apiPath, + headers: apiHeaders, + params: apiParams ) + } + + /// + /// Transfer an application to another team by its unique ID. + /// + /// - Parameters: + /// - appId: String + /// - teamId: String + /// - Throws: Exception if the request fails + /// - Returns: AppwriteModels.App + /// + open func updateTeam( + appId: String, + teamId: String + ) async throws -> AppwriteModels.App { + let apiPath: String = "/apps/{appId}/team" + .replacingOccurrences(of: "{appId}", with: appId) + + let apiParams: [String: Any?] = [ + "teamId": teamId + ] + + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" + ] + + let converter: (Any) throws -> AppwriteModels.App = { response in + return AppwriteModels.App.from(map: response as! [String: Any]) + } + + return try await client.call( + method: "PATCH", + path: apiPath, + headers: apiHeaders, + params: apiParams, + converter: converter + ) + } + + /// + /// Revoke all tokens for an application by its unique ID. + /// + /// - Parameters: + /// - appId: String + /// - Throws: Exception if the request fails + /// - Returns: Any + /// + open func deleteTokens( + appId: String + ) async throws -> Any { + let apiPath: String = "/apps/{appId}/tokens" + .replacingOccurrences(of: "{appId}", with: appId) + + let apiParams: [String: Any] = [:] + + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" + ] + + return try await client.call( + method: "DELETE", + path: apiPath, + headers: apiHeaders, + params: apiParams ) + } + + +} diff --git a/Sources/Appwrite/Services/Databases.swift b/Sources/Appwrite/Services/Databases.swift index 2ab5617..a0a369a 100644 --- a/Sources/Appwrite/Services/Databases.swift +++ b/Sources/Appwrite/Services/Databases.swift @@ -25,7 +25,10 @@ open class Databases: Service { "queries": queries ] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.TransactionList = { response in return AppwriteModels.TransactionList.from(map: response as! [String: Any]) @@ -58,7 +61,9 @@ open class Databases: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Transaction = { response in @@ -90,7 +95,10 @@ open class Databases: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.Transaction = { response in return AppwriteModels.Transaction.from(map: response as! [String: Any]) @@ -129,7 +137,9 @@ open class Databases: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Transaction = { response in @@ -162,6 +172,7 @@ open class Databases: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", "content-type": "application/json" ] @@ -193,7 +204,9 @@ open class Databases: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Transaction = { response in @@ -244,7 +257,10 @@ open class Databases: Service { "ttl": ttl ] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.DocumentList = { response in return AppwriteModels.DocumentList.from(map: response as! [String: Any]) @@ -331,7 +347,9 @@ open class Databases: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Document = { response in @@ -415,7 +433,10 @@ open class Databases: Service { "transactionId": transactionId ] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.Document = { response in return AppwriteModels.Document.from(map: response as! [String: Any]) @@ -499,7 +520,9 @@ open class Databases: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Document = { response in @@ -587,7 +610,9 @@ open class Databases: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Document = { response in @@ -665,6 +690,7 @@ open class Databases: Service { ] let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", "content-type": "application/json" ] @@ -713,7 +739,9 @@ open class Databases: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Document = { response in @@ -803,7 +831,9 @@ open class Databases: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Document = { response in diff --git a/Sources/Appwrite/Services/Functions.swift b/Sources/Appwrite/Services/Functions.swift index 7a63a48..f5fa181 100644 --- a/Sources/Appwrite/Services/Functions.swift +++ b/Sources/Appwrite/Services/Functions.swift @@ -32,7 +32,10 @@ open class Functions: Service { "total": total ] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.ExecutionList = { response in return AppwriteModels.ExecutionList.from(map: response as! [String: Any]) @@ -86,7 +89,9 @@ open class Functions: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "multipart/form-data" ] let converter: (Any) throws -> AppwriteModels.Execution = { response in @@ -121,7 +126,10 @@ open class Functions: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.Execution = { response in return AppwriteModels.Execution.from(map: response as! [String: Any]) diff --git a/Sources/Appwrite/Services/Graphql.swift b/Sources/Appwrite/Services/Graphql.swift index 3bc2cda..34b49f8 100644 --- a/Sources/Appwrite/Services/Graphql.swift +++ b/Sources/Appwrite/Services/Graphql.swift @@ -26,8 +26,10 @@ open class Graphql: Service { ] let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", "x-sdk-graphql": "true", - "content-type": "application/json" + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> Any = { response in @@ -61,8 +63,10 @@ open class Graphql: Service { ] let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", "x-sdk-graphql": "true", - "content-type": "application/json" + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> Any = { response in diff --git a/Sources/Appwrite/Services/Locale.swift b/Sources/Appwrite/Services/Locale.swift index 5b70743..86cc129 100644 --- a/Sources/Appwrite/Services/Locale.swift +++ b/Sources/Appwrite/Services/Locale.swift @@ -25,7 +25,10 @@ open class Locale: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.Locale = { response in return AppwriteModels.Locale.from(map: response as! [String: Any]) @@ -53,7 +56,10 @@ open class Locale: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.LocaleCodeList = { response in return AppwriteModels.LocaleCodeList.from(map: response as! [String: Any]) @@ -81,7 +87,10 @@ open class Locale: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.ContinentList = { response in return AppwriteModels.ContinentList.from(map: response as! [String: Any]) @@ -109,7 +118,10 @@ open class Locale: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.CountryList = { response in return AppwriteModels.CountryList.from(map: response as! [String: Any]) @@ -137,7 +149,10 @@ open class Locale: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.CountryList = { response in return AppwriteModels.CountryList.from(map: response as! [String: Any]) @@ -165,7 +180,10 @@ open class Locale: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.PhoneList = { response in return AppwriteModels.PhoneList.from(map: response as! [String: Any]) @@ -194,7 +212,10 @@ open class Locale: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.CurrencyList = { response in return AppwriteModels.CurrencyList.from(map: response as! [String: Any]) @@ -222,7 +243,10 @@ open class Locale: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.LanguageList = { response in return AppwriteModels.LanguageList.from(map: response as! [String: Any]) diff --git a/Sources/Appwrite/Services/Messaging.swift b/Sources/Appwrite/Services/Messaging.swift index c25be74..79ba04e 100644 --- a/Sources/Appwrite/Services/Messaging.swift +++ b/Sources/Appwrite/Services/Messaging.swift @@ -32,7 +32,9 @@ open class Messaging: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Subscriber = { response in @@ -68,6 +70,7 @@ open class Messaging: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", "content-type": "application/json" ] diff --git a/Sources/Appwrite/Services/Oauth2.swift b/Sources/Appwrite/Services/Oauth2.swift new file mode 100644 index 0000000..e2d263f --- /dev/null +++ b/Sources/Appwrite/Services/Oauth2.swift @@ -0,0 +1,253 @@ +import AsyncHTTPClient +import Foundation +import NIO +import JSONCodable +import AppwriteEnums +import AppwriteModels + +/// +open class Oauth2: Service { + + /// + /// Approve an OAuth2 grant after the user gives consent. Returns the + /// `redirectUrl` the end user should be sent to. The consent screen may + /// optionally pass enriched `authorization_details` to record the concrete + /// resources the user selected. You can pass Accept header of + /// `application/json` to receive a JSON response instead of a redirect. + /// + /// - Parameters: + /// - projectId: String + /// - grantId: String + /// - authorizationDetails: String (optional) + /// - Throws: Exception if the request fails + /// - Returns: AppwriteModels.Oauth2Approve + /// + open func approve( + projectId: String, + grantId: String, + authorizationDetails: String? = nil + ) async throws -> AppwriteModels.Oauth2Approve { + let apiPath: String = "/oauth2/{project_id}/approve" + .replacingOccurrences(of: "{project_id}", with: projectId) + + "?project=\(client.config["project"]?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")" + + let apiParams: [String: Any?] = [ + "grant_id": grantId, + "authorization_details": authorizationDetails + ] + + let apiHeaders: [String: String] = [ + "content-type": "application/json", + "accept": "application/json" + ] + + let converter: (Any) throws -> AppwriteModels.Oauth2Approve = { response in + return AppwriteModels.Oauth2Approve.from(map: response as! [String: Any]) + } + + return try await client.call( + method: "POST", + path: apiPath, + headers: apiHeaders, + params: apiParams, + converter: converter + ) + } + + /// + /// Begin the OAuth2 authorization flow. When called without a session, the + /// user is redirected to the consent screen without grant ID. When called with + /// a session, the redirect URL includes param for grant ID. You can pass + /// Accept header of `application/json` to receive a JSON response instead of a + /// redirect. + /// + /// - Parameters: + /// - projectId: String + /// - clientId: String + /// - redirectUri: String + /// - responseType: String + /// - scope: String + /// - state: String (optional) + /// - nonce: String (optional) + /// - codeChallenge: String (optional) + /// - codeChallengeMethod: String (optional) + /// - prompt: String (optional) + /// - maxAge: Int (optional) + /// - authorizationDetails: String (optional) + /// - Throws: Exception if the request fails + /// - Returns: AppwriteModels.Oauth2Authorize + /// + open func authorize( + projectId: String, + clientId: String, + redirectUri: String, + responseType: String, + scope: String, + state: String? = nil, + nonce: String? = nil, + codeChallenge: String? = nil, + codeChallengeMethod: String? = nil, + prompt: String? = nil, + maxAge: Int? = nil, + authorizationDetails: String? = nil + ) async throws -> AppwriteModels.Oauth2Authorize { + let apiPath: String = "/oauth2/{project_id}/authorize" + .replacingOccurrences(of: "{project_id}", with: projectId) + + "?project=\(client.config["project"]?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")" + + let apiParams: [String: Any?] = [ + "client_id": clientId, + "redirect_uri": redirectUri, + "response_type": responseType, + "scope": scope, + "state": state, + "nonce": nonce, + "code_challenge": codeChallenge, + "code_challenge_method": codeChallengeMethod, + "prompt": prompt, + "max_age": maxAge, + "authorization_details": authorizationDetails + ] + + let apiHeaders: [String: String] = [ + "accept": "application/json" + ] + + let converter: (Any) throws -> AppwriteModels.Oauth2Authorize = { response in + return AppwriteModels.Oauth2Authorize.from(map: response as! [String: Any]) + } + + return try await client.call( + method: "GET", + path: apiPath, + headers: apiHeaders, + params: apiParams, + converter: converter + ) + } + + /// + /// Exchange a device flow user code for an OAuth2 grant. The authenticated + /// user is bound to the pending grant. Pass the returned grant ID to the get + /// grant endpoint to render the consent screen, then to the approve or reject + /// endpoint to complete the flow. + /// + /// - Parameters: + /// - projectId: String + /// - userCode: String + /// - Throws: Exception if the request fails + /// - Returns: AppwriteModels.Oauth2Grant + /// + open func createGrant( + projectId: String, + userCode: String + ) async throws -> AppwriteModels.Oauth2Grant { + let apiPath: String = "/oauth2/{project_id}/grants" + .replacingOccurrences(of: "{project_id}", with: projectId) + + let apiParams: [String: Any?] = [ + "user_code": userCode + ] + + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" + ] + + let converter: (Any) throws -> AppwriteModels.Oauth2Grant = { response in + return AppwriteModels.Oauth2Grant.from(map: response as! [String: Any]) + } + + return try await client.call( + method: "POST", + path: apiPath, + headers: apiHeaders, + params: apiParams, + converter: converter + ) + } + + /// + /// Get an OAuth2 grant by its ID. Used by the consent screen to display the + /// details of the authorization the user is being asked to approve. A grant + /// can only be read by the user it belongs to, or by server SDK. + /// + /// - Parameters: + /// - projectId: String + /// - grantId: String + /// - Throws: Exception if the request fails + /// - Returns: AppwriteModels.Oauth2Grant + /// + open func getGrant( + projectId: String, + grantId: String + ) async throws -> AppwriteModels.Oauth2Grant { + let apiPath: String = "/oauth2/{project_id}/grants/{grant_id}" + .replacingOccurrences(of: "{project_id}", with: projectId) + .replacingOccurrences(of: "{grant_id}", with: grantId) + + let apiParams: [String: Any] = [:] + + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] + + let converter: (Any) throws -> AppwriteModels.Oauth2Grant = { response in + return AppwriteModels.Oauth2Grant.from(map: response as! [String: Any]) + } + + return try await client.call( + method: "GET", + path: apiPath, + headers: apiHeaders, + params: apiParams, + converter: converter + ) + } + + /// + /// Reject an OAuth2 grant when the user denies consent. Returns the + /// `redirectUrl` the end user should be sent to with an `access_denied` error. + /// You can pass Accept header of `application/json` to receive a JSON response + /// instead of a redirect. + /// + /// - Parameters: + /// - projectId: String + /// - grantId: String + /// - Throws: Exception if the request fails + /// - Returns: AppwriteModels.Oauth2Reject + /// + open func reject( + projectId: String, + grantId: String + ) async throws -> AppwriteModels.Oauth2Reject { + let apiPath: String = "/oauth2/{project_id}/reject" + .replacingOccurrences(of: "{project_id}", with: projectId) + + "?project=\(client.config["project"]?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")" + + let apiParams: [String: Any?] = [ + "grant_id": grantId + ] + + let apiHeaders: [String: String] = [ + "content-type": "application/json", + "accept": "application/json" + ] + + let converter: (Any) throws -> AppwriteModels.Oauth2Reject = { response in + return AppwriteModels.Oauth2Reject.from(map: response as! [String: Any]) + } + + return try await client.call( + method: "POST", + path: apiPath, + headers: apiHeaders, + params: apiParams, + converter: converter + ) + } + + +} diff --git a/Sources/Appwrite/Services/Presences.swift b/Sources/Appwrite/Services/Presences.swift index 715e963..16f7047 100644 --- a/Sources/Appwrite/Services/Presences.swift +++ b/Sources/Appwrite/Services/Presences.swift @@ -32,7 +32,10 @@ open class Presences: Service { "ttl": ttl ] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.PresenceList = { response in return AppwriteModels.PresenceList.from(map: response as! [String: Any]) @@ -65,7 +68,10 @@ open class Presences: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.Presence = { response in return AppwriteModels.Presence.from(map: response as! [String: Any]) @@ -111,7 +117,9 @@ open class Presences: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Presence = { response in @@ -162,7 +170,9 @@ open class Presences: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Presence = { response in @@ -196,6 +206,7 @@ open class Presences: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", "content-type": "application/json" ] diff --git a/Sources/Appwrite/Services/Storage.swift b/Sources/Appwrite/Services/Storage.swift index be1ffd5..4c84a35 100644 --- a/Sources/Appwrite/Services/Storage.swift +++ b/Sources/Appwrite/Services/Storage.swift @@ -35,7 +35,10 @@ open class Storage: Service { "total": total ] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.FileList = { response in return AppwriteModels.FileList.from(map: response as! [String: Any]) @@ -95,7 +98,9 @@ open class Storage: Service { ] var apiHeaders: [String: String] = [ - "content-type": "multipart/form-data" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "multipart/form-data", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.File = { response in @@ -135,7 +140,10 @@ open class Storage: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.File = { response in return AppwriteModels.File.from(map: response as! [String: Any]) @@ -178,7 +186,9 @@ open class Storage: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.File = { response in @@ -215,6 +225,7 @@ open class Storage: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", "content-type": "application/json" ] diff --git a/Sources/Appwrite/Services/TablesDB.swift b/Sources/Appwrite/Services/TablesDB.swift index c812ccb..a057333 100644 --- a/Sources/Appwrite/Services/TablesDB.swift +++ b/Sources/Appwrite/Services/TablesDB.swift @@ -25,7 +25,10 @@ open class TablesDB: Service { "queries": queries ] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.TransactionList = { response in return AppwriteModels.TransactionList.from(map: response as! [String: Any]) @@ -58,7 +61,9 @@ open class TablesDB: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Transaction = { response in @@ -90,7 +95,10 @@ open class TablesDB: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.Transaction = { response in return AppwriteModels.Transaction.from(map: response as! [String: Any]) @@ -129,7 +137,9 @@ open class TablesDB: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Transaction = { response in @@ -162,6 +172,7 @@ open class TablesDB: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", "content-type": "application/json" ] @@ -193,7 +204,9 @@ open class TablesDB: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Transaction = { response in @@ -243,7 +256,10 @@ open class TablesDB: Service { "ttl": ttl ] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.RowList = { response in return AppwriteModels.RowList.from(map: response as! [String: Any]) @@ -328,7 +344,9 @@ open class TablesDB: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Row = { response in @@ -410,7 +428,10 @@ open class TablesDB: Service { "transactionId": transactionId ] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.Row = { response in return AppwriteModels.Row.from(map: response as! [String: Any]) @@ -492,7 +513,9 @@ open class TablesDB: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Row = { response in @@ -578,7 +601,9 @@ open class TablesDB: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Row = { response in @@ -654,6 +679,7 @@ open class TablesDB: Service { ] let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", "content-type": "application/json" ] @@ -701,7 +727,9 @@ open class TablesDB: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Row = { response in @@ -789,7 +817,9 @@ open class TablesDB: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Row = { response in diff --git a/Sources/Appwrite/Services/Teams.swift b/Sources/Appwrite/Services/Teams.swift index b40b9b7..506d4ad 100644 --- a/Sources/Appwrite/Services/Teams.swift +++ b/Sources/Appwrite/Services/Teams.swift @@ -33,7 +33,10 @@ open class Teams: Service { "total": total ] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.TeamList = { response in return AppwriteModels.TeamList.from(map: response as! [String: Any]) @@ -99,7 +102,9 @@ open class Teams: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Team = { response in @@ -157,7 +162,10 @@ open class Teams: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.Team = { response in return AppwriteModels.Team.from(map: response as! [String: Any]) @@ -211,7 +219,9 @@ open class Teams: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Team = { response in @@ -265,6 +275,7 @@ open class Teams: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", "content-type": "application/json" ] @@ -303,7 +314,10 @@ open class Teams: Service { "total": total ] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.MembershipList = { response in return AppwriteModels.MembershipList.from(map: response as! [String: Any]) @@ -374,7 +388,9 @@ open class Teams: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Membership = { response in @@ -411,7 +427,10 @@ open class Teams: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.Membership = { response in return AppwriteModels.Membership.from(map: response as! [String: Any]) @@ -453,7 +472,9 @@ open class Teams: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Membership = { response in @@ -491,6 +512,7 @@ open class Teams: Service { let apiParams: [String: Any] = [:] let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", "content-type": "application/json" ] @@ -534,7 +556,9 @@ open class Teams: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Membership = { response in @@ -569,7 +593,10 @@ open class Teams: Service { let apiParams: [String: Any] = [:] - let apiHeaders: [String: String] = [:] + let apiHeaders: [String: String] = [ + "X-Appwrite-Project": client.config["project"] ?? "", + "accept": "application/json" + ] let converter: (Any) throws -> AppwriteModels.Preferences = { response in return AppwriteModels.Preferences.from(map: response as! [String: Any]) @@ -627,7 +654,9 @@ open class Teams: Service { ] let apiHeaders: [String: String] = [ - "content-type": "application/json" + "X-Appwrite-Project": client.config["project"] ?? "", + "content-type": "application/json", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Preferences = { response in diff --git a/Sources/AppwriteModels/App.swift b/Sources/AppwriteModels/App.swift new file mode 100644 index 0000000..545e69e --- /dev/null +++ b/Sources/AppwriteModels/App.swift @@ -0,0 +1,133 @@ +import Foundation +import JSONCodable + +/// App +open class App: Codable { + + enum CodingKeys: String, CodingKey { + case id = "$id" + case createdAt = "$createdAt" + case updatedAt = "$updatedAt" + case name = "name" + case redirectUris = "redirectUris" + case enabled = "enabled" + case type = "type" + case deviceFlow = "deviceFlow" + case teamId = "teamId" + case userId = "userId" + case secrets = "secrets" + } + + /// App ID. + public let id: String + /// App creation time in ISO 8601 format. + public let createdAt: String + /// App update date in ISO 8601 format. + public let updatedAt: String + /// Application name. + public let name: String + /// List of authorized redirect URIs. These URIs can be used to redirect users after they authenticate. + public let redirectUris: [String] + /// Whether the app is enabled or not. + public let enabled: Bool + /// OAuth2 client type. `public` for SPAs, mobile, and native apps that cannot keep a client secret (PKCE required); `confidential` for server-side clients that authenticate with a client secret. + public let type: String + /// Whether this client may use the OAuth2 Device Authorization Grant (RFC 8628). + public let deviceFlow: Bool + /// ID of team that owns the application, if owned by team. Otherwise, user ID will be used. + public let teamId: String + /// ID of user who owns the application, if owned by user. Otherwise, team ID will be used. + public let userId: String + /// List of application secrets. + public let secrets: [AppSecret] + + init( + id: String, + createdAt: String, + updatedAt: String, + name: String, + redirectUris: [String], + enabled: Bool, + type: String, + deviceFlow: Bool, + teamId: String, + userId: String, + secrets: [AppSecret] + ) { + self.id = id + self.createdAt = createdAt + self.updatedAt = updatedAt + self.name = name + self.redirectUris = redirectUris + self.enabled = enabled + self.type = type + self.deviceFlow = deviceFlow + self.teamId = teamId + self.userId = userId + self.secrets = secrets + } + + public required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.id = try container.decode(String.self, forKey: .id) + self.createdAt = try container.decode(String.self, forKey: .createdAt) + self.updatedAt = try container.decode(String.self, forKey: .updatedAt) + self.name = try container.decode(String.self, forKey: .name) + self.redirectUris = try container.decode([String].self, forKey: .redirectUris) + self.enabled = try container.decode(Bool.self, forKey: .enabled) + self.type = try container.decode(String.self, forKey: .type) + self.deviceFlow = try container.decode(Bool.self, forKey: .deviceFlow) + self.teamId = try container.decode(String.self, forKey: .teamId) + self.userId = try container.decode(String.self, forKey: .userId) + self.secrets = try container.decode([AppSecret].self, forKey: .secrets) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(id, forKey: .id) + try container.encode(createdAt, forKey: .createdAt) + try container.encode(updatedAt, forKey: .updatedAt) + try container.encode(name, forKey: .name) + try container.encode(redirectUris, forKey: .redirectUris) + try container.encode(enabled, forKey: .enabled) + try container.encode(type, forKey: .type) + try container.encode(deviceFlow, forKey: .deviceFlow) + try container.encode(teamId, forKey: .teamId) + try container.encode(userId, forKey: .userId) + try container.encode(secrets, forKey: .secrets) + } + + public func toMap() -> [String: Any] { + return [ + "$id": id as Any, + "$createdAt": createdAt as Any, + "$updatedAt": updatedAt as Any, + "name": name as Any, + "redirectUris": redirectUris as Any, + "enabled": enabled as Any, + "type": type as Any, + "deviceFlow": deviceFlow as Any, + "teamId": teamId as Any, + "userId": userId as Any, + "secrets": secrets.map { $0.toMap() } as Any + ] + } + + public static func from(map: [String: Any] ) -> App { + return App( + id: map["$id"] as! String, + createdAt: map["$createdAt"] as! String, + updatedAt: map["$updatedAt"] as! String, + name: map["name"] as! String, + redirectUris: map["redirectUris"] as! [String], + enabled: map["enabled"] as! Bool, + type: map["type"] as! String, + deviceFlow: map["deviceFlow"] as! Bool, + teamId: map["teamId"] as! String, + userId: map["userId"] as! String, + secrets: (map["secrets"] as! [[String: Any]]).map { AppSecret.from(map: $0) } + ) + } +} diff --git a/Sources/AppwriteModels/AppSecret.swift b/Sources/AppwriteModels/AppSecret.swift new file mode 100644 index 0000000..aae5952 --- /dev/null +++ b/Sources/AppwriteModels/AppSecret.swift @@ -0,0 +1,115 @@ +import Foundation +import JSONCodable + +/// AppSecret +open class AppSecret: Codable { + + enum CodingKeys: String, CodingKey { + case id = "$id" + case createdAt = "$createdAt" + case updatedAt = "$updatedAt" + case appId = "appId" + case secret = "secret" + case hint = "hint" + case createdById = "createdById" + case createdByName = "createdByName" + case lastAccessedAt = "lastAccessedAt" + } + + /// Secret ID. + public let id: String + /// Secret creation time in ISO 8601 format. + public let createdAt: String + /// Secret update time in ISO 8601 format. + public let updatedAt: String + /// Application ID this secret belongs to. + public let appId: String + /// Hashed application client secret. + public let secret: String + /// Last few characters of the client secret, used to help identify it. + public let hint: String + /// ID of the user who created the secret. + public let createdById: String + /// Name of the user who created the secret. + public let createdByName: String + /// Time the secret was last used for authentication in ISO 8601 format. Null if never used. + public let lastAccessedAt: String? + + init( + id: String, + createdAt: String, + updatedAt: String, + appId: String, + secret: String, + hint: String, + createdById: String, + createdByName: String, + lastAccessedAt: String? + ) { + self.id = id + self.createdAt = createdAt + self.updatedAt = updatedAt + self.appId = appId + self.secret = secret + self.hint = hint + self.createdById = createdById + self.createdByName = createdByName + self.lastAccessedAt = lastAccessedAt + } + + public required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.id = try container.decode(String.self, forKey: .id) + self.createdAt = try container.decode(String.self, forKey: .createdAt) + self.updatedAt = try container.decode(String.self, forKey: .updatedAt) + self.appId = try container.decode(String.self, forKey: .appId) + self.secret = try container.decode(String.self, forKey: .secret) + self.hint = try container.decode(String.self, forKey: .hint) + self.createdById = try container.decode(String.self, forKey: .createdById) + self.createdByName = try container.decode(String.self, forKey: .createdByName) + self.lastAccessedAt = try container.decodeIfPresent(String.self, forKey: .lastAccessedAt) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(id, forKey: .id) + try container.encode(createdAt, forKey: .createdAt) + try container.encode(updatedAt, forKey: .updatedAt) + try container.encode(appId, forKey: .appId) + try container.encode(secret, forKey: .secret) + try container.encode(hint, forKey: .hint) + try container.encode(createdById, forKey: .createdById) + try container.encode(createdByName, forKey: .createdByName) + try container.encodeIfPresent(lastAccessedAt, forKey: .lastAccessedAt) + } + + public func toMap() -> [String: Any] { + return [ + "$id": id as Any, + "$createdAt": createdAt as Any, + "$updatedAt": updatedAt as Any, + "appId": appId as Any, + "secret": secret as Any, + "hint": hint as Any, + "createdById": createdById as Any, + "createdByName": createdByName as Any, + "lastAccessedAt": lastAccessedAt as Any + ] + } + + public static func from(map: [String: Any] ) -> AppSecret { + return AppSecret( + id: map["$id"] as! String, + createdAt: map["$createdAt"] as! String, + updatedAt: map["$updatedAt"] as! String, + appId: map["appId"] as! String, + secret: map["secret"] as! String, + hint: map["hint"] as! String, + createdById: map["createdById"] as! String, + createdByName: map["createdByName"] as! String, + lastAccessedAt: map["lastAccessedAt"] as? String + ) + } +} diff --git a/Sources/AppwriteModels/AppSecretList.swift b/Sources/AppwriteModels/AppSecretList.swift new file mode 100644 index 0000000..927673d --- /dev/null +++ b/Sources/AppwriteModels/AppSecretList.swift @@ -0,0 +1,52 @@ +import Foundation +import JSONCodable + +/// App secrets list +open class AppSecretList: Codable { + + enum CodingKeys: String, CodingKey { + case total = "total" + case secrets = "secrets" + } + + /// Total number of secrets that matched your query. + public let total: Int + /// List of secrets. + public let secrets: [AppSecret] + + init( + total: Int, + secrets: [AppSecret] + ) { + self.total = total + self.secrets = secrets + } + + public required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.total = try container.decode(Int.self, forKey: .total) + self.secrets = try container.decode([AppSecret].self, forKey: .secrets) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(total, forKey: .total) + try container.encode(secrets, forKey: .secrets) + } + + public func toMap() -> [String: Any] { + return [ + "total": total as Any, + "secrets": secrets.map { $0.toMap() } as Any + ] + } + + public static func from(map: [String: Any] ) -> AppSecretList { + return AppSecretList( + total: map["total"] as! Int, + secrets: (map["secrets"] as! [[String: Any]]).map { AppSecret.from(map: $0) } + ) + } +} diff --git a/Sources/AppwriteModels/AppSecretPlaintext.swift b/Sources/AppwriteModels/AppSecretPlaintext.swift new file mode 100644 index 0000000..8902a68 --- /dev/null +++ b/Sources/AppwriteModels/AppSecretPlaintext.swift @@ -0,0 +1,115 @@ +import Foundation +import JSONCodable + +/// AppSecretPlaintext +open class AppSecretPlaintext: Codable { + + enum CodingKeys: String, CodingKey { + case id = "$id" + case createdAt = "$createdAt" + case updatedAt = "$updatedAt" + case appId = "appId" + case secret = "secret" + case hint = "hint" + case createdById = "createdById" + case createdByName = "createdByName" + case lastAccessedAt = "lastAccessedAt" + } + + /// Secret ID. + public let id: String + /// Secret creation time in ISO 8601 format. + public let createdAt: String + /// Secret update time in ISO 8601 format. + public let updatedAt: String + /// Application ID this secret belongs to. + public let appId: String + /// Application client secret. Returned in full only when the secret is created; subsequent reads return a masked value. + public let secret: String + /// Last few characters of the client secret, used to help identify it. + public let hint: String + /// ID of the user who created the secret. + public let createdById: String + /// Name of the user who created the secret. + public let createdByName: String + /// Time the secret was last used for authentication in ISO 8601 format. Null if never used. + public let lastAccessedAt: String? + + init( + id: String, + createdAt: String, + updatedAt: String, + appId: String, + secret: String, + hint: String, + createdById: String, + createdByName: String, + lastAccessedAt: String? + ) { + self.id = id + self.createdAt = createdAt + self.updatedAt = updatedAt + self.appId = appId + self.secret = secret + self.hint = hint + self.createdById = createdById + self.createdByName = createdByName + self.lastAccessedAt = lastAccessedAt + } + + public required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.id = try container.decode(String.self, forKey: .id) + self.createdAt = try container.decode(String.self, forKey: .createdAt) + self.updatedAt = try container.decode(String.self, forKey: .updatedAt) + self.appId = try container.decode(String.self, forKey: .appId) + self.secret = try container.decode(String.self, forKey: .secret) + self.hint = try container.decode(String.self, forKey: .hint) + self.createdById = try container.decode(String.self, forKey: .createdById) + self.createdByName = try container.decode(String.self, forKey: .createdByName) + self.lastAccessedAt = try container.decodeIfPresent(String.self, forKey: .lastAccessedAt) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(id, forKey: .id) + try container.encode(createdAt, forKey: .createdAt) + try container.encode(updatedAt, forKey: .updatedAt) + try container.encode(appId, forKey: .appId) + try container.encode(secret, forKey: .secret) + try container.encode(hint, forKey: .hint) + try container.encode(createdById, forKey: .createdById) + try container.encode(createdByName, forKey: .createdByName) + try container.encodeIfPresent(lastAccessedAt, forKey: .lastAccessedAt) + } + + public func toMap() -> [String: Any] { + return [ + "$id": id as Any, + "$createdAt": createdAt as Any, + "$updatedAt": updatedAt as Any, + "appId": appId as Any, + "secret": secret as Any, + "hint": hint as Any, + "createdById": createdById as Any, + "createdByName": createdByName as Any, + "lastAccessedAt": lastAccessedAt as Any + ] + } + + public static func from(map: [String: Any] ) -> AppSecretPlaintext { + return AppSecretPlaintext( + id: map["$id"] as! String, + createdAt: map["$createdAt"] as! String, + updatedAt: map["$updatedAt"] as! String, + appId: map["appId"] as! String, + secret: map["secret"] as! String, + hint: map["hint"] as! String, + createdById: map["createdById"] as! String, + createdByName: map["createdByName"] as! String, + lastAccessedAt: map["lastAccessedAt"] as? String + ) + } +} diff --git a/Sources/AppwriteModels/AppsList.swift b/Sources/AppwriteModels/AppsList.swift new file mode 100644 index 0000000..9d20102 --- /dev/null +++ b/Sources/AppwriteModels/AppsList.swift @@ -0,0 +1,52 @@ +import Foundation +import JSONCodable + +/// Apps list +open class AppsList: Codable { + + enum CodingKeys: String, CodingKey { + case total = "total" + case apps = "apps" + } + + /// Total number of apps that matched your query. + public let total: Int + /// List of apps. + public let apps: [App] + + init( + total: Int, + apps: [App] + ) { + self.total = total + self.apps = apps + } + + public required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.total = try container.decode(Int.self, forKey: .total) + self.apps = try container.decode([App].self, forKey: .apps) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(total, forKey: .total) + try container.encode(apps, forKey: .apps) + } + + public func toMap() -> [String: Any] { + return [ + "total": total as Any, + "apps": apps.map { $0.toMap() } as Any + ] + } + + public static func from(map: [String: Any] ) -> AppsList { + return AppsList( + total: map["total"] as! Int, + apps: (map["apps"] as! [[String: Any]]).map { App.from(map: $0) } + ) + } +} diff --git a/Sources/AppwriteModels/Membership.swift b/Sources/AppwriteModels/Membership.swift index 277601c..79228ee 100644 --- a/Sources/AppwriteModels/Membership.swift +++ b/Sources/AppwriteModels/Membership.swift @@ -18,6 +18,7 @@ open class Membership: Codable { case joined = "joined" case confirm = "confirm" case mfa = "mfa" + case userAccessedAt = "userAccessedAt" case roles = "roles" } @@ -47,6 +48,8 @@ open class Membership: Codable { public let confirm: Bool /// Multi factor authentication status, true if the user has MFA enabled or false otherwise. Hide this attribute by toggling membership privacy in the Console. public let mfa: Bool + /// Most recent access date in ISO 8601 format. Show this attribute by toggling membership privacy in the Console. + public let userAccessedAt: String /// User list of roles public let roles: [String] @@ -64,6 +67,7 @@ open class Membership: Codable { joined: String, confirm: Bool, mfa: Bool, + userAccessedAt: String, roles: [String] ) { self.id = id @@ -79,6 +83,7 @@ open class Membership: Codable { self.joined = joined self.confirm = confirm self.mfa = mfa + self.userAccessedAt = userAccessedAt self.roles = roles } @@ -98,6 +103,7 @@ open class Membership: Codable { self.joined = try container.decode(String.self, forKey: .joined) self.confirm = try container.decode(Bool.self, forKey: .confirm) self.mfa = try container.decode(Bool.self, forKey: .mfa) + self.userAccessedAt = try container.decode(String.self, forKey: .userAccessedAt) self.roles = try container.decode([String].self, forKey: .roles) } @@ -117,6 +123,7 @@ open class Membership: Codable { try container.encode(joined, forKey: .joined) try container.encode(confirm, forKey: .confirm) try container.encode(mfa, forKey: .mfa) + try container.encode(userAccessedAt, forKey: .userAccessedAt) try container.encode(roles, forKey: .roles) } @@ -135,6 +142,7 @@ open class Membership: Codable { "joined": joined as Any, "confirm": confirm as Any, "mfa": mfa as Any, + "userAccessedAt": userAccessedAt as Any, "roles": roles as Any ] } @@ -154,6 +162,7 @@ open class Membership: Codable { joined: map["joined"] as! String, confirm: map["confirm"] as! Bool, mfa: map["mfa"] as! Bool, + userAccessedAt: map["userAccessedAt"] as! String, roles: map["roles"] as! [String] ) } diff --git a/Sources/AppwriteModels/Oauth2Approve.swift b/Sources/AppwriteModels/Oauth2Approve.swift new file mode 100644 index 0000000..3cee7ad --- /dev/null +++ b/Sources/AppwriteModels/Oauth2Approve.swift @@ -0,0 +1,43 @@ +import Foundation +import JSONCodable + +/// OAuth2 Approve +open class Oauth2Approve: Codable { + + enum CodingKeys: String, CodingKey { + case redirectUrl = "redirectUrl" + } + + /// URL the end user should be redirected to after the grant is approved, carrying the authorization `code` and/or `id_token` along with the original `state`. + public let redirectUrl: String + + init( + redirectUrl: String + ) { + self.redirectUrl = redirectUrl + } + + public required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.redirectUrl = try container.decode(String.self, forKey: .redirectUrl) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(redirectUrl, forKey: .redirectUrl) + } + + public func toMap() -> [String: Any] { + return [ + "redirectUrl": redirectUrl as Any + ] + } + + public static func from(map: [String: Any] ) -> Oauth2Approve { + return Oauth2Approve( + redirectUrl: map["redirectUrl"] as! String + ) + } +} diff --git a/Sources/AppwriteModels/Oauth2Authorize.swift b/Sources/AppwriteModels/Oauth2Authorize.swift new file mode 100644 index 0000000..62c10d5 --- /dev/null +++ b/Sources/AppwriteModels/Oauth2Authorize.swift @@ -0,0 +1,52 @@ +import Foundation +import JSONCodable + +/// OAuth2 Authorize +open class Oauth2Authorize: Codable { + + enum CodingKeys: String, CodingKey { + case grantId = "grantId" + case redirectUrl = "redirectUrl" + } + + /// OAuth2 grant ID. Set when the user must give explicit consent; pass it to the approve or reject endpoint. Empty when a redirect URL is returned instead. + public let grantId: String + /// URL the end user should be redirected to when the flow can complete without consent. Empty when consent is still required. + public let redirectUrl: String + + init( + grantId: String, + redirectUrl: String + ) { + self.grantId = grantId + self.redirectUrl = redirectUrl + } + + public required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.grantId = try container.decode(String.self, forKey: .grantId) + self.redirectUrl = try container.decode(String.self, forKey: .redirectUrl) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(grantId, forKey: .grantId) + try container.encode(redirectUrl, forKey: .redirectUrl) + } + + public func toMap() -> [String: Any] { + return [ + "grantId": grantId as Any, + "redirectUrl": redirectUrl as Any + ] + } + + public static func from(map: [String: Any] ) -> Oauth2Authorize { + return Oauth2Authorize( + grantId: map["grantId"] as! String, + redirectUrl: map["redirectUrl"] as! String + ) + } +} diff --git a/Sources/AppwriteModels/Oauth2Grant.swift b/Sources/AppwriteModels/Oauth2Grant.swift new file mode 100644 index 0000000..9ef9f1e --- /dev/null +++ b/Sources/AppwriteModels/Oauth2Grant.swift @@ -0,0 +1,133 @@ +import Foundation +import JSONCodable + +/// OAuth2 Grant +open class Oauth2Grant: Codable { + + enum CodingKeys: String, CodingKey { + case id = "$id" + case createdAt = "$createdAt" + case updatedAt = "$updatedAt" + case userId = "userId" + case appId = "appId" + case scopes = "scopes" + case authorizationDetails = "authorizationDetails" + case prompt = "prompt" + case redirectUri = "redirectUri" + case authTime = "authTime" + case expire = "expire" + } + + /// Grant ID. + public let id: String + /// Grant creation time in ISO 8601 format. + public let createdAt: String + /// Grant update date in ISO 8601 format. + public let updatedAt: String + /// ID of the user the grant belongs to. + public let userId: String + /// ID of the OAuth2 client (app) the grant was requested for. + public let appId: String + /// Requested OAuth2 scopes the user is being asked to consent to. + public let scopes: [String] + /// Requested authorization_details the user is being asked to consent to, as a JSON string. Each entry has a `type` plus project-defined fields. + public let authorizationDetails: String + /// OIDC prompt directive the consent screen should honor. Space-separated list of: login, consent, select_account. + public let prompt: String + /// Redirect URI the user will be sent to after the flow completes. + public let redirectUri: String + /// Unix timestamp of when the user last authenticated. + public let authTime: Int + /// Grant expiration time in ISO 8601 format. + public let expire: String + + init( + id: String, + createdAt: String, + updatedAt: String, + userId: String, + appId: String, + scopes: [String], + authorizationDetails: String, + prompt: String, + redirectUri: String, + authTime: Int, + expire: String + ) { + self.id = id + self.createdAt = createdAt + self.updatedAt = updatedAt + self.userId = userId + self.appId = appId + self.scopes = scopes + self.authorizationDetails = authorizationDetails + self.prompt = prompt + self.redirectUri = redirectUri + self.authTime = authTime + self.expire = expire + } + + public required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.id = try container.decode(String.self, forKey: .id) + self.createdAt = try container.decode(String.self, forKey: .createdAt) + self.updatedAt = try container.decode(String.self, forKey: .updatedAt) + self.userId = try container.decode(String.self, forKey: .userId) + self.appId = try container.decode(String.self, forKey: .appId) + self.scopes = try container.decode([String].self, forKey: .scopes) + self.authorizationDetails = try container.decode(String.self, forKey: .authorizationDetails) + self.prompt = try container.decode(String.self, forKey: .prompt) + self.redirectUri = try container.decode(String.self, forKey: .redirectUri) + self.authTime = try container.decode(Int.self, forKey: .authTime) + self.expire = try container.decode(String.self, forKey: .expire) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(id, forKey: .id) + try container.encode(createdAt, forKey: .createdAt) + try container.encode(updatedAt, forKey: .updatedAt) + try container.encode(userId, forKey: .userId) + try container.encode(appId, forKey: .appId) + try container.encode(scopes, forKey: .scopes) + try container.encode(authorizationDetails, forKey: .authorizationDetails) + try container.encode(prompt, forKey: .prompt) + try container.encode(redirectUri, forKey: .redirectUri) + try container.encode(authTime, forKey: .authTime) + try container.encode(expire, forKey: .expire) + } + + public func toMap() -> [String: Any] { + return [ + "$id": id as Any, + "$createdAt": createdAt as Any, + "$updatedAt": updatedAt as Any, + "userId": userId as Any, + "appId": appId as Any, + "scopes": scopes as Any, + "authorizationDetails": authorizationDetails as Any, + "prompt": prompt as Any, + "redirectUri": redirectUri as Any, + "authTime": authTime as Any, + "expire": expire as Any + ] + } + + public static func from(map: [String: Any] ) -> Oauth2Grant { + return Oauth2Grant( + id: map["$id"] as! String, + createdAt: map["$createdAt"] as! String, + updatedAt: map["$updatedAt"] as! String, + userId: map["userId"] as! String, + appId: map["appId"] as! String, + scopes: map["scopes"] as! [String], + authorizationDetails: map["authorizationDetails"] as! String, + prompt: map["prompt"] as! String, + redirectUri: map["redirectUri"] as! String, + authTime: map["authTime"] as! Int, + expire: map["expire"] as! String + ) + } +} diff --git a/Sources/AppwriteModels/Oauth2Reject.swift b/Sources/AppwriteModels/Oauth2Reject.swift new file mode 100644 index 0000000..b0cd5be --- /dev/null +++ b/Sources/AppwriteModels/Oauth2Reject.swift @@ -0,0 +1,43 @@ +import Foundation +import JSONCodable + +/// OAuth2 Reject +open class Oauth2Reject: Codable { + + enum CodingKeys: String, CodingKey { + case redirectUrl = "redirectUrl" + } + + /// URL the end user should be redirected to after the grant is rejected, carrying an `access_denied` error. + public let redirectUrl: String + + init( + redirectUrl: String + ) { + self.redirectUrl = redirectUrl + } + + public required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.redirectUrl = try container.decode(String.self, forKey: .redirectUrl) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(redirectUrl, forKey: .redirectUrl) + } + + public func toMap() -> [String: Any] { + return [ + "redirectUrl": redirectUrl as Any + ] + } + + public static func from(map: [String: Any] ) -> Oauth2Reject { + return Oauth2Reject( + redirectUrl: map["redirectUrl"] as! String + ) + } +} diff --git a/Sources/AppwriteModels/User.swift b/Sources/AppwriteModels/User.swift index ad9de15..a3ae446 100644 --- a/Sources/AppwriteModels/User.swift +++ b/Sources/AppwriteModels/User.swift @@ -19,6 +19,11 @@ open class User: Codable { case email = "email" case phone = "phone" case emailVerification = "emailVerification" + case emailCanonical = "emailCanonical" + case emailIsFree = "emailIsFree" + case emailIsDisposable = "emailIsDisposable" + case emailIsCorporate = "emailIsCorporate" + case emailIsCanonical = "emailIsCanonical" case phoneVerification = "phoneVerification" case mfa = "mfa" case prefs = "prefs" @@ -56,6 +61,16 @@ open class User: Codable { public let phone: String /// Email verification status. public let emailVerification: Bool + /// Canonical form of the user email address. + public let emailCanonical: String? + /// Whether the user email is from a free email provider. + public let emailIsFree: Bool? + /// Whether the user email is from a disposable email provider. + public let emailIsDisposable: Bool? + /// Whether the user email is from a corporate domain. + public let emailIsCorporate: Bool? + /// Whether the user email is in its canonical form. + public let emailIsCanonical: Bool? /// Phone verification status. public let phoneVerification: Bool /// Multi factor authentication status. @@ -86,6 +101,11 @@ open class User: Codable { email: String, phone: String, emailVerification: Bool, + emailCanonical: String?, + emailIsFree: Bool?, + emailIsDisposable: Bool?, + emailIsCorporate: Bool?, + emailIsCanonical: Bool?, phoneVerification: Bool, mfa: Bool, prefs: Preferences, @@ -108,6 +128,11 @@ open class User: Codable { self.email = email self.phone = phone self.emailVerification = emailVerification + self.emailCanonical = emailCanonical + self.emailIsFree = emailIsFree + self.emailIsDisposable = emailIsDisposable + self.emailIsCorporate = emailIsCorporate + self.emailIsCanonical = emailIsCanonical self.phoneVerification = phoneVerification self.mfa = mfa self.prefs = prefs @@ -134,6 +159,11 @@ open class User: Codable { self.email = try container.decode(String.self, forKey: .email) self.phone = try container.decode(String.self, forKey: .phone) self.emailVerification = try container.decode(Bool.self, forKey: .emailVerification) + self.emailCanonical = try container.decodeIfPresent(String.self, forKey: .emailCanonical) + self.emailIsFree = try container.decodeIfPresent(Bool.self, forKey: .emailIsFree) + self.emailIsDisposable = try container.decodeIfPresent(Bool.self, forKey: .emailIsDisposable) + self.emailIsCorporate = try container.decodeIfPresent(Bool.self, forKey: .emailIsCorporate) + self.emailIsCanonical = try container.decodeIfPresent(Bool.self, forKey: .emailIsCanonical) self.phoneVerification = try container.decode(Bool.self, forKey: .phoneVerification) self.mfa = try container.decode(Bool.self, forKey: .mfa) self.prefs = try container.decode(Preferences.self, forKey: .prefs) @@ -160,6 +190,11 @@ open class User: Codable { try container.encode(email, forKey: .email) try container.encode(phone, forKey: .phone) try container.encode(emailVerification, forKey: .emailVerification) + try container.encodeIfPresent(emailCanonical, forKey: .emailCanonical) + try container.encodeIfPresent(emailIsFree, forKey: .emailIsFree) + try container.encodeIfPresent(emailIsDisposable, forKey: .emailIsDisposable) + try container.encodeIfPresent(emailIsCorporate, forKey: .emailIsCorporate) + try container.encodeIfPresent(emailIsCanonical, forKey: .emailIsCanonical) try container.encode(phoneVerification, forKey: .phoneVerification) try container.encode(mfa, forKey: .mfa) try container.encode(prefs, forKey: .prefs) @@ -185,6 +220,11 @@ open class User: Codable { "email": email as Any, "phone": phone as Any, "emailVerification": emailVerification as Any, + "emailCanonical": emailCanonical as Any, + "emailIsFree": emailIsFree as Any, + "emailIsDisposable": emailIsDisposable as Any, + "emailIsCorporate": emailIsCorporate as Any, + "emailIsCanonical": emailIsCanonical as Any, "phoneVerification": phoneVerification as Any, "mfa": mfa as Any, "prefs": prefs.toMap() as Any, @@ -211,6 +251,11 @@ open class User: Codable { email: map["email"] as! String, phone: map["phone"] as! String, emailVerification: map["emailVerification"] as! Bool, + emailCanonical: map["emailCanonical"] as? String, + emailIsFree: map["emailIsFree"] as? Bool, + emailIsDisposable: map["emailIsDisposable"] as? Bool, + emailIsCorporate: map["emailIsCorporate"] as? Bool, + emailIsCanonical: map["emailIsCanonical"] as? Bool, phoneVerification: map["phoneVerification"] as! Bool, mfa: map["mfa"] as! Bool, prefs: Preferences.from(map: map["prefs"] as! [String: Any]), diff --git a/docs/examples/account/update-password.md b/docs/examples/account/update-password.md index fe287d7..dbbddb7 100644 --- a/docs/examples/account/update-password.md +++ b/docs/examples/account/update-password.md @@ -9,7 +9,7 @@ let account = Account(client) let user = try await account.updatePassword( password: "", - oldPassword: "password" // optional + oldPassword: "" // optional ) ``` diff --git a/docs/examples/apps/create-secret.md b/docs/examples/apps/create-secret.md new file mode 100644 index 0000000..5fe4c5e --- /dev/null +++ b/docs/examples/apps/create-secret.md @@ -0,0 +1,14 @@ +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +let apps = Apps(client) + +let appSecretPlaintext = try await apps.createSecret( + appId: "" +) + +``` diff --git a/docs/examples/apps/create.md b/docs/examples/apps/create.md new file mode 100644 index 0000000..f03ec2d --- /dev/null +++ b/docs/examples/apps/create.md @@ -0,0 +1,20 @@ +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +let apps = Apps(client) + +let app = try await apps.create( + appId: "", + name: "", + redirectUris: [], + enabled: false, // optional + type: "public", // optional + deviceFlow: false, // optional + teamId: "" // optional +) + +``` diff --git a/docs/examples/apps/delete-secret.md b/docs/examples/apps/delete-secret.md new file mode 100644 index 0000000..66af5a5 --- /dev/null +++ b/docs/examples/apps/delete-secret.md @@ -0,0 +1,15 @@ +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +let apps = Apps(client) + +let result = try await apps.deleteSecret( + appId: "", + secretId: "" +) + +``` diff --git a/docs/examples/apps/delete-tokens.md b/docs/examples/apps/delete-tokens.md new file mode 100644 index 0000000..89e7329 --- /dev/null +++ b/docs/examples/apps/delete-tokens.md @@ -0,0 +1,14 @@ +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +let apps = Apps(client) + +let result = try await apps.deleteTokens( + appId: "" +) + +``` diff --git a/docs/examples/apps/delete.md b/docs/examples/apps/delete.md new file mode 100644 index 0000000..2229ea2 --- /dev/null +++ b/docs/examples/apps/delete.md @@ -0,0 +1,14 @@ +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +let apps = Apps(client) + +let result = try await apps.delete( + appId: "" +) + +``` diff --git a/docs/examples/apps/get-secret.md b/docs/examples/apps/get-secret.md new file mode 100644 index 0000000..215dcb6 --- /dev/null +++ b/docs/examples/apps/get-secret.md @@ -0,0 +1,15 @@ +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +let apps = Apps(client) + +let appSecret = try await apps.getSecret( + appId: "", + secretId: "" +) + +``` diff --git a/docs/examples/apps/get.md b/docs/examples/apps/get.md new file mode 100644 index 0000000..27ebc27 --- /dev/null +++ b/docs/examples/apps/get.md @@ -0,0 +1,14 @@ +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +let apps = Apps(client) + +let app = try await apps.get( + appId: "" +) + +``` diff --git a/docs/examples/apps/list-secrets.md b/docs/examples/apps/list-secrets.md new file mode 100644 index 0000000..a956b13 --- /dev/null +++ b/docs/examples/apps/list-secrets.md @@ -0,0 +1,16 @@ +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +let apps = Apps(client) + +let appSecretList = try await apps.listSecrets( + appId: "", + queries: [], // optional + total: false // optional +) + +``` diff --git a/docs/examples/apps/list.md b/docs/examples/apps/list.md new file mode 100644 index 0000000..7b99731 --- /dev/null +++ b/docs/examples/apps/list.md @@ -0,0 +1,15 @@ +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +let apps = Apps(client) + +let appsList = try await apps.list( + queries: [], // optional + total: false // optional +) + +``` diff --git a/docs/examples/apps/update-team.md b/docs/examples/apps/update-team.md new file mode 100644 index 0000000..09b24dc --- /dev/null +++ b/docs/examples/apps/update-team.md @@ -0,0 +1,15 @@ +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +let apps = Apps(client) + +let app = try await apps.updateTeam( + appId: "", + teamId: "" +) + +``` diff --git a/docs/examples/apps/update.md b/docs/examples/apps/update.md new file mode 100644 index 0000000..79bb450 --- /dev/null +++ b/docs/examples/apps/update.md @@ -0,0 +1,19 @@ +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +let apps = Apps(client) + +let app = try await apps.update( + appId: "", + name: "", + enabled: false, // optional + redirectUris: [], // optional + type: "public", // optional + deviceFlow: false // optional +) + +``` diff --git a/docs/examples/oauth2/approve.md b/docs/examples/oauth2/approve.md new file mode 100644 index 0000000..8045039 --- /dev/null +++ b/docs/examples/oauth2/approve.md @@ -0,0 +1,16 @@ +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProjectQuery("") // Your project ID + +let oauth2 = Oauth2(client) + +let oauth2Approve = try await oauth2.approve( + project_id: "", + grant_id: "", + authorization_details: "" // optional +) + +``` diff --git a/docs/examples/oauth2/authorize.md b/docs/examples/oauth2/authorize.md new file mode 100644 index 0000000..d36ee25 --- /dev/null +++ b/docs/examples/oauth2/authorize.md @@ -0,0 +1,25 @@ +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProjectQuery("") // Your project ID + +let oauth2 = Oauth2(client) + +let oauth2Authorize = try await oauth2.authorize( + project_id: "", + client_id: "", + redirect_uri: "https://example.com", + response_type: "code", + scope: "", + state: "", // optional + nonce: "", // optional + code_challenge: "", // optional + code_challenge_method: "s256", // optional + prompt: "", // optional + max_age: 0, // optional + authorization_details: "" // optional +) + +``` diff --git a/docs/examples/oauth2/create-grant.md b/docs/examples/oauth2/create-grant.md new file mode 100644 index 0000000..c912379 --- /dev/null +++ b/docs/examples/oauth2/create-grant.md @@ -0,0 +1,15 @@ +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +let oauth2 = Oauth2(client) + +let oauth2Grant = try await oauth2.createGrant( + project_id: "", + user_code: "" +) + +``` diff --git a/docs/examples/oauth2/get-grant.md b/docs/examples/oauth2/get-grant.md new file mode 100644 index 0000000..0585cc0 --- /dev/null +++ b/docs/examples/oauth2/get-grant.md @@ -0,0 +1,15 @@ +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +let oauth2 = Oauth2(client) + +let oauth2Grant = try await oauth2.getGrant( + project_id: "", + grant_id: "" +) + +``` diff --git a/docs/examples/oauth2/reject.md b/docs/examples/oauth2/reject.md new file mode 100644 index 0000000..6ea406d --- /dev/null +++ b/docs/examples/oauth2/reject.md @@ -0,0 +1,15 @@ +```swift +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProjectQuery("") // Your project ID + +let oauth2 = Oauth2(client) + +let oauth2Reject = try await oauth2.reject( + project_id: "", + grant_id: "" +) + +``` From a78e412bc86da244e0ad16876f08a0424cf34a1a Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Mon, 8 Jun 2026 11:26:11 +0530 Subject: [PATCH 2/5] chore: update Apple SDK to 18.1.0 --- CHANGELOG.md | 4 - Sources/Appwrite/Services/Apps.swift | 431 ------------------ Sources/Appwrite/Services/Oauth2.swift | 253 ---------- Sources/AppwriteModels/App.swift | 133 ------ Sources/AppwriteModels/AppSecret.swift | 115 ----- Sources/AppwriteModels/AppSecretList.swift | 52 --- .../AppwriteModels/AppSecretPlaintext.swift | 115 ----- Sources/AppwriteModels/AppsList.swift | 52 --- Sources/AppwriteModels/Oauth2Approve.swift | 43 -- Sources/AppwriteModels/Oauth2Authorize.swift | 52 --- Sources/AppwriteModels/Oauth2Grant.swift | 133 ------ Sources/AppwriteModels/Oauth2Reject.swift | 43 -- docs/examples/apps/create-secret.md | 14 - docs/examples/apps/create.md | 20 - docs/examples/apps/delete-secret.md | 15 - docs/examples/apps/delete-tokens.md | 14 - docs/examples/apps/delete.md | 14 - docs/examples/apps/get-secret.md | 15 - docs/examples/apps/get.md | 14 - docs/examples/apps/list-secrets.md | 16 - docs/examples/apps/list.md | 15 - docs/examples/apps/update-team.md | 15 - docs/examples/apps/update.md | 19 - docs/examples/oauth2/approve.md | 16 - docs/examples/oauth2/authorize.md | 25 - docs/examples/oauth2/create-grant.md | 15 - docs/examples/oauth2/get-grant.md | 15 - docs/examples/oauth2/reject.md | 15 - 28 files changed, 1683 deletions(-) delete mode 100644 Sources/Appwrite/Services/Apps.swift delete mode 100644 Sources/Appwrite/Services/Oauth2.swift delete mode 100644 Sources/AppwriteModels/App.swift delete mode 100644 Sources/AppwriteModels/AppSecret.swift delete mode 100644 Sources/AppwriteModels/AppSecretList.swift delete mode 100644 Sources/AppwriteModels/AppSecretPlaintext.swift delete mode 100644 Sources/AppwriteModels/AppsList.swift delete mode 100644 Sources/AppwriteModels/Oauth2Approve.swift delete mode 100644 Sources/AppwriteModels/Oauth2Authorize.swift delete mode 100644 Sources/AppwriteModels/Oauth2Grant.swift delete mode 100644 Sources/AppwriteModels/Oauth2Reject.swift delete mode 100644 docs/examples/apps/create-secret.md delete mode 100644 docs/examples/apps/create.md delete mode 100644 docs/examples/apps/delete-secret.md delete mode 100644 docs/examples/apps/delete-tokens.md delete mode 100644 docs/examples/apps/delete.md delete mode 100644 docs/examples/apps/get-secret.md delete mode 100644 docs/examples/apps/get.md delete mode 100644 docs/examples/apps/list-secrets.md delete mode 100644 docs/examples/apps/list.md delete mode 100644 docs/examples/apps/update-team.md delete mode 100644 docs/examples/apps/update.md delete mode 100644 docs/examples/oauth2/approve.md delete mode 100644 docs/examples/oauth2/authorize.md delete mode 100644 docs/examples/oauth2/create-grant.md delete mode 100644 docs/examples/oauth2/get-grant.md delete mode 100644 docs/examples/oauth2/reject.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dedfa8..599d4d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,6 @@ ## 18.1.0 -* Added: `apps` service with app and secret management methods. -* Added: `oauth2` service with `authorize`, `approve`, `reject`, `createGrant`, and `getGrant`. -* Added: `App`, `AppSecret`, `AppSecretPlaintext`, `AppsList`, and `AppSecretList` models. -* Added: `Oauth2Authorize`, `Oauth2Approve`, `Oauth2Reject`, and `Oauth2Grant` models. * Added: Email metadata fields to `User` (`emailCanonical`, `emailIsFree`, `emailIsDisposable`, `emailIsCorporate`, `emailIsCanonical`). * Added: `Membership.userAccessedAt` field. diff --git a/Sources/Appwrite/Services/Apps.swift b/Sources/Appwrite/Services/Apps.swift deleted file mode 100644 index ab13d65..0000000 --- a/Sources/Appwrite/Services/Apps.swift +++ /dev/null @@ -1,431 +0,0 @@ -import AsyncHTTPClient -import Foundation -import NIO -import JSONCodable -import AppwriteEnums -import AppwriteModels - -/// -open class Apps: Service { - - /// - /// List applications. - /// - /// - Parameters: - /// - queries: [String] (optional) - /// - total: Bool (optional) - /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.AppsList - /// - open func list( - queries: [String]? = nil, - total: Bool? = nil - ) async throws -> AppwriteModels.AppsList { - let apiPath: String = "/apps" - - let apiParams: [String: Any?] = [ - "queries": queries, - "total": total - ] - - let apiHeaders: [String: String] = [ - "X-Appwrite-Project": client.config["project"] ?? "", - "accept": "application/json" - ] - - let converter: (Any) throws -> AppwriteModels.AppsList = { response in - return AppwriteModels.AppsList.from(map: response as! [String: Any]) - } - - return try await client.call( - method: "GET", - path: apiPath, - headers: apiHeaders, - params: apiParams, - converter: converter - ) - } - - /// - /// Create a new application. - /// - /// - Parameters: - /// - appId: String - /// - name: String - /// - redirectUris: [String] - /// - enabled: Bool (optional) - /// - type: String (optional) - /// - deviceFlow: Bool (optional) - /// - teamId: String (optional) - /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.App - /// - open func create( - appId: String, - name: String, - redirectUris: [String], - enabled: Bool? = nil, - type: String? = nil, - deviceFlow: Bool? = nil, - teamId: String? = nil - ) async throws -> AppwriteModels.App { - let apiPath: String = "/apps" - - let apiParams: [String: Any?] = [ - "appId": appId, - "name": name, - "redirectUris": redirectUris, - "enabled": enabled, - "type": type, - "deviceFlow": deviceFlow, - "teamId": teamId - ] - - let apiHeaders: [String: String] = [ - "X-Appwrite-Project": client.config["project"] ?? "", - "content-type": "application/json", - "accept": "application/json" - ] - - let converter: (Any) throws -> AppwriteModels.App = { response in - return AppwriteModels.App.from(map: response as! [String: Any]) - } - - return try await client.call( - method: "POST", - path: apiPath, - headers: apiHeaders, - params: apiParams, - converter: converter - ) - } - - /// - /// Get an application by its unique ID. - /// - /// - Parameters: - /// - appId: String - /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.App - /// - open func get( - appId: String - ) async throws -> AppwriteModels.App { - let apiPath: String = "/apps/{appId}" - .replacingOccurrences(of: "{appId}", with: appId) - - let apiParams: [String: Any] = [:] - - let apiHeaders: [String: String] = [ - "X-Appwrite-Project": client.config["project"] ?? "", - "accept": "application/json" - ] - - let converter: (Any) throws -> AppwriteModels.App = { response in - return AppwriteModels.App.from(map: response as! [String: Any]) - } - - return try await client.call( - method: "GET", - path: apiPath, - headers: apiHeaders, - params: apiParams, - converter: converter - ) - } - - /// - /// Update an application by its unique ID. - /// - /// - Parameters: - /// - appId: String - /// - name: String - /// - enabled: Bool (optional) - /// - redirectUris: [String] (optional) - /// - type: String (optional) - /// - deviceFlow: Bool (optional) - /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.App - /// - open func update( - appId: String, - name: String, - enabled: Bool? = nil, - redirectUris: [String]? = nil, - type: String? = nil, - deviceFlow: Bool? = nil - ) async throws -> AppwriteModels.App { - let apiPath: String = "/apps/{appId}" - .replacingOccurrences(of: "{appId}", with: appId) - - let apiParams: [String: Any?] = [ - "name": name, - "enabled": enabled, - "redirectUris": redirectUris, - "type": type, - "deviceFlow": deviceFlow - ] - - let apiHeaders: [String: String] = [ - "X-Appwrite-Project": client.config["project"] ?? "", - "content-type": "application/json", - "accept": "application/json" - ] - - let converter: (Any) throws -> AppwriteModels.App = { response in - return AppwriteModels.App.from(map: response as! [String: Any]) - } - - return try await client.call( - method: "PUT", - path: apiPath, - headers: apiHeaders, - params: apiParams, - converter: converter - ) - } - - /// - /// Delete an application by its unique ID. - /// - /// - Parameters: - /// - appId: String - /// - Throws: Exception if the request fails - /// - Returns: Any - /// - open func delete( - appId: String - ) async throws -> Any { - let apiPath: String = "/apps/{appId}" - .replacingOccurrences(of: "{appId}", with: appId) - - let apiParams: [String: Any] = [:] - - let apiHeaders: [String: String] = [ - "X-Appwrite-Project": client.config["project"] ?? "", - "content-type": "application/json", - "accept": "application/json" - ] - - return try await client.call( - method: "DELETE", - path: apiPath, - headers: apiHeaders, - params: apiParams ) - } - - /// - /// List client secrets for an application. - /// - /// - Parameters: - /// - appId: String - /// - queries: [String] (optional) - /// - total: Bool (optional) - /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.AppSecretList - /// - open func listSecrets( - appId: String, - queries: [String]? = nil, - total: Bool? = nil - ) async throws -> AppwriteModels.AppSecretList { - let apiPath: String = "/apps/{appId}/secrets" - .replacingOccurrences(of: "{appId}", with: appId) - - let apiParams: [String: Any?] = [ - "queries": queries, - "total": total - ] - - let apiHeaders: [String: String] = [ - "X-Appwrite-Project": client.config["project"] ?? "", - "accept": "application/json" - ] - - let converter: (Any) throws -> AppwriteModels.AppSecretList = { response in - return AppwriteModels.AppSecretList.from(map: response as! [String: Any]) - } - - return try await client.call( - method: "GET", - path: apiPath, - headers: apiHeaders, - params: apiParams, - converter: converter - ) - } - - /// - /// Create a new client secret for an application. - /// - /// - Parameters: - /// - appId: String - /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.AppSecretPlaintext - /// - open func createSecret( - appId: String - ) async throws -> AppwriteModels.AppSecretPlaintext { - let apiPath: String = "/apps/{appId}/secrets" - .replacingOccurrences(of: "{appId}", with: appId) - - let apiParams: [String: Any] = [:] - - let apiHeaders: [String: String] = [ - "X-Appwrite-Project": client.config["project"] ?? "", - "content-type": "application/json", - "accept": "application/json" - ] - - let converter: (Any) throws -> AppwriteModels.AppSecretPlaintext = { response in - return AppwriteModels.AppSecretPlaintext.from(map: response as! [String: Any]) - } - - return try await client.call( - method: "POST", - path: apiPath, - headers: apiHeaders, - params: apiParams, - converter: converter - ) - } - - /// - /// Get an application client secret by its unique ID. - /// - /// - Parameters: - /// - appId: String - /// - secretId: String - /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.AppSecret - /// - open func getSecret( - appId: String, - secretId: String - ) async throws -> AppwriteModels.AppSecret { - let apiPath: String = "/apps/{appId}/secrets/{secretId}" - .replacingOccurrences(of: "{appId}", with: appId) - .replacingOccurrences(of: "{secretId}", with: secretId) - - let apiParams: [String: Any] = [:] - - let apiHeaders: [String: String] = [ - "X-Appwrite-Project": client.config["project"] ?? "", - "accept": "application/json" - ] - - let converter: (Any) throws -> AppwriteModels.AppSecret = { response in - return AppwriteModels.AppSecret.from(map: response as! [String: Any]) - } - - return try await client.call( - method: "GET", - path: apiPath, - headers: apiHeaders, - params: apiParams, - converter: converter - ) - } - - /// - /// Delete an application client secret by its unique ID. - /// - /// - Parameters: - /// - appId: String - /// - secretId: String - /// - Throws: Exception if the request fails - /// - Returns: Any - /// - open func deleteSecret( - appId: String, - secretId: String - ) async throws -> Any { - let apiPath: String = "/apps/{appId}/secrets/{secretId}" - .replacingOccurrences(of: "{appId}", with: appId) - .replacingOccurrences(of: "{secretId}", with: secretId) - - let apiParams: [String: Any] = [:] - - let apiHeaders: [String: String] = [ - "X-Appwrite-Project": client.config["project"] ?? "", - "content-type": "application/json", - "accept": "application/json" - ] - - return try await client.call( - method: "DELETE", - path: apiPath, - headers: apiHeaders, - params: apiParams ) - } - - /// - /// Transfer an application to another team by its unique ID. - /// - /// - Parameters: - /// - appId: String - /// - teamId: String - /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.App - /// - open func updateTeam( - appId: String, - teamId: String - ) async throws -> AppwriteModels.App { - let apiPath: String = "/apps/{appId}/team" - .replacingOccurrences(of: "{appId}", with: appId) - - let apiParams: [String: Any?] = [ - "teamId": teamId - ] - - let apiHeaders: [String: String] = [ - "X-Appwrite-Project": client.config["project"] ?? "", - "content-type": "application/json", - "accept": "application/json" - ] - - let converter: (Any) throws -> AppwriteModels.App = { response in - return AppwriteModels.App.from(map: response as! [String: Any]) - } - - return try await client.call( - method: "PATCH", - path: apiPath, - headers: apiHeaders, - params: apiParams, - converter: converter - ) - } - - /// - /// Revoke all tokens for an application by its unique ID. - /// - /// - Parameters: - /// - appId: String - /// - Throws: Exception if the request fails - /// - Returns: Any - /// - open func deleteTokens( - appId: String - ) async throws -> Any { - let apiPath: String = "/apps/{appId}/tokens" - .replacingOccurrences(of: "{appId}", with: appId) - - let apiParams: [String: Any] = [:] - - let apiHeaders: [String: String] = [ - "X-Appwrite-Project": client.config["project"] ?? "", - "content-type": "application/json", - "accept": "application/json" - ] - - return try await client.call( - method: "DELETE", - path: apiPath, - headers: apiHeaders, - params: apiParams ) - } - - -} diff --git a/Sources/Appwrite/Services/Oauth2.swift b/Sources/Appwrite/Services/Oauth2.swift deleted file mode 100644 index e2d263f..0000000 --- a/Sources/Appwrite/Services/Oauth2.swift +++ /dev/null @@ -1,253 +0,0 @@ -import AsyncHTTPClient -import Foundation -import NIO -import JSONCodable -import AppwriteEnums -import AppwriteModels - -/// -open class Oauth2: Service { - - /// - /// Approve an OAuth2 grant after the user gives consent. Returns the - /// `redirectUrl` the end user should be sent to. The consent screen may - /// optionally pass enriched `authorization_details` to record the concrete - /// resources the user selected. You can pass Accept header of - /// `application/json` to receive a JSON response instead of a redirect. - /// - /// - Parameters: - /// - projectId: String - /// - grantId: String - /// - authorizationDetails: String (optional) - /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.Oauth2Approve - /// - open func approve( - projectId: String, - grantId: String, - authorizationDetails: String? = nil - ) async throws -> AppwriteModels.Oauth2Approve { - let apiPath: String = "/oauth2/{project_id}/approve" - .replacingOccurrences(of: "{project_id}", with: projectId) - + "?project=\(client.config["project"]?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")" - - let apiParams: [String: Any?] = [ - "grant_id": grantId, - "authorization_details": authorizationDetails - ] - - let apiHeaders: [String: String] = [ - "content-type": "application/json", - "accept": "application/json" - ] - - let converter: (Any) throws -> AppwriteModels.Oauth2Approve = { response in - return AppwriteModels.Oauth2Approve.from(map: response as! [String: Any]) - } - - return try await client.call( - method: "POST", - path: apiPath, - headers: apiHeaders, - params: apiParams, - converter: converter - ) - } - - /// - /// Begin the OAuth2 authorization flow. When called without a session, the - /// user is redirected to the consent screen without grant ID. When called with - /// a session, the redirect URL includes param for grant ID. You can pass - /// Accept header of `application/json` to receive a JSON response instead of a - /// redirect. - /// - /// - Parameters: - /// - projectId: String - /// - clientId: String - /// - redirectUri: String - /// - responseType: String - /// - scope: String - /// - state: String (optional) - /// - nonce: String (optional) - /// - codeChallenge: String (optional) - /// - codeChallengeMethod: String (optional) - /// - prompt: String (optional) - /// - maxAge: Int (optional) - /// - authorizationDetails: String (optional) - /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.Oauth2Authorize - /// - open func authorize( - projectId: String, - clientId: String, - redirectUri: String, - responseType: String, - scope: String, - state: String? = nil, - nonce: String? = nil, - codeChallenge: String? = nil, - codeChallengeMethod: String? = nil, - prompt: String? = nil, - maxAge: Int? = nil, - authorizationDetails: String? = nil - ) async throws -> AppwriteModels.Oauth2Authorize { - let apiPath: String = "/oauth2/{project_id}/authorize" - .replacingOccurrences(of: "{project_id}", with: projectId) - + "?project=\(client.config["project"]?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")" - - let apiParams: [String: Any?] = [ - "client_id": clientId, - "redirect_uri": redirectUri, - "response_type": responseType, - "scope": scope, - "state": state, - "nonce": nonce, - "code_challenge": codeChallenge, - "code_challenge_method": codeChallengeMethod, - "prompt": prompt, - "max_age": maxAge, - "authorization_details": authorizationDetails - ] - - let apiHeaders: [String: String] = [ - "accept": "application/json" - ] - - let converter: (Any) throws -> AppwriteModels.Oauth2Authorize = { response in - return AppwriteModels.Oauth2Authorize.from(map: response as! [String: Any]) - } - - return try await client.call( - method: "GET", - path: apiPath, - headers: apiHeaders, - params: apiParams, - converter: converter - ) - } - - /// - /// Exchange a device flow user code for an OAuth2 grant. The authenticated - /// user is bound to the pending grant. Pass the returned grant ID to the get - /// grant endpoint to render the consent screen, then to the approve or reject - /// endpoint to complete the flow. - /// - /// - Parameters: - /// - projectId: String - /// - userCode: String - /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.Oauth2Grant - /// - open func createGrant( - projectId: String, - userCode: String - ) async throws -> AppwriteModels.Oauth2Grant { - let apiPath: String = "/oauth2/{project_id}/grants" - .replacingOccurrences(of: "{project_id}", with: projectId) - - let apiParams: [String: Any?] = [ - "user_code": userCode - ] - - let apiHeaders: [String: String] = [ - "X-Appwrite-Project": client.config["project"] ?? "", - "content-type": "application/json", - "accept": "application/json" - ] - - let converter: (Any) throws -> AppwriteModels.Oauth2Grant = { response in - return AppwriteModels.Oauth2Grant.from(map: response as! [String: Any]) - } - - return try await client.call( - method: "POST", - path: apiPath, - headers: apiHeaders, - params: apiParams, - converter: converter - ) - } - - /// - /// Get an OAuth2 grant by its ID. Used by the consent screen to display the - /// details of the authorization the user is being asked to approve. A grant - /// can only be read by the user it belongs to, or by server SDK. - /// - /// - Parameters: - /// - projectId: String - /// - grantId: String - /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.Oauth2Grant - /// - open func getGrant( - projectId: String, - grantId: String - ) async throws -> AppwriteModels.Oauth2Grant { - let apiPath: String = "/oauth2/{project_id}/grants/{grant_id}" - .replacingOccurrences(of: "{project_id}", with: projectId) - .replacingOccurrences(of: "{grant_id}", with: grantId) - - let apiParams: [String: Any] = [:] - - let apiHeaders: [String: String] = [ - "X-Appwrite-Project": client.config["project"] ?? "", - "accept": "application/json" - ] - - let converter: (Any) throws -> AppwriteModels.Oauth2Grant = { response in - return AppwriteModels.Oauth2Grant.from(map: response as! [String: Any]) - } - - return try await client.call( - method: "GET", - path: apiPath, - headers: apiHeaders, - params: apiParams, - converter: converter - ) - } - - /// - /// Reject an OAuth2 grant when the user denies consent. Returns the - /// `redirectUrl` the end user should be sent to with an `access_denied` error. - /// You can pass Accept header of `application/json` to receive a JSON response - /// instead of a redirect. - /// - /// - Parameters: - /// - projectId: String - /// - grantId: String - /// - Throws: Exception if the request fails - /// - Returns: AppwriteModels.Oauth2Reject - /// - open func reject( - projectId: String, - grantId: String - ) async throws -> AppwriteModels.Oauth2Reject { - let apiPath: String = "/oauth2/{project_id}/reject" - .replacingOccurrences(of: "{project_id}", with: projectId) - + "?project=\(client.config["project"]?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")" - - let apiParams: [String: Any?] = [ - "grant_id": grantId - ] - - let apiHeaders: [String: String] = [ - "content-type": "application/json", - "accept": "application/json" - ] - - let converter: (Any) throws -> AppwriteModels.Oauth2Reject = { response in - return AppwriteModels.Oauth2Reject.from(map: response as! [String: Any]) - } - - return try await client.call( - method: "POST", - path: apiPath, - headers: apiHeaders, - params: apiParams, - converter: converter - ) - } - - -} diff --git a/Sources/AppwriteModels/App.swift b/Sources/AppwriteModels/App.swift deleted file mode 100644 index 545e69e..0000000 --- a/Sources/AppwriteModels/App.swift +++ /dev/null @@ -1,133 +0,0 @@ -import Foundation -import JSONCodable - -/// App -open class App: Codable { - - enum CodingKeys: String, CodingKey { - case id = "$id" - case createdAt = "$createdAt" - case updatedAt = "$updatedAt" - case name = "name" - case redirectUris = "redirectUris" - case enabled = "enabled" - case type = "type" - case deviceFlow = "deviceFlow" - case teamId = "teamId" - case userId = "userId" - case secrets = "secrets" - } - - /// App ID. - public let id: String - /// App creation time in ISO 8601 format. - public let createdAt: String - /// App update date in ISO 8601 format. - public let updatedAt: String - /// Application name. - public let name: String - /// List of authorized redirect URIs. These URIs can be used to redirect users after they authenticate. - public let redirectUris: [String] - /// Whether the app is enabled or not. - public let enabled: Bool - /// OAuth2 client type. `public` for SPAs, mobile, and native apps that cannot keep a client secret (PKCE required); `confidential` for server-side clients that authenticate with a client secret. - public let type: String - /// Whether this client may use the OAuth2 Device Authorization Grant (RFC 8628). - public let deviceFlow: Bool - /// ID of team that owns the application, if owned by team. Otherwise, user ID will be used. - public let teamId: String - /// ID of user who owns the application, if owned by user. Otherwise, team ID will be used. - public let userId: String - /// List of application secrets. - public let secrets: [AppSecret] - - init( - id: String, - createdAt: String, - updatedAt: String, - name: String, - redirectUris: [String], - enabled: Bool, - type: String, - deviceFlow: Bool, - teamId: String, - userId: String, - secrets: [AppSecret] - ) { - self.id = id - self.createdAt = createdAt - self.updatedAt = updatedAt - self.name = name - self.redirectUris = redirectUris - self.enabled = enabled - self.type = type - self.deviceFlow = deviceFlow - self.teamId = teamId - self.userId = userId - self.secrets = secrets - } - - public required init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - - self.id = try container.decode(String.self, forKey: .id) - self.createdAt = try container.decode(String.self, forKey: .createdAt) - self.updatedAt = try container.decode(String.self, forKey: .updatedAt) - self.name = try container.decode(String.self, forKey: .name) - self.redirectUris = try container.decode([String].self, forKey: .redirectUris) - self.enabled = try container.decode(Bool.self, forKey: .enabled) - self.type = try container.decode(String.self, forKey: .type) - self.deviceFlow = try container.decode(Bool.self, forKey: .deviceFlow) - self.teamId = try container.decode(String.self, forKey: .teamId) - self.userId = try container.decode(String.self, forKey: .userId) - self.secrets = try container.decode([AppSecret].self, forKey: .secrets) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - try container.encode(id, forKey: .id) - try container.encode(createdAt, forKey: .createdAt) - try container.encode(updatedAt, forKey: .updatedAt) - try container.encode(name, forKey: .name) - try container.encode(redirectUris, forKey: .redirectUris) - try container.encode(enabled, forKey: .enabled) - try container.encode(type, forKey: .type) - try container.encode(deviceFlow, forKey: .deviceFlow) - try container.encode(teamId, forKey: .teamId) - try container.encode(userId, forKey: .userId) - try container.encode(secrets, forKey: .secrets) - } - - public func toMap() -> [String: Any] { - return [ - "$id": id as Any, - "$createdAt": createdAt as Any, - "$updatedAt": updatedAt as Any, - "name": name as Any, - "redirectUris": redirectUris as Any, - "enabled": enabled as Any, - "type": type as Any, - "deviceFlow": deviceFlow as Any, - "teamId": teamId as Any, - "userId": userId as Any, - "secrets": secrets.map { $0.toMap() } as Any - ] - } - - public static func from(map: [String: Any] ) -> App { - return App( - id: map["$id"] as! String, - createdAt: map["$createdAt"] as! String, - updatedAt: map["$updatedAt"] as! String, - name: map["name"] as! String, - redirectUris: map["redirectUris"] as! [String], - enabled: map["enabled"] as! Bool, - type: map["type"] as! String, - deviceFlow: map["deviceFlow"] as! Bool, - teamId: map["teamId"] as! String, - userId: map["userId"] as! String, - secrets: (map["secrets"] as! [[String: Any]]).map { AppSecret.from(map: $0) } - ) - } -} diff --git a/Sources/AppwriteModels/AppSecret.swift b/Sources/AppwriteModels/AppSecret.swift deleted file mode 100644 index aae5952..0000000 --- a/Sources/AppwriteModels/AppSecret.swift +++ /dev/null @@ -1,115 +0,0 @@ -import Foundation -import JSONCodable - -/// AppSecret -open class AppSecret: Codable { - - enum CodingKeys: String, CodingKey { - case id = "$id" - case createdAt = "$createdAt" - case updatedAt = "$updatedAt" - case appId = "appId" - case secret = "secret" - case hint = "hint" - case createdById = "createdById" - case createdByName = "createdByName" - case lastAccessedAt = "lastAccessedAt" - } - - /// Secret ID. - public let id: String - /// Secret creation time in ISO 8601 format. - public let createdAt: String - /// Secret update time in ISO 8601 format. - public let updatedAt: String - /// Application ID this secret belongs to. - public let appId: String - /// Hashed application client secret. - public let secret: String - /// Last few characters of the client secret, used to help identify it. - public let hint: String - /// ID of the user who created the secret. - public let createdById: String - /// Name of the user who created the secret. - public let createdByName: String - /// Time the secret was last used for authentication in ISO 8601 format. Null if never used. - public let lastAccessedAt: String? - - init( - id: String, - createdAt: String, - updatedAt: String, - appId: String, - secret: String, - hint: String, - createdById: String, - createdByName: String, - lastAccessedAt: String? - ) { - self.id = id - self.createdAt = createdAt - self.updatedAt = updatedAt - self.appId = appId - self.secret = secret - self.hint = hint - self.createdById = createdById - self.createdByName = createdByName - self.lastAccessedAt = lastAccessedAt - } - - public required init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - - self.id = try container.decode(String.self, forKey: .id) - self.createdAt = try container.decode(String.self, forKey: .createdAt) - self.updatedAt = try container.decode(String.self, forKey: .updatedAt) - self.appId = try container.decode(String.self, forKey: .appId) - self.secret = try container.decode(String.self, forKey: .secret) - self.hint = try container.decode(String.self, forKey: .hint) - self.createdById = try container.decode(String.self, forKey: .createdById) - self.createdByName = try container.decode(String.self, forKey: .createdByName) - self.lastAccessedAt = try container.decodeIfPresent(String.self, forKey: .lastAccessedAt) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - try container.encode(id, forKey: .id) - try container.encode(createdAt, forKey: .createdAt) - try container.encode(updatedAt, forKey: .updatedAt) - try container.encode(appId, forKey: .appId) - try container.encode(secret, forKey: .secret) - try container.encode(hint, forKey: .hint) - try container.encode(createdById, forKey: .createdById) - try container.encode(createdByName, forKey: .createdByName) - try container.encodeIfPresent(lastAccessedAt, forKey: .lastAccessedAt) - } - - public func toMap() -> [String: Any] { - return [ - "$id": id as Any, - "$createdAt": createdAt as Any, - "$updatedAt": updatedAt as Any, - "appId": appId as Any, - "secret": secret as Any, - "hint": hint as Any, - "createdById": createdById as Any, - "createdByName": createdByName as Any, - "lastAccessedAt": lastAccessedAt as Any - ] - } - - public static func from(map: [String: Any] ) -> AppSecret { - return AppSecret( - id: map["$id"] as! String, - createdAt: map["$createdAt"] as! String, - updatedAt: map["$updatedAt"] as! String, - appId: map["appId"] as! String, - secret: map["secret"] as! String, - hint: map["hint"] as! String, - createdById: map["createdById"] as! String, - createdByName: map["createdByName"] as! String, - lastAccessedAt: map["lastAccessedAt"] as? String - ) - } -} diff --git a/Sources/AppwriteModels/AppSecretList.swift b/Sources/AppwriteModels/AppSecretList.swift deleted file mode 100644 index 927673d..0000000 --- a/Sources/AppwriteModels/AppSecretList.swift +++ /dev/null @@ -1,52 +0,0 @@ -import Foundation -import JSONCodable - -/// App secrets list -open class AppSecretList: Codable { - - enum CodingKeys: String, CodingKey { - case total = "total" - case secrets = "secrets" - } - - /// Total number of secrets that matched your query. - public let total: Int - /// List of secrets. - public let secrets: [AppSecret] - - init( - total: Int, - secrets: [AppSecret] - ) { - self.total = total - self.secrets = secrets - } - - public required init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - - self.total = try container.decode(Int.self, forKey: .total) - self.secrets = try container.decode([AppSecret].self, forKey: .secrets) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - try container.encode(total, forKey: .total) - try container.encode(secrets, forKey: .secrets) - } - - public func toMap() -> [String: Any] { - return [ - "total": total as Any, - "secrets": secrets.map { $0.toMap() } as Any - ] - } - - public static func from(map: [String: Any] ) -> AppSecretList { - return AppSecretList( - total: map["total"] as! Int, - secrets: (map["secrets"] as! [[String: Any]]).map { AppSecret.from(map: $0) } - ) - } -} diff --git a/Sources/AppwriteModels/AppSecretPlaintext.swift b/Sources/AppwriteModels/AppSecretPlaintext.swift deleted file mode 100644 index 8902a68..0000000 --- a/Sources/AppwriteModels/AppSecretPlaintext.swift +++ /dev/null @@ -1,115 +0,0 @@ -import Foundation -import JSONCodable - -/// AppSecretPlaintext -open class AppSecretPlaintext: Codable { - - enum CodingKeys: String, CodingKey { - case id = "$id" - case createdAt = "$createdAt" - case updatedAt = "$updatedAt" - case appId = "appId" - case secret = "secret" - case hint = "hint" - case createdById = "createdById" - case createdByName = "createdByName" - case lastAccessedAt = "lastAccessedAt" - } - - /// Secret ID. - public let id: String - /// Secret creation time in ISO 8601 format. - public let createdAt: String - /// Secret update time in ISO 8601 format. - public let updatedAt: String - /// Application ID this secret belongs to. - public let appId: String - /// Application client secret. Returned in full only when the secret is created; subsequent reads return a masked value. - public let secret: String - /// Last few characters of the client secret, used to help identify it. - public let hint: String - /// ID of the user who created the secret. - public let createdById: String - /// Name of the user who created the secret. - public let createdByName: String - /// Time the secret was last used for authentication in ISO 8601 format. Null if never used. - public let lastAccessedAt: String? - - init( - id: String, - createdAt: String, - updatedAt: String, - appId: String, - secret: String, - hint: String, - createdById: String, - createdByName: String, - lastAccessedAt: String? - ) { - self.id = id - self.createdAt = createdAt - self.updatedAt = updatedAt - self.appId = appId - self.secret = secret - self.hint = hint - self.createdById = createdById - self.createdByName = createdByName - self.lastAccessedAt = lastAccessedAt - } - - public required init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - - self.id = try container.decode(String.self, forKey: .id) - self.createdAt = try container.decode(String.self, forKey: .createdAt) - self.updatedAt = try container.decode(String.self, forKey: .updatedAt) - self.appId = try container.decode(String.self, forKey: .appId) - self.secret = try container.decode(String.self, forKey: .secret) - self.hint = try container.decode(String.self, forKey: .hint) - self.createdById = try container.decode(String.self, forKey: .createdById) - self.createdByName = try container.decode(String.self, forKey: .createdByName) - self.lastAccessedAt = try container.decodeIfPresent(String.self, forKey: .lastAccessedAt) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - try container.encode(id, forKey: .id) - try container.encode(createdAt, forKey: .createdAt) - try container.encode(updatedAt, forKey: .updatedAt) - try container.encode(appId, forKey: .appId) - try container.encode(secret, forKey: .secret) - try container.encode(hint, forKey: .hint) - try container.encode(createdById, forKey: .createdById) - try container.encode(createdByName, forKey: .createdByName) - try container.encodeIfPresent(lastAccessedAt, forKey: .lastAccessedAt) - } - - public func toMap() -> [String: Any] { - return [ - "$id": id as Any, - "$createdAt": createdAt as Any, - "$updatedAt": updatedAt as Any, - "appId": appId as Any, - "secret": secret as Any, - "hint": hint as Any, - "createdById": createdById as Any, - "createdByName": createdByName as Any, - "lastAccessedAt": lastAccessedAt as Any - ] - } - - public static func from(map: [String: Any] ) -> AppSecretPlaintext { - return AppSecretPlaintext( - id: map["$id"] as! String, - createdAt: map["$createdAt"] as! String, - updatedAt: map["$updatedAt"] as! String, - appId: map["appId"] as! String, - secret: map["secret"] as! String, - hint: map["hint"] as! String, - createdById: map["createdById"] as! String, - createdByName: map["createdByName"] as! String, - lastAccessedAt: map["lastAccessedAt"] as? String - ) - } -} diff --git a/Sources/AppwriteModels/AppsList.swift b/Sources/AppwriteModels/AppsList.swift deleted file mode 100644 index 9d20102..0000000 --- a/Sources/AppwriteModels/AppsList.swift +++ /dev/null @@ -1,52 +0,0 @@ -import Foundation -import JSONCodable - -/// Apps list -open class AppsList: Codable { - - enum CodingKeys: String, CodingKey { - case total = "total" - case apps = "apps" - } - - /// Total number of apps that matched your query. - public let total: Int - /// List of apps. - public let apps: [App] - - init( - total: Int, - apps: [App] - ) { - self.total = total - self.apps = apps - } - - public required init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - - self.total = try container.decode(Int.self, forKey: .total) - self.apps = try container.decode([App].self, forKey: .apps) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - try container.encode(total, forKey: .total) - try container.encode(apps, forKey: .apps) - } - - public func toMap() -> [String: Any] { - return [ - "total": total as Any, - "apps": apps.map { $0.toMap() } as Any - ] - } - - public static func from(map: [String: Any] ) -> AppsList { - return AppsList( - total: map["total"] as! Int, - apps: (map["apps"] as! [[String: Any]]).map { App.from(map: $0) } - ) - } -} diff --git a/Sources/AppwriteModels/Oauth2Approve.swift b/Sources/AppwriteModels/Oauth2Approve.swift deleted file mode 100644 index 3cee7ad..0000000 --- a/Sources/AppwriteModels/Oauth2Approve.swift +++ /dev/null @@ -1,43 +0,0 @@ -import Foundation -import JSONCodable - -/// OAuth2 Approve -open class Oauth2Approve: Codable { - - enum CodingKeys: String, CodingKey { - case redirectUrl = "redirectUrl" - } - - /// URL the end user should be redirected to after the grant is approved, carrying the authorization `code` and/or `id_token` along with the original `state`. - public let redirectUrl: String - - init( - redirectUrl: String - ) { - self.redirectUrl = redirectUrl - } - - public required init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - - self.redirectUrl = try container.decode(String.self, forKey: .redirectUrl) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - try container.encode(redirectUrl, forKey: .redirectUrl) - } - - public func toMap() -> [String: Any] { - return [ - "redirectUrl": redirectUrl as Any - ] - } - - public static func from(map: [String: Any] ) -> Oauth2Approve { - return Oauth2Approve( - redirectUrl: map["redirectUrl"] as! String - ) - } -} diff --git a/Sources/AppwriteModels/Oauth2Authorize.swift b/Sources/AppwriteModels/Oauth2Authorize.swift deleted file mode 100644 index 62c10d5..0000000 --- a/Sources/AppwriteModels/Oauth2Authorize.swift +++ /dev/null @@ -1,52 +0,0 @@ -import Foundation -import JSONCodable - -/// OAuth2 Authorize -open class Oauth2Authorize: Codable { - - enum CodingKeys: String, CodingKey { - case grantId = "grantId" - case redirectUrl = "redirectUrl" - } - - /// OAuth2 grant ID. Set when the user must give explicit consent; pass it to the approve or reject endpoint. Empty when a redirect URL is returned instead. - public let grantId: String - /// URL the end user should be redirected to when the flow can complete without consent. Empty when consent is still required. - public let redirectUrl: String - - init( - grantId: String, - redirectUrl: String - ) { - self.grantId = grantId - self.redirectUrl = redirectUrl - } - - public required init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - - self.grantId = try container.decode(String.self, forKey: .grantId) - self.redirectUrl = try container.decode(String.self, forKey: .redirectUrl) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - try container.encode(grantId, forKey: .grantId) - try container.encode(redirectUrl, forKey: .redirectUrl) - } - - public func toMap() -> [String: Any] { - return [ - "grantId": grantId as Any, - "redirectUrl": redirectUrl as Any - ] - } - - public static func from(map: [String: Any] ) -> Oauth2Authorize { - return Oauth2Authorize( - grantId: map["grantId"] as! String, - redirectUrl: map["redirectUrl"] as! String - ) - } -} diff --git a/Sources/AppwriteModels/Oauth2Grant.swift b/Sources/AppwriteModels/Oauth2Grant.swift deleted file mode 100644 index 9ef9f1e..0000000 --- a/Sources/AppwriteModels/Oauth2Grant.swift +++ /dev/null @@ -1,133 +0,0 @@ -import Foundation -import JSONCodable - -/// OAuth2 Grant -open class Oauth2Grant: Codable { - - enum CodingKeys: String, CodingKey { - case id = "$id" - case createdAt = "$createdAt" - case updatedAt = "$updatedAt" - case userId = "userId" - case appId = "appId" - case scopes = "scopes" - case authorizationDetails = "authorizationDetails" - case prompt = "prompt" - case redirectUri = "redirectUri" - case authTime = "authTime" - case expire = "expire" - } - - /// Grant ID. - public let id: String - /// Grant creation time in ISO 8601 format. - public let createdAt: String - /// Grant update date in ISO 8601 format. - public let updatedAt: String - /// ID of the user the grant belongs to. - public let userId: String - /// ID of the OAuth2 client (app) the grant was requested for. - public let appId: String - /// Requested OAuth2 scopes the user is being asked to consent to. - public let scopes: [String] - /// Requested authorization_details the user is being asked to consent to, as a JSON string. Each entry has a `type` plus project-defined fields. - public let authorizationDetails: String - /// OIDC prompt directive the consent screen should honor. Space-separated list of: login, consent, select_account. - public let prompt: String - /// Redirect URI the user will be sent to after the flow completes. - public let redirectUri: String - /// Unix timestamp of when the user last authenticated. - public let authTime: Int - /// Grant expiration time in ISO 8601 format. - public let expire: String - - init( - id: String, - createdAt: String, - updatedAt: String, - userId: String, - appId: String, - scopes: [String], - authorizationDetails: String, - prompt: String, - redirectUri: String, - authTime: Int, - expire: String - ) { - self.id = id - self.createdAt = createdAt - self.updatedAt = updatedAt - self.userId = userId - self.appId = appId - self.scopes = scopes - self.authorizationDetails = authorizationDetails - self.prompt = prompt - self.redirectUri = redirectUri - self.authTime = authTime - self.expire = expire - } - - public required init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - - self.id = try container.decode(String.self, forKey: .id) - self.createdAt = try container.decode(String.self, forKey: .createdAt) - self.updatedAt = try container.decode(String.self, forKey: .updatedAt) - self.userId = try container.decode(String.self, forKey: .userId) - self.appId = try container.decode(String.self, forKey: .appId) - self.scopes = try container.decode([String].self, forKey: .scopes) - self.authorizationDetails = try container.decode(String.self, forKey: .authorizationDetails) - self.prompt = try container.decode(String.self, forKey: .prompt) - self.redirectUri = try container.decode(String.self, forKey: .redirectUri) - self.authTime = try container.decode(Int.self, forKey: .authTime) - self.expire = try container.decode(String.self, forKey: .expire) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - try container.encode(id, forKey: .id) - try container.encode(createdAt, forKey: .createdAt) - try container.encode(updatedAt, forKey: .updatedAt) - try container.encode(userId, forKey: .userId) - try container.encode(appId, forKey: .appId) - try container.encode(scopes, forKey: .scopes) - try container.encode(authorizationDetails, forKey: .authorizationDetails) - try container.encode(prompt, forKey: .prompt) - try container.encode(redirectUri, forKey: .redirectUri) - try container.encode(authTime, forKey: .authTime) - try container.encode(expire, forKey: .expire) - } - - public func toMap() -> [String: Any] { - return [ - "$id": id as Any, - "$createdAt": createdAt as Any, - "$updatedAt": updatedAt as Any, - "userId": userId as Any, - "appId": appId as Any, - "scopes": scopes as Any, - "authorizationDetails": authorizationDetails as Any, - "prompt": prompt as Any, - "redirectUri": redirectUri as Any, - "authTime": authTime as Any, - "expire": expire as Any - ] - } - - public static func from(map: [String: Any] ) -> Oauth2Grant { - return Oauth2Grant( - id: map["$id"] as! String, - createdAt: map["$createdAt"] as! String, - updatedAt: map["$updatedAt"] as! String, - userId: map["userId"] as! String, - appId: map["appId"] as! String, - scopes: map["scopes"] as! [String], - authorizationDetails: map["authorizationDetails"] as! String, - prompt: map["prompt"] as! String, - redirectUri: map["redirectUri"] as! String, - authTime: map["authTime"] as! Int, - expire: map["expire"] as! String - ) - } -} diff --git a/Sources/AppwriteModels/Oauth2Reject.swift b/Sources/AppwriteModels/Oauth2Reject.swift deleted file mode 100644 index b0cd5be..0000000 --- a/Sources/AppwriteModels/Oauth2Reject.swift +++ /dev/null @@ -1,43 +0,0 @@ -import Foundation -import JSONCodable - -/// OAuth2 Reject -open class Oauth2Reject: Codable { - - enum CodingKeys: String, CodingKey { - case redirectUrl = "redirectUrl" - } - - /// URL the end user should be redirected to after the grant is rejected, carrying an `access_denied` error. - public let redirectUrl: String - - init( - redirectUrl: String - ) { - self.redirectUrl = redirectUrl - } - - public required init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - - self.redirectUrl = try container.decode(String.self, forKey: .redirectUrl) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - try container.encode(redirectUrl, forKey: .redirectUrl) - } - - public func toMap() -> [String: Any] { - return [ - "redirectUrl": redirectUrl as Any - ] - } - - public static func from(map: [String: Any] ) -> Oauth2Reject { - return Oauth2Reject( - redirectUrl: map["redirectUrl"] as! String - ) - } -} diff --git a/docs/examples/apps/create-secret.md b/docs/examples/apps/create-secret.md deleted file mode 100644 index 5fe4c5e..0000000 --- a/docs/examples/apps/create-secret.md +++ /dev/null @@ -1,14 +0,0 @@ -```swift -import Appwrite - -let client = Client() - .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .setProject("") // Your project ID - -let apps = Apps(client) - -let appSecretPlaintext = try await apps.createSecret( - appId: "" -) - -``` diff --git a/docs/examples/apps/create.md b/docs/examples/apps/create.md deleted file mode 100644 index f03ec2d..0000000 --- a/docs/examples/apps/create.md +++ /dev/null @@ -1,20 +0,0 @@ -```swift -import Appwrite - -let client = Client() - .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .setProject("") // Your project ID - -let apps = Apps(client) - -let app = try await apps.create( - appId: "", - name: "", - redirectUris: [], - enabled: false, // optional - type: "public", // optional - deviceFlow: false, // optional - teamId: "" // optional -) - -``` diff --git a/docs/examples/apps/delete-secret.md b/docs/examples/apps/delete-secret.md deleted file mode 100644 index 66af5a5..0000000 --- a/docs/examples/apps/delete-secret.md +++ /dev/null @@ -1,15 +0,0 @@ -```swift -import Appwrite - -let client = Client() - .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .setProject("") // Your project ID - -let apps = Apps(client) - -let result = try await apps.deleteSecret( - appId: "", - secretId: "" -) - -``` diff --git a/docs/examples/apps/delete-tokens.md b/docs/examples/apps/delete-tokens.md deleted file mode 100644 index 89e7329..0000000 --- a/docs/examples/apps/delete-tokens.md +++ /dev/null @@ -1,14 +0,0 @@ -```swift -import Appwrite - -let client = Client() - .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .setProject("") // Your project ID - -let apps = Apps(client) - -let result = try await apps.deleteTokens( - appId: "" -) - -``` diff --git a/docs/examples/apps/delete.md b/docs/examples/apps/delete.md deleted file mode 100644 index 2229ea2..0000000 --- a/docs/examples/apps/delete.md +++ /dev/null @@ -1,14 +0,0 @@ -```swift -import Appwrite - -let client = Client() - .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .setProject("") // Your project ID - -let apps = Apps(client) - -let result = try await apps.delete( - appId: "" -) - -``` diff --git a/docs/examples/apps/get-secret.md b/docs/examples/apps/get-secret.md deleted file mode 100644 index 215dcb6..0000000 --- a/docs/examples/apps/get-secret.md +++ /dev/null @@ -1,15 +0,0 @@ -```swift -import Appwrite - -let client = Client() - .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .setProject("") // Your project ID - -let apps = Apps(client) - -let appSecret = try await apps.getSecret( - appId: "", - secretId: "" -) - -``` diff --git a/docs/examples/apps/get.md b/docs/examples/apps/get.md deleted file mode 100644 index 27ebc27..0000000 --- a/docs/examples/apps/get.md +++ /dev/null @@ -1,14 +0,0 @@ -```swift -import Appwrite - -let client = Client() - .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .setProject("") // Your project ID - -let apps = Apps(client) - -let app = try await apps.get( - appId: "" -) - -``` diff --git a/docs/examples/apps/list-secrets.md b/docs/examples/apps/list-secrets.md deleted file mode 100644 index a956b13..0000000 --- a/docs/examples/apps/list-secrets.md +++ /dev/null @@ -1,16 +0,0 @@ -```swift -import Appwrite - -let client = Client() - .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .setProject("") // Your project ID - -let apps = Apps(client) - -let appSecretList = try await apps.listSecrets( - appId: "", - queries: [], // optional - total: false // optional -) - -``` diff --git a/docs/examples/apps/list.md b/docs/examples/apps/list.md deleted file mode 100644 index 7b99731..0000000 --- a/docs/examples/apps/list.md +++ /dev/null @@ -1,15 +0,0 @@ -```swift -import Appwrite - -let client = Client() - .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .setProject("") // Your project ID - -let apps = Apps(client) - -let appsList = try await apps.list( - queries: [], // optional - total: false // optional -) - -``` diff --git a/docs/examples/apps/update-team.md b/docs/examples/apps/update-team.md deleted file mode 100644 index 09b24dc..0000000 --- a/docs/examples/apps/update-team.md +++ /dev/null @@ -1,15 +0,0 @@ -```swift -import Appwrite - -let client = Client() - .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .setProject("") // Your project ID - -let apps = Apps(client) - -let app = try await apps.updateTeam( - appId: "", - teamId: "" -) - -``` diff --git a/docs/examples/apps/update.md b/docs/examples/apps/update.md deleted file mode 100644 index 79bb450..0000000 --- a/docs/examples/apps/update.md +++ /dev/null @@ -1,19 +0,0 @@ -```swift -import Appwrite - -let client = Client() - .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .setProject("") // Your project ID - -let apps = Apps(client) - -let app = try await apps.update( - appId: "", - name: "", - enabled: false, // optional - redirectUris: [], // optional - type: "public", // optional - deviceFlow: false // optional -) - -``` diff --git a/docs/examples/oauth2/approve.md b/docs/examples/oauth2/approve.md deleted file mode 100644 index 8045039..0000000 --- a/docs/examples/oauth2/approve.md +++ /dev/null @@ -1,16 +0,0 @@ -```swift -import Appwrite - -let client = Client() - .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .setProjectQuery("") // Your project ID - -let oauth2 = Oauth2(client) - -let oauth2Approve = try await oauth2.approve( - project_id: "", - grant_id: "", - authorization_details: "" // optional -) - -``` diff --git a/docs/examples/oauth2/authorize.md b/docs/examples/oauth2/authorize.md deleted file mode 100644 index d36ee25..0000000 --- a/docs/examples/oauth2/authorize.md +++ /dev/null @@ -1,25 +0,0 @@ -```swift -import Appwrite - -let client = Client() - .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .setProjectQuery("") // Your project ID - -let oauth2 = Oauth2(client) - -let oauth2Authorize = try await oauth2.authorize( - project_id: "", - client_id: "", - redirect_uri: "https://example.com", - response_type: "code", - scope: "", - state: "", // optional - nonce: "", // optional - code_challenge: "", // optional - code_challenge_method: "s256", // optional - prompt: "", // optional - max_age: 0, // optional - authorization_details: "" // optional -) - -``` diff --git a/docs/examples/oauth2/create-grant.md b/docs/examples/oauth2/create-grant.md deleted file mode 100644 index c912379..0000000 --- a/docs/examples/oauth2/create-grant.md +++ /dev/null @@ -1,15 +0,0 @@ -```swift -import Appwrite - -let client = Client() - .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .setProject("") // Your project ID - -let oauth2 = Oauth2(client) - -let oauth2Grant = try await oauth2.createGrant( - project_id: "", - user_code: "" -) - -``` diff --git a/docs/examples/oauth2/get-grant.md b/docs/examples/oauth2/get-grant.md deleted file mode 100644 index 0585cc0..0000000 --- a/docs/examples/oauth2/get-grant.md +++ /dev/null @@ -1,15 +0,0 @@ -```swift -import Appwrite - -let client = Client() - .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .setProject("") // Your project ID - -let oauth2 = Oauth2(client) - -let oauth2Grant = try await oauth2.getGrant( - project_id: "", - grant_id: "" -) - -``` diff --git a/docs/examples/oauth2/reject.md b/docs/examples/oauth2/reject.md deleted file mode 100644 index 6ea406d..0000000 --- a/docs/examples/oauth2/reject.md +++ /dev/null @@ -1,15 +0,0 @@ -```swift -import Appwrite - -let client = Client() - .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .setProjectQuery("") // Your project ID - -let oauth2 = Oauth2(client) - -let oauth2Reject = try await oauth2.reject( - project_id: "", - grant_id: "" -) - -``` From 6e12afd027cc9f0f76449ad3743c169b0a700e40 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Mon, 8 Jun 2026 11:37:07 +0530 Subject: [PATCH 3/5] docs: add accept header and toString notes to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 599d4d3..b622be4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * Added: Email metadata fields to `User` (`emailCanonical`, `emailIsFree`, `emailIsDisposable`, `emailIsCorporate`, `emailIsCanonical`). * Added: `Membership.userAccessedAt` field. +* Updated: Requests now send an explicit `accept` header matching each endpoint's response type. ## 18.0.0 From 770ac9dc9ebc78f92a63f5ac2d69455f298e5deb Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Mon, 8 Jun 2026 11:59:04 +0530 Subject: [PATCH 4/5] chore: update Apple SDK to 18.1.0 --- Sources/Appwrite/Services/Functions.swift | 24 +++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/Sources/Appwrite/Services/Functions.swift b/Sources/Appwrite/Services/Functions.swift index f5fa181..0dc1e0a 100644 --- a/Sources/Appwrite/Services/Functions.swift +++ b/Sources/Appwrite/Services/Functions.swift @@ -74,12 +74,13 @@ open class Functions: Service { path: String? = nil, method: AppwriteEnums.ExecutionMethod? = nil, headers: Any? = nil, - scheduledAt: String? = nil + scheduledAt: String? = nil, + onProgress: ((UploadProgress) -> Void)? = nil ) async throws -> AppwriteModels.Execution { let apiPath: String = "/functions/{functionId}/executions" .replacingOccurrences(of: "{functionId}", with: functionId) - let apiParams: [String: Any?] = [ + var apiParams: [String: Any?] = [ "body": body, "async": async, "path": path, @@ -88,22 +89,25 @@ open class Functions: Service { "scheduledAt": scheduledAt ] - let apiHeaders: [String: String] = [ + var apiHeaders: [String: String] = [ "X-Appwrite-Project": client.config["project"] ?? "", - "content-type": "application/json", - "accept": "multipart/form-data" + "content-type": "multipart/form-data", + "accept": "application/json" ] let converter: (Any) throws -> AppwriteModels.Execution = { response in return AppwriteModels.Execution.from(map: response as! [String: Any]) } - return try await client.call( - method: "POST", + let idParamName: String? = nil + return try await client.chunkedUpload( path: apiPath, - headers: apiHeaders, - params: apiParams, - converter: converter + headers: &apiHeaders, + params: &apiParams, + paramName: paramName, + idParamName: idParamName, + converter: converter, + onProgress: onProgress ) } From ccb6b83ac008334632f153b7a647165a7b303774 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Mon, 8 Jun 2026 12:53:34 +0530 Subject: [PATCH 5/5] chore: update Apple SDK to 18.1.0 --- Sources/Appwrite/Services/Functions.swift | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/Sources/Appwrite/Services/Functions.swift b/Sources/Appwrite/Services/Functions.swift index 0dc1e0a..b7f0ecf 100644 --- a/Sources/Appwrite/Services/Functions.swift +++ b/Sources/Appwrite/Services/Functions.swift @@ -74,13 +74,12 @@ open class Functions: Service { path: String? = nil, method: AppwriteEnums.ExecutionMethod? = nil, headers: Any? = nil, - scheduledAt: String? = nil, - onProgress: ((UploadProgress) -> Void)? = nil + scheduledAt: String? = nil ) async throws -> AppwriteModels.Execution { let apiPath: String = "/functions/{functionId}/executions" .replacingOccurrences(of: "{functionId}", with: functionId) - var apiParams: [String: Any?] = [ + let apiParams: [String: Any?] = [ "body": body, "async": async, "path": path, @@ -89,9 +88,9 @@ open class Functions: Service { "scheduledAt": scheduledAt ] - var apiHeaders: [String: String] = [ + let apiHeaders: [String: String] = [ "X-Appwrite-Project": client.config["project"] ?? "", - "content-type": "multipart/form-data", + "content-type": "application/json", "accept": "application/json" ] @@ -99,15 +98,12 @@ open class Functions: Service { return AppwriteModels.Execution.from(map: response as! [String: Any]) } - let idParamName: String? = nil - return try await client.chunkedUpload( + return try await client.call( + method: "POST", path: apiPath, - headers: &apiHeaders, - params: &apiParams, - paramName: paramName, - idParamName: idParamName, - converter: converter, - onProgress: onProgress + headers: apiHeaders, + params: apiParams, + converter: converter ) }