Persistencia
La persistencia permite que Presage recuerde los atributos del usuario y las senales de comportamiento entre recargas de pagina y sesiones del navegador.
Drivers integrados
Sección titulada «Drivers integrados»Driver de localStorage
Sección titulada «Driver de localStorage»El driver recomendado para aplicaciones SaaS en el navegador:
import { createAdaptiveClient, createLocalStorageDriver } from '@presage-kit/core'
const client = createAdaptiveClient({ persistence: { driver: createLocalStorageDriver('my-app'), }, // ...rules})Los datos se almacenan en localStorage bajo claves con namespace:
my-app:traits— Atributos del usuario (rol, plan, etc.)my-app:signals— Senales de comportamiento
El prefijo evita colisiones con otras bibliotecas o multiples instancias de Presage en el mismo dominio.
Driver de memoria
Sección titulada «Driver de memoria»Un driver en memoria para entornos SSR y testing:
import { createAdaptiveClient, createMemoryDriver } from '@presage-kit/core'
const client = createAdaptiveClient({ persistence: { driver: createMemoryDriver(), }, // ...rules})Los datos viven unicamente en memoria y se pierden cuando el proceso termina. Esto es util para:
- Renderizado del lado del servidor —
localStorageno esta disponible en el servidor - Pruebas unitarias — Sin efectos secundarios entre ejecuciones de tests
- Storybook — Historias aisladas que no contaminan el almacenamiento del navegador
Que se persiste
Sección titulada «Que se persiste»| Clave | Datos | Cuando se actualiza |
|---|---|---|
traits | Objeto UserTraits | En identify(), updateTraits() y cualquier cambio de estado |
signals | Objeto BehavioralSignals | Despues del recalculo de senales (100ms despues de track()) |
Creacion de drivers personalizados
Sección titulada «Creacion de drivers personalizados»Implemente la interfaz StorageDriver para almacenar datos en cualquier lugar:
interface StorageDriver { get<T>(key: string): T | null set<T>(key: string, value: T): void remove(key: string): void clear(): void}Ejemplo: Driver de Session Storage
Sección titulada «Ejemplo: Driver de Session Storage»import type { StorageDriver } from '@presage-kit/core'
function createSessionStorageDriver(prefix: string): StorageDriver { function prefixed(key: string): string { return `${prefix}:${key}` }
return { get<T>(key: string): T | null { const raw = sessionStorage.getItem(prefixed(key)) if (raw === null) return null try { return JSON.parse(raw) as T } catch { return null } },
set<T>(key: string, value: T): void { sessionStorage.setItem(prefixed(key), JSON.stringify(value)) },
remove(key: string): void { sessionStorage.removeItem(prefixed(key)) },
clear(): void { const toRemove: string[] = [] for (let i = 0; i < sessionStorage.length; i++) { const key = sessionStorage.key(i) if (key?.startsWith(`${prefix}:`)) { toRemove.push(key) } } for (const key of toRemove) { sessionStorage.removeItem(key) } }, }}Ejemplo: Driver de Cookies
Sección titulada «Ejemplo: Driver de Cookies»import type { StorageDriver } from '@presage-kit/core'
function createCookieDriver(prefix: string): StorageDriver { return { get<T>(key: string): T | null { const name = `${prefix}_${key}` const match = document.cookie.match(new RegExp(`(?:^|; )${name}=([^;]*)`)) if (!match) return null try { return JSON.parse(decodeURIComponent(match[1])) as T } catch { return null } },
set<T>(key: string, value: T): void { const name = `${prefix}_${key}` const encoded = encodeURIComponent(JSON.stringify(value)) document.cookie = `${name}=${encoded}; path=/; max-age=31536000; SameSite=Lax` },
remove(key: string): void { const name = `${prefix}_${key}` document.cookie = `${name}=; path=/; max-age=0` },
clear(): void { // Clear all cookies with the prefix const cookies = document.cookie.split('; ') for (const cookie of cookies) { const name = cookie.split('=')[0] if (name.startsWith(`${prefix}_`)) { document.cookie = `${name}=; path=/; max-age=0` } } }, }}Anti-FOUC: Inicializacion sincrona
Sección titulada «Anti-FOUC: Inicializacion sincrona»Un problema comun con el estado persistido es el destello de contenido no personalizado (FOUC): la interfaz se renderiza con valores por defecto y luego parpadea al estado personalizado una vez que los datos se cargan.
Presage evita esto porque el metodo StorageDriver.get() es sincrono. Cuando se llama a createAdaptiveClient():
- El driver lee los atributos y senales en cache de forma sincrona
- La madurez se calcula a partir de las senales en cache
- El
UserContextinicial esta listo antes del primer renderizado - Los componentes reciben la variante correcta desde la primera pintura
// This is synchronous — no loading state neededconst client = createAdaptiveClient({ persistence: { driver: createLocalStorageDriver('my-app'), }, rules: [...],})
// client.getContext() already has cached dataconsole.log(client.getContext().traits) // { userId: 'user-123', role: 'admin', ... }Este diseno es intencional. Tanto localStorage como sessionStorage son APIs sincronas, lo que las hace ideales para anti-FOUC. Si construye un driver asincrono personalizado (por ejemplo, IndexedDB), debera manejar el estado de carga usted mismo.
Sin persistencia
Sección titulada «Sin persistencia»Si no configura un driver de persistencia, Presage sigue funcionando, pero el contexto del usuario se reinicia en cada recarga de pagina. Esto puede ser util para:
- Prototipos y demos
- Aplicaciones renderizadas en el servidor donde el contexto proviene del servidor
- Escenarios donde siempre llama a
identify()desde su sistema de autenticacion al montar el componente
// No persistence — context resets on reloadconst client = createAdaptiveClient({ rules: [...],})