veza/apps/web/src/utils/stateVersioning.example.ts
senke b4a4876fa5 [FE-STATE-011] fe-state: Add state versioning
- 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
2025-12-25 14:19:40 +01:00

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: [],
},
}),
}),
},
),
);