Перейти к содержимому
GitHubXDiscord

Triggery

Пиши бизнес-логику, а не шаблонный код.

Один файл описывает один сценарий. События приходят на вход, условия отсекают лишнее, действия выполняют побочные эффекты. Один и тот же API на хуках работает в React, Solid и Vue.

src/triggers/message.trigger.ts
import { createTrigger } from "@triggery/core";

type Settings = { sound: boolean; notifications: boolean };
type Payload = { author: string; text: string; channelId: string };

export const messageTrigger = createTrigger<{
  events: { "new-message": Payload };
  conditions: { settings: Settings; activeChannelId: string | null };
  actions: { showToast: { title: string; body: string }; playSound: "beep" };
}>({
  id: "message-received",
  required: ["settings"],
  handler({ event, conditions, actions, check }) {
    if (conditions.activeChannelId === event.payload.channelId) return;
    if (!check.is("settings", (s) => s.notifications)) return;

    actions.debounce(800).playSound?.("beep");
    actions.showToast?.({
      title: event.payload.author,
      body: event.payload.text,
    });
  },
});

Компоненты остаются сосредоточенными на своём порте. Никто из них не лезет в состояние соседа.

src/Chat.tsx
import { useEvent, useCondition, useAction } from "@triggery/react";
import { messageTrigger } from "./triggers/message.trigger";

// Продьюсер: поле ввода в чате отправляет событие.
const fireNewMessage = useEvent(messageTrigger, "new-message");

// Провайдер: панель настроек отдаёт снимок состояния через геттер.
useCondition(messageTrigger, "settings", () => settings, [settings]);

// Реактор: тост-компонент подписывается на действие.
useAction(messageTrigger, "showToast", (payload) =>
  toast.success(payload.title, { description: payload.body }),
);

Никакого проброса пропсов через всё дерево, никаких цепочек useEffect, никакой общей шины контекста. Меняешь файл триггера — меняется вся реакция, а компонентов касаться не нужно.

Ядро без зависимостей

Ноль зависимостей в рантайме. Используй @triggery/core напрямую из Node, чистого JavaScript или любого фреймворка. Биндинги — тонкие обёртки вокруг жизненного цикла, примерно по 50 строк каждая.

React · Solid · Vue

Один и тот же API на хуках в каждом биндинге. Меняй стек, не переписывая слой оркестрации.

Типобезопасность по умолчанию

Одна inline-обобщённая схема, три типизированные поверхности — события, условия, действия. Без приведений as, без .d.ts-файлов, без кодогенерации.

Тесты без React

Обработчики триггеров — почти чистые функции от снимка состояния. Подмени условия, подмени действия, отправь событие. React Testing Library не обязателен.

DevTools из коробки

Кольцевой буфер инспектора встроен в каждый рантайм. Подключи мост к Redux DevTools, поставь <InspectorView> или переигрывай записанные сессии.

ESLint и codemod-скрипты

Восемь правил ESLint ловят типичные ошибки. Codemod-скрипты переносят код с useEffect, RTK listenerMiddleware и (в 1.0) с Redux Saga.

pnpm add @triggery/core @triggery/react

Для SolidJS используй @triggery/solid, для Vue 3 — @triggery/vue. API одинаковый.

Открыть руководство

Посмотреть готовый рецепт

Открыть в StackBlitz

Открыть в CodeSandbox

Triggery — единственная библиотека оркестрации, в которой один и тот же файл со сценарием понятен и джуну в понедельник, и сеньору на ревью в пятницу.

— early adopter, 2026

TriggeryRedux SagaRTK listenerMiddlewareXStateRxJS
API на хукахданетчастичноданет
Файл на сценарийданетчастичноданет
Работает в любом фреймворкедатолько Reduxтолько Reduxдада
Inline-обобщённая схемаданетнетдаn/a
Встроенные DevToolsдавнешниеRTK DevToolsдавнешние
Размер ядра (gzip)< 6 кБ~17 кБвнутри RTK~16 кБ~46 кБ

Подробные сравнения — в разделе «Миграция → Сравнение».

Triggery находится в окне 0.9.x release candidate — заморозка фич, последний круг сообщественного тестирования перед 1.0. Рантайм уже работает в продакшене с начала 2026 года, в CI закреплены пороги покрытия (строки ≥ 95%, ветви ≥ 85%). Что дальше — смотри в публичной дорожной карте.

Поддержать проект