За пять минут у тебя получится один файл со сценарием («пришло новое сообщение, у пользователя включены уведомления — показать тост») и три небольших компонента, которые к этому файлу подключаются. Ни один из компонентов не знает о других.
Проект на React 18+/19, Solid 1.8+ или Vue 3.4+. (Если у тебя его пока нет, запусти pnpm dlx @triggery/cli create my-app, чтобы развернуть минимальный Vite-проект — см. @triggery/cli.)
TypeScript рекомендуется, но не обязателен. Примеры на этом сайте предполагают TS.
import { createRuntime } from '@triggery/core';import { TriggerRuntimeProvider } from '@triggery/react';import { StrictMode } from 'react';import { createRoot } from 'react-dom/client';import { App } from './App';const runtime = createRuntime();createRoot(document.getElementById('root')!).render( <StrictMode> <TriggerRuntimeProvider runtime={runtime}> <App /> </TriggerRuntimeProvider> </StrictMode>,);
src/index.tsx
import { createRuntime } from '@triggery/core';import { TriggerRuntimeProvider } from '@triggery/solid';import { render } from 'solid-js/web';import { App } from './App';const runtime = createRuntime();render( () => ( <TriggerRuntimeProvider runtime={runtime}> <App /> </TriggerRuntimeProvider> ), document.getElementById('root')!,);
src/main.ts
import { createRuntime } from '@triggery/core';import { TriggerRuntimePlugin } from '@triggery/vue';import { createApp } from 'vue';import App from './App.vue';const runtime = createRuntime();createApp(App).use(TriggerRuntimePlugin, { runtime }).mount('#root');
Провайдер можно вообще не ставить — тогда Triggery возьмёт общий рантайм, который создаётся по умолчанию при первом обращении. Явный провайдер нужен, чтобы изолировать рантаймы в тестах, микрофронтендах и мультиарендных приложениях.
Принятый стиль — один триггер на файл, с суффиксом .trigger.ts. Файл читается сверху вниз как спецификация.
src/triggers/message.trigger.ts
import { createTrigger } from '@triggery/core';type Settings = { sound: boolean; notifications: boolean };type Message = { author: string; text: string; channelId: string };export const messageTrigger = createTrigger<{ events: { 'new-message': Message }; conditions: { settings: Settings; activeChannelId: string | null }; actions: { showToast: { title: string; body: string }; playSound: 'beep' };}>({ id: 'message-received', events: ['new-message'], required: ['settings'], handler({ event, conditions, actions, check }) { // Skip if the user is already looking at this conversation. if (conditions.activeChannelId === event.payload.channelId) return; // Skip if notifications are off — `check.is` narrows the value. if (!check.is('settings', s => s.notifications)) return; // Debounce sound so a burst of messages plays one beep. actions.debounce(800).playSound?.('beep'); actions.showToast?.({ title: event.payload.author, body: event.payload.text, }); },});
Один inline-обобщённый параметр описывает все порты триггера — три словаря с типами событий, условий и действий. Контекст обработчика ctx теперь строго типизирован: попробуй передать неверное имя события или несовместимый payload — TypeScript остановит на этапе компиляции.
Нажми «send a fake message» в компоненте Chat. Слой уведомлений напишет в консоль или покажет тост. Выключи settings.notifications — и он замолчит. Весь сценарий целиком — это один файл, и каждый компонент может расти независимо.