Use atproto actions with ease in iOS shortcuts
at main 4.5 kB view raw
1// 2// Resolvers.swift 3// shortcut 4// 5// Created by Bailey Townsend on 7/2/25. 6// 7 8import ATCommonWeb 9import ATIdentityTools 10import ATProtoKit 11import Cache 12import Foundation 13 14public struct Resolvers { 15 16 let handleResolver: HandleResolver 17 var didCache: Storage<String, String>? 18 var didDocCache: Storage<String, CommonDIDDocument>? 19 20 init() { 21 self.handleResolver = HandleResolver() 22 let one_hour = Expiry.seconds(TimeInterval(3_600)) 23 let didCacheDiskConfig = DiskConfig(name: "DidCache", expiry: one_hour) 24 let didDocCacheDiskConfig = DiskConfig(name: "DidDocCache", expiry: one_hour) 25 let memoryConfig = MemoryConfig( 26 expiry: one_hour, countLimit: 10, totalCostLimit: 20) 27 28 do { 29 self.didCache = try Storage<String, String>( 30 diskConfig: didCacheDiskConfig, 31 memoryConfig: memoryConfig, 32 fileManager: FileManager(), 33 transformer: TransformerFactory.forCodable( 34 ofType: String.self 35 ) 36 ) 37 38 self.didDocCache = try Storage<String, CommonDIDDocument>( 39 diskConfig: didDocCacheDiskConfig, 40 memoryConfig: memoryConfig, 41 fileManager: FileManager(), 42 transformer: TransformerFactory.forCodable( 43 ofType: CommonDIDDocument.self 44 )) 45 } catch { 46 print(error) 47 48 self.didCache = nil 49 self.didDocCache = nil 50 } 51 } 52 53 public func resolveDid(handle: String) async throws -> String? { 54 55 if let cache = self.didCache { 56 if cache.objectExists(forKey: handle) { 57 let result = try cache.entry(forKey: handle) 58 if result.expiry.isExpired { 59 try cache.removeObject(forKey: handle) 60 } 61 return result.object 62 } 63 } 64 65 var didToReturn: String 66 67 if handle.hasSuffix(".bsky.social") { 68 let config = ATProtocolConfiguration() 69 let atProto = await ATProtoKit( 70 sessionConfiguration: config) 71 72 do { 73 let did = try await atProto.resolveHandle(from: handle) 74 didToReturn = did.did 75 } catch { 76 throw LoginError.handleDoesNotResolve 77 } 78 } else { 79 guard let did = try await handleResolver.resolve(handle: handle) else { 80 throw LoginError.handleDoesNotResolve 81 } 82 didToReturn = did 83 } 84 85 do { 86 try self.didCache?.setObject(didToReturn, forKey: handle) 87 } catch { 88 print(error) 89 } 90 return didToReturn 91 92 } 93 94 public func getDidDoc(handle: String) async throws -> CommonDIDDocument { 95 96 do { 97 98 guard let did = try await self.resolveDid(handle: handle) else { 99 throw LoginError.handleDoesNotResolve 100 } 101 102 if let cache = self.didDocCache { 103 if cache.objectExists(forKey: handle) { 104 let result = try cache.entry(forKey: handle) 105 if result.expiry.isExpired { 106 try cache.removeObject(forKey: handle) 107 } 108 return result.object 109 } 110 } 111 112 var didResolver = DIDResolver() 113 114 let didDoc = try await didResolver.resolve(did: did) 115 do { 116 try self.didDocCache?.setObject(didDoc, forKey: handle) 117 } catch { 118 print(error) 119 } 120 return didDoc 121 122 } catch { 123 throw error 124 } 125 } 126 127 public func getDidDoc(did: String) async throws -> CommonDIDDocument { 128 129 do { 130 131 if let cache = self.didDocCache { 132 if cache.objectExists(forKey: did) { 133 let result = try cache.entry(forKey: did) 134 if result.expiry.isExpired { 135 try cache.removeObject(forKey: did) 136 } 137 return result.object 138 } 139 } 140 141 var didResolver = DIDResolver() 142 143 let didDoc = try await didResolver.resolve(did: did) 144 do { 145 try self.didDocCache?.setObject(didDoc, forKey: did) 146 } catch { 147 print(error) 148 } 149 return didDoc 150 151 } catch { 152 throw error 153 } 154 } 155 156}