From c04a5708b9221def43005bea336d6c1e6209baf2 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Thu, 1 Oct 2026 10:54:41 -0400 Subject: [PATCH 1/2] chore(contract): sync flipcash2 protos to 993127b --- .../ContractInfo.swift | 4 +- .../chat_v1_chat_service.grpc.swift | 200 ++++++++++++++++++ .../chat_v1_chat_service.pb.swift | 163 ++++++++++++++ .../chat_v1_model.pb.swift | 79 +++++++ flipcash2.lock | 4 +- proto/chat/v1/chat_service.proto | 42 ++++ proto/chat/v1/model.proto | 15 ++ 7 files changed, 503 insertions(+), 4 deletions(-) diff --git a/Sources/Flipcash2ClientProtocol/ContractInfo.swift b/Sources/Flipcash2ClientProtocol/ContractInfo.swift index d01e2ed..27af65f 100644 --- a/Sources/Flipcash2ClientProtocol/ContractInfo.swift +++ b/Sources/Flipcash2ClientProtocol/ContractInfo.swift @@ -1,8 +1,8 @@ // Generated by scripts/generate-swift.sh. Do not edit. public enum Flipcash2ContractInfo { - public static let version = "0.14.0-dev" - public static let protoCommit = "d082b0a3dd268f884f75402ccd355b6548612221" + public static let version = "0.14.1-dev" + public static let protoCommit = "993127b50e42046ee2f290f122b05625774a0661" public static var isLocal: Bool { protoCommit == localSentinel } diff --git a/Sources/Flipcash2ClientProtocol/chat_v1_chat_service.grpc.swift b/Sources/Flipcash2ClientProtocol/chat_v1_chat_service.grpc.swift index 8ae8d48..13284e4 100644 --- a/Sources/Flipcash2ClientProtocol/chat_v1_chat_service.grpc.swift +++ b/Sources/Flipcash2ClientProtocol/chat_v1_chat_service.grpc.swift @@ -68,6 +68,18 @@ public enum Flipcash_Chat_V1_Chat { method: "GetRoster" ) } + /// Namespace for "GetMentionSuggestions" metadata. + public enum GetMentionSuggestions { + /// Request type for "GetMentionSuggestions". + public typealias Input = Flipcash_Chat_V1_GetMentionSuggestionsRequest + /// Response type for "GetMentionSuggestions". + public typealias Output = Flipcash_Chat_V1_GetMentionSuggestionsResponse + /// Descriptor for "GetMentionSuggestions". + public static let descriptor = GRPCCore.MethodDescriptor( + service: GRPCCore.ServiceDescriptor(fullyQualifiedService: "flipcash.chat.v1.Chat"), + method: "GetMentionSuggestions" + ) + } /// Namespace for "StartChat" metadata. public enum StartChat { /// Request type for "StartChat". @@ -146,6 +158,7 @@ public enum Flipcash_Chat_V1_Chat { GetDmChatFeed.descriptor, GetGroupChatFeed.descriptor, GetRoster.descriptor, + GetMentionSuggestions.descriptor, StartChat.descriptor, JoinChat.descriptor, LeaveChat.descriptor, @@ -337,6 +350,46 @@ extension Flipcash_Chat_V1_Chat { onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result ) async throws -> Result where Result: Sendable + /// Call the "GetMentionSuggestions" method. + /// + /// > Source IDL Documentation: + /// > + /// > GetMentionSuggestions returns people the caller may want to @mention in + /// > a group chat, ranked by the server, most relevant first. Today that is + /// > the group's most recent senders, most recent first, including people + /// > who have since left the group. + /// > + /// > The response is a ranked pool of suggestions, not the set of people who + /// > may be mentioned, and it is neither complete nor paged. The server + /// > decides how many to return, up to 200; the client filters the whole + /// > pool locally as the user types, however few rows it displays, and keeps + /// > it fresh from the event stream by moving the sender of each new message + /// > to the front. It fetches the pool once per composing session. The + /// > ranking and the pool's size may change without notice; clients must + /// > not depend on either beyond the order given. + /// > + /// > The caller, users the caller has blocked, and users without a username + /// > are never suggested. A user who has blocked the caller may still be. + /// > + /// > Requires that the caller may speak in the chat. A DM is DENIED. + /// + /// - Parameters: + /// - request: A request containing a single `Flipcash_Chat_V1_GetMentionSuggestionsRequest` message. + /// - serializer: A serializer for `Flipcash_Chat_V1_GetMentionSuggestionsRequest` messages. + /// - deserializer: A deserializer for `Flipcash_Chat_V1_GetMentionSuggestionsResponse` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + func getMentionSuggestions( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable + /// Call the "StartChat" method. /// /// > Source IDL Documentation: @@ -728,6 +781,57 @@ extension Flipcash_Chat_V1_Chat { ) } + /// Call the "GetMentionSuggestions" method. + /// + /// > Source IDL Documentation: + /// > + /// > GetMentionSuggestions returns people the caller may want to @mention in + /// > a group chat, ranked by the server, most relevant first. Today that is + /// > the group's most recent senders, most recent first, including people + /// > who have since left the group. + /// > + /// > The response is a ranked pool of suggestions, not the set of people who + /// > may be mentioned, and it is neither complete nor paged. The server + /// > decides how many to return, up to 200; the client filters the whole + /// > pool locally as the user types, however few rows it displays, and keeps + /// > it fresh from the event stream by moving the sender of each new message + /// > to the front. It fetches the pool once per composing session. The + /// > ranking and the pool's size may change without notice; clients must + /// > not depend on either beyond the order given. + /// > + /// > The caller, users the caller has blocked, and users without a username + /// > are never suggested. A user who has blocked the caller may still be. + /// > + /// > Requires that the caller may speak in the chat. A DM is DENIED. + /// + /// - Parameters: + /// - request: A request containing a single `Flipcash_Chat_V1_GetMentionSuggestionsRequest` message. + /// - serializer: A serializer for `Flipcash_Chat_V1_GetMentionSuggestionsRequest` messages. + /// - deserializer: A deserializer for `Flipcash_Chat_V1_GetMentionSuggestionsResponse` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + public func getMentionSuggestions( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + try await self.client.unary( + request: request, + descriptor: Flipcash_Chat_V1_Chat.Method.GetMentionSuggestions.descriptor, + serializer: serializer, + deserializer: deserializer, + options: options, + onResponse: handleResponse + ) + } + /// Call the "StartChat" method. /// /// > Source IDL Documentation: @@ -1153,6 +1257,52 @@ extension Flipcash_Chat_V1_Chat.ClientProtocol { ) } + /// Call the "GetMentionSuggestions" method. + /// + /// > Source IDL Documentation: + /// > + /// > GetMentionSuggestions returns people the caller may want to @mention in + /// > a group chat, ranked by the server, most relevant first. Today that is + /// > the group's most recent senders, most recent first, including people + /// > who have since left the group. + /// > + /// > The response is a ranked pool of suggestions, not the set of people who + /// > may be mentioned, and it is neither complete nor paged. The server + /// > decides how many to return, up to 200; the client filters the whole + /// > pool locally as the user types, however few rows it displays, and keeps + /// > it fresh from the event stream by moving the sender of each new message + /// > to the front. It fetches the pool once per composing session. The + /// > ranking and the pool's size may change without notice; clients must + /// > not depend on either beyond the order given. + /// > + /// > The caller, users the caller has blocked, and users without a username + /// > are never suggested. A user who has blocked the caller may still be. + /// > + /// > Requires that the caller may speak in the chat. A DM is DENIED. + /// + /// - Parameters: + /// - request: A request containing a single `Flipcash_Chat_V1_GetMentionSuggestionsRequest` message. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + public func getMentionSuggestions( + request: GRPCCore.ClientRequest, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + try await self.getMentionSuggestions( + request: request, + serializer: GRPCProtobuf.ProtobufSerializer(), + deserializer: GRPCProtobuf.ProtobufDeserializer(), + options: options, + onResponse: handleResponse + ) + } + /// Call the "StartChat" method. /// /// > Source IDL Documentation: @@ -1563,6 +1713,56 @@ extension Flipcash_Chat_V1_Chat.ClientProtocol { ) } + /// Call the "GetMentionSuggestions" method. + /// + /// > Source IDL Documentation: + /// > + /// > GetMentionSuggestions returns people the caller may want to @mention in + /// > a group chat, ranked by the server, most relevant first. Today that is + /// > the group's most recent senders, most recent first, including people + /// > who have since left the group. + /// > + /// > The response is a ranked pool of suggestions, not the set of people who + /// > may be mentioned, and it is neither complete nor paged. The server + /// > decides how many to return, up to 200; the client filters the whole + /// > pool locally as the user types, however few rows it displays, and keeps + /// > it fresh from the event stream by moving the sender of each new message + /// > to the front. It fetches the pool once per composing session. The + /// > ranking and the pool's size may change without notice; clients must + /// > not depend on either beyond the order given. + /// > + /// > The caller, users the caller has blocked, and users without a username + /// > are never suggested. A user who has blocked the caller may still be. + /// > + /// > Requires that the caller may speak in the chat. A DM is DENIED. + /// + /// - Parameters: + /// - message: request message to send. + /// - metadata: Additional metadata to send, defaults to empty. + /// - options: Options to apply to this RPC, defaults to `.defaults`. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + public func getMentionSuggestions( + _ message: Flipcash_Chat_V1_GetMentionSuggestionsRequest, + metadata: GRPCCore.Metadata = [:], + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + let request = GRPCCore.ClientRequest( + message: message, + metadata: metadata + ) + return try await self.getMentionSuggestions( + request: request, + options: options, + onResponse: handleResponse + ) + } + /// Call the "StartChat" method. /// /// > Source IDL Documentation: diff --git a/Sources/Flipcash2ClientProtocol/chat_v1_chat_service.pb.swift b/Sources/Flipcash2ClientProtocol/chat_v1_chat_service.pb.swift index 8145c31..21c3830 100644 --- a/Sources/Flipcash2ClientProtocol/chat_v1_chat_service.pb.swift +++ b/Sources/Flipcash2ClientProtocol/chat_v1_chat_service.pb.swift @@ -502,6 +502,91 @@ public struct Flipcash_Chat_V1_GetRosterResponse: Sendable { fileprivate var _pagingToken: Flipcash_Common_V1_PagingToken? = nil } +public struct Flipcash_Chat_V1_GetMentionSuggestionsRequest: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var chatID: Flipcash_Common_V1_ChatId { + get {return _chatID ?? Flipcash_Common_V1_ChatId()} + set {_chatID = newValue} + } + /// Returns true if `chatID` has been explicitly set. + public var hasChatID: Bool {return self._chatID != nil} + /// Clears the value of `chatID`. Subsequent reads from it will return its default value. + public mutating func clearChatID() {self._chatID = nil} + + public var auth: Flipcash_Common_V1_Auth { + get {return _auth ?? Flipcash_Common_V1_Auth()} + set {_auth = newValue} + } + /// Returns true if `auth` has been explicitly set. + public var hasAuth: Bool {return self._auth != nil} + /// Clears the value of `auth`. Subsequent reads from it will return its default value. + public mutating func clearAuth() {self._auth = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _chatID: Flipcash_Common_V1_ChatId? = nil + fileprivate var _auth: Flipcash_Common_V1_Auth? = nil +} + +public struct Flipcash_Chat_V1_GetMentionSuggestionsResponse: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var result: Flipcash_Chat_V1_GetMentionSuggestionsResponse.Result = .ok + + /// The suggestions, most relevant first, as many as the server chooses. + /// Set when result is OK. + public var suggestions: [Flipcash_Chat_V1_MentionSuggestion] = [] + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public enum Result: SwiftProtobuf.Enum, Swift.CaseIterable { + public typealias RawValue = Int + case ok // = 0 + case denied // = 1 + case notFound // = 2 + case UNRECOGNIZED(Int) + + public init() { + self = .ok + } + + public init?(rawValue: Int) { + switch rawValue { + case 0: self = .ok + case 1: self = .denied + case 2: self = .notFound + default: self = .UNRECOGNIZED(rawValue) + } + } + + public var rawValue: Int { + switch self { + case .ok: return 0 + case .denied: return 1 + case .notFound: return 2 + case .UNRECOGNIZED(let i): return i + } + } + + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Flipcash_Chat_V1_GetMentionSuggestionsResponse.Result] = [ + .ok, + .denied, + .notFound, + ] + + } + + public init() {} +} + public struct Flipcash_Chat_V1_StartChatRequest: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -1604,6 +1689,84 @@ extension Flipcash_Chat_V1_GetRosterResponse.Result: SwiftProtobuf._ProtoNamePro public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0OK\0\u{1}DENIED\0\u{1}NOT_FOUND\0") } +extension Flipcash_Chat_V1_GetMentionSuggestionsRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".GetMentionSuggestionsRequest" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}chat_id\0\u{2}\u{9}auth\0") + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularMessageField(value: &self._chatID) }() + case 10: try { try decoder.decodeSingularMessageField(value: &self._auth) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._chatID { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() + try { if let v = self._auth { + try visitor.visitSingularMessageField(value: v, fieldNumber: 10) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Flipcash_Chat_V1_GetMentionSuggestionsRequest, rhs: Flipcash_Chat_V1_GetMentionSuggestionsRequest) -> Bool { + if lhs._chatID != rhs._chatID {return false} + if lhs._auth != rhs._auth {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Flipcash_Chat_V1_GetMentionSuggestionsResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".GetMentionSuggestionsResponse" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}result\0\u{1}suggestions\0") + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularEnumField(value: &self.result) }() + case 2: try { try decoder.decodeRepeatedMessageField(value: &self.suggestions) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if self.result != .ok { + try visitor.visitSingularEnumField(value: self.result, fieldNumber: 1) + } + if !self.suggestions.isEmpty { + try visitor.visitRepeatedMessageField(value: self.suggestions, fieldNumber: 2) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Flipcash_Chat_V1_GetMentionSuggestionsResponse, rhs: Flipcash_Chat_V1_GetMentionSuggestionsResponse) -> Bool { + if lhs.result != rhs.result {return false} + if lhs.suggestions != rhs.suggestions {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Flipcash_Chat_V1_GetMentionSuggestionsResponse.Result: SwiftProtobuf._ProtoNameProviding { + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0OK\0\u{1}DENIED\0\u{1}NOT_FOUND\0") +} + extension Flipcash_Chat_V1_StartChatRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".StartChatRequest" public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}group\0\u{4}\u{8}idempotency_key\0\u{1}auth\0") diff --git a/Sources/Flipcash2ClientProtocol/chat_v1_model.pb.swift b/Sources/Flipcash2ClientProtocol/chat_v1_model.pb.swift index 93c4029..d281cc0 100644 --- a/Sources/Flipcash2ClientProtocol/chat_v1_model.pb.swift +++ b/Sources/Flipcash2ClientProtocol/chat_v1_model.pb.swift @@ -474,6 +474,46 @@ public struct Flipcash_Chat_V1_Member: @unchecked Sendable { fileprivate var _storage = _StorageClass.defaultInstance } +/// MentionSuggestion is one person the caller may want to @mention in a chat, +/// as returned by Chat.GetMentionSuggestions. It is not a Member: a suggestion +/// may name someone who has since left the chat. +public struct Flipcash_Chat_V1_MentionSuggestion: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + /// The suggested user's public profile. user_id and username are always + /// set. + public var userProfile: Flipcash_Profile_V1_UserProfile { + get {return _userProfile ?? Flipcash_Profile_V1_UserProfile()} + set {_userProfile = newValue} + } + /// Returns true if `userProfile` has been explicitly set. + public var hasUserProfile: Bool {return self._userProfile != nil} + /// Clears the value of `userProfile`. Subsequent reads from it will return its default value. + public mutating func clearUserProfile() {self._userProfile = nil} + + /// When the user last sent a message in this chat, as the server records + /// it: it may trail their latest message by up to a minute. A client + /// merging new messages from the event stream into its list compares + /// against it. Unset for a user suggested for another reason. + public var lastSentAt: SwiftProtobuf.Google_Protobuf_Timestamp { + get {return _lastSentAt ?? SwiftProtobuf.Google_Protobuf_Timestamp()} + set {_lastSentAt = newValue} + } + /// Returns true if `lastSentAt` has been explicitly set. + public var hasLastSentAt: Bool {return self._lastSentAt != nil} + /// Clears the value of `lastSentAt`. Subsequent reads from it will return its default value. + public mutating func clearLastSentAt() {self._lastSentAt = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _userProfile: Flipcash_Profile_V1_UserProfile? = nil + fileprivate var _lastSentAt: SwiftProtobuf.Google_Protobuf_Timestamp? = nil +} + /// RosterSummary describes a chat's roster — its member list — without /// containing it: what a client needs in order to know whether its copy of /// that list is stale, without holding the list. @@ -1549,6 +1589,45 @@ extension Flipcash_Chat_V1_Member: SwiftProtobuf.Message, SwiftProtobuf._Message } } +extension Flipcash_Chat_V1_MentionSuggestion: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".MentionSuggestion" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}user_profile\0\u{3}last_sent_at\0") + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularMessageField(value: &self._userProfile) }() + case 2: try { try decoder.decodeSingularMessageField(value: &self._lastSentAt) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._userProfile { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() + try { if let v = self._lastSentAt { + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Flipcash_Chat_V1_MentionSuggestion, rhs: Flipcash_Chat_V1_MentionSuggestion) -> Bool { + if lhs._userProfile != rhs._userProfile {return false} + if lhs._lastSentAt != rhs._lastSentAt {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension Flipcash_Chat_V1_RosterSummary: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".RosterSummary" public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}member_count\0\u{1}version\0") diff --git a/flipcash2.lock b/flipcash2.lock index 36b447d..fc9ef0c 100644 --- a/flipcash2.lock +++ b/flipcash2.lock @@ -1,4 +1,4 @@ # Pinned upstream contract. Regenerate with scripts/sync-protos.sh . upstream: code-payments/flipcash2-protobuf-api -commit: d082b0a3dd268f884f75402ccd355b6548612221 -subject: Add a creator requirement for speaker rules (#129) +commit: 993127b50e42046ee2f290f122b05625774a0661 +subject: Update GetMentionSuggestions comment (#131) diff --git a/proto/chat/v1/chat_service.proto b/proto/chat/v1/chat_service.proto index a595a2f..2c7151a 100644 --- a/proto/chat/v1/chat_service.proto +++ b/proto/chat/v1/chat_service.proto @@ -100,6 +100,26 @@ service Chat { // is DENIED. rpc GetRoster(GetRosterRequest) returns (GetRosterResponse); + // GetMentionSuggestions returns people the caller may want to @mention in + // a group chat, ranked by the server, most relevant first. Today that is + // the group's most recent senders, most recent first, including people + // who have since left the group. + // + // The response is a ranked pool of suggestions, not the set of people who + // may be mentioned, and it is neither complete nor paged. The server + // decides how many to return, up to 200; the client filters the whole + // pool locally as the user types, however few rows it displays, and keeps + // it fresh from the event stream by moving the sender of each new message + // to the front. It fetches the pool once per composing session. The + // ranking and the pool's size may change without notice; clients must + // not depend on either beyond the order given. + // + // The caller, users the caller has blocked, and users without a username + // are never suggested. A user who has blocked the caller may still be. + // + // Requires that the caller may speak in the chat. A DM is DENIED. + rpc GetMentionSuggestions(GetMentionSuggestionsRequest) returns (GetMentionSuggestionsResponse); + // StartChat starts a new chat. rpc StartChat(StartChatRequest) returns (StartChatResponse); @@ -324,6 +344,28 @@ message GetRosterResponse { bool has_more = 5; } +message GetMentionSuggestionsRequest { + common.v1.ChatId chat_id = 1 [(validate.rules).message.required = true]; + + common.v1.Auth auth = 10 [(validate.rules).message.required = true]; +} + +message GetMentionSuggestionsResponse { + Result result = 1; + enum Result { + OK = 0; + DENIED = 1; + NOT_FOUND = 2; + } + + // The suggestions, most relevant first, as many as the server chooses. + // Set when result is OK. + repeated MentionSuggestion suggestions = 2 [(validate.rules).repeated = { + min_items: 0 + max_items: 200 + }]; +} + message StartChatRequest { // Parameters for the kind of chat being created. The variant selects the // chat type. diff --git a/proto/chat/v1/model.proto b/proto/chat/v1/model.proto index 8e07f51..ccebff5 100644 --- a/proto/chat/v1/model.proto +++ b/proto/chat/v1/model.proto @@ -215,6 +215,21 @@ message Member { uint64 version = 5; } +// MentionSuggestion is one person the caller may want to @mention in a chat, +// as returned by Chat.GetMentionSuggestions. It is not a Member: a suggestion +// may name someone who has since left the chat. +message MentionSuggestion { + // The suggested user's public profile. user_id and username are always + // set. + profile.v1.UserProfile user_profile = 1 [(validate.rules).message.required = true]; + + // When the user last sent a message in this chat, as the server records + // it: it may trail their latest message by up to a minute. A client + // merging new messages from the event stream into its list compares + // against it. Unset for a user suggested for another reason. + google.protobuf.Timestamp last_sent_at = 2; +} + // RosterSummary describes a chat's roster — its member list — without // containing it: what a client needs in order to know whether its copy of // that list is stale, without holding the list. From 34cac29d18bfe6af39a5b4c5f471249dacddc506 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Thu, 1 Oct 2026 10:54:58 -0400 Subject: [PATCH 2/2] docs(changelog): add 0.15.0 for GetMentionSuggestions --- CHANGELOG.md | 23 +++++++++++++++++++ .../ContractInfo.swift | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cd868b..8e6e20b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,29 @@ called out explicitly even when nothing else did. release notes, so a version with no entry here does not release. Write the entry in the same PR that syncs the contract, while the diff is still in front of you. +## 0.15.0 + +Synced to [`flipcash2-protobuf-api@993127b5`](https://github.com/code-payments/flipcash2-protobuf-api/commit/993127b50e42046ee2f290f122b05625774a0661), +picking up [#130](https://github.com/code-payments/flipcash2-protobuf-api/pull/130) and +[#131](https://github.com/code-payments/flipcash2-protobuf-api/pull/131). Only `chat.v1` moved. + +### Added + +- `Chat.GetMentionSuggestions`, a new RPC: a ranked pool of people to suggest after an @ in a group + chat, most relevant first. Today that's the group's most recent senders, including people who + have since left. It is not paged and not complete; the server returns up to 200, and the client + filters the pool locally as the user types. A DM is `DENIED`. +- `GetMentionSuggestionsRequest` (`chat_id`, `auth`) and `GetMentionSuggestionsResponse` + (`result`: `OK`, `DENIED`, `NOT_FOUND`; repeated `suggestions`). +- `chat.v1.MentionSuggestion`: a `UserProfile` with `user_id` and `username` always set, and + `last_sent_at`, unset for someone suggested for another reason. It is not a `Member`. + +### Upgrading + +Nothing existing changed: no renames, and no field or enum renumbering. The server already drops +the caller, users the caller blocked, and users without a username from the pool, so a client +doesn't need its own username filter on these results. + ## 0.14.1 Synced to [`flipcash2-protobuf-api@d082b0a3`](https://github.com/code-payments/flipcash2-protobuf-api/commit/d082b0a3dd268f884f75402ccd355b6548612221), diff --git a/Sources/Flipcash2ClientProtocol/ContractInfo.swift b/Sources/Flipcash2ClientProtocol/ContractInfo.swift index 27af65f..0a1657b 100644 --- a/Sources/Flipcash2ClientProtocol/ContractInfo.swift +++ b/Sources/Flipcash2ClientProtocol/ContractInfo.swift @@ -1,7 +1,7 @@ // Generated by scripts/generate-swift.sh. Do not edit. public enum Flipcash2ContractInfo { - public static let version = "0.14.1-dev" + public static let version = "0.15.0-dev" public static let protoCommit = "993127b50e42046ee2f290f122b05625774a0661" public static var isLocal: Bool { protoCommit == localSentinel }