Overview
@lastshotlabs/slingshot-notifications is Slingshot’s shared notification package. It owns
notification records, user notification preferences, dispatcher scheduling, rate limiting,
preference resolution, and the builder/runtime surface that other packages use to enqueue or
deliver notifications.
The notification entities themselves follow the shared package-first/entity authoring model;
createNotificationsPackage() is the runtime shell that wires storage, dispatch, and delivery.
When To Use It
Section titled “When To Use It”Use this package when your app or plugin needs:
- persisted notification records
- user notification preferences and quiet-hours-aware resolution
- queued notification dispatch with a polling loop
- SSE delivery for the current user
- a common notification builder that feature packages can share
This is the right dependency for chat, community, push, and other product packages that need a shared notification backbone instead of private per-feature notification tables.
What You Need Before Wiring It In
Section titled “What You Need Before Wiring It In”The package declares slingshot-auth as a dependency. It expects the auth layer to be present
before notification routes and user-scoped SSE behavior are used.
The config is intentionally easy to start with. createNotificationsPackage() accepts a partial
config object and fills in defaults.
Minimum Setup
Section titled “Minimum Setup”With no config, the package already gives you:
- route mount path
/notifications - SSE endpoint
/notifications/sse - dispatcher enabled
- dispatcher interval
30000 - dispatcher max-per-tick
500 - memory-backed rate limiting
- default channel preferences of push, email, and in-app all enabled
The main knobs are:
mountPathsseEnabledssePathdispatcherrateLimitdefaultPreferencesreliability
For the PostgreSQL production path, opt into atomic notification persistence and event publication:
createNotificationsPackage({ reliability: { store: 'postgres', consumerName: 'slingshot-notifications-delivery-v1', },});The app must enable matching events.reliability outbox and inbox configuration. Immediate
notification creation and the governed notifications:notification.created envelope then
commit in one SQL transaction. Delivery runs through the stable named inbox consumer. Delivery
adapters receive the envelope event ID as context.idempotencyKey and should forward it to
external providers.
What You Get
Section titled “What You Get”The package provides:
- notification and notification-preference entities
- adapters resolved for the active store backend
- a notification builder surface created from package state
- a dispatcher that can poll and deliver queued notifications
- SSE routing for user-scoped notification streams
- a registration point for delivery adapters
At runtime, the package publishes typed capabilities:
NotificationsBuilderFactoryCap—({ source }) => NotificationBuilderfor building source-scoped notification buildersNotificationsDeliveryRegistryCap—.register(adapter)for registering delivery adaptersNotificationsHealthCap—() => NotificationsHealthfor the aggregated health snapshot
import type { HookServices } from '@lastshotlabs/slingshot-core';import { NotificationsHealthCap } from '@lastshotlabs/slingshot-notifications';
function readNotificationsHealth(ctx: HookServices) { return ctx.capabilities.require(NotificationsHealthCap)();}Internal state remains published under NOTIFICATIONS_PLUGIN_STATE_KEY for legacy consumers, but
new code should resolve the capabilities above.
Common Customization
Section titled “Common Customization”The first files to read are:
src/plugin.tsfor package lifecycle and runtime statesrc/public.tsfor the contract and capabilitiessrc/types/config.tsfor defaults and configurationsrc/builder.tsfor builder behaviorsrc/dispatcher.tsfor queue draining and deliverysrc/preferences.tsfor quiet hours and effective preference resolution
The highest-value changes are usually:
- dispatcher cadence and throughput
- default preference behavior
- rate-limit backend and thresholds
- delivery adapter registration
Gotchas
Section titled “Gotchas”mountPathmust start with/; trailing slashes are trimmed before routes are mounted.- Disabling the dispatcher does not remove notification persistence. It only stops the automatic polling loop that drains queued notifications.
- Delivery adapters are opt-in. Persisted notifications exist without them, but external delivery will not happen until another package registers an adapter.
- Package state is only complete after setup has resolved the entity adapters. If those adapters are missing, the package throws during setup instead of continuing in a half-wired state.
- SSE can be disabled independently from storage and dispatch. Treat it as a delivery surface, not the whole notification system.
Key Files
Section titled “Key Files”src/index.tssrc/plugin.tssrc/types/config.tssrc/builder.tssrc/dispatcher.tssrc/preferences.tssrc/sse.ts