Plugins / Digests
Digests
Timezone-aware batching for anyone who set their notification frequency to daily or weekly.
Enabling it
import { digests } from "easy-ping/plugins/digests";
plugins: [preferences(), digests()],
The order in that array doesn't matter at runtime — digests declares dependsOn: ["preferences"]
and the library resolves initialization order from that, not from array position. It does need
preferences present, though; digests without a frequency to read has nothing to batch by.
Options
digests({
digestType: "digest", // the notification type the composed digest sends as
sendHour: 9, // local hour at which a daily digest becomes due
sendWeekday: 1, // weekly digests only; 0 = Sunday
channel: "email", // the only channel that makes sense today
maxUsersPerRun: 500, // safety valve on one cron sweep
})
digestType is a notification type you define yourself, with an email template that expects an
items array in its payload — the plugin composes that payload for you from everything that
accumulated.
How a digest gets composed
- A user sets a notification type's frequency to
"daily"or"weekly"via the preferences plugin. - Every matching
send()for that user and type gets deferred into a bucket instead of firing immediately — this happens transparently, inafterSend. - The
/digests/cronroute (hourly — see Cron sweep) checks whose local time has crossedsendHourin their own timezone (fromgetRecipients), composes one notification of typedigestTypeper due user, and sends it through the normal pipeline — so digests get retry and backoff for free, same as anything else.
Why it depends on preferences
The frequency a digest respects — "instant" vs. "daily" vs. "weekly" — is preference state,
not digest state. Rather than duplicating that storage, digests reads it through the
preferences plugin's own store. This is also the pattern to copy if you're
writing a plugin that needs another plugin's data: declare dependsOn,
don't reimplement the table.