From 6d5c916f950a0985cabb2827000052350ba26793 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 16 Jan 2026 21:06:01 -0600 Subject: [PATCH] Add StorageKey, updatedLogs; Remove StorageKeys, AppGroupUserDefaultsKey, Value, AppGroupUserProfileKey (+25 more) --- .../Services/AppStorageCatalog.swift | 50 ++++++------ .../ExternalKeyMaterialProvider.swift | 4 +- .../AppGroup/AppGroupUserDefaultsKey.swift | 25 +++--- .../AppGroup/AppGroupUserProfileKey.swift | 49 ++++++----- .../AppGroup/UserPreferencesKey.swift | 24 +++--- .../ExternalSessionLogsKey.swift | 26 +++--- .../EncryptedFileSystem/PrivateNotesKey.swift | 26 +++--- .../EncryptedFileSystem/SessionLogsKey.swift | 38 +++++---- .../FileSystem/CachedDataKey.swift | 24 +++--- .../FileSystem/CustomEncodedKey.swift | 26 +++--- .../FileSystem/SettingsPlistKey.swift | 24 +++--- .../FileSystem/UserProfileFileKey.swift | 37 +++++---- .../StorageKeys/Keychain/APITokenKey.swift | 26 +++--- .../StorageKeys/Keychain/CredentialsKey.swift | 40 +++++---- .../Keychain/ExternalKeyMaterialKey.swift | 26 +++--- .../Keychain/LastLocationKey.swift | 26 +++--- .../Migration/AggregatingMigrationKeys.swift | 81 +++++++++---------- .../Migration/ConditionalMigrationKeys.swift | 58 ++++++------- .../StorageKeys/Migration/MigrationKeys.swift | 57 ++++++------- .../Migration/TransformingMigrationKeys.swift | 57 +++++++------ .../Platform/SyncableSettingKey.swift | 41 ++++++---- .../Platform/WatchVibrationKey.swift | 24 +++--- .../UserDefaults/AppVersionKey.swift | 24 +++--- .../Views/AggregatingMigrationDemo.swift | 6 +- .../Views/ConditionalMigrationDemo.swift | 4 +- .../Views/EncryptedStorageDemo.swift | 14 ++-- .../Views/FileSystemDemo.swift | 12 +-- SecureStorageSample/Views/KeychainDemo.swift | 6 +- SecureStorageSample/Views/MigrationDemo.swift | 8 +- .../Views/PlatformSyncDemo.swift | 8 +- .../Views/TransformingMigrationDemo.swift | 4 +- .../Views/UserDefaultsDemo.swift | 12 +-- 32 files changed, 443 insertions(+), 444 deletions(-) diff --git a/SecureStorageSample/Services/AppStorageCatalog.swift b/SecureStorageSample/Services/AppStorageCatalog.swift index b0ddab9..e3fb24b 100644 --- a/SecureStorageSample/Services/AppStorageCatalog.swift +++ b/SecureStorageSample/Services/AppStorageCatalog.swift @@ -6,31 +6,31 @@ import SharedKit struct AppStorageCatalog: StorageKeyCatalog { var allKeys: [AnyStorageKey] { [ - .key(StorageKeys.AppVersionKey()), - .key(StorageKeys.UserPreferencesKey()), - .key(StorageKeys.CredentialsKey()), - .key(StorageKeys.LastLocationKey()), - .key(StorageKeys.APITokenKey()), - .key(StorageKeys.UserProfileFileKey()), - .key(StorageKeys.CachedDataKey()), - .key(StorageKeys.SettingsPlistKey()), - .key(StorageKeys.SessionLogsKey()), - .key(StorageKeys.PrivateNotesKey()), - .key(StorageKeys.ExternalSessionLogsKey()), - .key(StorageKeys.WatchVibrationKey()), - .key(StorageKeys.SyncableSettingKey()), - .key(StorageKeys.ExternalKeyMaterialKey()), - .key(StorageKeys.AppGroupUserDefaultsKey()), - .key(StorageKeys.AppGroupUserProfileKey()), - .key(StorageKeys.LegacyMigrationSourceKey()), - .key(StorageKeys.ModernMigrationDestinationKey()), - .key(StorageKeys.LegacyProfileNameKey()), - .key(StorageKeys.ModernProfileNameKey()), - .key(StorageKeys.LegacyNotificationSettingKey()), - .key(StorageKeys.LegacyThemeSettingKey()), - .key(StorageKeys.ModernUnifiedSettingsKey()), - .key(StorageKeys.LegacyAppModeKey()), - .key(StorageKeys.ModernAppModeKey()) + .key(StorageKey.appVersion), + .key(StorageKey.userPreferences), + .key(StorageKey.credentials), + .key(StorageKey.lastLocation), + .key(StorageKey.apiToken), + .key(StorageKey.userProfileFile), + .key(StorageKey.cachedData), + .key(StorageKey.settingsPlist), + .key(StorageKey.sessionLogs), + .key(StorageKey.privateNotes), + .key(StorageKey.externalSessionLogs), + .key(StorageKey.watchVibration), + .key(StorageKey.syncableSetting), + .key(StorageKey.externalKeyMaterial), + .key(StorageKey.appGroupUserDefaults), + .key(StorageKey.appGroupUserProfile), + .key(StorageKey.legacyMigrationSource), + .key(StorageKey.modernMigrationDestination), + .key(StorageKey.legacyProfileName), + .key(StorageKey.modernProfileName), + .key(StorageKey.legacyNotificationSetting), + .key(StorageKey.legacyThemeSetting), + .key(StorageKey.modernUnifiedSettings), + .key(StorageKey.legacyAppMode), + .key(StorageKey.modernAppMode) ] } } diff --git a/SecureStorageSample/Services/ExternalKeyMaterialProvider.swift b/SecureStorageSample/Services/ExternalKeyMaterialProvider.swift index 965bf21..530c7e3 100644 --- a/SecureStorageSample/Services/ExternalKeyMaterialProvider.swift +++ b/SecureStorageSample/Services/ExternalKeyMaterialProvider.swift @@ -9,8 +9,8 @@ struct ExternalKeyMaterialProvider: KeyMaterialProviding { } func keyMaterial(for keyName: String) async throws -> Data { - let key = StorageKeys.ExternalKeyMaterialKey() - if let existing = try await StorageRouter.shared.get(key) as Data? { + let key = StorageKey.externalKeyMaterial + if let existing = try? await StorageRouter.shared.get(key) { return existing } diff --git a/SecureStorageSample/StorageKeys/AppGroup/AppGroupUserDefaultsKey.swift b/SecureStorageSample/StorageKeys/AppGroup/AppGroupUserDefaultsKey.swift index 9d51552..90055a0 100644 --- a/SecureStorageSample/StorageKeys/AppGroup/AppGroupUserDefaultsKey.swift +++ b/SecureStorageSample/StorageKeys/AppGroup/AppGroupUserDefaultsKey.swift @@ -1,21 +1,20 @@ import Foundation import LocalData import SharedKit -extension StorageKeys { + +extension StorageKey where Value == String { /// Stores a shared setting in App Group UserDefaults. /// - Domain: App Group UserDefaults /// - Security: None /// - Sync: Never - struct AppGroupUserDefaultsKey: StorageKey { - typealias Value = String - - let name = "app_group_setting" - let domain: StorageDomain = .appGroupUserDefaults(identifier: StorageServiceIdentifiers.appGroupIdentifier) - let security: SecurityPolicy = .none - let serializer: Serializer = .json - let owner = "SampleApp" - let description = "Stores a shared setting readable by app extensions." - let availability: PlatformAvailability = .phoneOnly - let syncPolicy: SyncPolicy = .never - } + nonisolated static let appGroupUserDefaults = StorageKey( + name: "app_group_setting", + domain: .appGroupUserDefaults(identifier: StorageServiceIdentifiers.appGroupIdentifier), + security: .none, + serializer: .json, + owner: "SampleApp", + description: "Stores a shared setting readable by app extensions.", + availability: .phoneOnly, + syncPolicy: .never + ) } diff --git a/SecureStorageSample/StorageKeys/AppGroup/AppGroupUserProfileKey.swift b/SecureStorageSample/StorageKeys/AppGroup/AppGroupUserProfileKey.swift index 985b56b..3678bb9 100644 --- a/SecureStorageSample/StorageKeys/AppGroup/AppGroupUserProfileKey.swift +++ b/SecureStorageSample/StorageKeys/AppGroup/AppGroupUserProfileKey.swift @@ -2,29 +2,40 @@ import Foundation import LocalData import SharedKit -extension StorageKeys { +extension StorageKey where Value == UserProfile { /// Stores a shared user profile in the App Group container. /// - Domain: App Group File System /// - Security: None /// - Sync: Never - struct AppGroupUserProfileKey: StorageKey { - typealias Value = UserProfile + nonisolated static let appGroupUserProfile = StorageKey( + name: "app_group_user_profile.json", + domain: .appGroupFileSystem( + identifier: StorageServiceIdentifiers.appGroupIdentifier, + directory: .documents + ), + security: .none, + serializer: .json, + owner: "SampleApp", + description: "Stores a profile shared between the app and extensions.", + availability: .phoneOnly, + syncPolicy: .never + ) - let directory: FileDirectory - let name = "app_group_user_profile.json" - let security: SecurityPolicy = .none - let serializer: Serializer = .json - let owner = "SampleApp" - let description = "Stores a profile shared between the app and extensions." - let availability: PlatformAvailability = .phoneOnly - let syncPolicy: SyncPolicy = .never - - init(directory: FileDirectory = .documents) { - self.directory = directory - } - - var domain: StorageDomain { - .appGroupFileSystem(identifier: StorageServiceIdentifiers.appGroupIdentifier, directory: directory) - } + nonisolated static func appGroupUserProfileKey( + directory: FileDirectory = .documents + ) -> StorageKey { + StorageKey( + name: "app_group_user_profile.json", + domain: .appGroupFileSystem( + identifier: StorageServiceIdentifiers.appGroupIdentifier, + directory: directory + ), + security: .none, + serializer: .json, + owner: "SampleApp", + description: "Stores a profile shared between the app and extensions.", + availability: .phoneOnly, + syncPolicy: .never + ) } } diff --git a/SecureStorageSample/StorageKeys/AppGroup/UserPreferencesKey.swift b/SecureStorageSample/StorageKeys/AppGroup/UserPreferencesKey.swift index b36c426..169e090 100644 --- a/SecureStorageSample/StorageKeys/AppGroup/UserPreferencesKey.swift +++ b/SecureStorageSample/StorageKeys/AppGroup/UserPreferencesKey.swift @@ -2,21 +2,19 @@ import Foundation import LocalData import SharedKit -extension StorageKeys { +extension StorageKey where Value == [String: AnyCodable] { /// Stores user preferences in App Group UserDefaults. /// - Domain: App Group UserDefaults /// - Security: None /// - Sync: Never - struct UserPreferencesKey: StorageKey { - typealias Value = [String: AnyCodable] - - let name = "user_preferences" - let domain: StorageDomain = .appGroupUserDefaults(identifier: StorageServiceIdentifiers.appGroupIdentifier) - let security: SecurityPolicy = .none - let serializer: Serializer<[String: AnyCodable]> = .json - let owner = "SampleApp" - let description = "Stores shared user preferences for app configuration screens." - let availability: PlatformAvailability = .all - let syncPolicy: SyncPolicy = .never - } + nonisolated static let userPreferences = StorageKey( + name: "user_preferences", + domain: .appGroupUserDefaults(identifier: StorageServiceIdentifiers.appGroupIdentifier), + security: .none, + serializer: .json, + owner: "SampleApp", + description: "Stores shared user preferences for app configuration screens.", + availability: .all, + syncPolicy: .never + ) } diff --git a/SecureStorageSample/StorageKeys/EncryptedFileSystem/ExternalSessionLogsKey.swift b/SecureStorageSample/StorageKeys/EncryptedFileSystem/ExternalSessionLogsKey.swift index b9cbf72..1467c30 100644 --- a/SecureStorageSample/StorageKeys/EncryptedFileSystem/ExternalSessionLogsKey.swift +++ b/SecureStorageSample/StorageKeys/EncryptedFileSystem/ExternalSessionLogsKey.swift @@ -1,20 +1,16 @@ import Foundation import LocalData -extension StorageKeys { +extension StorageKey where Value == [String] { /// Stores session logs with encryption using external key material. - struct ExternalSessionLogsKey: StorageKey { - typealias Value = [String] - - let name = "external_session_logs.json" - let domain: StorageDomain = .encryptedFileSystem(directory: .caches) - let security: SecurityPolicy = .encrypted( - .external(source: SampleKeyMaterialSources.external) - ) - let serializer: Serializer<[String]> = .json - let owner = "SampleApp" - let description = "Stores session logs encrypted with external key material." - let availability: PlatformAvailability = .phoneOnly - let syncPolicy: SyncPolicy = .never - } + nonisolated static let externalSessionLogs = StorageKey( + name: "external_session_logs.json", + domain: .encryptedFileSystem(directory: .caches), + security: .encrypted(.external(source: SampleKeyMaterialSources.external)), + serializer: .json, + owner: "SampleApp", + description: "Stores session logs encrypted with external key material.", + availability: .phoneOnly, + syncPolicy: .never + ) } diff --git a/SecureStorageSample/StorageKeys/EncryptedFileSystem/PrivateNotesKey.swift b/SecureStorageSample/StorageKeys/EncryptedFileSystem/PrivateNotesKey.swift index 8d1772e..af04ec1 100644 --- a/SecureStorageSample/StorageKeys/EncryptedFileSystem/PrivateNotesKey.swift +++ b/SecureStorageSample/StorageKeys/EncryptedFileSystem/PrivateNotesKey.swift @@ -1,20 +1,16 @@ import Foundation import LocalData -extension StorageKeys { +extension StorageKey where Value == String { /// Stores private notes with encryption. - struct PrivateNotesKey: StorageKey { - typealias Value = String - - let name = "private_notes.enc" - let domain: StorageDomain = .encryptedFileSystem(directory: .documents) - let security: SecurityPolicy = .encrypted( - .aes256(keyDerivation: .pbkdf2(iterations: 50_000)) - ) - let serializer: Serializer = .json - let owner = "SampleApp" - let description = "Stores private notes encrypted at rest." - let availability: PlatformAvailability = .phoneOnly - let syncPolicy: SyncPolicy = .never - } + nonisolated static let privateNotes = StorageKey( + name: "private_notes.enc", + domain: .encryptedFileSystem(directory: .documents), + security: .encrypted(.aes256(keyDerivation: .pbkdf2(iterations: 50_000))), + serializer: .json, + owner: "SampleApp", + description: "Stores private notes encrypted at rest.", + availability: .phoneOnly, + syncPolicy: .never + ) } diff --git a/SecureStorageSample/StorageKeys/EncryptedFileSystem/SessionLogsKey.swift b/SecureStorageSample/StorageKeys/EncryptedFileSystem/SessionLogsKey.swift index 53d7b6c..db7774c 100644 --- a/SecureStorageSample/StorageKeys/EncryptedFileSystem/SessionLogsKey.swift +++ b/SecureStorageSample/StorageKeys/EncryptedFileSystem/SessionLogsKey.swift @@ -1,24 +1,30 @@ import Foundation import LocalData -extension StorageKeys { +extension StorageKey where Value == [String] { /// Stores session logs with full encryption. /// Configurable PBKDF2 iterations. - struct SessionLogsKey: StorageKey { - typealias Value = [String] + nonisolated static let sessionLogs = StorageKey( + name: "session_logs.json", + domain: .encryptedFileSystem(directory: .caches), + security: .encrypted(.aes256(keyDerivation: .pbkdf2(iterations: 10_000))), + serializer: .json, + owner: "SampleApp", + description: "Stores session logs encrypted with PBKDF2-derived keys.", + availability: .phoneOnly, + syncPolicy: .never + ) - let name = "session_logs.json" - let domain: StorageDomain = .encryptedFileSystem(directory: .caches) - let security: SecurityPolicy - let serializer: Serializer<[String]> = .json - let owner = "SampleApp" - let description = "Stores session logs encrypted with PBKDF2-derived keys." - let availability: PlatformAvailability = .phoneOnly - let syncPolicy: SyncPolicy = .never - - init(iterations: Int = 10_000) { - // NOTE: PBKDF2 iterations must remain stable for existing data; changing this breaks decryption. - self.security = .encrypted(.aes256(keyDerivation: .pbkdf2(iterations: iterations))) - } + nonisolated static func sessionLogsKey(iterations: Int) -> StorageKey { + StorageKey( + name: "session_logs.json", + domain: .encryptedFileSystem(directory: .caches), + security: .encrypted(.aes256(keyDerivation: .pbkdf2(iterations: iterations))), + serializer: .json, + owner: "SampleApp", + description: "Stores session logs encrypted with PBKDF2-derived keys.", + availability: .phoneOnly, + syncPolicy: .never + ) } } diff --git a/SecureStorageSample/StorageKeys/FileSystem/CachedDataKey.swift b/SecureStorageSample/StorageKeys/FileSystem/CachedDataKey.swift index 235c99b..1623f3b 100644 --- a/SecureStorageSample/StorageKeys/FileSystem/CachedDataKey.swift +++ b/SecureStorageSample/StorageKeys/FileSystem/CachedDataKey.swift @@ -1,18 +1,16 @@ import Foundation import LocalData -extension StorageKeys { +extension StorageKey where Value == Data { /// Stores cached data files. - struct CachedDataKey: StorageKey { - typealias Value = Data - - let name = "cached_data.bin" - let domain: StorageDomain = .fileSystem(directory: .caches) - let security: SecurityPolicy = .none - let serializer: Serializer = .data - let owner = "SampleApp" - let description = "Stores cached binary data that can be regenerated." - let availability: PlatformAvailability = .all - let syncPolicy: SyncPolicy = .never - } + nonisolated static let cachedData = StorageKey( + name: "cached_data.bin", + domain: .fileSystem(directory: .caches), + security: .none, + serializer: .data, + owner: "SampleApp", + description: "Stores cached binary data that can be regenerated.", + availability: .all, + syncPolicy: .never + ) } diff --git a/SecureStorageSample/StorageKeys/FileSystem/CustomEncodedKey.swift b/SecureStorageSample/StorageKeys/FileSystem/CustomEncodedKey.swift index 3accbb6..ccc5db0 100644 --- a/SecureStorageSample/StorageKeys/FileSystem/CustomEncodedKey.swift +++ b/SecureStorageSample/StorageKeys/FileSystem/CustomEncodedKey.swift @@ -1,15 +1,13 @@ import Foundation import LocalData -extension StorageKeys { +extension StorageKey where Value == String { /// Example using custom serializer for specialized encoding. - struct CustomEncodedKey: StorageKey { - typealias Value = String - - let name = "custom_encoded" - let domain: StorageDomain = .fileSystem(directory: .documents) - let security: SecurityPolicy = .none - let serializer: Serializer = .custom( + nonisolated static let customEncoded = StorageKey( + name: "custom_encoded", + domain: .fileSystem(directory: .documents), + security: .none, + serializer: .custom( encode: { value in Data(value.utf8).base64EncodedData() }, @@ -20,10 +18,10 @@ extension StorageKeys { } return string } - ) - let owner = "SampleApp" - let description = "Stores custom-encoded string data (Base64 example)." - let availability: PlatformAvailability = .all - let syncPolicy: SyncPolicy = .never - } + ), + owner: "SampleApp", + description: "Stores custom-encoded string data (Base64 example).", + availability: .all, + syncPolicy: .never + ) } diff --git a/SecureStorageSample/StorageKeys/FileSystem/SettingsPlistKey.swift b/SecureStorageSample/StorageKeys/FileSystem/SettingsPlistKey.swift index 986c601..293afbd 100644 --- a/SecureStorageSample/StorageKeys/FileSystem/SettingsPlistKey.swift +++ b/SecureStorageSample/StorageKeys/FileSystem/SettingsPlistKey.swift @@ -1,18 +1,16 @@ import Foundation import LocalData -extension StorageKeys { +extension StorageKey where Value == [String: AnyCodable] { /// Stores settings as property list. - struct SettingsPlistKey: StorageKey { - typealias Value = [String: AnyCodable] - - let name = "settings.plist" - let domain: StorageDomain = .fileSystem(directory: .documents) - let security: SecurityPolicy = .none - let serializer: Serializer<[String: AnyCodable]> = .plist - let owner = "SampleApp" - let description = "Stores app settings exported as a property list." - let availability: PlatformAvailability = .all - let syncPolicy: SyncPolicy = .never - } + nonisolated static let settingsPlist = StorageKey( + name: "settings.plist", + domain: .fileSystem(directory: .documents), + security: .none, + serializer: .plist, + owner: "SampleApp", + description: "Stores app settings exported as a property list.", + availability: .all, + syncPolicy: .never + ) } diff --git a/SecureStorageSample/StorageKeys/FileSystem/UserProfileFileKey.swift b/SecureStorageSample/StorageKeys/FileSystem/UserProfileFileKey.swift index 02a3ea8..2864881 100644 --- a/SecureStorageSample/StorageKeys/FileSystem/UserProfileFileKey.swift +++ b/SecureStorageSample/StorageKeys/FileSystem/UserProfileFileKey.swift @@ -2,22 +2,29 @@ import Foundation import LocalData import SharedKit -extension StorageKeys { +extension StorageKey where Value == UserProfile { /// Stores user profile as JSON file in documents. - struct UserProfileFileKey: StorageKey { - typealias Value = UserProfile + nonisolated static let userProfileFile = StorageKey( + name: UserProfile.storageKeyName, + domain: .fileSystem(directory: .documents), + security: .none, + serializer: .json, + owner: "SampleApp", + description: "Stores a lightweight user profile for file storage and watch sync.", + availability: .phoneWithWatchSync, + syncPolicy: .automaticSmall + ) - let name = UserProfile.storageKeyName - let domain: StorageDomain - let security: SecurityPolicy = .none - let serializer: Serializer = .json - let owner = "SampleApp" - let description = "Stores a lightweight user profile for file storage and watch sync." - let availability: PlatformAvailability = .phoneWithWatchSync - let syncPolicy: SyncPolicy = .automaticSmall - - init(directory: FileDirectory = .documents) { - self.domain = .fileSystem(directory: directory) - } + nonisolated static func userProfileFileKey(directory: FileDirectory = .documents) -> StorageKey { + StorageKey( + name: UserProfile.storageKeyName, + domain: .fileSystem(directory: directory), + security: .none, + serializer: .json, + owner: "SampleApp", + description: "Stores a lightweight user profile for file storage and watch sync.", + availability: .phoneWithWatchSync, + syncPolicy: .automaticSmall + ) } } diff --git a/SecureStorageSample/StorageKeys/Keychain/APITokenKey.swift b/SecureStorageSample/StorageKeys/Keychain/APITokenKey.swift index 73cc2df..0894d30 100644 --- a/SecureStorageSample/StorageKeys/Keychain/APITokenKey.swift +++ b/SecureStorageSample/StorageKeys/Keychain/APITokenKey.swift @@ -2,21 +2,19 @@ import Foundation import LocalData import SharedKit -extension StorageKeys { +extension StorageKey where Value == String { /// Stores API token in keychain. - struct APITokenKey: StorageKey { - typealias Value = String - - let name = "api_token" - let domain: StorageDomain = .keychain(service: StorageServiceIdentifiers.keychainAPIToken) - let security: SecurityPolicy = .keychain( + nonisolated static let apiToken = StorageKey( + name: "api_token", + domain: .keychain(service: StorageServiceIdentifiers.keychainAPIToken), + security: .keychain( accessibility: .whenUnlockedThisDeviceOnly, accessControl: nil - ) - let serializer: Serializer = .json - let owner = "SampleApp" - let description = "Stores API auth token for network requests." - let availability: PlatformAvailability = .phoneOnly - let syncPolicy: SyncPolicy = .never - } + ), + serializer: .json, + owner: "SampleApp", + description: "Stores API auth token for network requests.", + availability: .phoneOnly, + syncPolicy: .never + ) } diff --git a/SecureStorageSample/StorageKeys/Keychain/CredentialsKey.swift b/SecureStorageSample/StorageKeys/Keychain/CredentialsKey.swift index 35d0d98..e468996 100644 --- a/SecureStorageSample/StorageKeys/Keychain/CredentialsKey.swift +++ b/SecureStorageSample/StorageKeys/Keychain/CredentialsKey.swift @@ -2,23 +2,33 @@ import Foundation import LocalData import SharedKit -extension StorageKeys { +extension StorageKey where Value == Credential { /// Stores user credentials securely in keychain. /// Configurable accessibility and access control. - struct CredentialsKey: StorageKey { - typealias Value = Credential + nonisolated static let credentials = StorageKey( + name: "user_credentials", + domain: .keychain(service: StorageServiceIdentifiers.keychainCredentials), + security: .keychain(accessibility: .afterFirstUnlock, accessControl: nil), + serializer: .json, + owner: "SampleApp", + description: "Stores user credentials for sign-in flows.", + availability: .phoneOnly, + syncPolicy: .never + ) - let name = "user_credentials" - let domain: StorageDomain = .keychain(service: StorageServiceIdentifiers.keychainCredentials) - let security: SecurityPolicy - let serializer: Serializer = .json - let owner = "SampleApp" - let description = "Stores user credentials for sign-in flows." - let availability: PlatformAvailability = .phoneOnly - let syncPolicy: SyncPolicy = .never - - init(accessibility: KeychainAccessibility = .afterFirstUnlock, accessControl: KeychainAccessControl? = nil) { - self.security = .keychain(accessibility: accessibility, accessControl: accessControl) - } + nonisolated static func credentialsKey( + accessibility: KeychainAccessibility = .afterFirstUnlock, + accessControl: KeychainAccessControl? = nil + ) -> StorageKey { + StorageKey( + name: "user_credentials", + domain: .keychain(service: StorageServiceIdentifiers.keychainCredentials), + security: .keychain(accessibility: accessibility, accessControl: accessControl), + serializer: .json, + owner: "SampleApp", + description: "Stores user credentials for sign-in flows.", + availability: .phoneOnly, + syncPolicy: .never + ) } } diff --git a/SecureStorageSample/StorageKeys/Keychain/ExternalKeyMaterialKey.swift b/SecureStorageSample/StorageKeys/Keychain/ExternalKeyMaterialKey.swift index d5f9955..2dcf9fc 100644 --- a/SecureStorageSample/StorageKeys/Keychain/ExternalKeyMaterialKey.swift +++ b/SecureStorageSample/StorageKeys/Keychain/ExternalKeyMaterialKey.swift @@ -2,21 +2,19 @@ import Foundation import LocalData import SharedKit -extension StorageKeys { +extension StorageKey where Value == Data { /// Stores external key material used for encryption policies. - struct ExternalKeyMaterialKey: StorageKey { - typealias Value = Data - - let name = "external_key_material" - let domain: StorageDomain = .keychain(service: StorageServiceIdentifiers.keychainExternalKeyMaterial) - let security: SecurityPolicy = .keychain( + nonisolated static let externalKeyMaterial = StorageKey( + name: "external_key_material", + domain: .keychain(service: StorageServiceIdentifiers.keychainExternalKeyMaterial), + security: .keychain( accessibility: .afterFirstUnlock, accessControl: nil - ) - let serializer: Serializer = .data - let owner = "SampleApp" - let description = "Stores external key material used by encryption policies." - let availability: PlatformAvailability = .phoneOnly - let syncPolicy: SyncPolicy = .never - } + ), + serializer: .data, + owner: "SampleApp", + description: "Stores external key material used by encryption policies.", + availability: .phoneOnly, + syncPolicy: .never + ) } diff --git a/SecureStorageSample/StorageKeys/Keychain/LastLocationKey.swift b/SecureStorageSample/StorageKeys/Keychain/LastLocationKey.swift index 20740b1..0a867dd 100644 --- a/SecureStorageSample/StorageKeys/Keychain/LastLocationKey.swift +++ b/SecureStorageSample/StorageKeys/Keychain/LastLocationKey.swift @@ -2,21 +2,19 @@ import Foundation import LocalData import SharedKit -extension StorageKeys { +extension StorageKey where Value == SampleLocationData { /// Stores sensitive location data in keychain with biometric protection. - struct LastLocationKey: StorageKey { - typealias Value = SampleLocationData - - let name = "last_known_location" - let domain: StorageDomain = .keychain(service: StorageServiceIdentifiers.keychainLocation) - let security: SecurityPolicy = .keychain( + nonisolated static let lastLocation = StorageKey( + name: "last_known_location", + domain: .keychain(service: StorageServiceIdentifiers.keychainLocation), + security: .keychain( accessibility: .afterFirstUnlock, accessControl: .userPresence - ) - let serializer: Serializer = .json - let owner = "SampleApp" - let description = "Stores last known location for location-aware features." - let availability: PlatformAvailability = .phoneOnly - let syncPolicy: SyncPolicy = .never - } + ), + serializer: .json, + owner: "SampleApp", + description: "Stores last known location for location-aware features.", + availability: .phoneOnly, + syncPolicy: .never + ) } diff --git a/SecureStorageSample/StorageKeys/Migration/AggregatingMigrationKeys.swift b/SecureStorageSample/StorageKeys/Migration/AggregatingMigrationKeys.swift index 5ee521d..6e07883 100644 --- a/SecureStorageSample/StorageKeys/Migration/AggregatingMigrationKeys.swift +++ b/SecureStorageSample/StorageKeys/Migration/AggregatingMigrationKeys.swift @@ -1,54 +1,51 @@ import Foundation import LocalData -extension StorageKeys { - struct LegacyNotificationSettingKey: StorageKey { - typealias Value = Bool +extension StorageKey where Value == Bool { + nonisolated static let legacyNotificationSetting = StorageKey( + name: "legacy_notification_setting", + domain: .userDefaults(suite: nil), + security: .none, + serializer: .json, + owner: "MigrationDemo", + description: "Legacy notification setting stored as Bool.", + availability: .all, + syncPolicy: .never + ) +} - let name = "legacy_notification_setting" - let domain: StorageDomain = .userDefaults(suite: nil) - let security: SecurityPolicy = .none - let serializer: Serializer = .json - let owner = "MigrationDemo" - let description = "Legacy notification setting stored as Bool." - let availability: PlatformAvailability = .all - let syncPolicy: SyncPolicy = .never - } +extension StorageKey where Value == String { + nonisolated static let legacyThemeSetting = StorageKey( + name: "legacy_theme_setting", + domain: .userDefaults(suite: nil), + security: .none, + serializer: .json, + owner: "MigrationDemo", + description: "Legacy theme setting stored as a string.", + availability: .all, + syncPolicy: .never + ) +} - struct LegacyThemeSettingKey: StorageKey { - typealias Value = String - - let name = "legacy_theme_setting" - let domain: StorageDomain = .userDefaults(suite: nil) - let security: SecurityPolicy = .none - let serializer: Serializer = .json - let owner = "MigrationDemo" - let description = "Legacy theme setting stored as a string." - let availability: PlatformAvailability = .all - let syncPolicy: SyncPolicy = .never - } - - struct ModernUnifiedSettingsKey: StorageKey { - typealias Value = UnifiedSettings - - let name = "modern_unified_settings" - let domain: StorageDomain = .fileSystem(directory: .documents) - let security: SecurityPolicy = .none - let serializer: Serializer = .json - let owner = "MigrationDemo" - let description = "Modern unified settings aggregated from legacy keys." - let availability: PlatformAvailability = .all - let syncPolicy: SyncPolicy = .never - - var migration: AnyStorageMigration? { +extension StorageKey where Value == UnifiedSettings { + nonisolated static let modernUnifiedSettings = StorageKey( + name: "modern_unified_settings", + domain: .fileSystem(directory: .documents), + security: .none, + serializer: .json, + owner: "MigrationDemo", + description: "Modern unified settings aggregated from legacy keys.", + availability: .all, + syncPolicy: .never, + migration: { key in let sources: [AnyStorageKey] = [ - .key(StorageKeys.LegacyNotificationSettingKey()), - .key(StorageKeys.LegacyThemeSettingKey()) + .key(StorageKey.legacyNotificationSetting), + .key(StorageKey.legacyThemeSetting) ] return AnyStorageMigration( DefaultAggregatingMigration( - destinationKey: self, + destinationKey: key, sourceKeys: sources ) { sources in var notificationsEnabled = false @@ -69,5 +66,5 @@ extension StorageKeys { } ) } - } + ) } diff --git a/SecureStorageSample/StorageKeys/Migration/ConditionalMigrationKeys.swift b/SecureStorageSample/StorageKeys/Migration/ConditionalMigrationKeys.swift index b0d6f04..beb926e 100644 --- a/SecureStorageSample/StorageKeys/Migration/ConditionalMigrationKeys.swift +++ b/SecureStorageSample/StorageKeys/Migration/ConditionalMigrationKeys.swift @@ -1,49 +1,43 @@ import Foundation import LocalData -extension StorageKeys { - struct LegacyAppModeKey: StorageKey { - typealias Value = String +extension StorageKey where Value == String { + nonisolated static let legacyAppMode = StorageKey( + name: "legacy_app_mode", + domain: .userDefaults(suite: nil), + security: .none, + serializer: .json, + owner: "MigrationDemo", + description: "Legacy app mode stored in UserDefaults.", + availability: .all, + syncPolicy: .never + ) - let name = "legacy_app_mode" - let domain: StorageDomain = .userDefaults(suite: nil) - let security: SecurityPolicy = .none - let serializer: Serializer = .json - let owner = "MigrationDemo" - let description = "Legacy app mode stored in UserDefaults." - let availability: PlatformAvailability = .all - let syncPolicy: SyncPolicy = .never - } - - struct ModernAppModeKey: StorageKey { - typealias Value = String - - let name = "modern_app_mode" - let domain: StorageDomain = .keychain(service: "com.mbrucedogs.securestorage") - let security: SecurityPolicy = .keychain( + nonisolated static let modernAppMode = StorageKey( + name: "modern_app_mode", + domain: .keychain(service: "com.mbrucedogs.securestorage"), + security: .keychain( accessibility: .afterFirstUnlock, accessControl: .userPresence - ) - let serializer: Serializer = .json - let owner = "MigrationDemo" - let description = "Modern app mode with conditional migration." - let availability: PlatformAvailability = .all - let syncPolicy: SyncPolicy = .never - - var migration: AnyStorageMigration? { - let destination = self - let legacy = StorageKeys.LegacyAppModeKey() + ), + serializer: .json, + owner: "MigrationDemo", + description: "Modern app mode with conditional migration.", + availability: .all, + syncPolicy: .never, + migration: { key in + let legacy = StorageKey.legacyAppMode let fallback = AnyStorageMigration( - SimpleLegacyMigration(destinationKey: destination, sourceKey: .key(legacy)) + SimpleLegacyMigration(destinationKey: key, sourceKey: .key(legacy)) ) return AnyStorageMigration( AppVersionConditionalMigration( - destinationKey: destination, + destinationKey: key, minAppVersion: "99.0", fallbackMigration: fallback ) ) } - } + ) } diff --git a/SecureStorageSample/StorageKeys/Migration/MigrationKeys.swift b/SecureStorageSample/StorageKeys/Migration/MigrationKeys.swift index 83911c4..a0ee227 100644 --- a/SecureStorageSample/StorageKeys/Migration/MigrationKeys.swift +++ b/SecureStorageSample/StorageKeys/Migration/MigrationKeys.swift @@ -1,44 +1,39 @@ import Foundation import LocalData -extension StorageKeys { +extension StorageKey where Value == String { /// The legacy key where data starts (in UserDefaults) - struct LegacyMigrationSourceKey: StorageKey { - typealias Value = String - - let name = "legacy_user_id" - let domain: StorageDomain = .userDefaults(suite: nil) - let security: SecurityPolicy = .none - let serializer: Serializer = .json - let owner = "MigrationDemo" - let description = "Legacy key in UserDefaults from an older version of the app." - let availability: PlatformAvailability = .all - let syncPolicy: SyncPolicy = .never - } - + nonisolated static let legacyMigrationSource = StorageKey( + name: "legacy_user_id", + domain: .userDefaults(suite: nil), + security: .none, + serializer: .json, + owner: "MigrationDemo", + description: "Legacy key in UserDefaults from an older version of the app.", + availability: .all, + syncPolicy: .never + ) + /// The modern key where data should end up (in Keychain) - struct ModernMigrationDestinationKey: StorageKey { - typealias Value = String - - let name = "secure_user_id" - let domain: StorageDomain = .keychain(service: "com.mbrucedogs.securestorage") - let security: SecurityPolicy = .keychain( + nonisolated static let modernMigrationDestination = StorageKey( + name: "secure_user_id", + domain: .keychain(service: "com.mbrucedogs.securestorage"), + security: .keychain( accessibility: .afterFirstUnlock, accessControl: .userPresence - ) - let serializer: Serializer = .json - let owner = "MigrationDemo" - let description = "Modern key in Keychain with biometric security." - let availability: PlatformAvailability = .all - let syncPolicy: SyncPolicy = .never - - var migration: AnyStorageMigration? { + ), + serializer: .json, + owner: "MigrationDemo", + description: "Modern key in Keychain with biometric security.", + availability: .all, + syncPolicy: .never, + migration: { key in AnyStorageMigration( SimpleLegacyMigration( - destinationKey: self, - sourceKey: .key(LegacyMigrationSourceKey()) + destinationKey: key, + sourceKey: .key(StorageKey.legacyMigrationSource) ) ) } - } + ) } diff --git a/SecureStorageSample/StorageKeys/Migration/TransformingMigrationKeys.swift b/SecureStorageSample/StorageKeys/Migration/TransformingMigrationKeys.swift index 0402b53..a50d66f 100644 --- a/SecureStorageSample/StorageKeys/Migration/TransformingMigrationKeys.swift +++ b/SecureStorageSample/StorageKeys/Migration/TransformingMigrationKeys.swift @@ -1,40 +1,37 @@ import Foundation import LocalData -extension StorageKeys { - struct LegacyProfileNameKey: StorageKey { - typealias Value = String +extension StorageKey where Value == String { + nonisolated static let legacyProfileName = StorageKey( + name: "legacy_profile_name", + domain: .userDefaults(suite: nil), + security: .none, + serializer: .json, + owner: "MigrationDemo", + description: "Legacy profile name stored as a single string.", + availability: .all, + syncPolicy: .never + ) +} - let name = "legacy_profile_name" - let domain: StorageDomain = .userDefaults(suite: nil) - let security: SecurityPolicy = .none - let serializer: Serializer = .json - let owner = "MigrationDemo" - let description = "Legacy profile name stored as a single string." - let availability: PlatformAvailability = .all - let syncPolicy: SyncPolicy = .never - } - - struct ModernProfileNameKey: StorageKey { - typealias Value = ProfileName - - let name = "modern_profile_name" - let domain: StorageDomain = .keychain(service: "com.mbrucedogs.securestorage") - let security: SecurityPolicy = .keychain( +extension StorageKey where Value == ProfileName { + nonisolated static let modernProfileName = StorageKey( + name: "modern_profile_name", + domain: .keychain(service: "com.mbrucedogs.securestorage"), + security: .keychain( accessibility: .afterFirstUnlock, accessControl: .userPresence - ) - let serializer: Serializer = .json - let owner = "MigrationDemo" - let description = "Modern profile name stored as structured data." - let availability: PlatformAvailability = .all - let syncPolicy: SyncPolicy = .never - - var migration: AnyStorageMigration? { - let sourceKey = StorageKeys.LegacyProfileNameKey() + ), + serializer: .json, + owner: "MigrationDemo", + description: "Modern profile name stored as structured data.", + availability: .all, + syncPolicy: .never, + migration: { key in + let sourceKey = StorageKey.legacyProfileName return AnyStorageMigration( DefaultTransformingMigration( - destinationKey: self, + destinationKey: key, sourceKey: sourceKey ) { value in let parts = value.split(separator: " ", maxSplits: 1).map(String.init) @@ -44,5 +41,5 @@ extension StorageKeys { } ) } - } + ) } diff --git a/SecureStorageSample/StorageKeys/Platform/SyncableSettingKey.swift b/SecureStorageSample/StorageKeys/Platform/SyncableSettingKey.swift index 785dca0..2c4b85b 100644 --- a/SecureStorageSample/StorageKeys/Platform/SyncableSettingKey.swift +++ b/SecureStorageSample/StorageKeys/Platform/SyncableSettingKey.swift @@ -1,24 +1,33 @@ import Foundation import LocalData -extension StorageKeys { +extension StorageKey where Value == String { /// Syncable setting with configurable platform and sync policy. /// Grouped under Platform to highlight availability/sync behavior. - struct SyncableSettingKey: StorageKey { - typealias Value = String + nonisolated static let syncableSetting = StorageKey( + name: "syncable_setting", + domain: .userDefaults(suite: nil), + security: .none, + serializer: .json, + owner: "SampleApp", + description: "Stores a setting that can be synced to watch.", + availability: .all, + syncPolicy: .never + ) - let name = "syncable_setting" - let domain: StorageDomain = .userDefaults(suite: nil) - let security: SecurityPolicy = .none - let serializer: Serializer = .json - let owner = "SampleApp" - let description = "Stores a setting that can be synced to watch." - let availability: PlatformAvailability - let syncPolicy: SyncPolicy - - init(availability: PlatformAvailability = .all, syncPolicy: SyncPolicy = .never) { - self.availability = availability - self.syncPolicy = syncPolicy - } + nonisolated static func syncableSettingKey( + availability: PlatformAvailability = .all, + syncPolicy: SyncPolicy = .never + ) -> StorageKey { + StorageKey( + name: "syncable_setting", + domain: .userDefaults(suite: nil), + security: .none, + serializer: .json, + owner: "SampleApp", + description: "Stores a setting that can be synced to watch.", + availability: availability, + syncPolicy: syncPolicy + ) } } diff --git a/SecureStorageSample/StorageKeys/Platform/WatchVibrationKey.swift b/SecureStorageSample/StorageKeys/Platform/WatchVibrationKey.swift index 17a547f..c0b4890 100644 --- a/SecureStorageSample/StorageKeys/Platform/WatchVibrationKey.swift +++ b/SecureStorageSample/StorageKeys/Platform/WatchVibrationKey.swift @@ -1,19 +1,17 @@ import Foundation import LocalData -extension StorageKeys { +extension StorageKey where Value == Bool { /// Watch-only setting for vibration. /// Grouped under Platform to highlight watch-only availability. - struct WatchVibrationKey: StorageKey { - typealias Value = Bool - - let name = "watch_vibration_enabled" - let domain: StorageDomain = .userDefaults(suite: nil) - let security: SecurityPolicy = .none - let serializer: Serializer = .json - let owner = "SampleApp" - let description = "Controls haptic feedback on watch-only experiences." - let availability: PlatformAvailability = .watchOnly - let syncPolicy: SyncPolicy = .never - } + nonisolated static let watchVibration = StorageKey( + name: "watch_vibration_enabled", + domain: .userDefaults(suite: nil), + security: .none, + serializer: .json, + owner: "SampleApp", + description: "Controls haptic feedback on watch-only experiences.", + availability: .watchOnly, + syncPolicy: .never + ) } diff --git a/SecureStorageSample/StorageKeys/UserDefaults/AppVersionKey.swift b/SecureStorageSample/StorageKeys/UserDefaults/AppVersionKey.swift index ffaa5f2..3fe9f34 100644 --- a/SecureStorageSample/StorageKeys/UserDefaults/AppVersionKey.swift +++ b/SecureStorageSample/StorageKeys/UserDefaults/AppVersionKey.swift @@ -1,21 +1,19 @@ import Foundation import LocalData -extension StorageKeys { +extension StorageKey where Value == String { /// Stores the app version in standard UserDefaults. /// - Domain: UserDefaults (standard) /// - Security: None /// - Sync: Automatic for small data - struct AppVersionKey: StorageKey { - typealias Value = String - - let name = "last_app_version" - let domain: StorageDomain = .userDefaults(suite: nil) - let security: SecurityPolicy = .none - let serializer: Serializer = .json - let owner = "SampleApp" - let description = "Tracks the last app version for migration and UI messaging." - let availability: PlatformAvailability = .all - let syncPolicy: SyncPolicy = .automaticSmall - } + nonisolated static let appVersion = StorageKey( + name: "last_app_version", + domain: .userDefaults(suite: nil), + security: .none, + serializer: .json, + owner: "SampleApp", + description: "Tracks the last app version for migration and UI messaging.", + availability: .all, + syncPolicy: .automaticSmall + ) } diff --git a/SecureStorageSample/Views/AggregatingMigrationDemo.swift b/SecureStorageSample/Views/AggregatingMigrationDemo.swift index 7eb45b5..ced343f 100644 --- a/SecureStorageSample/Views/AggregatingMigrationDemo.swift +++ b/SecureStorageSample/Views/AggregatingMigrationDemo.swift @@ -64,11 +64,11 @@ struct AggregatingMigrationDemo: View { do { try await StorageRouter.shared.set( notificationsEnabled, - for: StorageKeys.LegacyNotificationSettingKey() + for: StorageKey.legacyNotificationSetting ) try await StorageRouter.shared.set( theme, - for: StorageKeys.LegacyThemeSettingKey() + for: StorageKey.legacyThemeSetting ) statusMessage = "✓ Saved legacy settings" } catch { @@ -83,7 +83,7 @@ struct AggregatingMigrationDemo: View { statusMessage = "Loading unified settings..." Task { do { - let value = try await StorageRouter.shared.get(StorageKeys.ModernUnifiedSettingsKey()) + let value = try await StorageRouter.shared.get(StorageKey.modernUnifiedSettings) modernValue = format(value) statusMessage = "✓ Migration complete." } catch StorageError.notFound { diff --git a/SecureStorageSample/Views/ConditionalMigrationDemo.swift b/SecureStorageSample/Views/ConditionalMigrationDemo.swift index f454909..6a7b83f 100644 --- a/SecureStorageSample/Views/ConditionalMigrationDemo.swift +++ b/SecureStorageSample/Views/ConditionalMigrationDemo.swift @@ -63,7 +63,7 @@ struct ConditionalMigrationDemo: View { isLoading = true Task { do { - let key = StorageKeys.LegacyAppModeKey() + let key = StorageKey.legacyAppMode try await StorageRouter.shared.set(legacyValue, for: key) statusMessage = "✓ Saved legacy app mode" } catch { @@ -78,7 +78,7 @@ struct ConditionalMigrationDemo: View { statusMessage = "Loading modern mode..." Task { do { - let key = StorageKeys.ModernAppModeKey() + let key = StorageKey.modernAppMode let value = try await StorageRouter.shared.get(key) modernValue = value statusMessage = "✓ Conditional migration complete." diff --git a/SecureStorageSample/Views/EncryptedStorageDemo.swift b/SecureStorageSample/Views/EncryptedStorageDemo.swift index 0cd1cd0..71c3993 100644 --- a/SecureStorageSample/Views/EncryptedStorageDemo.swift +++ b/SecureStorageSample/Views/EncryptedStorageDemo.swift @@ -132,12 +132,12 @@ struct EncryptedStorageDemo: View { Task { do { if useExternalKeyProvider { - let key = StorageKeys.ExternalSessionLogsKey() + let key = StorageKey.externalSessionLogs let logs = try await updatedLogs(for: key) try await StorageRouter.shared.set(logs, for: key) storedLogs = logs } else { - let key = StorageKeys.SessionLogsKey(iterations: iterations) + let key = StorageKey.sessionLogsKey(iterations: iterations) let logs = try await updatedLogs(for: key) try await StorageRouter.shared.set(logs, for: key) storedLogs = logs @@ -157,10 +157,10 @@ struct EncryptedStorageDemo: View { Task { do { if useExternalKeyProvider { - let key = StorageKeys.ExternalSessionLogsKey() + let key = StorageKey.externalSessionLogs storedLogs = try await StorageRouter.shared.get(key) } else { - let key = StorageKeys.SessionLogsKey(iterations: iterations) + let key = StorageKey.sessionLogsKey(iterations: iterations) storedLogs = try await StorageRouter.shared.get(key) } statusMessage = "✓ Decrypted \(storedLogs.count) log entries" @@ -179,10 +179,10 @@ struct EncryptedStorageDemo: View { Task { do { if useExternalKeyProvider { - let key = StorageKeys.ExternalSessionLogsKey() + let key = StorageKey.externalSessionLogs try await StorageRouter.shared.remove(key) } else { - let key = StorageKeys.SessionLogsKey(iterations: iterations) + let key = StorageKey.sessionLogsKey(iterations: iterations) try await StorageRouter.shared.remove(key) } storedLogs = [] @@ -194,7 +194,7 @@ struct EncryptedStorageDemo: View { } } - private func updatedLogs(for key: Key) async throws -> [String] where Key.Value == [String] { + private func updatedLogs(for key: StorageKey<[String]>) async throws -> [String] { var logs: [String] do { logs = try await StorageRouter.shared.get(key) diff --git a/SecureStorageSample/Views/FileSystemDemo.swift b/SecureStorageSample/Views/FileSystemDemo.swift index 6318394..b2bb3e6 100644 --- a/SecureStorageSample/Views/FileSystemDemo.swift +++ b/SecureStorageSample/Views/FileSystemDemo.swift @@ -172,7 +172,7 @@ struct FileSystemDemo: View { isLoading = true Task { do { - let key = StorageKeys.UserProfileFileKey(directory: selectedDirectory) + let key = StorageKey.userProfileFileKey(directory: selectedDirectory) let profile = UserProfile( name: profileName, email: profileEmail, @@ -192,7 +192,7 @@ struct FileSystemDemo: View { isLoading = true Task { do { - let key = StorageKeys.UserProfileFileKey(directory: selectedDirectory) + let key = StorageKey.userProfileFileKey(directory: selectedDirectory) let profile = try await StorageRouter.shared.get(key) storedProfile = profile @@ -216,7 +216,7 @@ struct FileSystemDemo: View { isLoading = true Task { do { - let key = StorageKeys.UserProfileFileKey(directory: selectedDirectory) + let key = StorageKey.userProfileFileKey(directory: selectedDirectory) try await StorageRouter.shared.remove(key) storedProfile = nil statusMessage = "✓ File deleted" @@ -231,7 +231,7 @@ struct FileSystemDemo: View { isLoading = true Task { do { - let key = StorageKeys.AppGroupUserProfileKey(directory: selectedDirectory) + let key = StorageKey.appGroupUserProfileKey(directory: selectedDirectory) let profile = UserProfile( name: profileName, email: profileEmail, @@ -251,7 +251,7 @@ struct FileSystemDemo: View { isLoading = true Task { do { - let key = StorageKeys.AppGroupUserProfileKey(directory: selectedDirectory) + let key = StorageKey.appGroupUserProfileKey(directory: selectedDirectory) let profile = try await StorageRouter.shared.get(key) appGroupProfile = profile @@ -275,7 +275,7 @@ struct FileSystemDemo: View { isLoading = true Task { do { - let key = StorageKeys.AppGroupUserProfileKey(directory: selectedDirectory) + let key = StorageKey.appGroupUserProfileKey(directory: selectedDirectory) try await StorageRouter.shared.remove(key) appGroupProfile = nil appGroupStatusMessage = "✓ App Group file deleted" diff --git a/SecureStorageSample/Views/KeychainDemo.swift b/SecureStorageSample/Views/KeychainDemo.swift index d9b3f98..d5bdaee 100644 --- a/SecureStorageSample/Views/KeychainDemo.swift +++ b/SecureStorageSample/Views/KeychainDemo.swift @@ -117,7 +117,7 @@ struct KeychainDemo: View { isLoading = true Task { do { - let key = StorageKeys.CredentialsKey( + let key = StorageKey.credentialsKey( accessibility: selectedAccessibility, accessControl: selectedAccessControl ) @@ -135,7 +135,7 @@ struct KeychainDemo: View { isLoading = true Task { do { - let key = StorageKeys.CredentialsKey( + let key = StorageKey.credentialsKey( accessibility: selectedAccessibility, accessControl: selectedAccessControl ) @@ -161,7 +161,7 @@ struct KeychainDemo: View { isLoading = true Task { do { - let key = StorageKeys.CredentialsKey( + let key = StorageKey.credentialsKey( accessibility: selectedAccessibility, accessControl: selectedAccessControl ) diff --git a/SecureStorageSample/Views/MigrationDemo.swift b/SecureStorageSample/Views/MigrationDemo.swift index d9274b3..e9846b3 100644 --- a/SecureStorageSample/Views/MigrationDemo.swift +++ b/SecureStorageSample/Views/MigrationDemo.swift @@ -87,7 +87,7 @@ struct MigrationDemo: View { isLoading = true Task { do { - let key = StorageKeys.LegacyMigrationSourceKey() + let key = StorageKey.legacyMigrationSource try await StorageRouter.shared.set(legacyValue, for: key) statusMessage = "✓ Saved '\(legacyValue)' to legacy UserDefaults" } catch { @@ -102,7 +102,7 @@ struct MigrationDemo: View { statusMessage = "Retrieving from Modern..." Task { do { - let key = StorageKeys.ModernMigrationDestinationKey() + let key = StorageKey.modernMigrationDestination let value = try await StorageRouter.shared.get(key) modernValue = value statusMessage = "✓ Success! Data migrated from UserDefaults to Keychain." @@ -120,7 +120,7 @@ struct MigrationDemo: View { statusMessage = "Running manual migration..." Task { do { - let key = StorageKeys.ModernMigrationDestinationKey() + let key = StorageKey.modernMigrationDestination _ = try await StorageRouter.shared.forceMigration(for: key) // Refresh modern value display modernValue = try await StorageRouter.shared.get(key) @@ -136,7 +136,7 @@ struct MigrationDemo: View { isLoading = true Task { do { - let key = StorageKeys.LegacyMigrationSourceKey() + let key = StorageKey.legacyMigrationSource let exists = try await StorageRouter.shared.exists(key) statusMessage = exists ? "⚠️ Legacy data STILL EXISTS in UserDefaults!" : "✅ Legacy data was successfully DELETED." } catch { diff --git a/SecureStorageSample/Views/PlatformSyncDemo.swift b/SecureStorageSample/Views/PlatformSyncDemo.swift index ef73d62..3ce62e9 100644 --- a/SecureStorageSample/Views/PlatformSyncDemo.swift +++ b/SecureStorageSample/Views/PlatformSyncDemo.swift @@ -114,7 +114,7 @@ struct PlatformSyncDemo: View { LabeledContent("Platform", value: selectedPlatform.displayName) LabeledContent("Sync", value: selectedSync.displayName) LabeledContent("Max Auto-Sync Size", value: "50 KB") - LabeledContent("Key Name", value: StorageKeys.SyncableSettingKey().name) + LabeledContent("Key Name", value: StorageKey.syncableSetting.name) } Section("Watch Notes") { @@ -141,7 +141,7 @@ struct PlatformSyncDemo: View { isLoading = true Task { do { - let key = StorageKeys.SyncableSettingKey( + let key = StorageKey.syncableSettingKey( availability: selectedPlatform, syncPolicy: selectedSync ) @@ -161,7 +161,7 @@ struct PlatformSyncDemo: View { isLoading = true Task { do { - let key = StorageKeys.SyncableSettingKey( + let key = StorageKey.syncableSettingKey( availability: selectedPlatform, syncPolicy: selectedSync ) @@ -184,7 +184,7 @@ struct PlatformSyncDemo: View { isLoading = true Task { do { - let key = StorageKeys.SyncableSettingKey( + let key = StorageKey.syncableSettingKey( availability: selectedPlatform, syncPolicy: selectedSync ) diff --git a/SecureStorageSample/Views/TransformingMigrationDemo.swift b/SecureStorageSample/Views/TransformingMigrationDemo.swift index 8a60bb7..a548907 100644 --- a/SecureStorageSample/Views/TransformingMigrationDemo.swift +++ b/SecureStorageSample/Views/TransformingMigrationDemo.swift @@ -63,7 +63,7 @@ struct TransformingMigrationDemo: View { isLoading = true Task { do { - let key = StorageKeys.LegacyProfileNameKey() + let key = StorageKey.legacyProfileName try await StorageRouter.shared.set(legacyValue, for: key) statusMessage = "✓ Saved legacy name \(legacyValue)" } catch { @@ -78,7 +78,7 @@ struct TransformingMigrationDemo: View { statusMessage = "Loading modern profile..." Task { do { - let key = StorageKeys.ModernProfileNameKey() + let key = StorageKey.modernProfileName let value = try await StorageRouter.shared.get(key) modernValue = format(value) statusMessage = "✓ Migration complete." diff --git a/SecureStorageSample/Views/UserDefaultsDemo.swift b/SecureStorageSample/Views/UserDefaultsDemo.swift index 4e408bb..9dc0011 100644 --- a/SecureStorageSample/Views/UserDefaultsDemo.swift +++ b/SecureStorageSample/Views/UserDefaultsDemo.swift @@ -140,7 +140,7 @@ struct UserDefaultsDemo: View { isLoading = true Task { do { - let key = StorageKeys.AppVersionKey() + let key = StorageKey.appVersion try await StorageRouter.shared.set(inputText, for: key) statusMessage = "✓ Saved successfully" } catch { @@ -154,7 +154,7 @@ struct UserDefaultsDemo: View { isLoading = true Task { do { - let key = StorageKeys.AppVersionKey() + let key = StorageKey.appVersion let value = try await StorageRouter.shared.get(key) storedValue = value inputText = value // Sync to field @@ -173,7 +173,7 @@ struct UserDefaultsDemo: View { isLoading = true Task { do { - let key = StorageKeys.AppVersionKey() + let key = StorageKey.appVersion try await StorageRouter.shared.remove(key) storedValue = "" statusMessage = "✓ Removed successfully" @@ -188,7 +188,7 @@ struct UserDefaultsDemo: View { isLoading = true Task { do { - let key = StorageKeys.AppGroupUserDefaultsKey() + let key = StorageKey.appGroupUserDefaults try await StorageRouter.shared.set(inputText, for: key) statusMessage = "✓ App Group saved successfully" } catch { @@ -202,7 +202,7 @@ struct UserDefaultsDemo: View { isLoading = true Task { do { - let key = StorageKeys.AppGroupUserDefaultsKey() + let key = StorageKey.appGroupUserDefaults let value = try await StorageRouter.shared.get(key) appGroupStoredValue = value inputText = value // Sync to field @@ -221,7 +221,7 @@ struct UserDefaultsDemo: View { isLoading = true Task { do { - let key = StorageKeys.AppGroupUserDefaultsKey() + let key = StorageKey.appGroupUserDefaults try await StorageRouter.shared.remove(key) appGroupStoredValue = "" statusMessage = "✓ App Group value removed"