- Created state versioning system (stateVersioning.ts) with: * Version management: Wrap/unwrap state with version info * Migration support: Sequential migrations between versions * Versioned storage: Adapter for Zustand persist middleware * Error handling: Fallback to initial state on migration failure * Automatic migration: Migrate state on load if needed - Added comprehensive test suite (17 tests, 14 passing) - Created example integration showing usage with stores - Supports legacy state (unversioned) and version mismatches
123 lines
2.9 KiB
TypeScript
123 lines
2.9 KiB
TypeScript
/**
|
|
* Example usage of State Versioning
|
|
* FE-STATE-011: Example integration with Zustand persist middleware
|
|
*
|
|
* This file demonstrates how to use state versioning with Zustand stores.
|
|
*/
|
|
|
|
import { create } from 'zustand';
|
|
import { persist } from 'zustand/middleware';
|
|
import { createVersionedStorage, createMigration, type Migration } from './stateVersioning';
|
|
|
|
// Example state interfaces for different versions
|
|
interface LibraryStateV1 {
|
|
items: Array<{ id: string; title: string }>;
|
|
favorites: string[]; // Array of IDs
|
|
}
|
|
|
|
interface LibraryStateV2 {
|
|
items: Array<{ id: string; title: string }>;
|
|
favorites: {
|
|
byId: Record<string, { id: string; title: string }>;
|
|
allIds: string[];
|
|
};
|
|
}
|
|
|
|
interface LibraryStateV3 {
|
|
items: {
|
|
byId: Record<string, { id: string; title: string }>;
|
|
allIds: string[];
|
|
};
|
|
favorites: {
|
|
byId: Record<string, { id: string; title: string }>;
|
|
allIds: string[];
|
|
};
|
|
}
|
|
|
|
// Define migrations
|
|
const migrations: Migration<LibraryStateV3>[] = [
|
|
createMigration<LibraryStateV2>(
|
|
2,
|
|
(state) => {
|
|
// Migrate from V1 to V2: Convert favorites array to normalized structure
|
|
const v1 = state as LibraryStateV1;
|
|
const favoritesById: Record<string, { id: string; title: string }> = {};
|
|
const favoritesAllIds: string[] = [];
|
|
|
|
for (const itemId of v1.favorites) {
|
|
const item = v1.items.find((i) => i.id === itemId);
|
|
if (item) {
|
|
favoritesById[itemId] = item;
|
|
favoritesAllIds.push(itemId);
|
|
}
|
|
}
|
|
|
|
return {
|
|
items: v1.items,
|
|
favorites: {
|
|
byId: favoritesById,
|
|
allIds: favoritesAllIds,
|
|
},
|
|
};
|
|
},
|
|
'Convert favorites array to normalized structure',
|
|
),
|
|
createMigration<LibraryStateV3>(
|
|
3,
|
|
(state) => {
|
|
// Migrate from V2 to V3: Normalize items as well
|
|
const v2 = state as LibraryStateV2;
|
|
const itemsById: Record<string, { id: string; title: string }> = {};
|
|
const itemsAllIds: string[] = [];
|
|
|
|
for (const item of v2.items) {
|
|
itemsById[item.id] = item;
|
|
itemsAllIds.push(item.id);
|
|
}
|
|
|
|
return {
|
|
items: {
|
|
byId: itemsById,
|
|
allIds: itemsAllIds,
|
|
},
|
|
favorites: v2.favorites,
|
|
};
|
|
},
|
|
'Normalize items structure',
|
|
),
|
|
];
|
|
|
|
// Example store with versioning
|
|
export const useVersionedLibraryStore = create<LibraryStateV3>()(
|
|
persist(
|
|
(set) => ({
|
|
items: {
|
|
byId: {},
|
|
allIds: [],
|
|
},
|
|
favorites: {
|
|
byId: {},
|
|
allIds: [],
|
|
},
|
|
}),
|
|
{
|
|
name: 'library-storage',
|
|
storage: createVersionedStorage<LibraryStateV3>({
|
|
currentVersion: 3,
|
|
storeName: 'LibraryStore',
|
|
migrations,
|
|
createInitialState: () => ({
|
|
items: {
|
|
byId: {},
|
|
allIds: [],
|
|
},
|
|
favorites: {
|
|
byId: {},
|
|
allIds: [],
|
|
},
|
|
}),
|
|
}),
|
|
},
|
|
),
|
|
);
|
|
|