Persistence API
Manual save and load operations for stores created with persistence enabled.
These methods are only available when the store is created with a persist option.
save()
Manually saves all flags to persistent storage.
Signature:
save(): void
Returns: void
Example:
const store = createFlagStore({
persist: { storage: localStorage, autoSave: false }
})
store.set('gold', 100)
store.set('level', 5)
// Changes not yet saved (autoSave is false)
store.save() // Now saved to localStorage
Note: If storage is unavailable or throws an error, the error is logged to console.error but not thrown.
load()
Manually loads all flags from persistent storage.
Signature:
load(): void
Returns: void
Example:
const store = createFlagStore({
persist: { storage: localStorage, autoSave: false }
})
// Assume localStorage has previously saved data
store.load() // Loads and overwrites current state
console.log(store.get('gold')) // Value from storage
Note:
- This clears the current store state and loads persisted values
- Subscribers are notified of all loaded values
- If storage is unavailable or contains invalid data, errors are logged but not thrown
Behavior Details
Auto-Save (Default)
By default, autoSave is true and changes are saved automatically:
const store = createFlagStore({
persist: { storage: localStorage }
})
store.set('gold', 100) // Automatically saved
store.increment('gold') // Automatically saved
store.delete('gold') // Automatically saved
Manual Save Mode
Disable auto-save for manual control:
const store = createFlagStore({
persist: { storage: localStorage, autoSave: false }
})
store.set('a', 1) // NOT saved
store.set('b', 2) // NOT saved
store.save() // NOW saved
Auto-Load on Creation
When persistence is enabled, the store automatically loads from storage on creation:
// First session
const store1 = createFlagStore({
persist: { storage: localStorage }
})
store1.set('gold', 500)
// Later session (new page load)
const store2 = createFlagStore({
persist: { storage: localStorage }
})
store2.get('gold') // 500 (loaded automatically)
Initial Values vs Persisted
Persisted data takes precedence over initial values:
// Assume localStorage has { gold: 500 } from previous session
const store = createFlagStore({
initial: { gold: 0 }, // Ignored if persisted data exists
persist: { storage: localStorage }
})
store.get('gold') // 500 (from storage, not 0)
Custom Storage Key
Avoid conflicts with multiple stores by using different keys:
const gameStore = createFlagStore({
persist: { storage: localStorage, key: 'my-game-state' }
})
const settingsStore = createFlagStore({
persist: { storage: localStorage, key: 'my-app-settings' }
})
Default key is '@motioneffector/flags'.
Type Preservation
Types are preserved through serialization:
store.set('bool', true)
store.set('num', 42)
store.set('str', 'hello')
store.save()
// After reload
store.load()
typeof store.get('bool') // 'boolean'
typeof store.get('num') // 'number'
typeof store.get('str') // 'string'
Error Handling
Storage errors are caught and logged, not thrown:
const failingStorage = {
getItem: () => { throw new Error('Storage unavailable') },
setItem: () => { throw new Error('Storage unavailable') },
removeItem: () => { throw new Error('Storage unavailable') }
}
const store = createFlagStore({
persist: { storage: failingStorage }
})
// No error thrown, store still works in-memory
store.set('x', 1)
store.get('x') // 1
Corrupted Data
Invalid JSON in storage is handled gracefully:
localStorage.setItem('@motioneffector/flags', 'invalid{json')
const store = createFlagStore({
persist: { storage: localStorage }
})
// Error logged, store starts fresh
store.get('anything') // undefined
Types
FlagStoreWithPersistence
interface FlagStoreWithPersistence extends FlagStore {
save(): void
load(): void
}
Cast the store to access persistence methods:
import { createFlagStore, FlagStoreWithPersistence } from '@motioneffector/flags'
const store = createFlagStore({
persist: { storage: localStorage }
}) as FlagStoreWithPersistence
store.save() // TypeScript knows this exists
Storage
interface Storage {
getItem(key: string): string | null
setItem(key: string, value: string): void
removeItem(key: string): void
}
Implement this interface for custom storage backends. localStorage and sessionStorage both satisfy this interface.
PersistOptions
interface PersistOptions {
storage: Storage
key?: string
autoSave?: boolean
}
| Property | Type | Required | Description |
|---|---|---|---|
storage |
Storage |
Yes | Storage backend to use |
key |
string |
No | Storage key. Default: '@motioneffector/flags' |
autoSave |
boolean |
No | Auto-save on changes. Default: true |