Use atproto actions with ease in iOS shortcuts
at main 3.9 kB view raw
1// 2// ListRecordsIntent.swift 3// shortcut 4// 5// Created by Bailey Townsend on 7/4/25. 6// 7 8import ATProtoKit 9import AppIntents 10import SwiftData 11import SwiftUI 12 13struct ListRecordsIntent: AppIntent { 14 15 @Parameter( 16 title: "Repo", 17 description: "The handle or DID of the repo" 18 ) 19 var atIdentifier: String 20 21 @Parameter( 22 title: "Collection", 23 description: "The collection you want to write to, like app.bsky.feed.post") 24 var collection: String 25 26 @Parameter( 27 title: "Limit", 28 description: "The number of records to return. Between 2 and 100, defaults to 50", 29 default: nil) 30 var limit: Int? 31 32 @Parameter( 33 title: "Cursor", 34 description: 35 "This can be a Record Key to used as the last seen record top paginate the results", 36 default: nil 37 ) 38 var cursor: String? 39 40 @Parameter( 41 title: "Reverse", 42 description: 43 "Flag to reverse the order of the returned records", 44 default: nil 45 ) 46 var reverse: Bool? 47 48 static let title: LocalizedStringResource = "List Records" 49 50 static let description: IntentDescription = IntentDescription( 51 stringLiteral: 52 "List a range of records in a repository, matching a specific collection. Does not require auth" 53 ) 54 55 static var parameterSummary: some ParameterSummary { 56 Summary("List \(\.$collection) records from \(\.$atIdentifier)") { 57 \.$limit 58 \.$cursor 59 \.$reverse 60 } 61 } 62 63 func perform() async throws -> some IntentResult & ReturnsValue<ListRecordsAppEntity> { 64 let atProtoManager = AtProtocolManager() 65 let lowerCaseCollection = self.collection.lowercased() 66 let lowerCaseAtIdentifier = self.atIdentifier.lowercased() 67 print(lowerCaseAtIdentifier) 68 let info = try await GetRemoteInfo.getRemoteRepoInfo( 69 possibleRepo: lowerCaseAtIdentifier, atProtoManager: atProtoManager) 70 if let limit = self.limit { 71 if limit < 2 { 72 throw GenericIntentError.message("Limit must be greater than or equal to 2") 73 } 74 75 if limit > 100 { 76 throw GenericIntentError.message("Limit cannot be greater than 100") 77 } 78 } 79 80 do { 81 let response = try await atProtoManager.listRecords( 82 pdsURL: info.pdsURL, 83 repository: info.repo, 84 collection: lowerCaseCollection, 85 limit: self.limit, 86 cursor: self.cursor, 87 isArrayReverse: self.reverse) 88 89 let result: ListRecordsAppEntity = ListRecordsAppEntity() 90 result.cursor = response.cursor 91 result.records = [] 92 for record in response.records { 93 let recordAppEntity = RecordAppEntity() 94 recordAppEntity.uri = record.uri 95 recordAppEntity.cid = record.cid 96 if let attempt = try record.value?.toJSON() { 97 recordAppEntity.value = IntentFile( 98 data: attempt, filename: "\(record.uri).json") 99 } 100 result.records.append(recordAppEntity) 101 } 102 103 return .result( 104 value: result) 105 } catch let shortCutError as ShortcutErrors { 106 switch shortCutError { 107 case .NoSession: 108 throw GenericIntentError.message("No session found") 109 case .ErrorCreatingARecord(let errorMessage): 110 throw GenericIntentError.message(errorMessage) 111 case .AuthError(let authError): 112 throw MakeAPostIntentError.message(authError) 113 } 114 } catch let shortCutError as GenericIntentError { 115 throw shortCutError 116 } catch { 117 throw GenericIntentError.general 118 } 119 } 120 121}