Okay/Spec: Difference between revisions

No edit summary
No edit summary
 
(62 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{#css:Template:Colours.css}}{{#css:Template:Spec.css}}{{#css:
{{#css:
#firstHeading::after { content: '“an hypertext chat protocol”'; }
#firstHeading::after { content: " The Specification."; }
#toc {
}}{{spec|Okay.}}
  display: block;
  max-width: 24rem;
  margin: auto;
  background: transparent;
  border: none;
  color: var(--colour-grey-500);
}
.toctitle {
  margin-bottom: .5rem;
  display: grid;
  grid-template-columns: 1fr 2fr 1fr;
  justify-content: center;
  align-items: baseline;
}
.toctogglespan {
  grid-column: 3;
  color: var(--colour-grey-300);
  label { color: var(--colour-grey-500); }
  label:hover { color: var(--colour-grey-700); }
}
#mw-toc-heading {
  color: var(--colour-grey-600);
  font-family: inherit;
  text-transform: uppercase;
  font-weight: 500;
  letter-spacing: 7%;
  grid-column: 2;
}


#content a {
<p class="lede">
  font-variant: small-caps;
'''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?
  letter-spacing: 5%;
</p>
}
 
.lede {
  font-size: 1.1rem;
  color: var(--colour-grey-700);
  text-align: center !important;
  max-width: 36rem;
  margin-left: auto !important;
  margin-right: auto !important;
  margin-top: 0;
}
}}<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 is a group chat protocol. You join “Rooms” which contain “People” who “Talk” by sending and receiving “Messages” to and from a “Space”.
* ''[[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 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.


* A room is just a special URI which you can POST messages to and GET them back from at a later date.
== the warning (Hot Chip album) ==
* You can use WebSockets to get a real-time feed of events that you’re interested in.
This standard is '''deeply unserious'''. It is also '''deeply in progress'''. Implement at your own peril.
* Events are represented as HTML over the wire. This allows most client implementations skip the bit where they convert every message into HTML, while providing a stable format for non-web platforms to convert into their own inferior representations. This also lets you do really really stupid things with your messages.
* Every client is authenticated with a certificate that gets generated by the client on first use.


== 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?
* Should room names be unique?
* check out webauthn. maybe it's a better idea than client side certs lol


* <del>what “server” means is kind of nebulous.</del>
== connections ==
* what do we do about invalid html
Connections in Okay <span class="should">should</span> happen over HTTPS. Plaintext HTTP is acceptable for testing purposes.
 
== connection flow ==


A typical connection to an never before seen space usually goes like this:
A typical connection to a never before seen space usually goes like this:


* 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 examines the response;
* 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 the [[Okay#discovery|discovery requirements]], it generates a new certificate and registers itself with the spaces’s registration endpoint;
* 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.


== spaces ==
== 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) [https://microformats.org/wiki/Main_Page microformats].
 
=== 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].


A '''space''' is a container for rooms and accounts. In practical terms, a space is a HTML document that contains links to resources associated with the space; this document is known as the space's '''root'''. Each space root <span class="must">must</span> meet all [[Okay#discovery|discovery requirements]] and <span class="must">must</span> provide some metadata for clients to display, a [[Okay#rooms|room directory]], and preferences page.
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>


=== discovery ===
== sending stuff ==
Sometimes you need to send stuff to the server. That's fine. That's okay. You'll be okay.


For a client to recognise a URI as a space, it <span class="must">must</span>:
=== forms ===
Forms come in various forms.


* Respond with 200 OK upon a GET request;
Servers must accept form responses as <code>application/x-www-form-urlencoded</code> or <code>application/json</code>.
* Have a Content-Type of text/html;
* Respond with a valid HTML document, -- TODO: define valid;
* Have the Access-Control-Allow-Origin header set to <code>*</code>;
* Contain a valid [[Okay#the element thereof|discovery element]].


If multiple discovery elements are present on a page, the client <span class="should">should</span> ask the user to select which space it should use.
== 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'''.


==== the element thereof ====
=== discovery ===
For a client to recognise a document as containing a space, it <span class="must">must</span>:


