Osy#the first language built for agents
Agents firstAgentic appsWorkflowsDurable Execution — built inSecurityTestingThe editorThe UI modelOne program

Reference / Realtime

Here, Announce

live var here = Topic.For(<address>).Here; // the converging set of who is present Topic.For(<address>).Announce(<status>); // decorate your own entry

Who is currently on a presence topic, and what they say they are doing. Here is the converging set of people present, derived from their connections rather than written by the app; Announce decorates your own entry in that set and can never create or modify anybody else's, because the platform stamps who each entry is about.

stable1 example compiled by CIrealtimetopicpresenceui

Summary#

Here is who is currently connected to a presence topic; Announce says what you are doing. Both are read and written on a page, and neither needs a row: the set is derived from the connections themselves.

[Principal] entity User {
  [MaxLength(200)] string Email;
  security { allow read when IsAuthenticated; }
}

entity Room {
  [Required, MaxLength(120)] string Name;
  security { allow read, create when IsAuthenticated; }
}

entity Member {
  [Required] Room Room;
  [Required] User Person;
  security {
    allow read where Member.Any(m => m.Room == Room && m.Person == user);
    allow create where Person == user;
  }
}

class Presence {
  public User Person;        // STAMPED by the platform — who this entry is about
  public string Activity;    // announced by that person
}

topic RoomPresence(Guid roomId) {
  Candidates = u => Member.Any(m => m.Room.Id == roomId && m.Person == u);
  Carries    = Presence;
  Presence   = true;
}

[Page("/room/{roomId}/header")]
[Render(CSR)]
component RoomHeader(Guid roomId) {
  live var here = RoomPresence.For(roomId).Here;

  on mount {
    RoomPresence.For(roomId).Announce(new Presence { Activity = "reading" });
  }

  render {
    Text($"{here.Count} here");
    foreach (var p in here) { Text($"{p.Person.Email} — {p.Activity}"); }
  }
}

Signature#

live var here = Topic.For(<address>).Here;       // the set of people currently present
Topic.For(<address>).Announce(<status>);         // decorate your OWN entry; never somebody else's

Description#

Here is a set, not a feed#

A presence topic's Here is the converging set of who is currently present — not a log of arrivals and departures. Reading it as a set is what makes it self-correcting: a page that misses one update is fixed by the next, rather than drifting further from the truth with every missed event.

One person is one entry however many pages they have open.

Presence is derived from the connection#

You are in the set because your page is subscribed, and you leave because it went away. Nothing an app writes can put somebody in a room they are not in, or keep them there after they have gone — which is what makes the set worth trusting, and what stops a crashed browser staying online for ever.

Invisible mode needs no flag: a page that does not subscribe is not in the set.

An entry is your own type, with WHO filled in for you#

Carries names the class an entry is made of. Declare one field of your app's principal type on it — call it whatever you like — and the platform fills that field in. Everything else on the class is yours to announce.

class Presence {
  public User Person;        // the platform writes this; an app that tries is refused at compile time
  public string Activity;    // yours
}

The field is chosen by its type, not its name. A class with two principal-typed fields is ambiguous — the compiler cannot tell which one means who this entry is about — and is refused at the call site naming both.

Announce decorates your own entry, and only your own#

Announce adds your detail to that entry — a status, an activity. It cannot create or modify anybody else's, and that is structural rather than checked: the entry exists because your page is subscribed, and who it is about comes from your connection. There is nothing in an Announce that names a person, so announcing as somebody else is not a refused request — it is one you cannot write.

Presence vocabulary like away or do not disturb is the app's to define, not the platform's.

You see the people you may see#

A presence set contains real records, so it obeys the same read rules everything else does: each viewer's set is built under their own authority. Somebody present whose record you may not read is simply not in your set — the same answer a query would give you, not a blank silhouette.

Announcing is not a message#

An announcement is a statement about your current state, not an event. Re-announcing replaces; it does not accumulate, and nobody receives a history of what you were doing. One person is one entry however many pages they have open, and the most recent thing they said is what everyone sees.

Examples#

The example above is compiled by the documentation gate.

For what people SAY in a room rather than who is in it, see Listen.

See also#

  • Listen — receiving what was SAID in a room, rather than who is in it
  • topic — the declaration, Presence = true, and publishing
  • Realtime — realtime in one page
  • component — the live var a presence set feeds

Related

topic

A topic is a named, addressable realtime destination: a declared place to put a message so that every open page…

Listen

The receiving half of a topic, consumed on a page. Listen yields a stream of the topic's payloads, and a live var bound…

Realtime

Realtime in Osy# is one construct: a topic. A topic is a declared, addressable destination — publishing to one delivers…

component

The one archetype for all UI: a bounded reactive unit — typed props, reactive members (fields, `live`…