Skip to the content
Krizaka TypeScript
Krizaka TypeScript

@krizaka/notifications

The bell, channels and preferences: one notify writes the item and one outbox message per enabled channel; burst caps hold under concurrency; the admin tunes defaults.

Install

bashTerminal
npm install @krizaka/notifications

Also published as subpath exports: @krizaka/notifications/settings, @krizaka/notifications/testkit.

The bell, the channels and the preferences for every Krizaka product. One notify writes the in-app item and appends one outbox message per enabled channel, respecting the account's matrix and a burst cap per category. No push or realtime import (the workers that deliver a channel are the product's), no database client, no wall clock.

  • Channels. app (the bell and the live event of the open pages, one switch), push (one message per registered device) and email. The outbox topics are notifications.live, notifications.push and notifications.email; the event is evt.notification.requested.v1, the name and the shape of Java's krizaka-notifications-api request (channel, recipient, template, locale, variables, plus the ids; channel is EMAIL, and PUSH / LIVE for the web). A product delivers e-mail with its own worker (@krizaka/email to render, @krizaka/mail to queue) or lets the Java service consume it.
  • The product declares its categories and their defaults (notificationSettings(declared) is the registry fragment); the admin tunes the default channels and the caps without a redeploy. A locked category (security, the account) cannot be switched off by anyone.
  • Burst caps. After burstMax notifications of one category to one account within burstWindowSeconds, the next ones are bell-only: the item is kept, no channel is used. The count and the insert run under a transaction-level advisory lock per account and category, so the cap holds under concurrency when notify gets the caller's tx.
  • Idempotent. dedupeKey makes one fact one notification; the outbox message ids derive from the item, so a retried append is a no-op.
  • The bell. list (newest first, cursor), unreadCount, markRead (the account's own items; the first read_at stays). An item whose app channel was off is kept for the history and the cap, never shown.
  • Preferences. preferences (every category by channel with its source: default, account, locked), setPreference, setMatrix (a preset applied).
  • Devices. registerDevice (a token belongs to one account; registering it again moves it), revokeDevice when the push service refuses it.
  • Privacy. The module holds no address (the product passes email per call); erase(accountId) removes the items, choices and devices; purge applies the retention.
import { createOutbox } from "@krizaka/outbox";
import { createNotifications, dbNotificationStore } from "@krizaka/notifications";
import { notificationSettings, readNotificationConfig } from "@krizaka/notifications/settings";

const declared = {
  messages: { defaults: { app: true, push: true, email: true }, burst: { max: 5, windowSeconds: 3600 } },
  follows: { defaults: { app: true, push: false, email: false } },
  account: { locked: true, defaults: { app: true, push: true, email: true } },
};
// settingsRegistry = { ...otherSettings, ...notificationSettings(declared) }

const notifications = createNotifications({
  clock,
  outbox: createOutbox({ clock, settings: outboxSettings }),
  config: () => readNotificationConfig(declared, (key) => settings.get(key)),
});

// in the use case's transaction
await notifications.notify(tx, { accountId, category: "messages", template: "new-message", variables: { name }, locale: "fr", email, dedupeKey: `message:${messageId}` });

Tables (schema notifications, notificationsSchema): item, preference, device. notificationStoreContract (@krizaka/notifications/testkit) is the contract every store runs.

Apache-2.0.

Exports

The 38 names the package exports, read from its types.

NameKindWhat it is
CategoryDefaultstypeA category as the product declares it.
categoryOffunction
Channeltype
CHANNELconstantThe channels an account switches.
CHANNELSconstant
checkConfigfunction
checkInputfunction
Clocktype
createNotificationsfunctionThe notifications of a product.
dbNotificationStorefunctionThe PostgreSQL store of « notifications » over a Query, in schema notifications (or the one the product renamed it to).
Deliverytype
DELIVERYconstantWhat the outbox carries: the channel of Java's evt.notification.requested.v1 (EMAIL) and two more for the web (PUSH, LIVE).
Devicetype
ItemtypeOne line of the bell.
memoryNotificationStorefunctionAn in-memory store, for unit tests and demos: the behaviour of the database's (the contract kit runs on both).
NOTIFICATION_BOUNDSconstant
NOTIFICATION_CODEconstant
NOTIFICATION_DEFAULTSconstant
NOTIFICATION_EVENTconstantThe event the outbox carries, the name Java's krizaka-notifications-api gives its request.
NOTIFICATION_TOPICconstantOne topic per delivery, so a worker claims only what it delivers (notifications.email, notifications.push, notifications.live).
NotificationCodetype
NotificationConfigtypeThe categories (declared by the product, tuned by the admin) and the retention.
NotificationDepstype
NotificationErrorclass
NotificationOutboxtypeWhat the module needs of @krizaka/outbox (its Outbox satisfies it): append in the caller's transaction.
NotificationRequesttypeThe request one delivery worker receives: Java's NotificationRequest (channel, recipient, template, locale, variables) plus the ids.
Notificationstype
notificationsSchemaconstantThe tables of « notifications », in their own Postgres schema: item (the bell, and the history the burst caps count), preference (the account's explicit…
NotificationStoretypeWhere the state lives.
Notifiedtype
NotifyInputtype
Platformtype
PLATFORMconstant
PreferenceViewtypeWhat an account sees in its settings: every category, every channel, and why.
Querytype
resolveChannelsfunctionThe channels on for an account: the category's defaults, overridden by the account's choices, unless the category is locked.
uuidOffunctionA stable UUID (version 5 shaped) from a seed: the same fact appended twice is one outbox message.
viewOffunction

@krizaka/notifications/settings

NameKindWhat it is
CategoryDeclarationtypeWhat a product declares for a category; the admin tunes the values (except locked, which is code).
Declaredtype
notificationSettingsfunctionThe settings of « notifications » for the categories a product declares, a fragment it adds to its registry (@krizaka/notifications/settings): for each cat…
readNotificationConfigfunctionThe module's configuration as createNotifications takes it, from the product's accessor ((key) => service.get(key, ctx)).

@krizaka/notifications/testkit

NameKindWhat it is
atfunction
itemOffunctionAn item for tests; the account ids are UUIDs because the database's are.
notificationStoreContractfunctionWhat every NotificationStore adapter must do: the same behaviour behind the same port.
T0constant

Package

Version on npm0.2.2 (npm)
LicenceApache-2.0
Node.js>=22
Dependencies@krizaka/db workspace:^, @krizaka/settings workspace:^, @krizaka/time workspace:^
Peer dependenciesvitest >=4, zod >=3.23
Sourcenotifications

Changelog

0.2.2

Patch changes

  • The READMEs, comments and published declarations no longer name the products that left the organisation (krizaka/.github#413, rule no-departed-published). The sources were cleaned in #262 with an empty changeset, so the published tarballs still carried the old text; this release replaces them. No behaviour change.
  • Updated dependencies [2a7898c]
  • Updated dependencies [2272b57]

0.2.1

Patch changes

0.2.0

Minor changes

  • New package (#60): @krizaka/notifications. createNotifications (notify writing the bell item and one outbox message per enabled channel: live, e-mail, push per device, as evt.notification.requested.v1 in the shape of Java's request; list, unreadCount, markRead, preferences, setPreference, setMatrix, registerDevice, revokeDevice, purge, erase), per-category burst caps that hold under concurrency (advisory lock per account and category), locked categories, dedupeKey, notificationsSchema (notifications.item, notifications.preference, notifications.device), dbNotificationStore, memoryNotificationStore, @krizaka/notifications/settings (notificationSettings(declared), readNotificationConfig) and notificationStoreContract.

Patch changes

On this page