@presage-kit/core
El paquete core proporciona el cliente adaptativo, el motor de reglas, el tracker, los drivers de persistencia y todos los tipos compartidos.
pnpm add @presage-kit/corecreateAdaptiveClient(config)
Sección titulada «createAdaptiveClient(config)»Crea una instancia de AdaptiveClient, el centro de operaciones para reglas, rastreo y gestion del contexto.
import { createAdaptiveClient, createLocalStorageDriver } from '@presage-kit/core'
const client = createAdaptiveClient({ rules: [/* ... */], tracker: { adapters: [/* ... */], builtIn: { maxEvents: 500 }, }, persistence: { driver: createLocalStorageDriver('my-app'), }, maturity: { newMaxSessions: 5, dormantDaysInactive: 21, },})AdaptiveClientConfig
Sección titulada «AdaptiveClientConfig»interface AdaptiveClientConfig { rules?: AdaptationRule[] tracker?: { adapters?: TrackerAdapter[] builtIn?: Partial<BuiltInTrackerConfig> } persistence?: { driver: StorageDriver } maturity?: Partial<MaturityConfig>}| Campo | Tipo | Por defecto | Descripcion |
|---|---|---|---|
rules | AdaptationRule[] | [] | Conjunto inicial de reglas de adaptacion |
tracker.adapters | TrackerAdapter[] | [] | Adaptadores de analitica externos |
tracker.builtIn.maxEvents | number | 1000 | Maximo de eventos en memoria |
tracker.builtIn.maxAgeMs | number | 2592000000 (30 dias) | Edad maxima de eventos antes de la poda |
persistence.driver | StorageDriver | null | Driver de almacenamiento para atributos y senales |
maturity | Partial<MaturityConfig> | Ver valores por defecto | Sobreescrituras de umbrales de madurez |
AdaptiveClient
Sección titulada «AdaptiveClient»interface AdaptiveClient { state: ReadableAtom<AdaptiveStoreState> identify(userId: string, traits?: UserTraits): void updateTraits(traits: Partial<UserTraits>): void track(event: string, properties?: Record<string, unknown>): void resolve(point: AdaptationPoint): ResolvedAdaptation evaluateAction(adaptationId: string): AdaptationAction | null getContext(): UserContext destroy(): void}Un atom reactivo que contiene el estado actual del store. Suscribase para recibir notificaciones de cambios.
const unsubscribe = client.state.subscribe((state) => { console.log('Context changed:', state.context)})identify(userId, traits?)
Sección titulada «identify(userId, traits?)»Asocia la sesion actual con un usuario. Fusiona los atributos proporcionados con los atributos existentes.
client.identify('user-123', { role: 'admin', plan: 'enterprise', signupDate: '2025-01-15', company: 'Acme Corp', companySize: 150,})Tambien reenvía la llamada identify a todos los adaptadores de tracker registrados.
updateTraits(traits)
Sección titulada «updateTraits(traits)»Fusiona nuevos atributos con los atributos existentes sin requerir una llamada completa a identify().
client.updateTraits({ plan: 'enterprise', locale: 'fr' })track(event, properties?)
Sección titulada «track(event, properties?)»Registra un evento. Activa el recalculo de senales con debounce (100ms).
client.track('feature_used', { featureId: 'export' })client.track('click', { elementId: 'sidebar-settings' })client.track('custom_signal', { signalId: 'engagement', value: 3 })client.track('page_view', { path: '/dashboard' })resolve(point)
Sección titulada «resolve(point)»Resuelve un adaptation point evaluando las reglas y devolviendo la variante seleccionada.
const result = client.resolve({ id: 'onboarding', variants: ['guided-tour', 'standard', 'minimal'], defaultVariant: 'standard', strategy: { type: 'rules' },})
console.log(result.selectedVariant) // 'guided-tour'console.log(result.reason) // 'Rule "new-user-tour" matched'evaluateAction(adaptationId)
Sección titulada «evaluateAction(adaptationId)»Evalua las reglas para un adaptation point y devuelve la accion sin procesar (o null si ninguna regla coincide). Util para flujos de control imperativos.
const action = client.evaluateAction('sidebar-nav')
if (action?.type === 'reorder') { // Reorder navigation items}getContext()
Sección titulada «getContext()»Devuelve una instantanea del UserContext actual.
const ctx = client.getContext()console.log(ctx.traits.role) // 'admin'console.log(ctx.signals.sessionCount) // 12console.log(ctx.maturity) // 'active'destroy()
Sección titulada «destroy()»Destruye el cliente. Cancela los temporizadores pendientes y se desuscribe de los cambios de estado.
client.destroy()AdaptiveStoreState
Sección titulada «AdaptiveStoreState»interface AdaptiveStoreState { context: UserContext isReady: boolean}UserContext
Sección titulada «UserContext»interface UserContext { traits: UserTraits signals: BehavioralSignals maturity: Maturity}UserTraits
Sección titulada «UserTraits»interface UserTraits { userId?: string role?: string plan?: string signupDate?: string company?: string companySize?: number locale?: string [key: string]: unknown}Extensible con cualquier par clave-valor personalizado.
BehavioralSignals
Sección titulada «BehavioralSignals»interface BehavioralSignals { sessionCount: number totalEvents: number featureUsage: Record<string, number> lastSeenAt: string // ISO 8601 timestamp firstSeenAt: string // ISO 8601 timestamp currentSessionDuration: number daysSinceSignup: number clickMap: Record<string, number> customSignals: Record<string, number>}Maturity
Sección titulada «Maturity»type Maturity = 'new' | 'onboarding' | 'active' | 'power' | 'dormant'MaturityConfig
Sección titulada «MaturityConfig»interface MaturityConfig { newMaxSessions: number // Default: 3 onboardingMaxSessions: number // Default: 10 powerMinFeatures: number // Default: 5 dormantDaysInactive: number // Default: 14}AdaptationRule
Sección titulada «AdaptationRule»interface AdaptationRule { id: string adaptationId: string priority: number conditions: ConditionGroup action: AdaptationAction}Condition
Sección titulada «Condition»interface Condition { field: string operator: ConditionOperator value: unknown}ConditionOperator
Sección titulada «ConditionOperator»type ConditionOperator = | 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'notIn' | 'contains' | 'notContains' | 'exists' | 'notExists' | 'between' | 'matches'ConditionGroup
Sección titulada «ConditionGroup»interface ConditionGroup { all?: (Condition | ConditionGroup)[] any?: (Condition | ConditionGroup)[] not?: Condition | ConditionGroup}AdaptationAction
Sección titulada «AdaptationAction»type AdaptationAction = | { type: 'show'; variantId: string } | { type: 'hide' } | { type: 'reorder'; order: string[] } | { type: 'modify'; props: Record<string, unknown> }AdaptationPoint
Sección titulada «AdaptationPoint»interface AdaptationPoint { id: string variants: readonly string[] defaultVariant: string strategy: Strategy}ResolvedAdaptation
Sección titulada «ResolvedAdaptation»interface ResolvedAdaptation { adaptationId: string selectedVariant: string strategy: Strategy['type'] // 'rules' reason: string // e.g. 'Rule "my-rule" matched' or 'default' resolvedAt: number // timestamp}Strategy
Sección titulada «Strategy»type Strategy = { type: 'rules' }TrackerAdapter
Sección titulada «TrackerAdapter»Interfaz para conectar servicios de analitica externos al tracker.
interface TrackerAdapter { name: string track(event: TrackerEvent): void | Promise<void> identify(userId: string, traits: UserTraits): void | Promise<void> flush?(): Promise<void>}TrackerEvent
Sección titulada «TrackerEvent»interface TrackerEvent { name: string properties?: Record<string, unknown> timestamp: number userId?: string sessionId: string}BuiltInTrackerConfig
Sección titulada «BuiltInTrackerConfig»interface BuiltInTrackerConfig { maxEvents: number // Default: 1000 maxAgeMs: number // Default: 2592000000 (30 days)}StorageDriver
Sección titulada «StorageDriver»Interfaz para drivers de persistencia personalizados.
interface StorageDriver { get<T>(key: string): T | null set<T>(key: string, value: T): void remove(key: string): void clear(): void}createLocalStorageDriver(prefix)
Sección titulada «createLocalStorageDriver(prefix)»Crea un StorageDriver respaldado por localStorage. Las claves se almacenan como prefix:key.
import { createLocalStorageDriver } from '@presage-kit/core'
const driver = createLocalStorageDriver('my-app')// Stores as 'my-app:traits', 'my-app:signals'Devuelve null de forma segura en get() cuando localStorage no esta disponible (por ejemplo, SSR).
createMemoryDriver()
Sección titulada «createMemoryDriver()»Crea un StorageDriver en memoria. Los datos se pierden cuando el proceso termina.
import { createMemoryDriver } from '@presage-kit/core'
const driver = createMemoryDriver()RulesEngine
Sección titulada «RulesEngine»El motor de reglas puede usarse directamente para testing o casos de uso avanzados.
import { RulesEngine } from '@presage-kit/core'
const engine = new RulesEngine()addRule(rule)
Sección titulada «addRule(rule)»Agrega una regla individual. Reordena las reglas por prioridad.
engine.addRule({ id: 'my-rule', adaptationId: 'onboarding', priority: 10, conditions: { all: [{ field: 'maturity', operator: 'eq', value: 'new' }] }, action: { type: 'show', variantId: 'guided-tour' },})addRules(rules)
Sección titulada «addRules(rules)»Agrega multiples reglas a la vez. Reordena una sola vez.
engine.addRules([rule1, rule2, rule3])removeRule(ruleId)
Sección titulada «removeRule(ruleId)»Elimina una regla por su ID.
engine.removeRule('my-rule')evaluate(adaptationId, context)
Sección titulada «evaluate(adaptationId, context)»Evalua todas las reglas para el ID de adaptacion dado contra un UserContext. Devuelve la primera accion que coincida, o null.
const action = engine.evaluate('onboarding', { traits: { role: 'admin' }, signals: { sessionCount: 2, totalEvents: 10, /* ... */ }, maturity: 'new',})getRules()
Sección titulada «getRules()»Devuelve todas las reglas registradas como un array de solo lectura.
const rules = engine.getRules() // readonly AdaptationRule[]atom(initialValue)
Sección titulada «atom(initialValue)»Una primitiva reactiva minima para casos de uso avanzados. Sigue el contrato de store de Svelte.
import { atom } from '@presage-kit/core'
const count = atom(0)
// Readconsole.log(count.get()) // 0
// Writecount.set(1)
// Subscribe (called immediately with current value)const unsub = count.subscribe((value, oldValue) => { console.log(`Changed from ${oldValue} to ${value}`)})
// Listen (NOT called immediately)const unlisten = count.listen((value, oldValue) => { console.log(`Changed from ${oldValue} to ${value}`)})
// Cleanupunsub()unlisten()ReadableAtom<T>
Sección titulada «ReadableAtom<T>»interface ReadableAtom<T> { get(): T subscribe(listener: Listener<T>): Unsubscribe listen(listener: Listener<T>): Unsubscribe}WritableAtom<T>
Sección titulada «WritableAtom<T>»Extiende ReadableAtom con un metodo set().
interface WritableAtom<T> extends ReadableAtom<T> { set(value: T): void}Listener<T>
Sección titulada «Listener<T>»type Listener<T> = (value: T, oldValue: T) => voidUnsubscribe
Sección titulada «Unsubscribe»type Unsubscribe = () => void