@open-matrix/system-notifications (1.1.32)

Published 2026-10-24 11:05:53 +00:00 by hivecast-admin

Installation

@open-matrix:registry=
npm install @open-matrix/system-notifications@1.1.32
"@open-matrix/system-notifications": "1.1.32"

About this package

system.notifications

Persistent per-home needs-you inbox, served by @open-matrix/system-notifications. The standalone factory and platform load-list use system.notifications. Configure the database through package config.databaseUrl (or an already configured system-postgres pool) before invoking storage operations.

Public inbox read/post/acknowledgement operations require busToken. Auth verifies the caller and resolves their home; an optional authorityRoot must be owned by or shared with that principal. Payload principal IDs never select the caller. Hosted forwarding stamps the delivered home.

  • notification.post {kind,title,body,source,action?:{application,route}}: source is a stable producer event ID, unique within the home. Replays return the existing notification. Sources beginning announcement:, agent:, alerts:, device:, access.request:, access.response:, account.lifecycle: or home.projection: are reserved for the scoped agent projection and canonical platform producers.
  • notification.list {limit?,cursor?} returns {ok,notifications,cursor}; unread first, newest first within read state. Pages default to 50, maximum 100. Cursors belong to one home.
  • notification.acknowledge {id} and notification.acknowledge.all {} are idempotent.
  • notification.watch {sinceSequence?} returns {ok,eventTopic,sequence,events}. Subscribe to notification.changed, then replay from the last durable sequence. Events invalidate the inbox; refresh list after acknowledgements because read ordering changes. NOTIFICATION_HISTORY_UNAVAILABLE requires refreshing the list and watch snapshot.

notification.source.reconcile {sourceKind,eventId} is central-only, excluded from hosted facades. It treats the payload as an untrusted hint and resolves device, access.request, access.response, account.lifecycle or home.projection facts from their fixed canonical owner operation. Only that verified result selects the recipient, reserved source, content and answered state; the reply contains no private event content or home. Canonical source delivery markers retain the event ID for 30 days independently of inbox eviction; duplicate hints never recreate an evicted notification, including an answered question. Source owners refuse facts older than this horizon. Each home allows at most 10,000 unexpired source markers, enough for ten complete inbox turnovers within a month. New events at capacity refuse internally with NOTIFICATION_SOURCE_CAPACITY_REACHED; the hint operation retains its privacy-preserving NOTIFICATION_SOURCE_UNAVAILABLE reply. Unexpired markers are never discarded to make room. Expired markers are collected on home access. Answered facts acknowledge the matching source; an already-evicted source is a successful no-op. Account deletion removes all source markers. The two lifecycle kinds are complete snapshots with an explicit current operator audience. Missing entries for an operator still in that audience are acknowledged atomically when a deletion finishes or a home becomes ready. Removing an operator deletes that source's inbox rows and replay markers for the removed home, so account and home details do not remain in another account's history. A deleted-home tombstone is skipped per root without rolling back healthy operator homes. The prefix lookup uses the partial notifications_active_source_prefix index rather than scanning unrelated or acknowledged notifications. Failed-terminal home rows and suspended-owner deletion rows remain durable owner facts; if still unresolved after retention evicts a card, their next snapshot intentionally pages every current operator again with a new delivery marker.

notification.alert.reconcile {eventId} is the hosted alert-specific hint. An alerts fact is owned by the home observability service. Its stable source identifies one rule and target. A firing fact creates one needs-you item and replays keep that item singular; a clearing fact deletes the current item and marker so a future firing can create a new item. The hosted reconcile facade derives the recipient from broker-stamped authority and namespace roots. The notification runtime reaches only a tenant's dedicated read-only alert source for alerts.notification.get. The account bridge remaps that exact inbox beneath system.notifications.alert-source.<tenant-root>; it neither exports Health nor grants the runtime a tenant subtree.

notification.agent.project {kind,title,body,source,action,occurredAt,acknowledged?} is the installed agent producer path. The hosted facade derives the home from the broker-authenticated tenant subject, refuses conflicting roots, and stamps both authorityRoot and namespaceRoot before forwarding. The private central actor requires these equal roots. This authorizes a tenant to populate its own inbox; it does not distinguish an agent from another peer authorized in that same tenant. Only agent.question/agent.failed, stable agent:<sha256> source IDs, Chat conversation routes, and events within 30 days are accepted. Device/access sources and management actions are refused. acknowledged:true acknowledges the source, and independent delivery markers prevent recreation after eviction. Root fields are transport-derived authority, never a user-selectable recipient.

