Skip to content
GitHubXDiscord

createTrigger

Stable · since 0.1.0

The only constructor in Triggery. Returns a Trigger<Schema> registered in the given runtime (or the default runtime if omitted). Most apps create one trigger per scenario, one file per trigger.

import { createTrigger } from '@triggery/core';
function createTrigger<S extends TriggerSchema>(
  config: CreateTriggerConfig<S>,
  runtime?: Runtime,
): Trigger<S>;

The generic S is the schema — three optional maps for events, conditions and actions. It is never inferred in normal use; always passed explicitly.

type TriggerSchema = {
  events?:     Record<string, unknown>;  // payload type per event name
  conditions?: Record<string, unknown>;  // value type per condition name
  actions?:    Record<string, unknown>;  // payload type per action name
};

For a void payload, use void (events) or undefined (actions). Names can be any valid string; convention is kebab-case verbs for events, camelCase for conditions and actions.

FieldTypeRequiredDefaultDescription
idstring (literal)yesUnique runtime registry key. Must be a string literal — see no-dynamic-id.
eventsreadonly EventKey<S>[]yesEvent names from S['events'] this trigger reacts to.
requiredreadonly ConditionKey<S>[]no[]Conditions that must be registered for the handler to run.
schedule'microtask' | 'sync'no'microtask'When to dispatch matching events.
concurrencyConcurrencyStrategyno'take-latest'How async handler runs interact.
scopestringno''Restrict to a <TriggerScope id="…"> subtree.
handlerTriggerHandler<S>yesFunction called when an event matches and required are satisfied.

A Trigger<S> object — a stable identity you can pass to React/Solid/Vue hooks.