The '''discovery element''' provides a list of resources associated with the space. They look like this:
* Respond with 200 OK upon a GET request;
* Have a MIME type of <code>text/html</code>;
* Respond with a valid HTML document; <span class="todo">define valid</span>
* Have the Access-Control-Allow-Origin header set to <code>*</code>;
* Contain valid [[Okay/Spec#the element thereof|ok-space]] markup.


<syntaxhighlight lang="html"><nav class=“ok-discover”>
If a document contains multiple spaces, the client <span class="should">should</span> prompt the user to select which space it should use.
  <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></syntaxhighlight>


The discovery element is defined as any element with the <code>ok-discover</code> class. Any non-void element can be the discovery element, but it really <span class="should">should</span> be a <code><nav /></code> if you can help it. The discovery element <span class="must">must</span> contain a number of anchor (<code><a /></code>) elements with valid <code>rel</code> and <code>href</code> attributes. Any invalid anchors <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.
==== 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">
  <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></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.


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">◈ '''Required'''</span>, <span class="optional>◇ '''Optional'''</span>, <span class="multiple">❖ '''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>
|<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>
|<span class="required"><span class="symbol">◈</span></span>
|<span class="required"><code>'''ok-register'''</code></span>
|<span class="required"><code>'''ok-register'''</code></span>
|The space's registration page.
|The space's registration page.
|-
|-
|<span class="required">◈</span>
|<span class="required"><span class="symbol">◈</span></span>
|<span class="required"><code>'''ok-prefs'''</code></span>
|<span class="required"><code>'''ok-prefs'''</code></span>
|The space's preferences page.
|The space's preferences page.
|}
|}
==== 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.
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" />
<!-- 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></syntaxhighlight>
==== metadata ====
Spaces can provide metadata about themselves to help users identify them.<syntaxhighlight lang="html"><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></syntaxhighlight>Space metadata can be declared anywhere within the ok-space element, using the class names given below:
{| class="wikitable"
|+
!Class Name
!Tag
!Purpose
|-
|<code>ok-icon</code>
|<code><img /></code> or <code><picture /></code>.
|An image to represent the space visually. These are typically square and rendered at small sizes.
|-
|<code>ok-title</code>
|Any non-void element, <code><nowiki><h1 /></nowiki></code> preferred.
|What the space is called in common parlance.
|-
|<code>ok-subtitle</code>
|Any non-void element, <code><nowiki><p /></nowiki></code> preferred.
|An extra bit of text that is displayed alongside the title in certain contexts.
|-
|<code>ok-description</code>
|Any non-void element, <code><nowiki><p /></nowiki></code> 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.
<span class="todo">class name bikeshedding</span>


== initiation ==
== initiation ==
A client <span class="must">must</span> register itself with a space before it can perform most actions.
=== 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.
=== registration ===
The registration page allows clients to register their public key and [[Okay/Spec#profiles|profile]] with the space.


A client must register itself with a space before it can send messages to rooms.
== 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]].


== the directory ==
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.
The '''Room Directory''' is a list of every room contained within the space. This list may be [[Okay#pagination|paginated]].


The path to the space's room directory <span class="must">must</span> be defined in its [[Okay#the element thereof|discovery element]] with the <code>ok-rooms</code> rel value.
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:
Here's an example of what a room directory might look like:<syntaxhighlight lang="html"><main class="ok-rooms">
<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" class="ok-room">General</a></li>
     <li><a href="/rooms/1" rel="ok-room">General</a></li>
     <li><a href="/rooms/evil" class="ok-room">Evildoing Room (evil)</a></li>
     <li><a href="/rooms/evil" rel="ok-room">Evildoing Room (evil)</a></li>
   </ul>
   </ul>
</main></syntaxhighlight>
</main></syntaxhighlight>A room directory is still just a rat in a cage.


=== sections ===
=== sections ===
Clients <span class="may">may</span> recognise a <code><section /></code> element containing a heading element of any level and any number of room links to be a "section" and present it as such in the user interface.
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.


== critical reception ==
== critical reception ==
It’s okay.
It’s okay.


[[Category:Pages that need things added to them]] [[Category:Pages with some amount of information in them]]
[[Category:Pages that need things added to them]]