# LocalData Migration Guide ## Overview `LocalData` provides protocol-based migration support to move data from legacy storage locations to modern `StorageKey` values. ## Automatic Migration When calling `get(_:)` on a key, the `StorageRouter` automatically: 1. Checks the primary location. 2. If not found, evaluates `migration` defined on the key. 3. If data is found in a source: - Unsecures it using the source's old policy. - Re-secures it using the destination key's policy. - Stores it in the new location. - Deletes the legacy data. - Returns the value. ## Proactive Migration (Sweep) You can trigger a sweep of all registered keys at app launch: ```swift try await StorageRouter.shared.registerCatalog(MyCatalog(), migrateImmediately: true) ``` This iterates through all keys in the catalog and calls `forceMigration(for:)` on each, ensuring all legacy data is consolidated. ## Defining Migration Sources ### Simple Legacy Migration For 1:1 migrations, attach a `SimpleLegacyMigration`: ```swift extension StorageKey where Value == String { static let legacyToken = StorageKey( name: "old_key_name", domain: .userDefaults(suite: nil), security: .none, serializer: .json, owner: "MigrationDemo", description: "Legacy token stored in UserDefaults." ) static let modernToken = StorageKey( name: "modern_token", domain: .keychain(service: "com.myapp"), owner: "MigrationDemo", description: "Modern token stored in Keychain.", migration: { key in AnyStorageMigration( SimpleLegacyMigration( destinationKey: key, sourceKey: .key(StorageKey.legacyToken) ) ) } ) } ``` ### Protocol-Based Migration For complex scenarios, attach an explicit migration: ```swift struct MyMigration: StorageMigration { typealias Value = String let destinationKey = StorageKey.modernToken func shouldMigrate(using router: StorageRouter, context: MigrationContext) async throws -> Bool { try await router.exists(destinationKey) } func migrate(using router: StorageRouter, context: MigrationContext) async throws -> MigrationResult { // Custom migration logic MigrationResult(success: true) } } extension StorageKey where Value == String { static let modernToken = StorageKey( name: "modern_token", domain: .keychain(service: "com.myapp"), owner: "MigrationDemo", description: "Modern token stored in Keychain.", migration: { _ in AnyStorageMigration(MyMigration()) } ) } ```