diff --git a/.vitepress/config.mts b/.vitepress/config.mts index 59e3728..5ec6b16 100644 --- a/.vitepress/config.mts +++ b/.vitepress/config.mts @@ -17,7 +17,6 @@ export default defineConfig({ text: 'Spec Details', items: [ { text: 'Spec', link: '/spec' }, - { text: "Objects", link: '/objects' }, ] }, { @@ -25,6 +24,25 @@ export default defineConfig({ items: [ { text: "Content Format", link: '/structures/content-format' }, { text: "Custom Emoji", link: '/structures/custom-emoji' }, + { text: "Collection", link: '/structures/collection' }, + ] + }, + { + text: "Cryptography", + items: [ + { text: "Keys", link: "/cryptography/keys" } + ] + }, + { + text: "Objects", + link: "/objects", + items: [ + { + text: "Publications", link: "/objects/publications", items: [ + { text: "Note", link: "/objects/note" }, + { text: "Patch", link: "objects/patch" }, + ] + } ] } ], diff --git a/docs/api-examples.md b/docs/api-examples.md deleted file mode 100644 index 6bd8bb5..0000000 --- a/docs/api-examples.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -outline: deep ---- - -# Runtime API Examples - -This page demonstrates usage of some of the runtime APIs provided by VitePress. - -The main `useData()` API can be used to access site, theme, and page data for the current page. It works in both `.md` and `.vue` files: - -```md - - -## Results - -### Theme Data -
{{ theme }}
- -### Page Data -
{{ page }}
- -### Page Frontmatter -
{{ frontmatter }}
-``` - - - -## Results - -### Theme Data -
{{ theme }}
- -### Page Data -
{{ page }}
- -### Page Frontmatter -
{{ frontmatter }}
- -## More - -Check out the documentation for the [full list of runtime APIs](https://vitepress.dev/reference/runtime-api#usedata). diff --git a/docs/cryptography/keys.md b/docs/cryptography/keys.md new file mode 100644 index 0000000..44724bf --- /dev/null +++ b/docs/cryptography/keys.md @@ -0,0 +1,38 @@ +# Public Key Cryptography + +Lysand uses public key cryptography to sign objects. It is used to verify that an object was created by the user that claims to have created it. + +All public keys in Lysand **MUST** be encoded using the [ed25519](https://ed25519.cr.yp.to/) algorithm. This algorithm is used because it is fast, secure, and has a small key size. Legacy algorithms such as RSA are not supported, and **SHOULD NOT** be implemented using extensions for security. + +Other encryption algorithms could be implemented using extensions, but it is not recommended. + +Here is an example of generating a public-private key pair in TypeScript using the WebCrypto API: +```ts +const keyPair = await crypto.subtle.generateKey( + "Ed25519", + true, + ["sign", "verify"] +); + +// Encode both to base64 +const publicKey = btoa(String.fromCharCode(...new Uint8Array(await crypto.subtle.exportKey("spki", keyPair.publicKey)))); + +const privateKey = btoa(String.fromCharCode(...new Uint8Array(await crypto.subtle.exportKey("pkcs8", keyPair.privateKey)))); + +// Store the public and private key somewhere in your user data +``` + +> **Note**: Support for Ed25519 in the WebCrypto API is recent and may not be available in some older runtimes, such as Node.js or older browsers. + +Public key data is represented as such across the protocol: + +```ts +interface ActorPublicKeyData { + public_key: string; + actor: string; +} +``` + +The `public_key` field is a string that contains the public key of the user. It **MUST** be encoded using base64. + +The `actor` field is a string that contains the URI of the user. It is required. \ No newline at end of file diff --git a/docs/markdown-examples.md b/docs/markdown-examples.md deleted file mode 100644 index 3ea9aa9..0000000 --- a/docs/markdown-examples.md +++ /dev/null @@ -1,85 +0,0 @@ -# Markdown Extension Examples - -This page demonstrates some of the built-in markdown extensions provided by VitePress. - -## Syntax Highlighting - -VitePress provides Syntax Highlighting powered by [Shikiji](https://github.com/antfu/shikiji), with additional features like line-highlighting: - -**Input** - -````md -```js{4} -export default { - data () { - return { - msg: 'Highlighted!' - } - } -} -``` -```` - -**Output** - -```js{4} -export default { - data () { - return { - msg: 'Highlighted!' - } - } -} -``` - -## Custom Containers - -**Input** - -```md -::: info -This is an info box. -::: - -::: tip -This is a tip. -::: - -::: warning -This is a warning. -::: - -::: danger -This is a dangerous warning. -::: - -::: details -This is a details block. -::: -``` - -**Output** - -::: info -This is an info box. -::: - -::: tip -This is a tip. -::: - -::: warning -This is a warning. -::: - -::: danger -This is a dangerous warning. -::: - -::: details -This is a details block. -::: - -## More - -Check out the documentation for the [full list of markdown extensions](https://vitepress.dev/guide/markdown). diff --git a/docs/objects/note.md b/docs/objects/note.md new file mode 100644 index 0000000..daf8eb1 --- /dev/null +++ b/docs/objects/note.md @@ -0,0 +1,5 @@ +# Note + +A `Note` object is a simple object that represents a post or publication. It is the most common type of object. + +`Note` objects inherit from all Publication properties. \ No newline at end of file diff --git a/docs/objects/patch.md b/docs/objects/patch.md new file mode 100644 index 0000000..8ed78f6 --- /dev/null +++ b/docs/objects/patch.md @@ -0,0 +1,31 @@ +# Patch + +A `Patch` object is an object that represents a change to a `Note`. It is used to update a `Note`, such as when a spelling mistake is made and needs to be corrected. + +`Patch` objects are not meant to be displayed to the user, and are only meant to be used internally by the server. + +`Patch` objects **MUST** have a different `id` as the object that they are patching, and **MUST** have a `patched_at` field that contains the date and time that the object was patched. The `id` of the object that is being patched **MUST** be stored in the `patched_id` field. + +Subsequent patches are applied to the original object, not to the previous patch. It is up to the server to display the most recent patch it has in storage to the client. + +> **Note:**: A `Patch` object must replace the object that it is patching when displayed to the client. As such, if a Patch object is missing some fields from the previous object, these fields should not be displayed to the user + +Here is an example `Patch` for the aforementioned object: +```json5 +{ + "type": "Patch", + "id": "4c21fdea-1318-4d14-b3aa-1ac2f3db2e53", + "uri": "https://example.com/publications/4c21fdea-1318-4d14-b3aa-1ac2f3db2e53", + "patched_id": "f08a124e-fe90-439e-8be4-15a428a72a19", + "patched_at": "2021-01-01T00:00:00.000Z", + "contents": [ + { + "content": "This is patched!", + "content_type": "text/plain" + }, + ], + // ... +} +``` + +`Patch`es inherit all other properties from Publications. \ No newline at end of file diff --git a/docs/objects/publications.md b/docs/objects/publications.md new file mode 100644 index 0000000..12166ce --- /dev/null +++ b/docs/objects/publications.md @@ -0,0 +1,180 @@ +# Publications + +Publications are the main building blocks of the Lysand protocol. They are JSON objects that represent a publication, such as a post or a comment. + +Here is an example publication: +```json5 +{ + "type": "Note", + "id": "f08a124e-fe90-439e-8be4-15a428a72a19", + "uri": "https://example.com/publications/f08a124e-fe90-439e-8be4-15a428a72a19", + "author": "https://example.com/users/6e0204a2-746c-4972-8602-c4f37fc63bbe", + "created_at": "2021-01-01T00:00:00.000Z", + "contents": [ + { + "content": "Hello, world!", + "content_type": "text/plain" + }, + { + "content": "Hello, world!", + "content_type": "text/html" + } + ], + "attachments": [ + [ + { + "content": "https://cdn.example.com/attachments/ece2f9d9-27d7-457d-b657-4ce9172bdcf8.png", + "content_type": "image/png" + }, + { + "content": "https://cdn.example.com/attachments/ece2f9d9-27d7-457d-b657-4ce9172bdcf8.webp", + "content_type": "image/webp" + } + ] + ], + "replies_to": "https://test.com/publications/0b6ecf49-2959-4590-afb6-232f57036fa6", + "mentions": [ + "https://test.com/users/02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" + ], +} +``` + +## Type + +Currently available types are: +- [`Note`](/objects/note) +- [`Patch`](/objects/patch) + +## Author + +The `author` field on a Publication is a string that represents the URI of the user that created the object. It is used to identify the author of the Publication. + +The `author` field is required on all publications. + +## Contents + +The `contents` field on a Publication is an array that contains a list of `ContentFormat` objects. + +The `contents` field is not required on all publications. If it is not provided, it is assumed that the publication does not have any content. + +It is recommended that servers limit the length of the content from 500 to a couple thousand characters, but it is up to the server to decide how long the content can be. The protocol does not have an upper limit for the length of the content. + +The `contents` field **MUST** be a text format, such as `text/plain` or `text/html`. The `contents` field **MUST NOT** be a binary format, such as `image/png` or `video/mp4`. Platforms such as video sharing sites should use the `attachments` field for media instead. + +An example value for the `contents` field would be: +```json5 +{ + // ... + "contents": [ + { + "content": "Hello, world!", + "content_type": "text/plain" + }, + { + "content": "Hello, world!", + "content_type": "text/html" + } + ] + // ... +} +``` + +> **Note:** Lysand heavily recommends that servers support the `text/html` content type, as it is the richest content type that is supported by most clients. + +> **Note**: Lysand also recommends that servers always include a `text/plain` version of each object, as it is the most basic content type that is supported by all clients, such as command line clients. + +It is up to the client to choose which content format to display to the user. The client may choose to display the first content format that it supports, or it may choose to display the content format that it thinks is the most appropriate. + +Lysand recommends that clients display the richest content format that they support, such as HTML or more exotic formats such as MFM. + +## Attachments + +The `attachments` field on a Publication is an array that contains arrays of `ContentFormat` structures. It is used to attach files to a publication. + +The `attachments` field is not required on all publications. If it is not provided, it is assumed that the publication does not have any attachments. + +It is recommended that servers limit the number of attachments to 20, but it is up to the server to decide how many attachments a publication can have. The protocol does not have an upper limit for the number of attachments. + +The `attachments` field **MAY** be in any format, such as `image/png`, `image/webp`, `video/mp4`, or `audio/mpeg`. It is up to the server to decide which formats are allowed. + +> **Note:** Lysand recommends that servers let users upload any file as an attachment, but clients should warn users before downloading potentially malicious files, such as `.exe` files. + +## Replies To + +The `replies_to` field on a Publication is the URI of the `Note` that the publication is replying to. It is used to determine the reply chain of an object. + +The `replies_to` field is not required on all publications. If it is not provided, it is assumed that the object is not replying to any other object. + +## Quotes + +The `quotes` field on a Publication is the URI of the `Note` that the publication is quoting. It is used to determine the quote chain of an object. + +Quoting is similar to replying, but it does not (by default) notify the user that they were quoted. It is meant to be used to comment or add context to another publication. + +The `quotes` field is not required on all publications. If it is not provided, it is assumed that the object is not quoting any other object. + +Example of quoting: +```json5 +{ + // ... + "quotes": "https://test.com/publications/5f886c84-f8f7-4f65-8ac2-4691d385c509", + // ... +} +``` + +Quoting **SHOULD BE** rendered differently from replying, such as by adding a quote block to the publication or including the quoted post in the publication. + +## Mentions + +The `mentions` field on a Publication is an array that contains a list of URIs that represent the users that the publication is mentioning. It is used to determine which users are mentioned in a publication. + +The `mentions` field is not required on all publications. If it is not provided, it is assumed that the publication is not mentioning any other users. + +An example value for `mentions` would be: +```json5 +{ + // ... + "mentions": [ + "https://test.com/users/02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" + ] + // ... +} +``` + +## Subject + +The `subject` field on a Publication is a **string** that represents the subject of the publication. It may be used as a content warning or spoiler warning. + +The `subject` field is not required on all publications. If it is not provided, it is assumed that the publication does not have a subject. + +It is recommended that servers limit the length of the subject from 1 to 300 characters, but it is up to the server to decide how long the subject can be. The protocol does not have an upper limit for the length of the subject. + +The `subject` field **MUST NOT** be a `ContentFormat` object. It **MUST** be a string, and **MUST** be plain text. It **MUST NOT** contain any HTML or other markup. + +> See [ContentFormat](#contentformat) for more information on `ContentFormat` objects. + +> Client extensions are welcome to add support for HTML or other markup in the `subject` field, but it is not recommended. + +An example value for `subject` would be: +```json5 +{ + // ... + "subject": "This is a subject!" + // ... +} +``` + +## Is Sensitive + +The `is_sensitive` field on a Publication is a **boolean** that represents whether or not the publication is sensitive. It may be used as a content warning or spoiler warning. + +The `is_sensitive` field is not required on all publications. If it is not provided, it is assumed that the publication is not sensitive. + +An example value for `is_sensitive` would be: +```json5 +{ + // ... + "is_sensitive": true + // ... +} +``` \ No newline at end of file diff --git a/docs/structures/collection.md b/docs/structures/collection.md new file mode 100644 index 0000000..fbe5245 --- /dev/null +++ b/docs/structures/collection.md @@ -0,0 +1,31 @@ +# Collections + +Collections are JSON objects that contain a list of other objects. They are used to represent a list of objects, such as a list of publications or a list of users. + +Collections can be represented as such in TypeScript: + +```ts +interface Collection { + first: string; + last: string; + total_items: number; + author: string; + next?: string; + prev?: string; + items: T[]; +} +``` + +Collections **MUST** contain a `first` field that contains the URI of the first item in the collection, and a `last` field that contains the URI of the last item in the collection. + +Collections **MUST** contain a `total_items` field that contains the total number of items in the collection. + +Collections **MUST** contain a `next` field that contains the URI of the next page of items in the collection, and a `prev` field that contains the URI of the previous page of items in the collection, unless the user is on the first or last page of the collection. + +Collections **MUST** contain an `items` field that contains an array of items in the collection. (for example, a list of publications or a list of users) + +## Properties + +### Author + +Collections **MUST** contain an `author` field that contains the URI of the user that created the collection. It is used to identify the author of the collection. If this collection is made by the server and not by a specific user (such as the Endorserment collection with the [ServerEndorsement Extension](/extensions/endorsement)), it must be the server actor's URI. \ No newline at end of file