Storage Utilities
Storage adapters: persist tour state with localStorage, sessionStorage, or custom backends for completion tracking
Storage Utilities
Factory functions for creating storage adapters. Used by persistence hooks to save and restore tour state.
Why Use These Utilities?
Tour state needs to persist across sessions and page navigations:
- Multiple backends - localStorage, sessionStorage, cookies
- Custom storage - Redis, IndexedDB, or your own backend
- Namespace isolation - Prevent key collisions with prefixed storage
- SSR safety - Graceful degradation when storage is unavailable
createStorageAdapter
Create a storage adapter from configuration.
Usage
import { createStorageAdapter } from '@tour-kit/core';
// From string config
const localStorage = createStorageAdapter('localStorage');
const sessionStorage = createStorageAdapter('sessionStorage');
const cookieStorage = createStorageAdapter('cookie');
// From custom object
const customStorage = createStorageAdapter({
getItem: (key) => redis.get(key),
setItem: (key, value) => redis.set(key, value),
removeItem: (key) => redis.del(key),
});Parameters
Prop
Type
Return Value
Returns a Storage interface:
interface Storage {
getItem(key: string): string | null;
setItem(key: string, value: string): void;
removeItem(key: string): void;
}createCookieStorage
Create a cookie-based storage adapter with configurable expiration.
Usage
import { createCookieStorage } from '@tour-kit/core';
// Default: 365 days, root path
const cookies = createCookieStorage();
// Custom options
const sessionCookies = createCookieStorage({
expires: 1, // 1 day
path: '/app',
});Parameters
Prop
Type
When to Use Cookies
- Client-only access sufficient
- Larger data storage needed
- Faster access (no network overhead)
createPrefixedStorage
Wrap a storage adapter with key prefixes to avoid collisions.
Usage
import { createPrefixedStorage, createStorageAdapter } from '@tour-kit/core';
const localStorage = createStorageAdapter('localStorage');
const appStorage = createPrefixedStorage(localStorage, 'myapp');
// Keys are automatically prefixed
appStorage.setItem('tour-state', '...'); // Stored as "myapp:tour-state"
appStorage.getItem('tour-state'); // Looks up "myapp:tour-state"Parameters
Prop
Type
Multi-App Example
// Prevent collisions when multiple apps use the same storage
const mainAppTours = createPrefixedStorage(localStorage, 'main-app');
const adminTours = createPrefixedStorage(localStorage, 'admin');
mainAppTours.setItem('completed', '["welcome"]');
adminTours.setItem('completed', '["admin-tour"]');
// Stored as:
// "main-app:completed" → '["welcome"]'
// "admin:completed" → '["admin-tour"]'createNoopStorage
Create a no-operation storage for SSR or testing.
Usage
import { createNoopStorage } from '@tour-kit/core';
const noopStorage = createNoopStorage();
noopStorage.setItem('key', 'value'); // Does nothing
noopStorage.getItem('key'); // Returns null
noopStorage.removeItem('key'); // Does nothingThis is used internally when storage is unavailable (e.g., during SSR). You typically don't need to use it directly.
safeJSONParse
Safely parse JSON with a fallback value.
Usage
import { safeJSONParse } from '@tour-kit/core';
// Safe parsing with fallback
const tours = safeJSONParse(localStorage.getItem('tours'), []);
// Returns parsed array or [] if null/invalid
const config = safeJSONParse(localStorage.getItem('config'), { theme: 'light' });
// Returns parsed object or default configParameters
Prop
Type
Custom Storage Backend
Implement the Storage interface for custom backends:
import { createStorageAdapter } from '@tour-kit/core';
// Redis example (Node.js)
const redisStorage = {
getItem: async (key: string) => {
return await redis.get(`tourkit:${key}`);
},
setItem: async (key: string, value: string) => {
await redis.set(`tourkit:${key}`, value);
},
removeItem: async (key: string) => {
await redis.del(`tourkit:${key}`);
},
};
// IndexedDB example
const idbStorage = {
getItem: (key: string) => {
return new Promise((resolve) => {
const tx = db.transaction('tours', 'readonly');
const store = tx.objectStore('tours');
const request = store.get(key);
request.onsuccess = () => resolve(request.result?.value ?? null);
});
},
setItem: (key: string, value: string) => {
const tx = db.transaction('tours', 'readwrite');
const store = tx.objectStore('tours');
store.put({ key, value });
},
removeItem: (key: string) => {
const tx = db.transaction('tours', 'readwrite');
const store = tx.objectStore('tours');
store.delete(key);
},
};Custom storage backends with async operations require special handling. The built-in persistence hooks expect synchronous storage.
Storage Types Reference
| Type | Capacity | Persistence | Server Access |
|---|---|---|---|
localStorage | ~5-10MB | Permanent | No |
sessionStorage | ~5-10MB | Session only | No |
cookie | ~4KB | Configurable | Yes |
| Custom | Varies | Varies | Varies |
Related
- usePersistence - Uses storage adapters
- useRoutePersistence - Multi-page persistence
- Persistence Guide - Advanced patterns