notification.account.purge {principalId} is central-only and excluded from hosted facades. It independently confirms account deletion with auth.account.deletion.get and purges only the homes returned by that authority; caller roots are ignored. The operation removes notification content and replay history atomically and is idempotent. A tiny deleted-home tombstone retains only the root and sequence metadata to fence already-authenticated writes: every store operation checks it under the same advisory lock and refuses with NOTIFICATION_HOME_DELETED. No notification content remains.

Operator announcements use the same mount:

  • announcement.post {sessionToken,audience:'all'|'home',home?,title,body,severity,expiresAt} requires platform.operator verified by auth.platform.operator.check. home is required for home audience and forbidden for all audience; severity is info, warning or critical. Expiry must be a valid future timestamp. It returns {ok,announcement,deliveredHomes}.
  • announcement.list {busToken,authorityRoot?} returns {ok,announcements} with active announcements for the verified caller home, newest first. There are at most 1,000 active announcements platform-wide; posting beyond that refuses with ANNOUNCEMENT_CAPACITY_REACHED.
  • announcement.withdraw {sessionToken,id} requires the same operator capability and returns {ok,withdrawn}. Withdrawal permanently removes the announcement and its inbox copies; repeated withdrawal returns withdrawn:false.

Posting obtains current homes through the canonical auth.platform.userAuthorityRoots.list inventory, which includes organization homes and retired roots. Retired notification-home tombstones are skipped for all-home delivery and refused for explicit home delivery. The announcement, initial home copies, durable delivery markers and change events commit in one transaction. A failed transaction delivers nothing. New homes project active announcements on their first inbox or announcement operation, including watch before it selects replay. Each announcement appears only once per home, even after acknowledgement or inbox retention. Notification copies have kind announcement, stable source announcement:<id>, severity and expiry, with no navigation action. Source content and notification content are plain text.

The 1,000 active limit bounds the banner response and per-home delivery markers. Expired copies are removed when their home is accessed; expired announcement records and markers are collected on the next post, and withdrawn records immediately. This retains at most 1,000 announcement records after each successful post without retaining an announcement archive. Deleting an account removes its delivery markers and home-targeted announcements as well as inbox history. Changes are emitted only after commit; withdrawal and expiry invalidate affected home lists. Watch history can include historical posted content: consumers treat events as invalidations and obtain the active state from list, rather than displaying a replay as a current banner.

Retention is 1,000 notifications and 30 days per home, enforced transactionally on access and posting. This gives a month of actionable history without turning an inbox into an unbounded archive. Idle expired rows are removed on the next access. Replay retains at most 2,000 changes for 30 days. Public notification.post deduplicates while its card is retained. Agent/device/access projections use the independent 30-day source markers above. Titles are bounded to 240 characters, bodies 8,000, source IDs 512. Content is plain text; clients must render it as text. Application and route are navigation hints, not executable URLs.

Quiet does not mean resolved examines the distinction between inbox acknowledgement and the source owner's pending request. It proposes truthful unread wording and an owner-backed request presentation; acknowledgedAt and action presence alone do not establish whether a decision remains. This is an exploratory consumer/projection improvement, not a changed wire contract, new notification store or authorization to extend retention.

Development and deployment

pnpm test runs actor dispatch against a disposable PostgreSQL-compatible database. pnpm build builds the runtime and declarations. No shared environment is required.

Deployment uses one notification owner in the platform load list. The existing authenticated platform-owned service bridge imports its inbox into the services account. A token-protected stream import carries its changes to that account's Registry, which fans each event out only to its named home. Tenants receive the scoped facade and never import the central inbox.

Dependencies

Dependencies

ID Version
@open-matrix/contracts 1.1.32
@open-matrix/core 1.1.32
@open-matrix/system-postgres 1.1.32

Development Dependencies

ID Version
@matrix/test-utils 1.1.32
@open-matrix/package-runtime 1.1.32
@open-matrix/system-auth 1.1.32
@types/node ^20.0.0
esbuild ^0.25.0
tsx ^4.0.0
typescript ^5.3.0
Details
npm
2026-10-24 11:05:53 +00:00
0
18 KiB
Assets (1)
Versions (2) View all
1.1.33 2026-10-24
1.1.32 2026-10-24