Add StorageKey, updatedLogs; Remove StorageKeys, AppGroupUserDefaultsKey, Value, AppGroupUserProfileKey (+25 more)
This commit is contained in:
parent
e025e435bc
commit
6d5c916f95
@ -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)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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<String> = .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
|
||||
)
|
||||
}
|
||||
|
||||
@ -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<UserProfile> = .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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
)
|
||||
}
|
||||
|
||||
@ -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)
|
||||
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
|
||||
)
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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))
|
||||
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
|
||||
)
|
||||
let serializer: Serializer<String> = .json
|
||||
let owner = "SampleApp"
|
||||
let description = "Stores private notes encrypted at rest."
|
||||
let availability: PlatformAvailability = .phoneOnly
|
||||
let syncPolicy: SyncPolicy = .never
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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> = .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
|
||||
)
|
||||
}
|
||||
|
||||
@ -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<String> = .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
|
||||
}
|
||||
),
|
||||
owner: "SampleApp",
|
||||
description: "Stores custom-encoded string data (Base64 example).",
|
||||
availability: .all,
|
||||
syncPolicy: .never
|
||||
)
|
||||
let owner = "SampleApp"
|
||||
let description = "Stores custom-encoded string data (Base64 example)."
|
||||
let availability: PlatformAvailability = .all
|
||||
let syncPolicy: SyncPolicy = .never
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
)
|
||||
}
|
||||
|
||||
@ -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<UserProfile> = .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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
),
|
||||
serializer: .json,
|
||||
owner: "SampleApp",
|
||||
description: "Stores API auth token for network requests.",
|
||||
availability: .phoneOnly,
|
||||
syncPolicy: .never
|
||||
)
|
||||
let serializer: Serializer<String> = .json
|
||||
let owner = "SampleApp"
|
||||
let description = "Stores API auth token for network requests."
|
||||
let availability: PlatformAvailability = .phoneOnly
|
||||
let syncPolicy: SyncPolicy = .never
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<Credential> = .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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
),
|
||||
serializer: .data,
|
||||
owner: "SampleApp",
|
||||
description: "Stores external key material used by encryption policies.",
|
||||
availability: .phoneOnly,
|
||||
syncPolicy: .never
|
||||
)
|
||||
let serializer: Serializer<Data> = .data
|
||||
let owner = "SampleApp"
|
||||
let description = "Stores external key material used by encryption policies."
|
||||
let availability: PlatformAvailability = .phoneOnly
|
||||
let syncPolicy: SyncPolicy = .never
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
),
|
||||
serializer: .json,
|
||||
owner: "SampleApp",
|
||||
description: "Stores last known location for location-aware features.",
|
||||
availability: .phoneOnly,
|
||||
syncPolicy: .never
|
||||
)
|
||||
let serializer: Serializer<SampleLocationData> = .json
|
||||
let owner = "SampleApp"
|
||||
let description = "Stores last known location for location-aware features."
|
||||
let availability: PlatformAvailability = .phoneOnly
|
||||
let syncPolicy: SyncPolicy = .never
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<Bool> = .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<String> = .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<UnifiedSettings> = .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<Bool>.legacyNotificationSetting),
|
||||
.key(StorageKey<String>.legacyThemeSetting)
|
||||
]
|
||||
|
||||
return AnyStorageMigration(
|
||||
DefaultAggregatingMigration(
|
||||
destinationKey: self,
|
||||
destinationKey: key,
|
||||
sourceKeys: sources
|
||||
) { sources in
|
||||
var notificationsEnabled = false
|
||||
@ -69,5 +66,5 @@ extension StorageKeys {
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@ -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<String> = .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<String> = .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
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@ -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<String> = .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<String> = .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)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@ -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<String> = .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<ProfileName> = .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<String>.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 {
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@ -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<String> = .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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<Bool> = .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
|
||||
)
|
||||
}
|
||||
|
||||
@ -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<String> = .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
|
||||
)
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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."
|
||||
|
||||
@ -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<Key: StorageKey>(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)
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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
|
||||
)
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
)
|
||||
|
||||
@ -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."
|
||||
|
||||
@ -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"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user