MethodDescription
trigger.idSame string you passed in.
trigger.enable()Re-enable a disabled trigger.
trigger.disable()Skip future events (records 'disabled' in inspector).
trigger.isEnabled()Boolean.
trigger.inspect()Latest TriggerInspectSnapshot or undefined.
trigger.dispose()Unregister from the runtime. Rare — use in tests.
trigger.namedHooks()Throws on @triggery/core directly — use createNamedHooks from a binding.
import { createTriggerfunction createTrigger<S extends TriggerSchema>(config: CreateTriggerConfig<S>, runtime?: Runtime): Trigger<S>
Create a trigger and register it in a runtime (the default runtime if none is passed).
@example```ts const messageTrigger = createTrigger<{ events: { 'new-message': { author: string; text: string } }; conditions: { user: { id: string }; settings: { sound: boolean } }; actions: { showToast: { title: string }; playSound: void }; }>({ id: 'message-received', events: ['new-message'], required: ['user', 'settings'], handler({ event, conditions, actions, check }) { if (!conditions.user || !conditions.settings) return; // V1: manual narrowing if (check.is('settings', (s) => s.sound)) actions.playSound?.(); actions.showToast?.({ title: event.payload.author }); }, }); ```
} from '@triggery/core';
const ping
const ping: Trigger<{
    events: {
        tick: number;
    };
}>
= createTrigger
createTrigger<{
    events: {
        tick: number;
    };
}>(config: CreateTriggerConfig<{
    events: {
        tick: number;
    };
}>, runtime?: Runtime): Trigger<{
    events: {
        tick: number;
    };
}>
Create a trigger and register it in a runtime (the default runtime if none is passed).
@example```ts const messageTrigger = createTrigger<{ events: { 'new-message': { author: string; text: string } }; conditions: { user: { id: string }; settings: { sound: boolean } }; actions: { showToast: { title: string }; playSound: void }; }>({ id: 'message-received', events: ['new-message'], required: ['user', 'settings'], handler({ event, conditions, actions, check }) { if (!conditions.user || !conditions.settings) return; // V1: manual narrowing if (check.is('settings', (s) => s.sound)) actions.playSound?.(); actions.showToast?.({ title: event.payload.author }); }, }); ```
<{
events
events: {
    tick: number;
}
: { ticktick: number: number };
}>({ idid: string: 'demo:ping', eventsevents: readonly "tick"[]: ['tick'], handler
handler: TriggerHandler<{
    events: {
        tick: number;
    };
}, never>
({ event
event: {
    readonly name: "tick";
    readonly payload: number;
}
}) {
consolevar console: Console.logConsole.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
('tick', event
event: {
    readonly name: "tick";
    readonly payload: number;
}
.payloadpayload: number);
}, });
import { createTriggerfunction createTrigger<S extends TriggerSchema>(config: CreateTriggerConfig<S>, runtime?: Runtime): Trigger<S>
Create a trigger and register it in a runtime (the default runtime if none is passed).
@example```ts const messageTrigger = createTrigger<{ events: { 'new-message': { author: string; text: string } }; conditions: { user: { id: string }; settings: { sound: boolean } }; actions: { showToast: { title: string }; playSound: void }; }>({ id: 'message-received', events: ['new-message'], required: ['user', 'settings'], handler({ event, conditions, actions, check }) { if (!conditions.user || !conditions.settings) return; // V1: manual narrowing if (check.is('settings', (s) => s.sound)) actions.playSound?.(); actions.showToast?.({ title: event.payload.author }); }, }); ```
} from '@triggery/core';
type Settings
type Settings = {
    sound: boolean;
    notifications: boolean;
}
= { soundsound: boolean: boolean; notificationsnotifications: boolean: boolean };
type Message
type Message = {
    author: string;
    text: string;
    channelId: string;
}
= { authorauthor: string: string; texttext: string: string; channelIdchannelId: string: string };
const messageTrigger
const messageTrigger: Trigger<{
    events: {
        "new-message": Message;
    };
    conditions: {
        settings: Settings;
        activeChannelId: string | null;
    };
    actions: {
        showToast: {
            title: string;
            body: string;
        };
        playSound: "beep";
    };
}>
= createTrigger
createTrigger<{
    events: {
        "new-message": Message;
    };
    conditions: {
        settings: Settings;
        activeChannelId: string | null;
    };
    actions: {
        showToast: {
            title: string;
            body: string;
        };
        playSound: "beep";
    };
}>(config: CreateTriggerConfig<{
    events: {
        "new-message": Message;
    };
    conditions: {
        settings: Settings;
        activeChannelId: string | null;
    };
    actions: {
        showToast: {
            title: string;
            body: string;
        };
        playSound: "beep";
    };
}>, runtime?: Runtime): Trigger<{
    events: {
        "new-message": Message;
    };
    conditions: {
        settings: Settings;
        activeChannelId: string | null;
    };
    actions: {
        showToast: {
            title: string;
            body: string;
        };
        playSound: "beep";
    };
}>
Create a trigger and register it in a runtime (the default runtime if none is passed).
@example```ts const messageTrigger = createTrigger<{ events: { 'new-message': { author: string; text: string } }; conditions: { user: { id: string }; settings: { sound: boolean } }; actions: { showToast: { title: string }; playSound: void }; }>({ id: 'message-received', events: ['new-message'], required: ['user', 'settings'], handler({ event, conditions, actions, check }) { if (!conditions.user || !conditions.settings) return; // V1: manual narrowing if (check.is('settings', (s) => s.sound)) actions.playSound?.(); actions.showToast?.({ title: event.payload.author }); }, }); ```
<{
events
events: {
    'new-message': Message;
}
: { 'new-message': Message
type Message = {
    author: string;
    text: string;
    channelId: string;
}
};
conditions
conditions: {
    settings: Settings;
    activeChannelId: string | null;
}
: { settingssettings: Settings: Settings
type Settings = {
    sound: boolean;
    notifications: boolean;
}
; activeChannelIdactiveChannelId: string | null: string | null };
actions
actions: {
    showToast: {
        title: string;
        body: string;
    };
    playSound: "beep";
}
: { showToast
showToast: {
    title: string;
    body: string;
}
: { titletitle: string: string; bodybody: string: string }; playSoundplaySound: "beep": 'beep' };
}>({ idid: string: 'message-received', eventsevents: readonly "new-message"[]: ['new-message'], requiredrequired?: readonly ("settings" | "activeChannelId")[] | undefined
Required condition keys. The trigger will not run unless all of them are registered.
: ['settings'],
handler
handler: TriggerHandler<{
    events: {
        "new-message": Message;
    };
    conditions: {
        settings: Settings;
        activeChannelId: string | null;
    };
    actions: {
        showToast: {
            title: string;
            body: string;
        };
        playSound: "beep";
    };
}, never>
({ event
event: {
    readonly name: "new-message";
    readonly payload: Message;
}
, conditions
conditions: ConditionsCtx<{
    settings: Settings;
    activeChannelId: string | null;
}, never>
, actions
actions: ActionsCtx<{
    showToast: {
        title: string;
        body: string;
    };
    playSound: "beep";
}>
, check
check: CheckCtx<{
    settings: Settings;
    activeChannelId: string | null;
}>
}) {
if (event
event: {
    readonly name: "new-message";
    readonly payload: Message;
}
.payloadpayload: Message.channelIdchannelId: string === conditions
conditions: ConditionsCtx<{
    settings: Settings;
    activeChannelId: string | null;
}, never>
.activeChannelIdactiveChannelId?: string | null | undefined) return;
if (!check
check: CheckCtx<{
    settings: Settings;
    activeChannelId: string | null;
}>
.isis<"settings">(key: "settings", predicate: (value: Settings) => boolean): boolean('settings', ss: Settings => ss: Settings.notificationsnotifications: boolean)) return;
actions
actions: ActionsCtx<{
    showToast: {
        title: string;
        body: string;
    };
    playSound: "beep";
}>
.debounce
function debounce(ms: number): ActionsCtx<{
    showToast: {
        title: string;
        body: string;
    };
    playSound: "beep";
}>
(800).playSoundplaySound?: ((payload: "beep") => void) | undefined?.('beep');
actions
actions: ActionsCtx<{
    showToast: {
        title: string;
        body: string;
    };
    playSound: "beep";
}>
.showToast
showToast?: ((payload: {
    title: string;
    body: string;
}) => void) | undefined
?.({
titletitle: string: event
event: {
    readonly name: "new-message";
    readonly payload: Message;
}
.payloadpayload: Message.authorauthor: string,
bodybody: string: event
event: {
    readonly name: "new-message";
    readonly payload: Message;
}
.payloadpayload: Message.texttext: string,
}); }, });
import { createTriggerfunction createTrigger<S extends TriggerSchema>(config: CreateTriggerConfig<S>, runtime?: Runtime): Trigger<S>
Create a trigger and register it in a runtime (the default runtime if none is passed).
@example```ts const messageTrigger = createTrigger<{ events: { 'new-message': { author: string; text: string } }; conditions: { user: { id: string }; settings: { sound: boolean } }; actions: { showToast: { title: string }; playSound: void }; }>({ id: 'message-received', events: ['new-message'], required: ['user', 'settings'], handler({ event, conditions, actions, check }) { if (!conditions.user || !conditions.settings) return; // V1: manual narrowing if (check.is('settings', (s) => s.sound)) actions.playSound?.(); actions.showToast?.({ title: event.payload.author }); }, }); ```
} from '@triggery/core';
const fetchTrigger
const fetchTrigger: Trigger<{
    events: {
        "fetch-user": string;
    };
    actions: {
        setUser: {
            id: string;
            name: string;
        };
    };
}>
= createTrigger
createTrigger<{
    events: {
        "fetch-user": string;
    };
    actions: {
        setUser: {
            id: string;
            name: string;
        };
    };
}>(config: CreateTriggerConfig<{
    events: {
        "fetch-user": string;
    };
    actions: {
        setUser: {
            id: string;
            name: string;
        };
    };
}>, runtime?: Runtime): Trigger<{
    events: {
        "fetch-user": string;
    };
    actions: {
        setUser: {
            id: string;
            name: string;
        };
    };
}>
Create a trigger and register it in a runtime (the default runtime if none is passed).
@example```ts const messageTrigger = createTrigger<{ events: { 'new-message': { author: string; text: string } }; conditions: { user: { id: string }; settings: { sound: boolean } }; actions: { showToast: { title: string }; playSound: void }; }>({ id: 'message-received', events: ['new-message'], required: ['user', 'settings'], handler({ event, conditions, actions, check }) { if (!conditions.user || !conditions.settings) return; // V1: manual narrowing if (check.is('settings', (s) => s.sound)) actions.playSound?.(); actions.showToast?.({ title: event.payload.author }); }, }); ```
<{
events
events: {
    'fetch-user': string;
}
: { 'fetch-user': string };
actions
actions: {
    setUser: {
        id: string;
        name: string;
    };
}
: { setUser
setUser: {
    id: string;
    name: string;
}
: { idid: string: string; namename: string: string } };
}>({ idid: string: 'fetch-user', eventsevents: readonly "fetch-user"[]: ['fetch-user'], concurrencyconcurrency?: ConcurrencyStrategy | undefined
Concurrency strategy applied across handler runs (default: `'take-latest'`). - `take-latest` — new run aborts the previous (`signal.aborted` becomes true). - `take-every` — every run proceeds independently, no aborts. - `take-first` / `exhaust` — new runs are skipped while one is still in flight. - `queue` — new runs wait for the previous to finish (serialized). - `sync` — like `take-every`; provided as a documentation marker.
: 'take-latest',
async handler
handler: TriggerHandler<{
    events: {
        "fetch-user": string;
    };
    actions: {
        setUser: {
            id: string;
            name: string;
        };
    };
}, never>
({ event
event: {
    readonly name: "fetch-user";
    readonly payload: string;
}
, actions
actions: ActionsCtx<{
    setUser: {
        id: string;
        name: string;
    };
}>
, signalsignal: AbortSignal }) {
const resconst res: Response = await fetchfunction fetch(input: string | URL | Request, init?: RequestInit): Promise<Response> (+1 overload)
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/fetch)
(`/api/users/${event
event: {
    readonly name: "fetch-user";
    readonly payload: string;
}
.payloadpayload: string}`, { signalRequestInit.signal?: AbortSignal | null | undefined
An AbortSignal to set request's signal.
});
if (signalsignal: AbortSignal.abortedAbortSignal.aborted: boolean
The **`aborted`** read-only property returns a value that indicates whether the asynchronous operations the signal is communicating with are aborted (`true`) or not (`false`). [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/aborted)
) return;
actions
actions: ActionsCtx<{
    setUser: {
        id: string;
        name: string;
    };
}>
.setUser
setUser?: ((payload: {
    id: string;
    name: string;
}) => void) | undefined
?.(await resconst res: Response.jsonBody.json(): Promise<any>
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/json)
());
}, });
import { createRuntimefunction createRuntime(options?: RuntimeOptions): Runtime, createTriggerfunction createTrigger<S extends TriggerSchema>(config: CreateTriggerConfig<S>, runtime?: Runtime): Trigger<S>
Create a trigger and register it in a runtime (the default runtime if none is passed).
@example```ts const messageTrigger = createTrigger<{ events: { 'new-message': { author: string; text: string } }; conditions: { user: { id: string }; settings: { sound: boolean } }; actions: { showToast: { title: string }; playSound: void }; }>({ id: 'message-received', events: ['new-message'], required: ['user', 'settings'], handler({ event, conditions, actions, check }) { if (!conditions.user || !conditions.settings) return; // V1: manual narrowing if (check.is('settings', (s) => s.sound)) actions.playSound?.(); actions.showToast?.({ title: event.payload.author }); }, }); ```
} from '@triggery/core';
const runtimeconst runtime: Runtime = createRuntimefunction createRuntime(options?: RuntimeOptions): Runtime({ inspectorinspector?: InspectorOption | undefined
Enable / disable the per-run inspector. See {@link InspectorOption } .
: { devdev?: boolean | undefined: true, prodprod?: boolean | undefined: false } });
const trigger
const trigger: Trigger<{
    events: {
        hi: void;
    };
}>
= createTrigger
createTrigger<{
    events: {
        hi: void;
    };
}>(config: CreateTriggerConfig<{
    events: {
        hi: void;
    };
}>, runtime?: Runtime): Trigger<{
    events: {
        hi: void;
    };
}>
Create a trigger and register it in a runtime (the default runtime if none is passed).
@example```ts const messageTrigger = createTrigger<{ events: { 'new-message': { author: string; text: string } }; conditions: { user: { id: string }; settings: { sound: boolean } }; actions: { showToast: { title: string }; playSound: void }; }>({ id: 'message-received', events: ['new-message'], required: ['user', 'settings'], handler({ event, conditions, actions, check }) { if (!conditions.user || !conditions.settings) return; // V1: manual narrowing if (check.is('settings', (s) => s.sound)) actions.playSound?.(); actions.showToast?.({ title: event.payload.author }); }, }); ```
<{ events
events: {
    hi: void;
}
: { hihi: void: void } }>(
{ idid: string: 'demo:hi', eventsevents: readonly "hi"[]: ['hi'], handler
handler: TriggerHandler<{
    events: {
        hi: void;
    };
}, never>
() {
consolevar console: Console.logConsole.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
('hi');
}, }, runtimeconst runtime: Runtime, );