CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-legendapp--state

A super fast and powerful state management library for JavaScript and React applications with proxy-based observables and fine-grained reactivity

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

persistence.mddocs/

Persistence

Comprehensive persistence system for offline-first applications with local storage and remote sync capabilities. Legend State's persistence layer provides automatic synchronization, conflict resolution, and supports multiple storage backends.

Capabilities

Core Persistence Functions

Persist Observable

Makes observables persistent with automatic synchronization.

/**
 * Makes an observable persistent with configurable storage and sync
 * @param obs - Observable to make persistent
 * @param config - Persistence configuration
 */
function persistObservable<T>(
  obs: Observable<T>, 
  config: ObservablePersistenceConfig<T>
): void;

/**
 * Creates a new persistent observable with initial state
 * @param state - Initial state value
 * @param config - Persistence configuration  
 * @returns Persistent observable
 */
function persistState<T>(
  state: T, 
  config: ObservablePersistenceConfig<T>
): Observable<T>;

Configuration

Global persistence configuration and setup.

/**
 * Configures global persistence settings
 * @param config - Global persistence configuration
 */
function configureObservablePersistence(
  config: ObservablePersistenceConfig
): void;

/**
 * Maps multiple persistence configurations
 * @param persistences - Array of persistence configs to apply
 */
function mapPersistences<T>(
  persistences: ObservablePersistenceConfig<T>[]
): void;

Remote Change Detection

Functions for detecting and handling remote data changes.

/**
 * Checks if currently processing a remote change
 * @returns True if in remote change context
 */
function isInRemoteChange(): boolean;

/**
 * Listens for changes originating from remote sources
 * @param obs - Observable to listen to
 * @param callback - Function called for remote changes
 */
function onChangeRemote<T>(
  obs: Observable<T>, 
  callback: (value: T) => void
): void;

Field Transformation

Utilities for transforming field names during persistence operations.

/**
 * Inverts a field mapping object (keys become values, values become keys)
 * @param fieldMap - Field mapping to invert
 * @returns Inverted field mapping
 */
function invertFieldMap(
  fieldMap: Record<string, string>
): Record<string, string>;

/**
 * Transforms object field names using a field mapping
 * @param obj - Object to transform
 * @param fieldMap - Mapping of old field names to new field names
 * @returns Object with transformed field names
 */
function transformObject<T>(
  obj: T, 
  fieldMap: Record<string, string>
): T;

/**
 * Transforms a property path using field mapping
 * @param path - Property path as string array
 * @param fieldMap - Field name mapping
 * @returns Transformed path
 */
function transformPath(
  path: string[], 
  fieldMap: Record<string, string>
): string[];

Persistence Configuration

interface ObservablePersistenceConfig<T = any> {
  /** Unique key for this persistence */
  name?: string;
  /** Local storage plugin configuration */
  local?: LocalPersistenceConfig;
  /** Remote storage plugin configuration */
  remote?: RemotePersistenceConfig;
  /** Field transformations for data mapping */
  transform?: TransformConfig;
  /** Initial data to use if no persisted data exists */
  initial?: T;
  /** Whether to persist immediately on changes */
  persistImmediately?: boolean;
  /** Debounce time for persistence operations */
  debounceTime?: number;
  /** Function to generate unique IDs for new items */
  generateId?: () => string;
  /** Custom retry configuration */
  retry?: RetryConfig;
}

interface LocalPersistenceConfig {
  /** Storage plugin to use */
  plugin: StoragePlugin;
  /** Storage key prefix */
  prefix?: string;
  /** Whether to persist metadata */
  persistMetadata?: boolean;
}

interface RemotePersistenceConfig {
  /** Remote sync plugin configuration */
  plugin: RemotePlugin;
  /** URL or endpoint for remote sync */
  url?: string;
  /** Headers to include in requests */
  headers?: Record<string, string>;
  /** Sync mode: 'auto' | 'manual' */
  mode?: 'auto' | 'manual';
  /** Conflict resolution strategy */
  conflictResolution?: 'client' | 'server' | 'merge';
}

