BIN-5 A Renderable Conversation
When building stuff for the Fediverse there is a lot of stuff not covered in documentation or specification. One such thing is how to pass a conversation from the backend to the frontend to render it. This issue is further made difficult by json-ld being linked data, and thus not being a single thing, but something one can iteratively fetch more of. The approach described here is implemented as a renderer in buffalo-components in React see here.
What is a conversation?
First, when rendering one can safely ignore the CRUD operations (Create
, Update
, Delete
activities) as they contain little meaningful information. So what one
is commonly left with are Note
, Article
, and Page
objects. These can
be linked together in two ways:
- Object
two
has itsinReplyTo
property set to the id of objectone
- Object
one
containstwo
in itsreplies
collection
As option 1 is the one used in the Fediverse, we will focus on it.
We can now recursively define the conversation C
containing a certain object x
:
x
is a member ofC
y
is a member ofC
if there exists a memberz
ofC
withz["inReplyTo"] = y["id"]
ory["inReplyTo"] = z["id"]
What this does is define the conversation as including the replies of all it members, and all objects its members reply to. Unfortunately, this one cannot really implement this, so instead of the full conversation, one will usually use the conversation known to a server. Furthermore, additional restrictions might apply like:
- Only take public elements of a conversation
- Exclude muted people
- Filter by language
- Filter out members containing certain forms of lanugage
One can now represent the conversation as the set of its members. This will commonly be a JSON array. The elements of this array are representations of the ActivityStreams objects.
An element of a conversation
We now detail what we mean by a _representation of the ActivityStreams object. First this means that we are leaving the realm of linked data, as we do not wish to make the front end have to resolve links when rendering.
So in summary, the basic idea is simple: One should include everything that is necessary to render the object. This means that
- If present the value of the
attributedTo
property should be corresponding Actor object - If present tag properties should be resolved, e.g. Emojis
- One might decide to replace the
replies
,likes
, andshares
collections with their full representations, i.e. instead of references to pages, one just has a singleCollection
object.
There are a bunch of corner cases here, e.g. how to support FEP-e232: Object Links. If one wants to properly represent the linked object, one should probably also include it. However, one should not implement these things in a way that leads to infinite recursion.
The same thought applies to the likes
collection. One might want to resolve the activities and their actors in order to present a list of who liked an activity. However, one should stop resolving at one point, e.g. not resolve an actor’s outbox.
Further use: Archiving
As the list corresponding to a conversation can be used to render the entire conversation, it can also be used as an archive. When doing so, some care should be taken to include media resources. The above format only includes media resources via a reference.