FlipFlag

FlipFlag Persist

Плагин для локального кэширования флагов

Пакет @flipflag/persist позволяет сохранять значения feature flags в локальном хранилище браузера. Это обеспечивает:

  • Офлайн-устойчивость — флаги работают даже при отсутствии сети
  • Мгновенную загрузку — кэшированные значения доступны сразу
  • Снижение нагрузки — меньше запросов к серверу

Установка

npm install @flipflag/persist @flipflag/sdk
# или
yarn add @flipflag/persist @flipflag/sdk

Быстрый старт

import { FlipFlag } from "@flipflag/sdk";
import { withLocalStorage } from "@flipflag/persist";

const sdk = new FlipFlag({ publicKey: "YOUR_PUBLIC_KEY" });
const persistedSdk = withLocalStorage(sdk);

await persistedSdk.init();

// Значение флага автоматически кэшируется
if (persistedSdk.isEnabled("newFeature")) {
  console.log("Feature enabled!");
}

API

withLocalStorage

Обёртка для сохранения флагов в localStorage:

import { withLocalStorage } from "@flipflag/persist";

const persistedSdk = withLocalStorage(sdk, {
  prefix: "flipflag:",  // префикс ключей (по умолчанию)
  ttlMs: 86400000,      // время жизни кэша в мс (по умолчанию 24 часа)
});

withSessionStorage

Аналогично withLocalStorage, но использует sessionStorage (данные удаляются при закрытии вкладки):

import { withSessionStorage } from "@flipflag/persist";

const persistedSdk = withSessionStorage(sdk);

withCookies

Сохраняет флаги в cookies (полезно для SSR и доступа на сервере):

import { withCookies } from "@flipflag/persist";

const persistedSdk = withCookies(sdk, {
  prefix: "flipflag:",
  ttlMs: 86400000,
  // Опции cookie:
  path: "/",
  domain: undefined,
  secure: true,        // по умолчанию в production
  sameSite: "lax",
});

withPersistence

Базовая функция для создания обёртки с кастомным адаптером:

import { withPersistence, localStorageAdapter } from "@flipflag/persist";

const persistedSdk = withPersistence(sdk, {
  adapter: localStorageAdapter(),
  prefix: "myapp:",
  ttlMs: 3600000,  // 1 час
  onRestore: (flagName, value) => {
    console.log(`Restored ${flagName}: ${value}`);
  },
  onPersist: (flagName, value) => {
    console.log(`Persisted ${flagName}: ${value}`);
  },
  onError: (error) => {
    console.error("Persistence error:", error);
  },
});

Конфигурация

ОпцияТипПо умолчаниюОписание
adapterStorageAdapterАдаптер хранилища (обязательный для withPersistence)
prefixstring"flipflag:"Префикс ключей в хранилище
ttlMsnumber86400000Время жизни кэша в миллисекундах (24 часа)
onRestorefunctionКолбэк при восстановлении из кэша
onPersistfunctionКолбэк при сохранении в кэш
onErrorfunctionКолбэк при ошибках

Формат хранения

Каждый флаг сохраняется под отдельным ключом:

flipflag:myFeature → { "value": true, "persistedAt": 1234567890, "expiresAt": 1234654290 }
flipflag:anotherFlag → { "value": false, "persistedAt": 1234567890, "expiresAt": 1234654290 }

Кастомные адаптеры

Вы можете создать свой адаптер, реализовав интерфейс StorageAdapter:

import type { StorageAdapter, PersistedFlagEntry } from "@flipflag/persist";

const myAdapter: StorageAdapter = {
  get(key: string): PersistedFlagEntry | undefined {
    // Получить данные по ключу
    const data = myStorage.get(key);
    return data ? JSON.parse(data) : undefined;
  },

  set(key: string, entry: PersistedFlagEntry): void {
    // Сохранить данные
    myStorage.set(key, JSON.stringify(entry));
  },

  remove(key: string): void {
    // Удалить данные
    myStorage.delete(key);
  },

  isAvailable(): boolean {
    // Проверить доступность хранилища
    return typeof myStorage !== "undefined";
  },
};

Интеграция с React

Используйте опцию instance в FlipFlagProvider:

"use client";
import { FlipFlag } from "@flipflag/sdk";
import { withLocalStorage } from "@flipflag/persist";
import { FlipFlagProvider, useFlag } from "@flipflag/react";

// Создаём SDK с persistence
const sdk = new FlipFlag({ publicKey: "YOUR_PUBLIC_KEY" });
const persistedSdk = withLocalStorage(sdk);

function App() {
  return (
    <FlipFlagProvider options={{ instance: persistedSdk }}>
      <MyComponent />
    </FlipFlagProvider>
  );
}

function MyComponent() {
  const enabled = useFlag("newFeature", false);
  return <div>{enabled ? "Новая версия" : "Старая версия"}</div>;
}

Поведение при ошибках

Когда SDK не может получить данные с сервера (офлайн, ошибка сети), плагин автоматически возвращает кэшированное значение:

  1. isEnabled("flag") пытается получить значение из SDK
  2. Если успешно — значение кэшируется и возвращается
  3. Если ошибка — возвращается значение из кэша (если не истёк TTL)
  4. Если кэш пуст или истёк — возвращается false

Встроенные адаптеры

АдаптерОписание
localStorageAdapter()Сохраняет в localStorage
sessionStorageAdapter()Сохраняет в sessionStorage
cookieAdapter(options?)Сохраняет в cookies
memoryAdapter()Сохраняет в памяти (для тестов)

On this page