Ad-hoc sends
When you don’t need a reusable definition, fire one channel directly:
import { notify } from "@warlock.js/notifications";
await notify.mail(user, { subject: "Welcome", html: "<p>Hi!</p>" });await notify.database(user, { type: "welcome", title: "Welcome!" });notify.<channel> is a typed proxy — payload is checked against the channel’s registry entry, and it works for any registered channel including custom ones. For multi-channel sends, use defineNotification; there’s no inline multi-channel form on purpose.
Raw targets
Section titled “Raw targets”Pass a string instead of a model to address it directly — no recipient lookup:
await notify.mail("guest@example.com", { subject: "Receipt", html: "…" });Runtime-dynamic channel
Section titled “Runtime-dynamic channel”When the channel name isn’t a compile-time literal:
const channel = await pickChannel(user);await notify.channel(channel).send(user, payload);Opting into gating
Section titled “Opting into gating”Preference/rate-limit gates need a notification type. Ad-hoc sends provide it explicitly, or it’s auto-detected from a database payload’s type:
await notify.mail(user, payload, { type: "marketing.weekly" }); // explicitawait notify.database(user, { type: "welcome", title: "Hi" }); // auto-detectedWithout a type, ad-hoc sends skip the preference gate (there’s nothing to gate on). force: true bypasses preferences; rate limits always apply when a type is known.
Errors
Section titled “Errors”A send to an unregistered channel rejects with ChannelNotFoundError immediately. A channel whose route() returns undefined for the recipient rejects with UnresolvableRouteError.
- Define a notification — the reusable, multi-channel path.
- Custom channels — make
notify.<yourChannel>exist.