Mocking Stoat Discover
Or: Create a simple discover platform for your third-party Stoat instance
am in the process of writing a more "comprehensive" guide on self-hosting Stoat, however, I feel like talking about the main instance's "Discover Stoat" feature needs to have it's own standalone article.
Under the hood, Discover is your average NextJS application, rendering servers, bots and themes from a source JSON file that is generated/updated every couple of hours. In this article, I will only cover the IPC protocol that the app uses to communicate to the clients in order to show a join prompt, or in the case of bots, an invite dialog.
The protocol in a nutshell
Messages are passed to and from the frame using the iframe.contentWindow.postMessage and window.postMessage APIs. It communicates using objects, each having a unique type and a "source".
Source MUST be "discover", otherwise the client might outright reject the IPC message. And the client also MUST include a source of "revolt", to avoid discover rejecting your messages.
The frame may send the following messages to the client.
Client <- Frame
Theme
Set the theme of the current frame, usually sent after receiving init to allow the frame to use the current client's theme. The theme key must contain a valid Revite theme, to use the default colours, pass an empty object.
{
"type": "theme",
"source": "revolt",
"theme": {}
} Frame -> Client
Init
Discover is ready to send or receive events to and from the client.
{
"type": "init",
"source": "discover"
}Path
User switched tabs. Used for clients restore the last accessed tab.
{
"type": "path",
"path": "/discover/bots",
"source": "discover"
}Navigate
Tells the client to perform a navigation action, usually starting the "Accept Invite" or "Invite Bot" flow.
{
"type": "navigate",
"url" : "url_to_invite_or_bot"
}Apply Theme
Tells the client to apply the selected Revite theme, only works on the legacy web client.
{
"type": "applyTheme",
"theme": {
"variables": {},
"css": "css as string"
}
}As you can see, it's pretty simple
So why has no one made their own replacement for third-party instances?
Personally, I think it comes down to the fact that there aren't a lot of stoat instances in the wild just yet, and the ones that exist usually only need an admin panel.
But it annoys me that the FOSS people complain that the main discover service isn't open source, because technically it counts as a publicly available component of an AGPLv3 service, even though it's entirely separate, optional, and resides on its own repository.
Anyway, I also wanted to finally do my own replacement with most of the protocol implemented in the simplest way possible, basically, a discover MVP.
It's available on Tangled, licensed under the MIT license. The project is written in Go, using the fantastic labstack/echo library.
bunniesin.space/minidiscover
Minimum viable implementation of Stoat Discover
Feel free to fork the project and change it to your heart's content, or use it as a resource for your own implementation; but please, for the love of god, please don't use it as is in production.
Sources
Protocol reference: https://github.com/stoatchat/for-legacy-web/blob/57e8c0e274a48a913f1a33e406cfbfb68e8269ce/src/pages/discover/Discover.tsx
Cover art: Agnese Rudzīte on Unsplash
Did you enjoy this article?
Recommend it — Standard Reader surfaces well-loved writing to more readers across the network.