From 8151b300d3b40e3741fc04b004b7c48e47f43a9d Mon Sep 17 00:00:00 2001 From: Jon Shier Date: Mon, 16 Feb 2026 17:26:16 -0500 Subject: [PATCH 1/3] Duplicate typed throws API into @objc. --- Sources/Valet/SecureEnclaveValet.swift | 87 ++++++++++++++++++++++---- Sources/Valet/Valet.swift | 74 +++++++++++++++++++--- 2 files changed, 142 insertions(+), 19 deletions(-) diff --git a/Sources/Valet/SecureEnclaveValet.swift b/Sources/Valet/SecureEnclaveValet.swift index 9ce77397..9af67270 100644 --- a/Sources/Valet/SecureEnclaveValet.swift +++ b/Sources/Valet/SecureEnclaveValet.swift @@ -121,7 +121,6 @@ public final class SecureEnclaveValet: NSObject, Sendable { /// - key: A key that can be used to retrieve the `object` from the keychain. /// - Throws: An error of type `KeychainError`. /// - Important: Inserted data should be no larger than 4kb. - @objc public func setObject(_ object: Data, forKey key: String) throws(KeychainError) { lock.lock() defer { @@ -130,13 +129,23 @@ public final class SecureEnclaveValet: NSObject, Sendable { return try SecureEnclave.setObject(object, forKey: key, options: baseKeychainQuery) } + /// - Parameters: + /// - object: A Data value to be inserted into the keychain. + /// - key: A key that can be used to retrieve the `object` from the keychain. + /// - Throws: An error of type `KeychainError`. + /// - Important: Inserted data should be no larger than 4kb. + @available(*, unavailable) + @objc(setObject:forKey:error:) + public func objc_setObject(_ object: Data, forKey key: String) throws { + try setObject(object, forKey: key) + } + #if !os(tvOS) && !os(watchOS) && canImport(LocalAuthentication) /// - Parameters: /// - key: A key used to retrieve the desired object from the keychain. /// - userPrompt: The prompt displayed to the user in Apple's Face ID, Touch ID, or passcode entry UI. /// - Returns: The data currently stored in the keychain for the provided key. /// - Throws: An error of type `KeychainError`. - @objc public func object(forKey key: String, withPrompt userPrompt: String) throws(KeychainError) -> Data { lock.lock() defer { @@ -144,11 +153,21 @@ public final class SecureEnclaveValet: NSObject, Sendable { } return try SecureEnclave.object(forKey: key, withPrompt: userPrompt, context: nil, options: baseKeychainQuery) } + + /// - Parameters: + /// - key: A key used to retrieve the desired object from the keychain. + /// - userPrompt: The prompt displayed to the user in Apple's Face ID, Touch ID, or passcode entry UI. + /// - Returns: The data currently stored in the keychain for the provided key. + /// - Throws: An error of type `KeychainError`. + @available(*, unavailable) + @objc(objectForKey:withPrompt:error:) + public func objc_object(forKey key: String, withPrompt userPrompt: String) throws -> Data { + try object(forKey: key, withPrompt: userPrompt) + } #else /// - Parameter key: A key used to retrieve the desired object from the keychain. /// - Returns: The data currently stored in the keychain for the provided key. /// - Throws: An error of type `KeychainError`. - @objc public func object(forKey key: String) throws(KeychainError) -> Data { lock.lock() defer { @@ -156,6 +175,15 @@ public final class SecureEnclaveValet: NSObject, Sendable { } return try SecureEnclave.object(forKey: key, options: baseKeychainQuery) } + + /// - Parameter key: A key used to retrieve the desired object from the keychain. + /// - Returns: The data currently stored in the keychain for the provided key. + /// - Throws: An error of type `KeychainError`. + @available(*, unavailable) + @objc(objectForKey:error:) + public func objc_object(forKey key: String) throws -> Data { + try object(forKey: key) + } #endif #if !os(tvOS) && canImport(LocalAuthentication) @@ -177,7 +205,6 @@ public final class SecureEnclaveValet: NSObject, Sendable { /// - key: A key that can be used to retrieve the `string` from the keychain. /// - Throws: An error of type `KeychainError`. /// - Important: Inserted data should be no larger than 4kb. - @objc public func setString(_ string: String, forKey key: String) throws(KeychainError) { lock.lock() defer { @@ -186,13 +213,22 @@ public final class SecureEnclaveValet: NSObject, Sendable { return try SecureEnclave.setString(string, forKey: key, options: baseKeychainQuery) } + /// - Parameters: + /// - string: A String value to be inserted into the keychain. + /// - key: A key that can be used to retrieve the `string` from the keychain. + /// - Throws: An error of type `KeychainError`. + /// - Important: Inserted data should be no larger than 4kb. + @available(*, unavailable) + @objc(setString:forKey:error:) + public func objc_setString(_ string: String, forKey key: String) throws { + try setString(string, forKey: key) + } #if !os(tvOS) && !os(watchOS) && canImport(LocalAuthentication) /// - Parameters: /// - key: A key used to retrieve the desired object from the keychain. /// - userPrompt: The prompt displayed to the user in Apple's Face ID, Touch ID, or passcode entry UI. /// - Returns: The string currently stored in the keychain for the provided key. /// - Throws: An error of type `KeychainError`. - @objc public func string(forKey key: String, withPrompt userPrompt: String) throws(KeychainError) -> String { lock.lock() defer { @@ -200,11 +236,16 @@ public final class SecureEnclaveValet: NSObject, Sendable { } return try SecureEnclave.string(forKey: key, withPrompt: userPrompt, context: nil, options: baseKeychainQuery) } + + @available(*, unavailable) + @objc(stringForKey:withPrompt:error:) + public func objc_string(forKey key: String, withPrompt userPrompt: String) throws -> String { + try string(forKey: key, withPrompt: userPrompt) + } #else /// - Parameter key: A key used to retrieve the desired object from the keychain. /// - Returns: The string currently stored in the keychain for the provided key. /// - Throws: An error of type `KeychainError`. - @objc public func string(forKey key: String) throws(KeychainError) -> String { lock.lock() defer { @@ -212,12 +253,20 @@ public final class SecureEnclaveValet: NSObject, Sendable { } return try SecureEnclave.string(forKey: key, options: baseKeychainQuery) } + + /// - Parameter key: A key used to retrieve the desired object from the keychain. + /// - Returns: The string currently stored in the keychain for the provided key. + /// - Throws: An error of type `KeychainError`. + @available(*, unavailable) + @objc(stringForKey:error:) + public func objc_string(forKey key: String) throws -> String { + try string(forKey: key) + } #endif /// Removes a key/object pair from the keychain. /// - Parameter key: A key used to remove the desired object from the keychain. /// - Throws: An error of type `KeychainError`. - @objc public func removeObject(forKey key: String) throws(KeychainError) { lock.lock() defer { @@ -225,10 +274,18 @@ public final class SecureEnclaveValet: NSObject, Sendable { } return try Keychain.removeObject(forKey: key, options: baseKeychainQuery) } - + + /// Removes a key/object pair from the keychain. + /// - Parameter key: A key used to remove the desired object from the keychain. + /// - Throws: An error of type `KeychainError`. + @available(*, unavailable) + @objc(removeObjectForKey:error:) + public func objc_removeObject(forKey key: String) throws { + try removeObject(forKey: key) + } + /// Removes all key/object pairs accessible by this Valet instance from the keychain. /// - Throws: An error of type `KeychainError`. - @objc public func removeAllObjects() throws(KeychainError) { lock.lock() defer { @@ -236,7 +293,15 @@ public final class SecureEnclaveValet: NSObject, Sendable { } return try Keychain.removeAllObjects(matching: baseKeychainQuery) } - + + /// Removes all key/object pairs accessible by this Valet instance from the keychain. + /// - Throws: An error of type `KeychainError`. + @available(*, unavailable) + @objc(removeAllObjectsWithError:) + public func objc_removeAllObjects() throws { + try removeAllObjects() + } + /// Migrates objects matching the input query into the receiving SecureEnclaveValet instance. /// - Parameters: /// - query: The query with which to retrieve existing keychain data via a call to SecItemCopyMatching. @@ -249,7 +314,7 @@ public final class SecureEnclaveValet: NSObject, Sendable { try Keychain.migrateObjects(matching: query, into: baseKeychainQuery, removeOnCompletion: removeOnCompletion) } } - + /// Migrates objects matching the vended keychain query into the receiving SecureEnclaveValet instance. /// - Parameters: /// - valet: A Valet whose vended keychain query is used to retrieve existing keychain data via a call to SecItemCopyMatching. diff --git a/Sources/Valet/Valet.swift b/Sources/Valet/Valet.swift index e5768982..6426a640 100644 --- a/Sources/Valet/Valet.swift +++ b/Sources/Valet/Valet.swift @@ -251,7 +251,6 @@ public final class Valet: NSObject, Sendable { /// - key: A key that can be used to retrieve the `object` from the keychain. /// - Throws: An error of type `KeychainError`. /// - Important: Inserted data should be no larger than 4kb. - @objc public func setObject(_ object: Data, forKey key: String) throws(KeychainError) { lock.lock() defer { @@ -260,10 +259,20 @@ public final class Valet: NSObject, Sendable { return try Keychain.setObject(object, forKey: key, options: baseKeychainQuery) } + /// - Parameters: + /// - object: A Data value to be inserted into the keychain. + /// - key: A key that can be used to retrieve the `object` from the keychain. + /// - Throws: An error of type `KeychainError`. + /// - Important: Inserted data should be no larger than 4kb. + @available(*, unavailable) + @objc(setObject:forKey:error:) + public func objc_setObject(_ object: Data, forKey key: String) throws { + try setObject(object, forKey: key) + } + /// - Parameter key: A key used to retrieve the desired object from the keychain. /// - Returns: The data currently stored in the keychain for the provided key. /// - Throws: An error of type `KeychainError`. - @objc public func object(forKey key: String) throws(KeychainError) -> Data { lock.lock() defer { @@ -272,6 +281,15 @@ public final class Valet: NSObject, Sendable { return try Keychain.object(forKey: key, options: baseKeychainQuery) } + /// - Parameter key: A key used to retrieve the desired object from the keychain. + /// - Returns: The data currently stored in the keychain for the provided key. + /// - Throws: An error of type `KeychainError`. + @available(*, unavailable) + @objc(objectForKey:error:) + public func objc_object(forKey key: String) throws -> Data { + try object(forKey: key) + } + /// - Parameter key: The key to look up in the keychain. /// - Returns: `true` if a value has been set for the given key, `false` otherwise. /// - Throws: An error of type `KeychainError`. @@ -296,7 +314,6 @@ public final class Valet: NSObject, Sendable { /// - key: A key that can be used to retrieve the `string` from the keychain. /// - Throws: An error of type `KeychainError`. /// - Important: Inserted data should be no larger than 4kb. - @objc public func setString(_ string: String, forKey key: String) throws(KeychainError) { lock.lock() defer { @@ -305,10 +322,20 @@ public final class Valet: NSObject, Sendable { return try Keychain.setString(string, forKey: key, options: baseKeychainQuery) } + /// - Parameters: + /// - string: A String value to be inserted into the keychain. + /// - key: A key that can be used to retrieve the `string` from the keychain. + /// - Throws: An error of type `KeychainError`. + /// - Important: Inserted data should be no larger than 4kb. + @available(*, unavailable) + @objc(setString:forKey:error:) + public func objc_setString(_ string: String, forKey key: String) throws { + try setString(string, forKey: key) + } + /// - Parameter key: A key used to retrieve the desired object from the keychain. /// - Returns: The string currently stored in the keychain for the provided key. /// - Throws: An error of type `KeychainError`. - @objc public func string(forKey key: String) throws(KeychainError) -> String { lock.lock() defer { @@ -316,10 +343,17 @@ public final class Valet: NSObject, Sendable { } return try Keychain.string(forKey: key, options: baseKeychainQuery) } + + /// - Parameter key: A key used to retrieve the desired object from the keychain. + /// - Returns: The string currently stored in the keychain for the provided key. + /// - Throws: An error of type `KeychainError`. + @objc(stringForKey:error:) + public func objc_string(forKey key: String) throws -> String { + try string(forKey: key) + } /// - Returns: The set of all (String) keys currently stored in this Valet instance. If no items are found, will return an empty set. /// - Throws: An error of type `KeychainError`. - @objc public func allKeys() throws(KeychainError) -> Set { lock.lock() defer { @@ -327,12 +361,19 @@ public final class Valet: NSObject, Sendable { } return try Keychain.allKeys(options: baseKeychainQuery) } - + + /// - Returns: The set of all (String) keys currently stored in this Valet instance. If no items are found, will return an empty set. + /// - Throws: An error of type `KeychainError`. + @available(*, unavailable) + @objc(allKeysWithError:) + public func objc_allKeys() throws -> Set { + try allKeys() + } + /// Removes a key/object pair from the keychain. /// - Parameter key: A key used to remove the desired object from the keychain. /// - Throws: An error of type `KeychainError`. /// - Note: No error is thrown if the `key` is not found in the keychain. - @objc public func removeObject(forKey key: String) throws(KeychainError) { lock.lock() defer { @@ -340,10 +381,19 @@ public final class Valet: NSObject, Sendable { } return try Keychain.removeObject(forKey: key, options: baseKeychainQuery) } + + /// Removes a key/object pair from the keychain. + /// - Parameter key: A key used to remove the desired object from the keychain. + /// - Throws: An error of type `KeychainError`. + /// - Note: No error is thrown if the `key` is not found in the keychain. + @available(*, unavailable) + @objc(removeObjectForKey:error:) + public func objc_removeObject(forKey key: String) throws { + try removeObject(forKey: key) + } /// Removes all key/object pairs accessible by this Valet instance from the keychain. /// - Throws: An error of type `KeychainError`. - @objc public func removeAllObjects() throws(KeychainError) { lock.lock() defer { @@ -352,6 +402,14 @@ public final class Valet: NSObject, Sendable { return try Keychain.removeAllObjects(matching: baseKeychainQuery) } + /// Removes all key/object pairs accessible by this Valet instance from the keychain. + /// - Throws: An error of type `KeychainError`. + @available(*, unavailable) + @objc(removeAllObjectsWithError:) + public func objc_removeAllObjects() throws { + try removeAllObjects() + } + /// Migrates objects matching the input query into the receiving Valet instance. /// - Parameters: /// - query: The query with which to retrieve existing keychain data via a call to SecItemCopyMatching. From 46b92be8b137c478d83912bd872de9e694687b7e Mon Sep 17 00:00:00 2001 From: Jon Shier Date: Mon, 16 Feb 2026 17:34:49 -0500 Subject: [PATCH 2/3] Fix objc interface. --- Sources/Valet/SecureEnclaveValet.swift | 18 +++++++++--------- Sources/Valet/Valet.swift | 14 +++++++------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Sources/Valet/SecureEnclaveValet.swift b/Sources/Valet/SecureEnclaveValet.swift index 9af67270..0a122bd7 100644 --- a/Sources/Valet/SecureEnclaveValet.swift +++ b/Sources/Valet/SecureEnclaveValet.swift @@ -134,7 +134,7 @@ public final class SecureEnclaveValet: NSObject, Sendable { /// - key: A key that can be used to retrieve the `object` from the keychain. /// - Throws: An error of type `KeychainError`. /// - Important: Inserted data should be no larger than 4kb. - @available(*, unavailable) + @available(swift, obsoleted: 1.0) @objc(setObject:forKey:error:) public func objc_setObject(_ object: Data, forKey key: String) throws { try setObject(object, forKey: key) @@ -159,7 +159,7 @@ public final class SecureEnclaveValet: NSObject, Sendable { /// - userPrompt: The prompt displayed to the user in Apple's Face ID, Touch ID, or passcode entry UI. /// - Returns: The data currently stored in the keychain for the provided key. /// - Throws: An error of type `KeychainError`. - @available(*, unavailable) + @available(swift, obsoleted: 1.0) @objc(objectForKey:withPrompt:error:) public func objc_object(forKey key: String, withPrompt userPrompt: String) throws -> Data { try object(forKey: key, withPrompt: userPrompt) @@ -179,7 +179,7 @@ public final class SecureEnclaveValet: NSObject, Sendable { /// - Parameter key: A key used to retrieve the desired object from the keychain. /// - Returns: The data currently stored in the keychain for the provided key. /// - Throws: An error of type `KeychainError`. - @available(*, unavailable) + @available(swift, obsoleted: 1.0) @objc(objectForKey:error:) public func objc_object(forKey key: String) throws -> Data { try object(forKey: key) @@ -218,7 +218,7 @@ public final class SecureEnclaveValet: NSObject, Sendable { /// - key: A key that can be used to retrieve the `string` from the keychain. /// - Throws: An error of type `KeychainError`. /// - Important: Inserted data should be no larger than 4kb. - @available(*, unavailable) + @available(swift, obsoleted: 1.0) @objc(setString:forKey:error:) public func objc_setString(_ string: String, forKey key: String) throws { try setString(string, forKey: key) @@ -237,7 +237,7 @@ public final class SecureEnclaveValet: NSObject, Sendable { return try SecureEnclave.string(forKey: key, withPrompt: userPrompt, context: nil, options: baseKeychainQuery) } - @available(*, unavailable) + @available(swift, obsoleted: 1.0) @objc(stringForKey:withPrompt:error:) public func objc_string(forKey key: String, withPrompt userPrompt: String) throws -> String { try string(forKey: key, withPrompt: userPrompt) @@ -257,7 +257,7 @@ public final class SecureEnclaveValet: NSObject, Sendable { /// - Parameter key: A key used to retrieve the desired object from the keychain. /// - Returns: The string currently stored in the keychain for the provided key. /// - Throws: An error of type `KeychainError`. - @available(*, unavailable) + @available(swift, obsoleted: 1.0) @objc(stringForKey:error:) public func objc_string(forKey key: String) throws -> String { try string(forKey: key) @@ -278,7 +278,7 @@ public final class SecureEnclaveValet: NSObject, Sendable { /// Removes a key/object pair from the keychain. /// - Parameter key: A key used to remove the desired object from the keychain. /// - Throws: An error of type `KeychainError`. - @available(*, unavailable) + @available(swift, obsoleted: 1.0) @objc(removeObjectForKey:error:) public func objc_removeObject(forKey key: String) throws { try removeObject(forKey: key) @@ -296,8 +296,8 @@ public final class SecureEnclaveValet: NSObject, Sendable { /// Removes all key/object pairs accessible by this Valet instance from the keychain. /// - Throws: An error of type `KeychainError`. - @available(*, unavailable) - @objc(removeAllObjectsWithError:) + @available(swift, obsoleted: 1.0) + @objc(removeAllObjectsAndReturnError:) public func objc_removeAllObjects() throws { try removeAllObjects() } diff --git a/Sources/Valet/Valet.swift b/Sources/Valet/Valet.swift index 6426a640..33d98341 100644 --- a/Sources/Valet/Valet.swift +++ b/Sources/Valet/Valet.swift @@ -264,7 +264,7 @@ public final class Valet: NSObject, Sendable { /// - key: A key that can be used to retrieve the `object` from the keychain. /// - Throws: An error of type `KeychainError`. /// - Important: Inserted data should be no larger than 4kb. - @available(*, unavailable) + @available(swift, obsoleted: 1.0) @objc(setObject:forKey:error:) public func objc_setObject(_ object: Data, forKey key: String) throws { try setObject(object, forKey: key) @@ -284,7 +284,7 @@ public final class Valet: NSObject, Sendable { /// - Parameter key: A key used to retrieve the desired object from the keychain. /// - Returns: The data currently stored in the keychain for the provided key. /// - Throws: An error of type `KeychainError`. - @available(*, unavailable) + @available(swift, obsoleted: 1.0) @objc(objectForKey:error:) public func objc_object(forKey key: String) throws -> Data { try object(forKey: key) @@ -327,7 +327,7 @@ public final class Valet: NSObject, Sendable { /// - key: A key that can be used to retrieve the `string` from the keychain. /// - Throws: An error of type `KeychainError`. /// - Important: Inserted data should be no larger than 4kb. - @available(*, unavailable) + @available(swift, obsoleted: 1.0) @objc(setString:forKey:error:) public func objc_setString(_ string: String, forKey key: String) throws { try setString(string, forKey: key) @@ -364,7 +364,7 @@ public final class Valet: NSObject, Sendable { /// - Returns: The set of all (String) keys currently stored in this Valet instance. If no items are found, will return an empty set. /// - Throws: An error of type `KeychainError`. - @available(*, unavailable) + @available(swift, obsoleted: 1.0) @objc(allKeysWithError:) public func objc_allKeys() throws -> Set { try allKeys() @@ -386,7 +386,7 @@ public final class Valet: NSObject, Sendable { /// - Parameter key: A key used to remove the desired object from the keychain. /// - Throws: An error of type `KeychainError`. /// - Note: No error is thrown if the `key` is not found in the keychain. - @available(*, unavailable) + @available(swift, obsoleted: 1.0) @objc(removeObjectForKey:error:) public func objc_removeObject(forKey key: String) throws { try removeObject(forKey: key) @@ -404,8 +404,8 @@ public final class Valet: NSObject, Sendable { /// Removes all key/object pairs accessible by this Valet instance from the keychain. /// - Throws: An error of type `KeychainError`. - @available(*, unavailable) - @objc(removeAllObjectsWithError:) + @available(swift, obsoleted: 1.0) + @objc(removeAllObjectsAndReturnError:) public func objc_removeAllObjects() throws { try removeAllObjects() } From 3458ad1d67b11d00272209decf12636b5b7c3be5 Mon Sep 17 00:00:00 2001 From: Jon Shier Date: Mon, 16 Feb 2026 19:51:31 -0500 Subject: [PATCH 3/3] Bump podspec. --- Valet.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Valet.podspec b/Valet.podspec index f3cf3e18..fea77a4a 100644 --- a/Valet.podspec +++ b/Valet.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Valet' - s.version = '5.0.0' + s.version = '5.0.1' s.license = 'Apache License, Version 2.0' s.summary = 'Securely store data on iOS, tvOS, watchOS, or macOS without knowing a thing about how the Keychain works. It\'s easy. We promise.' s.homepage = 'https://github.com/square/Valet'