diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index fa46580d..eb2bb74b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,3 +1,3 @@ # Global rule: * @xmtp/mobile -*.md @jhaaaa +*.md @fabriguespe diff --git a/Sources/XMTPTestHelpers/TestHelpers.swift b/Sources/XMTPTestHelpers/TestHelpers.swift index 5182b70b..9ef4a82e 100644 --- a/Sources/XMTPTestHelpers/TestHelpers.swift +++ b/Sources/XMTPTestHelpers/TestHelpers.swift @@ -23,7 +23,7 @@ public struct TestConfig { } static public func skipIfNotRunningLocalNodeTests() throws { -// try XCTSkipIf(!TEST_SERVER_ENABLED, "requires local node") + try XCTSkipIf(!TEST_SERVER_ENABLED, "requires local node") } static public func skip(because: String) throws { diff --git a/Sources/XMTPiOS/ApiClient.swift b/Sources/XMTPiOS/ApiClient.swift index d85692fd..e4411b50 100644 --- a/Sources/XMTPiOS/ApiClient.swift +++ b/Sources/XMTPiOS/ApiClient.swift @@ -17,11 +17,24 @@ public typealias QueryRequest = Xmtp_MessageApi_V1_QueryRequest public typealias QueryResponse = Xmtp_MessageApi_V1_QueryResponse public typealias SubscribeRequest = Xmtp_MessageApi_V1_SubscribeRequest -public enum ApiClientError: Error { +public enum ApiClientError: Error, CustomStringConvertible { case batchQueryError(String) case queryError(String) case publishError(String) case subscribeError(String) + + public var description: String { + switch self { + case .batchQueryError(let err): + return "ApiClientError.batchQueryError: \(err)" + case .queryError(let err): + return "ApiClientError.queryError: \(err)" + case .publishError(let err): + return "ApiClientError.publishError: \(err)" + case .subscribeError(let err): + return "ApiClientError.subscribeError: \(err)" + } + } } protocol ApiClient: Sendable { diff --git a/Sources/XMTPiOS/Client.swift b/Sources/XMTPiOS/Client.swift index 7e6199a8..0ae6c1df 100644 --- a/Sources/XMTPiOS/Client.swift +++ b/Sources/XMTPiOS/Client.swift @@ -11,8 +11,15 @@ import web3 public typealias PreEventCallback = () async throws -> Void -public enum ClientError: Error { +public enum ClientError: Error, CustomStringConvertible { case creationError(String) + + public var description: String { + switch self { + case .creationError(let err): + return "ClientError.creationError: \(err)" + } + } } /// Specify configuration options for creating a ``Client``. @@ -100,7 +107,7 @@ public final class Client { public static func create(account: SigningKey, options: ClientOptions? = nil) async throws -> Client { let options = options ?? ClientOptions() do { - let client = try await LibXMTP.createV2Client(host: options.api.env.url, isSecure: options.api.env != .local) + let client = try await LibXMTP.createV2Client(host: options.api.env.url, isSecure: options.api.env.isSecure) let apiClient = try GRPCApiClient( environment: options.api.env, secure: options.api.isSecure, @@ -119,12 +126,12 @@ public final class Client { privateKeyBundleV1: PrivateKeyBundleV1, signingKey: SigningKey? ) async throws -> FfiXmtpClient? { - if options?.mlsAlpha == true, options?.api.env == .local { + if options?.mlsAlpha == true, options?.api.env.supportsMLS == true { let dbURL = URL.documentsDirectory.appendingPathComponent("xmtp-\(options?.api.env.rawValue ?? "")-\(address).db3") let v3Client = try await LibXMTP.createClient( logger: XMTPLogger(), host: (options?.api.env ?? .local).url, - isSecure: (options?.api.env ?? .local) != .local, + isSecure: options?.api.env.isSecure == true, db: dbURL.path, encryptionKey: options?.mlsEncryptionKey, accountAddress: address, @@ -241,8 +248,7 @@ public final class Client { let address = try v1Bundle.identityKey.publicKey.recoverWalletSignerPublicKey().walletAddress let options = options ?? ClientOptions() - - let client = try await LibXMTP.createV2Client(host: options.api.env.url, isSecure: options.api.env != .local) + let client = try await LibXMTP.createV2Client(host: options.api.env.url, isSecure: options.api.env.isSecure) let apiClient = try GRPCApiClient( environment: options.api.env, secure: options.api.isSecure, @@ -295,8 +301,7 @@ public final class Client { public static func canMessage(_ peerAddress: String, options: ClientOptions? = nil) async throws -> Bool { let options = options ?? ClientOptions() - - let client = try await LibXMTP.createV2Client(host: options.api.env.url, isSecure: options.api.env != .local) + let client = try await LibXMTP.createV2Client(host: options.api.env.url, isSecure: options.api.env.isSecure) let apiClient = try GRPCApiClient( environment: options.api.env, secure: options.api.isSecure, diff --git a/Sources/XMTPiOS/Codecs/RemoteAttachmentCodec.swift b/Sources/XMTPiOS/Codecs/RemoteAttachmentCodec.swift index 62af9969..32c1b103 100644 --- a/Sources/XMTPiOS/Codecs/RemoteAttachmentCodec.swift +++ b/Sources/XMTPiOS/Codecs/RemoteAttachmentCodec.swift @@ -11,8 +11,25 @@ import web3 public let ContentTypeRemoteAttachment = ContentTypeID(authorityID: "xmtp.org", typeID: "remoteStaticAttachment", versionMajor: 1, versionMinor: 0) -public enum RemoteAttachmentError: Error { +public enum RemoteAttachmentError: Error, CustomStringConvertible { case invalidURL, v1NotSupported, invalidParameters(String), invalidDigest(String), invalidScheme(String), payloadNotFound + + public var description: String { + switch self { + case .invalidURL: + return "RemoteAttachmentError.invalidURL" + case .v1NotSupported: + return "RemoteAttachmentError.v1NotSupported" + case .invalidParameters(let string): + return "RemoteAttachmentError.invalidParameters: \(string)" + case .invalidDigest(let string): + return "RemoteAttachmentError.invalidDigest: \(string)" + case .invalidScheme(let string): + return "RemoteAttachmentError.invalidScheme: \(string)" + case .payloadNotFound: + return "RemoteAttachmentError.payloadNotFound" + } + } } protocol RemoteContentFetcher { diff --git a/Sources/XMTPiOS/Conversations.swift b/Sources/XMTPiOS/Conversations.swift index 780e4416..63285664 100644 --- a/Sources/XMTPiOS/Conversations.swift +++ b/Sources/XMTPiOS/Conversations.swift @@ -1,12 +1,36 @@ import Foundation import LibXMTP -public enum ConversationError: Error { +public enum ConversationError: Error, CustomStringConvertible { case recipientNotOnNetwork, recipientIsSender, v1NotSupported(String) + + public var description: String { + switch self { + case .recipientIsSender: + return "ConversationError.recipientIsSender: Recipient cannot be sender" + case .recipientNotOnNetwork: + return "ConversationError.recipientNotOnNetwork: Recipient is not on network" + case .v1NotSupported(let str): + return "ConversationError.v1NotSupported: V1 does not support: \(str)" + } + } } -public enum GroupError: Error { +public enum GroupError: Error, CustomStringConvertible { case alphaMLSNotEnabled, emptyCreation, memberCannotBeSelf, memberNotRegistered([String]) + + public var description: String { + switch self { + case .alphaMLSNotEnabled: + return "GroupError.alphaMLSNotEnabled" + case .emptyCreation: + return "GroupError.emptyCreation you cannot create an empty group" + case .memberCannotBeSelf: + return "GroupError.memberCannotBeSelf you cannot add yourself to a group" + case .memberNotRegistered(let array): + return "GroupError.memberNotRegistered members not registered: \(array.joined(separator: ", "))" + } + } } final class GroupStreamCallback: FfiConversationCallback { diff --git a/Sources/XMTPiOS/Group.swift b/Sources/XMTPiOS/Group.swift index c5861048..8b0de9ca 100644 --- a/Sources/XMTPiOS/Group.swift +++ b/Sources/XMTPiOS/Group.swift @@ -59,7 +59,7 @@ public struct Group: Identifiable, Equatable, Hashable { id.hash(into: &hasher) } - public var members: [String] { + public var memberAddresses: [String] { do { return try ffiGroup.listMembers().map(\.fromFFI.accountAddress) } catch { diff --git a/Sources/XMTPiOS/Messages/PrivateKey.swift b/Sources/XMTPiOS/Messages/PrivateKey.swift index 4e2f4186..8d862dd3 100644 --- a/Sources/XMTPiOS/Messages/PrivateKey.swift +++ b/Sources/XMTPiOS/Messages/PrivateKey.swift @@ -13,8 +13,19 @@ import CryptoKit /// to create a ``Client``. public typealias PrivateKey = Xmtp_MessageContents_PrivateKey -enum PrivateKeyError: Error { +enum PrivateKeyError: Error, CustomStringConvertible { case invalidSignatureText, invalidPrefix, invalidSignature + + var description: String { + switch self { + case .invalidSignatureText: + return "PrivateKeyError.invalidSignatureText" + case .invalidPrefix: + return "PrivateKeyError.invalidPrefix" + case .invalidSignature: + return "PrivateKeyError.invalidSignature" + } + } } extension PrivateKey: SigningKey { diff --git a/Sources/XMTPiOS/Messages/SealedInvitation.swift b/Sources/XMTPiOS/Messages/SealedInvitation.swift index 2d5cae01..920ee2fc 100644 --- a/Sources/XMTPiOS/Messages/SealedInvitation.swift +++ b/Sources/XMTPiOS/Messages/SealedInvitation.swift @@ -10,8 +10,12 @@ import Foundation typealias SealedInvitation = Xmtp_MessageContents_SealedInvitation -enum SealedInvitationError: Error { +enum SealedInvitationError: Error, CustomStringConvertible { case noSignature + + var description: String { + "SealedInvitationError.noSignature" + } } extension SealedInvitation { diff --git a/Sources/XMTPiOS/Messages/Signature.swift b/Sources/XMTPiOS/Messages/Signature.swift index 01bf381f..e2964e36 100644 --- a/Sources/XMTPiOS/Messages/Signature.swift +++ b/Sources/XMTPiOS/Messages/Signature.swift @@ -11,8 +11,12 @@ import LibXMTP /// Represents a secp256k1 compact recoverable signature. public typealias Signature = Xmtp_MessageContents_Signature -enum SignatureError: Error { +enum SignatureError: Error, CustomStringConvertible { case invalidMessage + + var description: String { + return "SignatureError.invalidMessage" + } } public extension Signature { diff --git a/Sources/XMTPiOS/XMTPEnvironment.swift b/Sources/XMTPiOS/XMTPEnvironment.swift index 1c175069..4f12c8d2 100644 --- a/Sources/XMTPiOS/XMTPEnvironment.swift +++ b/Sources/XMTPiOS/XMTPEnvironment.swift @@ -23,4 +23,12 @@ public enum XMTPEnvironment: String, Sendable { return "http://\(rawValue)" } } + + public var supportsMLS: Bool { + self != .production + } + + public var isSecure: Bool { + url.starts(with: "https") + } } diff --git a/XMTP.podspec b/XMTP.podspec index bf9cb3e9..cb5e0eae 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| # spec.name = "XMTP" - spec.version = "0.8.0" + spec.version = "0.8.1" spec.summary = "XMTP SDK Cocoapod" # This description is used to generate tags and improve search results. diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 30e11be1..4ce86ce4 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -51,7 +51,7 @@ "location" : "https://github.com/kishikawakatsumi/KeychainAccess", "state" : { "branch" : "master", - "revision" : "ecb18d8ce4d88277cc4fb103973352d91e18c535" + "revision" : "e0c7eebc5a4465a3c4680764f26b7a61f567cdaf" } }, { @@ -231,7 +231,7 @@ "location" : "https://github.com/WalletConnect/WalletConnectSwiftV2", "state" : { "branch" : "main", - "revision" : "13446a81e678e8eddc6ab506e85c522df0163f1f" + "revision" : "f2db5e796976e6294b40da01c443f39a16b4732a" } }, { diff --git a/XMTPiOSExample/XMTPiOSExample/Views/ConversationListView.swift b/XMTPiOSExample/XMTPiOSExample/Views/ConversationListView.swift index 1b928095..2e73f24a 100644 --- a/XMTPiOSExample/XMTPiOSExample/Views/ConversationListView.swift +++ b/XMTPiOSExample/XMTPiOSExample/Views/ConversationListView.swift @@ -40,7 +40,7 @@ struct ConversationListView: View { case .conversation(let conversation): Text(Util.abbreviate(address: conversation.peerAddress)) case .group(let group): - Text(group.members.sorted().map { Util.abbreviate(address: $0) }.joined(separator: ", ")) + Text(group.memberAddresses.sorted().map { Util.abbreviate(address: $0) }.joined(separator: ", ")) } Text(item.createdAt.formatted()) diff --git a/XMTPiOSExample/XMTPiOSExample/Views/GroupSettingsView.swift b/XMTPiOSExample/XMTPiOSExample/Views/GroupSettingsView.swift index cefb95e2..87a66376 100644 --- a/XMTPiOSExample/XMTPiOSExample/Views/GroupSettingsView.swift +++ b/XMTPiOSExample/XMTPiOSExample/Views/GroupSettingsView.swift @@ -118,7 +118,7 @@ struct GroupSettingsView: View { try? await group.sync() // swiftlint:enable no_optional_try await MainActor.run { - self.groupMembers = group.members + self.groupMembers = group.memberAddresses } } } diff --git a/XMTPiOSExample/XMTPiOSExample/Views/NewConversationView.swift b/XMTPiOSExample/XMTPiOSExample/Views/NewConversationView.swift index 7586683a..e76bb025 100644 --- a/XMTPiOSExample/XMTPiOSExample/Views/NewConversationView.swift +++ b/XMTPiOSExample/XMTPiOSExample/Views/NewConversationView.swift @@ -24,7 +24,7 @@ enum ConversationOrGroup: Identifiable, Hashable { case .conversation(let conversation): return conversation.peerAddress case .group(let group): - return group.members.joined(separator: ",") + return group.memberAddresses.joined(separator: ",") } }