interface TransformConfig {
  /** Field name mappings */
  fields?: Record<string, string>;
  /** Value transformation functions */
  values?: {
    [field: string]: {
      parse: (value: any) => any;
      stringify: (value: any) => any;
    };
  };
}

interface RetryConfig {
  /** Maximum number of retry attempts */
  maxAttempts?: number;
  /** Delay between retries in milliseconds */
  delay?: number;
  /** Exponential backoff multiplier */
  backoff?: number;
}

Storage Plugins

Pre-built storage plugins for different platforms and use cases.

/** Local Storage plugin for web browsers */
declare const localStoragePlugin: StoragePlugin;

/** IndexedDB plugin for web browsers with larger storage */
declare const indexedDBPlugin: StoragePlugin;

/** AsyncStorage plugin for React Native */
declare const asyncStoragePlugin: StoragePlugin;

/** MMKV plugin for React Native high-performance storage */
declare const mmkvPlugin: StoragePlugin;

/** Firebase Realtime Database plugin */
declare const firebasePlugin: RemotePlugin;

/** Fetch-based remote plugin for REST APIs */
declare const fetchPlugin: RemotePlugin;

/** Query plugin for URL-based state persistence */
declare const queryPlugin: StoragePlugin;

interface StoragePlugin {
  get(key: string): Promise<any>;
  set(key: string, value: any): Promise<void>;
  delete(key: string): Promise<void>;
  getMetadata?(key: string): Promise<any>;
  setMetadata?(key: string, metadata: any): Promise<void>;
}

interface RemotePlugin {
  load(config: RemotePersistenceConfig): Promise<any>;
  save(value: any, config: RemotePersistenceConfig): Promise<void>;
  subscribe?(
    config: RemotePersistenceConfig, 
    callback: (value: any) => void
  ): () => void;
}

Usage Examples:

import { observable, persistObservable } from "@legendapp/state";
import { persistState } from "@legendapp/state/persist";
import { 
  localStoragePlugin, 
  fetchPlugin,
  firebasePlugin 
} from "@legendapp/state/persist-plugins";

// Simple local persistence
const user$ = observable({ name: "", email: "", preferences: {} });

persistObservable(user$, {
  name: "user",
  local: {
    plugin: localStoragePlugin
  }
});

// Local + Remote sync with conflict resolution
const todos$ = persistState([], {
  name: "todos",
  local: {
    plugin: localStoragePlugin,
    prefix: "myapp"
  },
  remote: {
    plugin: fetchPlugin,
    url: "https://api.example.com/todos",
    mode: "auto",
    conflictResolution: "merge",
    headers: {
      "Authorization": "Bearer token123"
    }
  },
  transform: {
    fields: {
      "isCompleted": "done",
      "description": "text"
    }
  },
  retry: {
    maxAttempts: 3,
    delay: 1000,
    backoff: 2
  }
});

// Firebase real-time sync
const chat$ = persistState({ messages: [], users: [] }, {
  name: "chat",
  remote: {
    plugin: firebasePlugin,
    url: "https://myapp.firebaseio.com/chat"
  }
});

// Field transformation example
const apiData$ = persistState({ user_id: 1, full_name: "John" }, {
  name: "user",
  local: {
    plugin: localStoragePlugin
  },
  transform: {
    fields: {
      "user_id": "userId",
      "full_name": "name"
    },
    values: {
      "createdAt": {
        parse: (dateString) => new Date(dateString),
        stringify: (date) => date.toISOString()
      }
    }
  }
});

// Listening for remote changes
onChangeRemote(todos$, (newTodos) => {
  console.log("Todos updated from remote source:", newTodos);
  // Handle remote updates (show notification, etc.)
});

// Manual sync control
const settings$ = persistState({ theme: "light" }, {
  name: "settings",
  local: { plugin: localStoragePlugin },
  remote: { 
    plugin: fetchPlugin,
    url: "/api/settings",
    mode: "manual"
  }
});

// Trigger manual sync
settings$.theme.set("dark");
// Will persist locally immediately, but won't sync to remote until:
// (Manual sync would be triggered by the app as needed)

docs

configuration.md

core-observables.md

helper-functions.md

index.md

persistence.md

react-integration.md

tile.json