Raise alerts
Rules over readings and Actions raise alerts, delivered only to the Worlds whose scope contains the object.
@klorad/notify watches a scene's events and raises an alert when a rule's condition becomes
true. Alerts are addressed to Worlds, and an alert reaches a World only if the object is in that
World's scope, so a crew is never alerted about what it cannot see.
import { createAccessPolicy } from "@klorad/access";
import { createScene } from "@klorad/api/world";
import { createNotifier, inAppChannel } from "@klorad/notify";
const scene = createScene({ coordinateSystem: { origin: { lat: 40.62637, lon: 22.94838 } } });
scene.add({
id: "door-3",
name: "Loading door 3",
position: { east: 40, north: 10 },
correspondence: "shadow",
binding: { source: "acs", entity: "door-3" },
properties: { zone: "dock" },
});
const policy = createAccessPolicy({
scene,
roles: { guard: "*" },
worlds: [{ id: "control", name: "Control room", scope: { all: true }, capabilities: { actions: "*" }, principals: [{ kind: "role", id: "guard" }] }],
});
const inbox = inAppChannel();
const notifier = createNotifier({
scene,
policy,
channels: [inbox],
rules: [
{ id: "forced", name: "Door forced", condition: { kind: "equals", quantity: "state", value: "forced" }, severity: "critical", worlds: ["control"] },
{
id: "warm",
name: "Dock too warm",
condition: { kind: "threshold", quantity: "temperature", op: "gt", value: 30 },
objects: { properties: { zone: "dock" } },
severity: "warning",
worlds: ["control"],
},
],
});
scene.observe({ objectId: "door-3", quantity: "state", value: "forced", observedAt: Date.now(), source: "acs" });
const [alert] = inbox.list(["control"]); // "Door forced: Loading door 3 state is forced"
if (alert) notifier.acknowledge(alert.id, { id: "maria", roles: ["guard"] });
export { notifier };Conditions
| Kind | Fires when |
|---|---|
threshold | A numeric reading crosses a limit (gt, gte, lt, lte). |
equals | A reading equals a value: a door state of "forced", a pump running of false. |
action | An Action ends with one of the given outcomes, for example every denied request. |
Threshold and equality rules fire on the edge: once when the condition becomes true for an object, and again only after it has stopped holding. A temperature hovering above the limit raises one alert, not one per reading. A late reading never fires a rule, because it does not change the current state.
objects narrows a rule to some objects, by id or by properties.
Channels
A channel delivers alerts. inAppChannel() keeps them in memory for a notification centre: it
lists alerts per World and can be subscribed to (it works with React's
useSyncExternalStore). A channel is one deliver(alert) method, so web push, email or a
message queue are small adapters in your server code. One failing channel does not stop the
others.
Acknowledging
notifier.acknowledge(alertId, actor) marks an alert acknowledged, and only for an actor who
may enter one of the alert's Worlds.
Something wrong or unclear? Tell your contact at Prieston Technologies.