Okay/Spec: Difference between revisions
No edit summary |
No edit summary |
||
| (14 intermediate revisions by one other user not shown) | |||
| Line 2: | Line 2: | ||
#firstHeading::after { content: " The Specification."; } | #firstHeading::after { content: " The Specification."; } | ||
}}{{spec|Okay.}} | }}{{spec|Okay.}} | ||
<p class="lede">'''Okay''' dares to ask the big questions. What if group chat was hypertext? What if discord let you write arbitrary HTML? What if protocols were bad?</p> | |||
<p class="lede"> | |||
'''Okay''' dares to ask the big questions. What if group chat was hypertext? What if discord let you write arbitrary HTML? What if protocols were bad? | |||
</p> | |||
== in summary == | == in summary == | ||
The '''Okay''' standard introduces a simple and flexible way to represent group chats within HTML documents, and some methods of interacting with them. | |||
* ''[[Okay/Spec#messages|Messages]]'' are sent to ''[[Okay/Spec#rooms|Rooms]]'', which are organised into ''[[Okay/Spec#spaces|Spaces]]''. | |||
* Like all good protocols, all communication happens over HTTP(S) and WebSockets. | |||
* | * All data in Okay is formatted according to standardised HTML patterns (much like how [https://microformats.org/wiki/about Microformats] work). We call these [[Okay/Spec#michaelformats|Michaelformats]] because I thought it would be funny. | ||
* You can | * You can receive events as they happen by [[Okay/Spec#subscriptions|subscribing]] to them. | ||
* | * Authentication uses the magic of client-side certificates. When a user adds a space, the client registers itself with the server using a fresh certificate, and then uses that to sign each subsequent request. | ||
== the warning (Hot Chip album) == | == the warning (Hot Chip album) == | ||
| Line 16: | Line 20: | ||
== conventions == | == conventions == | ||
The key words “<span class="must">must</span>”, “<span class="mustnt">must not</span>”, “<span class="must">required</span>”, “<span class="must">shall</span>”, “<span class="mustnt">shall not</span>”, “<span class="should">should</span>”, “<span class="shouldnt">should not</span>”, “<span class="should">recommended</span>”, “<span class="may">may</span>”, and “<span class="may">optional</span>” in this document are to be interpreted as described in [https://datatracker.ietf.org/doc/bcp14 BCP14], although we use bold colourful text instead of capitals (so it doesn’t look like we’re yelling at you. This is a relaxed and cordial protocol specification). | |||
The key words “<span class="must">must</span>”, “<span class="mustnt">must not</span>”, “<span class="must">required</span>”, “<span class="must">shall</span>”, “<span class="mustnt>shall not</span>”, “<span class="should">should</span>”, “<span class="shouldnt">should not</span>”, “<span class="should">recommended</span>”, “<span class="may">may</span>”, and “<span class="may">optional</span>” in this document are to be interpreted as described in [https://datatracker.ietf.org/doc/bcp14 BCP14], although we use bold colourful text instead of capitals (so it doesn’t look like we’re yelling at you. This is a relaxed and cordial protocol specification). | |||
== controversies == | == controversies == | ||
* <s>What “server” means is kind of nebulous.</s> | |||
* < | |||
* What do we do about invalid HTML? | * What do we do about invalid HTML? | ||
* Should room names be unique? | * Should room names be unique? | ||
* check out webauthn. maybe it's a better idea than client side certs lol | |||
== connections == | == connections == | ||
| Line 31: | Line 34: | ||
* The user hands the client a URI to examine; | * The user hands the client a URI to examine; | ||
* The client issues a GET request to the URI and checks the response against the [[Okay#discovery|discovery requirements]]; | * The client issues a GET request to the URI and checks the response against the [[Okay/Spec#discovery|discovery requirements]]; | ||
* If the response meets all requirements, it generates a new key pair and [[Okay#registration|registers]] itself; | * If the response meets all requirements, it generates a new key pair and [[Okay/Spec#registration|registers]] itself; | ||
* Once everyone’s happy, the client can begin posting messages to rooms. | * Once everyone’s happy, the client can begin posting messages to rooms. | ||
| Line 42: | Line 45: | ||
=== looking for stuff === | === looking for stuff === | ||
=== linking to stuff === | |||
Unless otherwise specified, michaelformats can be included inline or '''linked''' in a <code><a/></code> or <code><link/></code> element, using the michaelformat's name as the <code>rel</code> attribute. | |||
As an example, each of these elements are functionally equivalent:<syntaxhighlight lang="html"><!-- a room directory, rendered inline --> | |||
<div class="ok-rooms"> | |||
<!-- ... --> | |||
</div> | |||
== | <!-- a room directory, linked with an anchor tag --> | ||
<a href="/rooms/" rel="ok-rooms">Room Directory</a> | |||
<!-- a room directory, linked with an link tag --> | |||
<link href="/rooms/" rel="ok-rooms"></syntaxhighlight>The value of the <code>href</code> attribute <span class="must">must</span> be a ''valid URL potentially surrounded by spaces'', as [https://html.spec.whatwg.org/multipage/urls-and-fetching.html#valid-url-potentially-surrounded-by-spaces defined in the HTML standard]. | |||
When a client encounters a URI with a fragment, it <span class="must">must</span> search for an element with a matching <code>id</code> in the linked document. If the specified element is present, the client <span class="mustnt">must not</span> scan the document for the desired markup, and instead consider the linked element to be the desired markup. If multiple instances of the same <code>id</code> exist in the document, the client <span class="must">must</span> ignore all but the first instance. <span class="todo">make this make sense</span> | When a client encounters a URI with a fragment, it <span class="must">must</span> search for an element with a matching <code>id</code> in the linked document. If the specified element is present, the client <span class="mustnt">must not</span> scan the document for the desired markup, and instead consider the linked element to be the desired markup. If multiple instances of the same <code>id</code> exist in the document, the client <span class="must">must</span> ignore all but the first instance. <span class="todo">make this make sense</span> | ||
| Line 58: | Line 70: | ||
== spaces == | == spaces == | ||
Conceptually, a '''space''' is an isolated container that stores room state and user data. They are each represented by a [[Okay/Spec#ok-space|HTML element]] which provides URIs for clients to send their requests to (for example, its [[Okay/Spec#rooms|room directory]] or [[Okay/Spec#initiation|registration page]]). The URI of the document that contains this is called the space’s '''root URI'''. | |||
Conceptually, a '''space''' is an isolated container that stores room state and user data. They are each represented by a [[Okay#ok-space|HTML element]] which provides URIs for clients to send their requests to (for example, its [[Okay#rooms|room directory]] or [[Okay#initiation|registration page]]). The URI of the document that contains this is called the space’s '''root URI'''. | |||
=== discovery === | === discovery === | ||
For a client to recognise a document as containing a space, it <span class="must">must</span>: | For a client to recognise a document as containing a space, it <span class="must">must</span>: | ||
| Line 69: | Line 79: | ||
* Respond with a valid HTML document; <span class="todo">define valid</span> | * Respond with a valid HTML document; <span class="todo">define valid</span> | ||
* Have the Access-Control-Allow-Origin header set to <code>*</code>; | * Have the Access-Control-Allow-Origin header set to <code>*</code>; | ||
* Contain valid [[Okay#the element thereof|ok-space]] markup. | * Contain valid [[Okay/Spec#the element thereof|ok-space]] markup. | ||
If a document contains multiple spaces, the client <span class="should">should</span> prompt the user to select which space it should use. | If a document contains multiple spaces, the client <span class="should">should</span> prompt the user to select which space it should use. | ||
==== ok-space ==== | ==== ok-space ==== | ||
Spaces are declared using the '''ok-space''' [[Okay/Spec#michaelformats|michaelformat]]. Upon retrieving a document, the client <span class="must">must</span> scan for elements with the <code>ok-space</code> class, as well as [[Okay/Spec#linking to other spaces|links and anchors]] with the <code>ok-space</code> rel attribute. Here's an example of valid <code>ok-space</code> markup:<syntaxhighlight lang="html"><nav class="ok-space"> | |||
Spaces are declared using the '''ok-space''' [[Okay#michaelformats|michaelformat]]. Upon retrieving a document, the client <span class="must">must</span> scan for elements with the <code>ok-space</code> class, as well as [[Okay#linking to other spaces|links and anchors]] with the <code>ok-space</code> rel attribute. Here's an example of valid <code>ok-space</code> markup: | |||
<syntaxhighlight lang="html"><nav class="ok-space"> | |||
<h1>This is an Okay space</h1> | <h1>This is an Okay space</h1> | ||
<a href="/rooms/" rel="ok-rooms">Rooms</a> | <a href="/rooms/" rel="ok-rooms">Rooms</a> | ||
<a href="/register/" rel="ok-register">Registration</a> | <a href="/register/" rel="ok-register">Registration</a> | ||
<a href="/prefs/" rel="ok-prefs">Preferences</a> | <a href="/prefs/" rel="ok-prefs">Preferences</a> | ||
</nav></syntaxhighlight> | </nav></syntaxhighlight>For an element to be considered valid <code>ok-space</code> markup, it <span class="must">must</span> be a non-void element (ideally a <code><nav /></code>) with the <code>ok-space</code> class and contain anchor elements with valid <code>rel</code> and <code>href</code> attributes. Any invalid anchors or elements not specified in the format <span class="must">must</span> be ignored by the client. The inner text of the anchor elements is not significant and <span class="must">must</span>be ignored by clients. | ||
For an element to be considered valid <code>ok-space</code> markup, it <span class="must">must</span> be a non-void element (ideally a <code><nav /></code>) with the <code>ok-space</code> class and contain anchor elements with valid <code>rel</code> and <code>href</code> attributes. Any invalid anchors or elements not specified in the format <span class="must">must</span> be ignored by the client. The inner text of the anchor elements is not significant and <span class="must">must</span> be ignored by clients. | |||
A list of valid anchor <code>rel</code> attributes and their purposes is described below: | A list of valid anchor <code>rel</code> attributes and their purposes is described below: | ||
'''Key''': <span class="required"><span class="symbol">◈</span> '''required'''</span>, <span class="optional><span class="symbol">◇</span> '''optional'''</span>, <span class="multiple"><span class="symbol">❖</span> '''can be specified multiple times''' | '''Key''': <span class="required"><span class="symbol">◈</span> '''required'''</span>, <span class="optional"><span class="symbol">◇</span> '''optional'''</span>, <span class="multiple"><span class="symbol">❖</span> '''can be specified multiple times'''</span> | ||
{| class="wikitable" | {| class="wikitable" | ||
|+ | |+ | ||
|<span class="required"><span class="symbol">◈</span></span> | |<span class="required"><span class="symbol">◈</span></span> | ||
|<span class="required"><code>'''ok-rooms'''</code></span> | |<span class="required"><code>'''ok-rooms'''</code></span> | ||
|The space's [[Okay#the directory|room directory]]. | |The space's [[Okay/Spec#the directory|room directory]]. | ||
|- | |- | ||
|<span class="required"><span class="symbol">◈</span></span> | |<span class="required"><span class="symbol">◈</span></span> | ||
| Line 106: | Line 110: | ||
==== linking to other spaces ==== | ==== linking to other spaces ==== | ||
A document can direct clients to another document containing a space using an <code><a /></code> or <code><link /></code> element with the <code>rel="ok-space"</code> attribute. The client <span class="must">must</span> scan the linked document for valid <code>ok-space</code> markup, but it <span class="mustnt">must not</span> follow any further links or anchors with the <code>rel="ok-space"</code> attribute. | A document can direct clients to another document containing a space using an <code><a /></code> or <code><link /></code> element with the <code>rel="ok-space"</code> attribute. The client <span class="must">must</span> scan the linked document for valid <code>ok-space</code> markup, but it <span class="mustnt">must not</span> follow any further links or anchors with the <code>rel="ok-space"</code> attribute. | ||
The URI provided <span class="may">may</span> include a fragment component to specify which element the client should treat as [[Okay#ok-space|ok-space]] markup (e.g., <code><nowiki>https://example.com/#my-elem</nowiki></code>). The linked element <span class="must">must</span> be valid <code>ok-space</code> markup. If the fragment is specified and the corresponding element is present in the linked document, the client <span class="mustnt">must not</span> scan any other part of the document for <code>ok-space</code> markup. <syntaxhighlight lang="html"><!-- link to a space with the id "space" --> | The URI provided <span class="may">may</span> include a fragment component to specify which element the client should treat as [[Okay/Spec#ok-space|ok-space]]<nowiki/>markup (e.g., <code><nowiki>https://example.com/#my-elem</nowiki></code>). The linked element <span class="must">must</span> be valid <code>ok-space</code> markup. If the fragment is specified and the corresponding element is present in the linked document, the client <span class="mustnt">must not</span> scan any other part of the document for <code>ok-space</code> markup.<syntaxhighlight lang="html"><!-- link to a space with the id "space" --> | ||
<link rel="ok-space" href="https://example.ok/#space" /> | <link rel="ok-space" href="https://example.ok/#space" /> | ||
<!-- anchors work, too. thanks to the lack of fragment (the bit after the #), | <!-- anchors work, too. thanks to the lack of fragment (the bit after the #), | ||
| Line 118: | Line 121: | ||
==== metadata ==== | ==== metadata ==== | ||
Spaces can provide metadata about themselves to help users identify them.<syntaxhighlight lang="html"><nav class="ok-space"> | Spaces can provide metadata about themselves to help users identify them.<syntaxhighlight lang="html"><nav class="ok-space"> | ||
<h1 class="ok-title"></h1> | <h1 class="ok-title"></h1> | ||
| Line 153: | Line 155: | ||
== initiation == | == initiation == | ||
A client <span class="must">must</span> register itself with a space before it can perform most actions. | |||
A client <span class="must">must</span> register itself with a space before it can | |||
=== keys === | === keys === | ||
When registering with a space, a client <span class="should">should</span> transparently generate a key pair (<span class="todo">what type(s)?</span>) and store it for use in subsequent requests. | When registering with a space, a client <span class="should">should</span> transparently generate a key pair (<span class="todo">what type(s)?</span>) and store it for use in subsequent requests. | ||
=== registration === | === registration === | ||
The registration page allows clients to register their public key and [[Okay/Spec#profiles|profile]] with the space. | |||
The | == directory == | ||
The '''room directory''' is represented using the <code>ok-rooms</code> [[Okay/Spec#michaelformats|michaelformat]]. It contains the list of every room in a space. This list <span class="may">may</span> be [[Okay/Spec#pagination|paginated]]. | |||
= | A space's room directory <span class="must">must</span> be present in its [[Okay/Spec#ok-space|ok-space]] element, either [[Okay/Spec#linking to stuff|linked]] using the <code>ok-rooms</code> rel value or included inline. | ||
Each room in the space <span class="must">must</span> be linked with a single <code><a /></code> element with the <code>ok-room</code> rel value. Rooms <span class="mustnt">must not</span> be included inline in the room directory. | |||
Here's an example of what a room directory might look like:<syntaxhighlight lang="html"><main class="ok-rooms"> | |||
Here's an example of what a room directory might look like: | |||
<syntaxhighlight lang="html"><main class="ok-rooms"> | |||
<h1>Rooms on This Server</h1> | <h1>Rooms on This Server</h1> | ||
<ul> | <ul> | ||
<li><a href="/rooms/1" | <li><a href="/rooms/1" rel="ok-room">General</a></li> | ||
<li><a href="/rooms/evil" | <li><a href="/rooms/evil" rel="ok-room">Evildoing Room (evil)</a></li> | ||
</ul> | </ul> | ||
</main></syntaxhighlight>A room directory is still just a rat in a cage. | </main></syntaxhighlight>A room directory is still just a rat in a cage. | ||
=== sections === | === sections === | ||
A <code><section /></code> element denotes a '''section''', which allows severs to provide more structure to their room directory. Sections <span class="must">must</span> have a heading of any level as a direct descendant and one or more room links. Anything within the section that isn't a header or room link <span class="must">must</span> be ignored by the client. | A <code><section /></code> element denotes a '''section''', which allows severs to provide more structure to their room directory. Sections <span class="must">must</span> have a heading of any level as a direct descendant and one or more room links. Anything within the section that isn't a header or room link <span class="must">must</span> be ignored by the client. | ||
== rooms == | == rooms == | ||
== messages == | == messages == | ||
== profiles == | == profiles == | ||
== subscriptions == | == subscriptions == | ||
== settings == | == settings == | ||
== pagination == | == pagination == | ||
Many lists can be '''paginated''' when it would be impractical to send its entire contents. This is common in message lists and room directories if you're getting a bit silly with it. | Many lists can be '''paginated''' when it would be impractical to send its entire contents. This is common in message lists and room directories if you're getting a bit silly with it. | ||
== critical reception == | == critical reception == | ||
It’s okay. | It’s okay. | ||
[[Category:Pages that need things added to them]] | [[Category:Pages that need things added to them]] | ||
Latest revision as of 18:29, 4 July 2025
Okay dares to ask the big questions. What if group chat was hypertext? What if discord let you write arbitrary HTML? What if protocols were bad?
in summary
The Okay standard introduces a simple and flexible way to represent group chats within HTML documents, and some methods of interacting with them.
- Messages are sent to Rooms, which are organised into Spaces.
- Like all good protocols, all communication happens over HTTP(S) and WebSockets.
- All data in Okay is formatted according to standardised HTML patterns (much like how Microformats work). We call these Michaelformats because I thought it would be funny.
- You can receive events as they happen by subscribing to them.
- Authentication uses the magic of client-side certificates. When a user adds a space, the client registers itself with the server using a fresh certificate, and then uses that to sign each subsequent request.
the warning (Hot Chip album)
This standard is deeply unserious. It is also deeply in progress. Implement at your own peril.
conventions
The key words “must”, “must not”, “required”, “shall”, “shall not”, “should”, “should not”, “recommended”, “may”, and “optional” in this document are to be interpreted as described in BCP14, although we use bold colourful text instead of capitals (so it doesn’t look like we’re yelling at you. This is a relaxed and cordial protocol specification).
controversies
What “server” means is kind of nebulous.- What do we do about invalid HTML?
- Should room names be unique?
- check out webauthn. maybe it's a better idea than client side certs lol
connections
Connections in Okay should happen over HTTPS. Plaintext HTTP is acceptable for testing purposes.
A typical connection to a never before seen space usually goes like this:
- The user hands the client a URI to examine;
- The client issues a GET request to the URI and checks the response against the discovery requirements;
- If the response meets all requirements, it generates a new key pair and registers itself;
- Once everyone’s happy, the client can begin posting messages to rooms.
processing documents
Much of the Okay protocol involves retrieving documents and scanning them for special markup.
michaelformats
The Okay Standard introduces a number of HTML patterns known as michaelformats. These are identical in concept to (and heavily plagiarise from) microformats.
looking for stuff
linking to stuff
Unless otherwise specified, michaelformats can be included inline or linked in a <a/> or <link/> element, using the michaelformat's name as the rel attribute.
As an example, each of these elements are functionally equivalent:
<!-- a room directory, rendered inline -->
<div class="ok-rooms">
<!-- ... -->
</div>
<!-- a room directory, linked with an anchor tag -->
<a href="/rooms/" rel="ok-rooms">Room Directory</a>
<!-- a room directory, linked with an link tag -->
<link href="/rooms/" rel="ok-rooms">
The value of the href attribute must be a valid URL potentially surrounded by spaces, as defined in the HTML standard.
When a client encounters a URI with a fragment, it must search for an element with a matching id in the linked document. If the specified element is present, the client must not scan the document for the desired markup, and instead consider the linked element to be the desired markup. If multiple instances of the same id exist in the document, the client must ignore all but the first instance. make this make sense
sending stuff
Sometimes you need to send stuff to the server. That's fine. That's okay. You'll be okay.
forms
Forms come in various forms.
Servers must accept form responses as application/x-www-form-urlencoded or application/json.
spaces
Conceptually, a space is an isolated container that stores room state and user data. They are each represented by a HTML element which provides URIs for clients to send their requests to (for example, its room directory or registration page). The URI of the document that contains this is called the space’s root URI.
discovery
For a client to recognise a document as containing a space, it must:
- Respond with 200 OK upon a GET request;
- Have a MIME type of
text/html; - Respond with a valid HTML document; define valid
- Have the Access-Control-Allow-Origin header set to
*; - Contain valid ok-space markup.
If a document contains multiple spaces, the client should prompt the user to select which space it should use.
ok-space
Spaces are declared using the ok-space michaelformat. Upon retrieving a document, the client must scan for elements with the ok-space class, as well as links and anchors with the ok-space rel attribute. Here's an example of valid ok-space markup:
<nav class="ok-space">
<h1>This is an Okay space</h1>
<a href="/rooms/" rel="ok-rooms">Rooms</a>
<a href="/register/" rel="ok-register">Registration</a>
<a href="/prefs/" rel="ok-prefs">Preferences</a>
</nav>
For an element to be considered valid ok-space markup, it must be a non-void element (ideally a <nav />) with the ok-space class and contain anchor elements with valid rel and href attributes. Any invalid anchors or elements not specified in the format must be ignored by the client. The inner text of the anchor elements is not significant and mustbe ignored by clients.
A list of valid anchor rel attributes and their purposes is described below:
Key: ◈ required, ◇ optional, ❖ can be specified multiple times
| ◈ | ok-rooms
|
The space's room directory. |
| ◈ | ok-register
|
The space's registration page. |
| ◈ | ok-prefs
|
The space's preferences page. |
linking to other spaces
A document can direct clients to another document containing a space using an <a /> or <link /> element with the rel="ok-space" attribute. The client must scan the linked document for valid ok-space markup, but it must not follow any further links or anchors with the rel="ok-space" attribute.
The URI provided may include a fragment component to specify which element the client should treat as ok-spacemarkup (e.g., https://example.com/#my-elem). The linked element must be valid ok-space markup. If the fragment is specified and the corresponding element is present in the linked document, the client must not scan any other part of the document for ok-space markup.
<!-- link to a space with the id "space" -->
<link rel="ok-space" href="https://example.ok/#space" />
<!-- anchors work, too. thanks to the lack of fragment (the bit after the #),
this link forces the client to rummage around for spaces like an animal -->
<a rel="ok-space" href="https://benfoldsfive.example/">
chat in the official Ben Folds Five space!!!
</a>
metadata
Spaces can provide metadata about themselves to help users identify them.
<nav class="ok-space">
<h1 class="ok-title"></h1>
<p class="ok-subtitle"></p>
<p class="ok-description"></p>
<img class="ok-icon" src="">
<!-- ... -->
</nav>
Space metadata can be declared anywhere within the ok-space element, using the class names given below:
| Class Name | Tag | Purpose |
|---|---|---|
ok-icon
|
<img /> or <picture />.
|
An image to represent the space visually. These are typically square and rendered at small sizes. |
ok-title
|
Any non-void element, <h1 /> preferred.
|
What the space is called in common parlance. |
ok-subtitle
|
Any non-void element, <p /> preferred.
|
An extra bit of text that is displayed alongside the title in certain contexts. |
ok-description
|
Any non-void element, <p /> preferred.
|
A long description of what the space is about. |
Clients may strip out child elements for some or all of the metadata elements, but should retain any text content from within the stripped elements.
class name bikeshedding
initiation
A client must register itself with a space before it can perform most actions.
keys
When registering with a space, a client should transparently generate a key pair (what type(s)?) and store it for use in subsequent requests.
registration
The registration page allows clients to register their public key and profile with the space.
directory
The room directory is represented using the ok-rooms michaelformat. It contains the list of every room in a space. This list may be paginated.
A space's room directory must be present in its ok-space element, either linked using the ok-rooms rel value or included inline.
Each room in the space must be linked with a single <a /> element with the ok-room rel value. Rooms must not be included inline in the room directory.
Here's an example of what a room directory might look like:
<main class="ok-rooms">
<h1>Rooms on This Server</h1>
<ul>
<li><a href="/rooms/1" rel="ok-room">General</a></li>
<li><a href="/rooms/evil" rel="ok-room">Evildoing Room (evil)</a></li>
</ul>
</main>
A room directory is still just a rat in a cage.
sections
A <section /> element denotes a section, which allows severs to provide more structure to their room directory. Sections must have a heading of any level as a direct descendant and one or more room links. Anything within the section that isn't a header or room link must be ignored by the client.
rooms
messages
profiles
subscriptions
settings
pagination
Many lists can be paginated when it would be impractical to send its entire contents. This is common in message lists and room directories if you're getting a bit silly with it.
critical reception
It’s okay.