Постепенный раскат и расписание
Два способа автоматически определять значение флага — по проценту пользователей или по дате — вместо ручного переопределения.
Постепенный раскат по процентам
Вместо обычного boolean или строки флаг в опции flags может быть объектом { value, rollout }:
app.use(FeatureToggles, {
flags: {
newSearch: { value: true, rollout: 0.2 }, // 20% пользователей
},
userId: currentUser.id, // стабильный идентификатор пользователя
})rollout — число от 0 до 1. Каждый пользователь распределяется детерминированно: имя флага и userId (по умолчанию 'anonymous', если userId не задан) хешируются вместе, и пользователь получает value, если хеш попадает ниже порога rollout — иначе флаг разрешается в false, никогда в defaultValue. Один и тот же userId всегда попадает в один и тот же бакет, поэтому раскат никогда не «мигает» для конкретного пользователя между перезагрузками, а увеличение процента позже только добавляет пользователей в включённую группу, никогда не убирает.
const { getRollout } = useFeatureProvider()
getRollout('newSearch') // → 0.2Разрешение раската происходит один раз, при создании провайдера — изменение userId позже не переразбивает уже существующие флаги реактивно.
Расписание
Флаг можно принудительно выключить вне настроенного диапазона дат, независимо от ручного переопределения:
app.use(FeatureToggles, {
flags: { holidayBanner: true },
schedule: {
holidayBanner: { from: '2025-12-01', to: '2025-12-31' },
},
})interface FlagSchedule {
from?: string // ISO-дата — флаг принудительно выключен до этой даты
to?: string // ISO-дата — флаг принудительно выключен после этой даты
}И from, и to опциональны — опустите from для окна «активен до», или to для окна «активен с». Проверка повторяется каждую минуту, пока страница открыта, так что запланированный флаг живо переключается вкл/выкл без перезагрузки.
Расписание принудительно делает флаг false только тогда, когда он иначе разрешился бы во что-то другое — оно никогда не переопределяет активное URL-переопределение или runtime-вызов setFlag(), поэтому ручное переопределение всегда побеждает неактивное окно расписания. Полный порядок приоритета показывает, где именно расписание находится в цепочке.
const { getSchedule, isScheduleActive } = useFeatureProvider()
getSchedule('holidayBanner') // → { from: '2025-12-01', to: '2025-12-31' }
isScheduleActive('holidayBanner') // → true только внутри окна (или если расписание не задано)getFlagSource('holidayBanner') возвращает 'schedule', пока причина, по которой флаг читается как false, — неактивное окно.