From 842e842e3cd7ca9ac5a5f0ae5017ad479dad083b Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Sat, 28 Sep 2024 21:43:17 +0200 Subject: [PATCH 01/50] refactor: :recycle: Improve Reports entity --- app/extensions/reports/page.mdx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/app/extensions/reports/page.mdx b/app/extensions/reports/page.mdx index 48c4de0..13f49e5 100644 --- a/app/extensions/reports/page.mdx +++ b/app/extensions/reports/page.mdx @@ -14,6 +14,9 @@ When an instance receives a report, it *should* be reviewed by a moderator or ad + + This entity does not have a URI. + Must be `pub.versia:reports/Report`. @@ -23,8 +26,8 @@ When an instance receives a report, it *should* be reviewed by a moderator or ad URIs of the content being reported. - - Reason for the report. Should be concise and clear, such as `spam`, `harassment`, `misinformation`, etc. + + Report tags. Should be concise and clear, such as `spam`, `harassment`, `misinformation`, etc. Used for categorization. Additional comments about the report. Can be used to provide more context or details. @@ -39,12 +42,14 @@ When an instance receives a report, it *should* be reviewed by a moderator or ad "id": "6f3001a1-641b-4763-a9c4-a089852eec84", "type": "pub.versia:reports/Report", "author": "https://example.com/users/6f3001a1-641b-4763-a9c4-a089852eec84", - "uri": "https://example.com/reports/f7bbf7fc-88d2-47dd-b241-5d1f770a10f0", "reported": [ "https://test.com/publications/46f936a3-9a1e-4b02-8cde-0902a89769fa", "https://test.com/publications/213d7c56-fb9b-4646-a4d2-7d70aa7d106a" ], - "reason": "spam", + "tags": [ + "spam", + "harassment" + ], "comment": "This is spam." } ``` From f67b327f7546fd181909d8c3043b1c5e8ecdf525 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Sat, 28 Sep 2024 21:57:17 +0200 Subject: [PATCH 02/50] feat: :sparkles: Add dev notice --- app/entities/instance-metadata/page.mdx | 3 ++- app/extensions/instance-messaging/page.mdx | 2 +- app/federation/discovery/page.mdx | 2 +- components/Header.tsx | 4 ++-- components/Logo.tsx | 3 ++- components/Navigation.tsx | 2 +- tailwind.config.ts | 4 ++++ 7 files changed, 13 insertions(+), 7 deletions(-) diff --git a/app/entities/instance-metadata/page.mdx b/app/entities/instance-metadata/page.mdx index 51dd14e..0c10a0b 100644 --- a/app/entities/instance-metadata/page.mdx +++ b/app/entities/instance-metadata/page.mdx @@ -110,7 +110,8 @@ On all entities that have an `author` field, the `author` can be `null` to repre "compatibility": { "versions": [ "0.3.0", - "0.4.0" + "0.4.0", + "0.5.0" ], "extensions": [ "pub.versia:reactions", diff --git a/app/extensions/instance-messaging/page.mdx b/app/extensions/instance-messaging/page.mdx index 7453d04..1f44b81 100644 --- a/app/extensions/instance-messaging/page.mdx +++ b/app/extensions/instance-messaging/page.mdx @@ -64,7 +64,7 @@ This extension adds the following metadata to instances: }, "compatibility": { "versions": [ - "0.4.0" + "0.5.0" ], "extensions": [ "pub.versia:reactions", diff --git a/app/federation/discovery/page.mdx b/app/federation/discovery/page.mdx index 79a11b8..a1baf1e 100644 --- a/app/federation/discovery/page.mdx +++ b/app/federation/discovery/page.mdx @@ -72,7 +72,7 @@ Accept: application/json }, "compatibility": { "versions": [ - "0.4.0" + "0.5.0" ], "extensions": [ "pub.versia:reactions", diff --git a/components/Header.tsx b/components/Header.tsx index 455e1e2..0e5876d 100644 --- a/components/Header.tsx +++ b/components/Header.tsx @@ -51,7 +51,7 @@ export const Header = forwardRef, { className?: string }>( ref={ref} className={clsx( className, - "fixed inset-x-0 top-0 z-50 flex h-14 items-center justify-between gap-2 px-4 transition sm:px-6 lg:left-72 lg:z-30 lg:px-8 xl:left-80", + "fixed bg-construction bg-opacity-10 [background-size:57px_57px] inset-x-0 top-0 z-50 flex h-14 items-center justify-between gap-2 px-4 transition sm:px-6 lg:left-72 lg:z-30 lg:px-8 xl:left-80", !isInsideMobileNavigation && "backdrop-blur-sm lg:left-72 xl:left-80 dark:backdrop-blur", isInsideMobileNavigation @@ -94,7 +94,7 @@ export const Header = forwardRef, { className?: string }>(
- +
diff --git a/components/Logo.tsx b/components/Logo.tsx index ad9cfa0..5b707ca 100644 --- a/components/Logo.tsx +++ b/components/Logo.tsx @@ -1,5 +1,6 @@ import clsx from "clsx"; import type { ComponentPropsWithoutRef } from "react"; +import { Badge } from "./Metadata"; export function Logo(props: ComponentPropsWithoutRef<"div">) { return ( @@ -16,7 +17,7 @@ export function Logo(props: ComponentPropsWithoutRef<"div">) { className="h-full rounded-sm" /> - Versia Protocol + Versia Protocol Dev ); diff --git a/components/Navigation.tsx b/components/Navigation.tsx index abb34ae..9b57278 100644 --- a/components/Navigation.tsx +++ b/components/Navigation.tsx @@ -323,7 +323,7 @@ export function Navigation(props: ComponentPropsWithoutRef<"nav">) { variant="filled" className="w-full" > - Working Draft 4 + Working Draft 5 diff --git a/tailwind.config.ts b/tailwind.config.ts index 922e84d..2668f4b 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -55,6 +55,10 @@ export default { animation: { roll: "roll 2s 1 ease-in-out", }, + backgroundImage: { + construction: + "linear-gradient(45deg, rgb(255 195 0 / var(--tw-bg-opacity)) 25%, rgb(46 39 37 / var(--tw-bg-opacity)) 25%, rgb(46 39 37 / var(--tw-bg-opacity)) 50%, rgb(255 195 0 / var(--tw-bg-opacity)) 50%, rgb(255 195 0 / var(--tw-bg-opacity)) 75%, rgb(46 39 37 / var(--tw-bg-opacity)) 75%, rgb(46 39 37 / var(--tw-bg-opacity)) 100%)", + }, keyframes: { roll: { "0%": { transform: "rotate(0deg)" }, From 9f412cd47fe258ba4e890728f1a65a3e8cf8e27a Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Sat, 28 Sep 2024 21:59:25 +0200 Subject: [PATCH 03/50] docs: :memo: Update changelog --- app/changelog/page.mdx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index 72ecd94..eaec9a9 100644 --- a/app/changelog/page.mdx +++ b/app/changelog/page.mdx @@ -6,9 +6,13 @@ export const metadata = { # Changelog -This page lists changes since Working Draft 03. {{ className: 'lead' }} +This page lists changes since Working Draft 3. {{ className: 'lead' }} -## Since WD 03 +## Since WD 4 + +- Removed URI from [Report](/extensions/reports), and replaced `reason` with `tags`. + +## Since WD 3 - Rewrote the signature system from scratch to be simpler and not depend on dates. - Moved Likes and Dislikes to an extension. From 9e4cec27db1ca3ff10b870d5f9c4249f6af38090 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 18 Oct 2024 10:49:43 +0200 Subject: [PATCH 04/50] chore: :arrow_up: Upgrade dependencies --- biome.json | 2 +- bun.lockb | Bin 198360 -> 198696 bytes package.json | 32 ++++++++++++++++---------------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/biome.json b/biome.json index b118871..9a308e8 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/1.9.2/schema.json", + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", "organizeImports": { "enabled": true }, diff --git a/bun.lockb b/bun.lockb index 2eda3bbcb357696c4ed35e1e227053dcbc6baeda..4099437e14c5340e53767c29ff213836afd53879 100755 GIT binary patch delta 28457 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%0D&e)y=&=_8UlsfUQ;risbD~p{Nnd&3mB1GR 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 diff --git a/package.json b/package.json index 51dcf31..bf5699c 100644 --- a/package.json +++ b/package.json @@ -11,28 +11,28 @@ "uuid": "bun --print 'crypto.randomUUID()'" }, "dependencies": { - "@algolia/autocomplete-core": "^1.17.4", - "@headlessui/react": "^2.1.8", + "@algolia/autocomplete-core": "^1.17.6", + "@headlessui/react": "^2.1.10", "@headlessui/tailwindcss": "^0.2.1", "@mdx-js/loader": "^3.0.1", "@mdx-js/react": "^3.0.1", - "@next/mdx": "^14.2.13", + "@next/mdx": "^14.2.15", "@sindresorhus/slugify": "^2.2.1", "@tailwindcss/typography": "^0.5.15", "@types/mdx": "^2.0.13", - "@types/node": "^22.7.4", - "@types/react": "^18.3.10", - "@types/react-dom": "^18.3.0", + "@types/node": "^22.7.6", + "@types/react": "^18.3.11", + "@types/react-dom": "^18.3.1", "@types/react-highlight-words": "^0.20.0", - "acorn": "^8.12.1", + "acorn": "^8.13.0", "autoprefixer": "^10.4.20", "clsx": "^2.1.1", "fast-glob": "^3.3.2", "flexsearch": "^0.7.43", - "framer-motion": "^11.9.0", + "framer-motion": "^11.11.9", "mdast-util-to-string": "^4.0.0", "mdx-annotations": "^0.1.4", - "next": "^14.2.13", + "next": "^14.2.15", "next-themes": "^0.3.0", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -40,19 +40,19 @@ "remark": "^15.0.1", "remark-gfm": "^4.0.0", "remark-mdx": "^3.0.1", - "shiki": "^1.20.0", + "shiki": "^1.22.0", "simple-functional-loader": "^1.2.1", - "tailwindcss": "^3.4.13", - "typescript": "^5.6.2", + "tailwindcss": "^3.4.14", + "typescript": "^5.6.3", "unist-util-filter": "^5.0.1", "unist-util-visit": "^5.0.0", - "zustand": "^5.0.0-rc.2" + "zustand": "^5.0.0" }, "devDependencies": { - "@biomejs/biome": "^1.9.2", + "@biomejs/biome": "^1.9.4", "@iconify-icon/react": "^2.1.0", - "@next/bundle-analyzer": "^14.2.13", - "@shikijs/transformers": "^1.20.0", + "@next/bundle-analyzer": "^14.2.15", + "@shikijs/transformers": "^1.22.0", "sharp": "^0.33.5" }, "trustedDependencies": ["@biomejs/biome", "sharp"] From 0530c2d50aa7db142a678d78dbbe4e68c39fa020 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 18 Oct 2024 10:52:00 +0200 Subject: [PATCH 05/50] feat: :sparkles: Mandata Unix-style LF line endings --- app/changelog/page.mdx | 1 + app/entities/page.mdx | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index eaec9a9..0bc13f7 100644 --- a/app/changelog/page.mdx +++ b/app/changelog/page.mdx @@ -11,6 +11,7 @@ This page lists changes since Working Draft 3. {{ className: 'lead' }} ## Since WD 4 - Removed URI from [Report](/extensions/reports), and replaced `reason` with `tags`. +- Mandated Unix-style `\n` line endings in all text fields. ## Since WD 3 diff --git a/app/entities/page.mdx b/app/entities/page.mdx index fb036a2..2bad0d5 100644 --- a/app/entities/page.mdx +++ b/app/entities/page.mdx @@ -79,7 +79,8 @@ Any field in an entity not marked as `required` may be omitted or set to `null`. ## Serialization -When serialized to a string, the JSON representation of an entity should follow the following rules: +When serialized to a string, the JSON representation of an entity must follow the following rules: - Keys must be sorted lexicographically. -- Should use UTF-8 encoding. +- Must use UTF-8 encoding. - Must be **signed** using the relevant [User](/entities/user)'s private key, or the [instance's private key](/entities/instance-metadata) if the entity is not associated with a particular user. +- Must use Unix-style `\n` line endings (LF). \ No newline at end of file From 1b3dd14c3d4a4cfd54787b37dfe20a838b82e287 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 18 Oct 2024 10:52:09 +0200 Subject: [PATCH 06/50] fix: :rotating_light: Fix new Biome warning --- components/Navigation.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/components/Navigation.tsx b/components/Navigation.tsx index 9b57278..09a47d4 100644 --- a/components/Navigation.tsx +++ b/components/Navigation.tsx @@ -209,6 +209,7 @@ function NavigationGroup({ {link.href === pathname && sections.length > 0 && ( role="list" initial={{ opacity: 0 }} animate={{ From 63446dee0225f33da01a867376decca2eea19f61 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 18 Oct 2024 11:04:11 +0200 Subject: [PATCH 07/50] docs: :recycle: Replace nonce with timestamps in signatures --- app/extensions/websockets/page.mdx | 12 ++++----- app/federation/http/page.mdx | 24 +++++++++--------- app/signatures/page.mdx | 40 +++++++++++++++--------------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/app/extensions/websockets/page.mdx b/app/extensions/websockets/page.mdx index aed1969..b2f21a5 100644 --- a/app/extensions/websockets/page.mdx +++ b/app/extensions/websockets/page.mdx @@ -24,13 +24,13 @@ Messages sent over the WebSocket connection are JSON objects. - Same as the `X-Signature` header in HTTP requests. + Same as the `Versia-Signature` header in HTTP requests. - - Same as the `X-Nonce` header in HTTP requests. + + Same as the `Versia-Signed-At` header in HTTP requests. - Same as the `X-Signed-By` header in HTTP requests. + Same as the `Versia-Signed-By` header in HTTP requests. Same as the request body in HTTP requests. Must be a string (stringified JSON), not JSON. @@ -42,8 +42,8 @@ Messages sent over the WebSocket connection are JSON objects. ```jsonc {{ 'title': 'Example Message' }} { - "signature": "post /users/1/inbox a2ebc29eb6762a9164fbcffc9271e8a53562a5e725e7187ea7d88d03cbe59341 n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=", - "nonce": "a2ebc29eb6762a9164fbcffc9271e8a53562a5e725e7187ea7d88d03cbe59341", + "signature": "/CjB2L9bcvRg+uP19B4/rqy7Ji9/cqMFPlL3GVCIndnQjYyOpBzJEAl9weDnXm7Jrqa3y6sBC+EYWKThO2r9Bw==", + "signed_at": "1729241807", "signed_by": "https://bongo.social/users/63a00ab3-39b1-49eb-b88e-ed65d2361f3e", "entity": "{\"id\":\"9a8928b6-2526-4979-aab1-ef2f88cd5700\",\"type\":\"Delete\",\"created_at\":\"2022-01-01T12:00:00Z\",\"author\":\"https://bongo.social/users/63a00ab3-39b1-49eb-b88e-ed65d2361f3e\",\"deleted\":\"https://bongo.social/notes/54059ce2-9332-46fa-bf6a-598b5493b81b\"}" } diff --git a/app/federation/http/page.mdx b/app/federation/http/page.mdx index 19b5f3b..5169ea0 100644 --- a/app/federation/http/page.mdx +++ b/app/federation/http/page.mdx @@ -21,13 +21,13 @@ ALL kinds of HTTP requests/responses between instances **MUST** include a [Signa Must include `application/json; charset=utf-8`, if the request has a body. - + See [Signatures](/signatures) for more information. - + See [Signatures](/signatures). - + See [Signatures](/signatures). @@ -40,9 +40,9 @@ ALL kinds of HTTP requests/responses between instances **MUST** include a [Signa POST https://bob.com/users/1/inbox HTTP/1.1 Accept: application/json User-Agent: CoolServer/1.0 (https://coolserver.com) - X-Signature: post /users/1/inbox a2ebc29eb6762a9164fbcffc9271e8a53562a5e725e7187ea7d88d03cbe59341 n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg= - X-Signed-By: https://example.com/users/1 - X-Nonce: a2ebc29eb6762a9164fbcffc9271e8a53562a5e725e7187ea7d88d03cbe59341 + Versia-Signature: /CjB2L9bcvRg+uP19B4/rqy7Ji9/cqMFPlL3GVCIndnQjYyOpBzJEAl9weDnXm7Jrqa3y6sBC+EYWKThO2r9Bw== + Versia-Signed-By: https://example.com/users/1 + Versia-Signed-At: 1729241687 ``` @@ -55,13 +55,13 @@ ALL kinds of HTTP requests/responses between instances **MUST** include a [Signa Must include `application/json; charset=utf-8`. - + See [Signatures](/signatures) for more information. - + See [Signatures](/signatures). - + See [Signatures](/signatures). @@ -70,9 +70,9 @@ ALL kinds of HTTP requests/responses between instances **MUST** include a [Signa ```http {{ 'title': 'Example Response' }} HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 - X-Signature: get /users/1/followers 8f872d4609d26819d03a7d60ce3db68f5b0dd5a80d5930260294f237e670ab76 YDA64iuZiGG847KPM+7BvnWKITyGyTwHbb6fVYwRx1I - X-Signed-By: https://example.com/users/1 - X-Nonce: 8f872d4609d26819d03a7d60ce3db68f5b0dd5a80d5930260294f237e670ab76 + Versia-Signature: /CjB2L9bcvRg+uP19B4/rqy7Ji9/cqMFPlL3GVCIndnQjYyOpBzJEAl9weDnXm7Jrqa3y6sBC+EYWKThO2r9Bw==+7BvnWKITyGyTwHbb6fVYwRx1I + Versia-Signed-By: https://example.com/users/1 + Versia-Signed-At: 1729241717 ``` \ No newline at end of file diff --git a/app/signatures/page.mdx b/app/signatures/page.mdx index 0efbbdb..afa0e2d 100644 --- a/app/signatures/page.mdx +++ b/app/signatures/page.mdx @@ -17,21 +17,15 @@ Versia uses cryptographic signatures to ensure the integrity and authenticity of ## Signature Definition A signature consists of a series of headers in an HTTP request. The following headers are used: -- **`X-Signature`**: The signature itself, encoded in base64. -- **`X-Signed-By`**: URI of the user who signed the request, [or the string `instance $1`, to represent the instance, where `$1` is the instance's host](/entities/instance-metadata#the-null-author). -- **`X-Nonce`**: A random string generated by the client. This is used to prevent replay attacks. +- **`Versia-Signature`**: The signature itself, encoded in base64. +- **`Versia-Signed-By`**: URI of the user who signed the request, [or the string `instance $1`, to represent the instance, where `$1` is the instance's host](/entities/instance-metadata#the-null-author). +- **`Versia-Signed-At`**: The current Unix timestamp, in seconds (no milliseconds), when the request was signed. Timezone must be UTC, like all Unix timestamps. Signatures are **required on ALL federation traffic**. If a request does not have a signature, it **MUST** be rejected. Specifically, signatures must be put on: - **All POST requests**. - **All responses to GET requests** (for example, when fetching a user's profile). In this case, the HTTP method used in the signature string must be `GET`. - - Versia's security model makes replay attacks useless, so they are not a concern. - - For more information, please read [the security model documentation](/security). - - -If a signature fails, is missing or is invalid, the instance **MUST** return a `401 Unauthorized` HTTP status code. +If a signature fails, is missing or is invalid, the instance **MUST** return a `401 Unauthorized` HTTP status code. If the signature timestamp is too old or too new (more than 5 minutes from the current time), the instance **MUST** return a `422 Unprocessable Entity` status code. ### Calculating the Signature @@ -43,7 +37,7 @@ $0 $1 $2 $3 Where: - `$0` is the HTTP method (e.g. `GET`, `POST`) in lowercase. - `$1` is the path of the request, in standard URI format (don't forget to URL-encode it). -- `$2` is the nonce, a random string generated by the client. +- `$2` is the Unix timestamp when the request was signed, in UTC seconds. - `$3` is the SHA-256 hash of the request body, encoded in base64. (if it's a `GET` request, this should be the hash of an empty string) Sign this string using the user's private key. The resulting signature should be encoded in base64. @@ -57,7 +51,8 @@ post /notes a2ebc29eb6762a9164fbcffc9271e8a53562a5e725e7187ea7d88d03cbe59341 n4b To verify a signature, the instance must: - Recreate the string as described above. -- Extract the signature provided in the `X-Signature` header. +- Extract the signature provided in the `Versia-Signature` header. +- Check that the `Versia-Signed-At` timestamp is within 5 minutes of the current time. - Decode the signature from base64. - Perform a signature verification using the user's public key. @@ -94,14 +89,14 @@ const privateKey = await crypto.subtle.importKey( ["sign"], ); -const nonce = crypto.getRandomValues(new Uint8Array(32)) +const timestamp = Date.now(); const digest = await crypto.subtle.digest( "SHA-256", new TextEncoder().encode(content) ); const stringToSign = - `post /notes ${Buffer.from(nonce).toString("hex")} ${Buffer.from(digest).toString("base64")}`; + `post /notes ${timestamp} ${Buffer.from(digest).toString("base64")}`; const signature = await crypto.subtle.sign( "Ed25519", @@ -117,9 +112,9 @@ To send the request, Bob would use the following code: ```typescript const headers = new Headers(); -headers.set("X-Signed-By", "https://bob.com/users/bf44e6ad-7c0a-4560-9938-cf3fd4066511"); -headers.set("X-Nonce", Buffer.from(nonce).toString("hex")); -headers.set("X-Signature", base64Signature); +headers.set("Versia-Signed-By", "https://bob.com/users/bf44e6ad-7c0a-4560-9938-cf3fd4066511"); +headers.set("Versia-Signed-At", timestamp); +headers.set("Versia-Signature", base64Signature); headers.set("Content-Type", "application/json"); const response = await fetch("https://alice.com/notes", { @@ -134,8 +129,13 @@ On Alice's side, she would verify the signature using Bob's public key. Here, we ```typescript const method = request.method.toLowerCase(); const path = new URL(request.url).pathname; -const signature = request.headers.get("X-Signature"); -const nonce = request.headers.get("X-Nonce"); +const signature = request.headers.get("Versia-Signature"); +const timestamp = request.headers.get("Versia-Signed-At"); + +// Check if timestamp is within 5 minutes of the current time +if (Math.abs(Date.now() - timestamp) > 300_000) { + return new Response("Timestamp is too old or too new", { status: 422 }); +} const digest = await crypto.subtle.digest( "SHA-256", @@ -143,7 +143,7 @@ const digest = await crypto.subtle.digest( ); const stringToVerify = - `${method} ${path} ${nonce} ${Buffer.from(digest).toString("base64")}`; + `${method} ${path} ${timestamp} ${Buffer.from(digest).toString("base64")}`; const isVerified = await crypto.subtle.verify( "Ed25519", From c88709dc2541d86dd07e75dce89fade971cbae1d Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 18 Oct 2024 11:07:03 +0200 Subject: [PATCH 08/50] feat: :sparkles: Add html_uri field to Notes --- app/entities/note/page.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/entities/note/page.mdx b/app/entities/note/page.mdx index 7a3f363..01c98e0 100644 --- a/app/entities/note/page.mdx +++ b/app/entities/note/page.mdx @@ -89,6 +89,9 @@ Notes represent a piece of content on a Versia instance. They can be posted by [ A subject for the note. Useful for clients to display a "content warning" or "spoiler" feature, such as on Mastodon. Must be a plaintext string (`text/plain`). + + URI to the note in HTML, for web browsers. Useful for "open this note on remote instance" functionality. + @@ -126,6 +129,7 @@ Notes represent a piece of content on a Versia instance. They can be posted by [ ], "author": "https://versia.social/users/018eb863-753f-76ff-83d6-fd590de7740a", "category": "microblog", + "html_uri": "https://versia.social/@jessew/17652802716161", "content": { "text/html": { "content": "

In the next versia-fe update: account settings, finally!

" From 7704d5e0ab977ed51d3c925bf365d961de0838b8 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 18 Oct 2024 11:11:09 +0200 Subject: [PATCH 09/50] chore: :memo: Update changelog --- app/changelog/page.mdx | 5 +++++ app/entities/note/page.mdx | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index 0bc13f7..fea79bf 100644 --- a/app/changelog/page.mdx +++ b/app/changelog/page.mdx @@ -12,6 +12,11 @@ This page lists changes since Working Draft 3. {{ className: 'lead' }} - Removed URI from [Report](/extensions/reports), and replaced `reason` with `tags`. - Mandated Unix-style `\n` line endings in all text fields. +- Renamed the following headers, as per [RFC 6648](https://tools.ietf.org/html/rfc6648): + - `X-Signature` to `Versia-Signature` + - `X-Signed-By` to `Versia-Signed-By` +- Removed the nonce from the [signature system](/signatures), replaced with `Versia-Signed-At` (timestamps). +- Added `html_uri` to [Notes](/entities/note). ## Since WD 3 diff --git a/app/entities/note/page.mdx b/app/entities/note/page.mdx index 01c98e0..999bfc9 100644 --- a/app/entities/note/page.mdx +++ b/app/entities/note/page.mdx @@ -90,7 +90,7 @@ Notes represent a piece of content on a Versia instance. They can be posted by [ A subject for the note. Useful for clients to display a "content warning" or "spoiler" feature, such as on Mastodon. Must be a plaintext string (`text/plain`).
- URI to the note in HTML, for web browsers. Useful for "open this note on remote instance" functionality. + URI to the note's eventual HTML representation, for web browsers. Useful for "open this note on remote instance" functionality.
From e69ef9c98942795ea85a2ad8407f3335159f15c2 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 18 Oct 2024 11:19:02 +0200 Subject: [PATCH 10/50] feat: :sparkles: Add rate limiting --- app/changelog/page.mdx | 1 + app/federation/http/page.mdx | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index fea79bf..14dea2b 100644 --- a/app/changelog/page.mdx +++ b/app/changelog/page.mdx @@ -17,6 +17,7 @@ This page lists changes since Working Draft 3. {{ className: 'lead' }} - `X-Signed-By` to `Versia-Signed-By` - Removed the nonce from the [signature system](/signatures), replaced with `Versia-Signed-At` (timestamps). - Added `html_uri` to [Notes](/entities/note). +- Standardize rate limits with [IETF draft draft-polli-ratelimit-headers-02](https://www.ietf.org/archive/id/draft-polli-ratelimit-headers-02.html). ## Since WD 3 diff --git a/app/federation/http/page.mdx b/app/federation/http/page.mdx index 5169ea0..47f4dc0 100644 --- a/app/federation/http/page.mdx +++ b/app/federation/http/page.mdx @@ -47,6 +47,16 @@ ALL kinds of HTTP requests/responses between instances **MUST** include a [Signa
+## Rate limits + +Implementations **MUST** respect the rate limits of remote instances. + +IETF draft [draft-polli-ratelimit-headers-02](https://www.ietf.org/archive/id/draft-polli-ratelimit-headers-02.html) **MUST** be used to communicate rate limits. Other rate limit headers/formats are not allowed. + + + This IETF draft is, well, a draft. However, there are no standards for rate limiting in HTTP, so this is the best we have. + + ## Responses From 8011076aa25511def467d924ac9e0db646291496 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 18 Oct 2024 11:24:00 +0200 Subject: [PATCH 11/50] fix: :bug: Correctly use unix timestamp instead of nonce in signature example --- app/signatures/page.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/signatures/page.mdx b/app/signatures/page.mdx index afa0e2d..5687b2b 100644 --- a/app/signatures/page.mdx +++ b/app/signatures/page.mdx @@ -44,7 +44,7 @@ Sign this string using the user's private key. The resulting signature should be Example: ``` -post /notes a2ebc29eb6762a9164fbcffc9271e8a53562a5e725e7187ea7d88d03cbe59341 n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg= +post /notes 1729243417 n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg= ``` ### Verifying the Signature From f0ab38424418333cbdb3c8614044d23b3e8e2f7d Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 18 Oct 2024 13:48:34 +0200 Subject: [PATCH 12/50] feat: :sparkles: Add Versia Links --- app/changelog/page.mdx | 1 + app/links/page.mdx | 63 +++++++++++++++++++++++++++++++++++++++ components/Navigation.tsx | 1 + 3 files changed, 65 insertions(+) create mode 100644 app/links/page.mdx diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index 14dea2b..0f56366 100644 --- a/app/changelog/page.mdx +++ b/app/changelog/page.mdx @@ -18,6 +18,7 @@ This page lists changes since Working Draft 3. {{ className: 'lead' }} - Removed the nonce from the [signature system](/signatures), replaced with `Versia-Signed-At` (timestamps). - Added `html_uri` to [Notes](/entities/note). - Standardize rate limits with [IETF draft draft-polli-ratelimit-headers-02](https://www.ietf.org/archive/id/draft-polli-ratelimit-headers-02.html). +- Added [Versia Links](/links). ## Since WD 3 diff --git a/app/links/page.mdx b/app/links/page.mdx new file mode 100644 index 0000000..c52940e --- /dev/null +++ b/app/links/page.mdx @@ -0,0 +1,63 @@ +export const metadata = { + title: 'Versia Links', + description: + 'How Versia Links work and how they are used in the Versia Protocol.', +} + +# Versia Links + +Versia Links are a way to reference entities in the Versia Protocol, in a way that can be handled by browsers and applications. They function the same way as `mailto:` links, but for Versia entities. + +## Syntax + + + + + + Must be `web+versia://` so that browsers and applications can recognize it. + + An IANA registration for the `versia://` scheme will be requested in the future. + + + Instance host, including the port if it is not the default (i.e. `443` for HTTPS). + + + Action to take on the entity. Can have multiple slashes as a way to segment the action. + + Possible actions: + + - `users/:username`: Open a user profile. + - `notes/:id`: Open a note. + - `groups/:id`: Open a group. + - `reply/:id`: Open the composer to reply to a note. + - `quote/:id`: Open the composer to quote a note. + - `share/:id`: Share a note. + + + + + + ``` {{ title: "Viewing a user profile" }} + web+versia://bob.social/users/alice + ``` + + ``` {{ title: "Viewing a note" }} + web+versia://jimbob.com/notes/01902e09-0f8b-72de-8ee3-9afc0cf5eae1 + ``` + + ``` {{ title: "Replying to a note" }} + web+versia://bob.social/reply/01902e09-0f8b-72de-8ee3-9afc0cf5eae1 + ``` + + + +## Handling + +Versia clients **should** register themselves as handlers for the `web+versia://` scheme in the user's operating system. When a Versia Link is clicked, the client should open the entity in the client's interface. + +The default client ("frontend") on a Versia instance **should** also display Versia links for logged-out users on: +- Profiles +- Notes +- Groups + +Clients **should** ask users to confirm any action that is not a simple view action, such as replying to a note or sharing a note. \ No newline at end of file diff --git a/components/Navigation.tsx b/components/Navigation.tsx index 09a47d4..062725f 100644 --- a/components/Navigation.tsx +++ b/components/Navigation.tsx @@ -253,6 +253,7 @@ export const navigation: NavGroup[] = [ { title: "Signatures", href: "/signatures" }, { title: "Security", href: "/security" }, { title: "Federation", href: "/federation" }, + { title: "Links", href: "/links" }, { title: "Extensions", href: "/extensions" }, ], }, From 6796a31d2bd8c506b090d4ae8a9df87d0c6d70ad Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 18 Oct 2024 14:51:23 +0200 Subject: [PATCH 13/50] refactor: :fire: Remove HTML URIs from Notes --- app/changelog/page.mdx | 1 - app/entities/note/page.mdx | 4 ---- 2 files changed, 5 deletions(-) diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index 0f56366..6f356f1 100644 --- a/app/changelog/page.mdx +++ b/app/changelog/page.mdx @@ -16,7 +16,6 @@ This page lists changes since Working Draft 3. {{ className: 'lead' }} - `X-Signature` to `Versia-Signature` - `X-Signed-By` to `Versia-Signed-By` - Removed the nonce from the [signature system](/signatures), replaced with `Versia-Signed-At` (timestamps). -- Added `html_uri` to [Notes](/entities/note). - Standardize rate limits with [IETF draft draft-polli-ratelimit-headers-02](https://www.ietf.org/archive/id/draft-polli-ratelimit-headers-02.html). - Added [Versia Links](/links). diff --git a/app/entities/note/page.mdx b/app/entities/note/page.mdx index 999bfc9..7a3f363 100644 --- a/app/entities/note/page.mdx +++ b/app/entities/note/page.mdx @@ -89,9 +89,6 @@ Notes represent a piece of content on a Versia instance. They can be posted by [ A subject for the note. Useful for clients to display a "content warning" or "spoiler" feature, such as on Mastodon. Must be a plaintext string (`text/plain`). - - URI to the note's eventual HTML representation, for web browsers. Useful for "open this note on remote instance" functionality. - @@ -129,7 +126,6 @@ Notes represent a piece of content on a Versia instance. They can be posted by [ ], "author": "https://versia.social/users/018eb863-753f-76ff-83d6-fd590de7740a", "category": "microblog", - "html_uri": "https://versia.social/@jessew/17652802716161", "content": { "text/html": { "content": "

In the next versia-fe update: account settings, finally!

" From a2c66d5b3a5d6490b996e770ecefb322f94980f1 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 18 Oct 2024 15:00:47 +0200 Subject: [PATCH 14/50] refactor: :memo: Switch from ISO 8601 to RFC 3339 --- app/changelog/page.mdx | 2 ++ app/entities/page.mdx | 4 ++-- app/extensions/polls/page.mdx | 4 ++-- app/extensions/vanity/page.mdx | 2 +- app/federation/validation/page.mdx | 2 +- app/types/page.mdx | 20 ++------------------ 6 files changed, 10 insertions(+), 24 deletions(-) diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index 6f356f1..5b11000 100644 --- a/app/changelog/page.mdx +++ b/app/changelog/page.mdx @@ -18,6 +18,8 @@ This page lists changes since Working Draft 3. {{ className: 'lead' }} - Removed the nonce from the [signature system](/signatures), replaced with `Versia-Signed-At` (timestamps). - Standardize rate limits with [IETF draft draft-polli-ratelimit-headers-02](https://www.ietf.org/archive/id/draft-polli-ratelimit-headers-02.html). - Added [Versia Links](/links). +- Switched from ISO 8601 to [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) for timestamps. + - In most cases, the two are interchangeable, but RFC 3339 is more strict. Most implementations should not need to change anything. ## Since WD 3 diff --git a/app/entities/page.mdx b/app/entities/page.mdx index 2bad0d5..ab6d22c 100644 --- a/app/entities/page.mdx +++ b/app/entities/page.mdx @@ -24,8 +24,8 @@ Any field in an entity not marked as `required` may be omitted or set to `null`. Type of the entity. Custom types must follow [Extension Naming](/extensions#naming). - - Date and time when the entity was created. Must be an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formatted string. + + Date and time when the entity was created. Must be an [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) timestamp. Handling of dates that are valid but obviously incorrect (e.g. in the future) is left to the Implementation's discretion. diff --git a/app/extensions/polls/page.mdx b/app/extensions/polls/page.mdx index dc048d2..e7be043 100644 --- a/app/extensions/polls/page.mdx +++ b/app/extensions/polls/page.mdx @@ -29,8 +29,8 @@ Note that there is no `question` field: the question should be included in the ` Whether the poll allows multiple votes to be cast for different options. - - ISO 8601 timestamp of when the poll ends and no more votes can be cast. If not present, the poll does not expire. + + RFC 3339 timestamp of when the poll ends and no more votes can be cast. If not present, the poll does not expire. diff --git a/app/extensions/vanity/page.mdx b/app/extensions/vanity/page.mdx index 3b6d3bb..c6da43f 100644 --- a/app/extensions/vanity/page.mdx +++ b/app/extensions/vanity/page.mdx @@ -61,7 +61,7 @@ All properties are optional. type LanguageCode = string; ``` - + User's birthday. If year is left out or set to `0000`, implementations **SHOULD** not display the year. diff --git a/app/federation/validation/page.mdx b/app/federation/validation/page.mdx index a980085..493b04b 100644 --- a/app/federation/validation/page.mdx +++ b/app/federation/validation/page.mdx @@ -17,7 +17,7 @@ Implementations **MUST** strictly validate all incoming data to ensure that it i Things that should be validated include, but are not limited to: - The presence of **all required fields**. -- The **format** of all fields (integers should not be strings, dates should be in ISO 8601 format, etc.). +- The **format** of all fields (integers should not be strings, timestamps should be in RFC 3339 format, etc.). - The presence of **all required headers**. - The presence of a **valid signature**. - The **length** of all fields (for example, the `username` field on a `User` entity) should be at least 1 character long. diff --git a/app/types/page.mdx b/app/types/page.mdx index bdf4524..d35e6fa 100644 --- a/app/types/page.mdx +++ b/app/types/page.mdx @@ -1,23 +1,7 @@ -## ISO8601 +## RFC3339 -```typescript -type Year = `${number}${number}${number}${number}`; -type Month = `${"0" | "1"}${number}`; -type Day = `${"0" | "1" | "2" | "3"}${number}`; - -type DateString = `${Year}-${Month}-${Day}`; - -type Hour = `${"0" | "1" | "2"}${number}`; -type Minute = `${"0" | "1" | "2" | "3" | "4" | "5"}${number}`; -type Second = `${"0" | "1" | "2" | "3" | "4" | "5"}${number}`; - -type TimeString = `${Hour}:${Minute}:${Second}`; - -type Offset = `${"Z" | "+" | "-"}${Hour}:${Minute}`; - -type ISO8601 = `${DateString}T${TimeString}${Offset}`; -``` +[https://datatracker.ietf.org/doc/html/rfc3339](https://datatracker.ietf.org/doc/html/rfc3339) ## UUID From 9ad94368456a16883e13f29379f6c7caa06e5a75 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 18 Oct 2024 15:10:23 +0200 Subject: [PATCH 15/50] feat: :sparkles: Add optional $schema field to entities --- app/changelog/page.mdx | 1 + app/entities/page.mdx | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index 5b11000..3e65512 100644 --- a/app/changelog/page.mdx +++ b/app/changelog/page.mdx @@ -20,6 +20,7 @@ This page lists changes since Working Draft 3. {{ className: 'lead' }} - Added [Versia Links](/links). - Switched from ISO 8601 to [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) for timestamps. - In most cases, the two are interchangeable, but RFC 3339 is more strict. Most implementations should not need to change anything. +- Add optional `$schema` field to [Entities](/entities). ## Since WD 3 diff --git a/app/entities/page.mdx b/app/entities/page.mdx index ab6d22c..0ae1ef8 100644 --- a/app/entities/page.mdx +++ b/app/entities/page.mdx @@ -36,6 +36,13 @@ Any field in an entity not marked as `required` may be omitted or set to `null`. **Some entity types may not need a URI. This will be specified in the entity's documentation.** + + URL of any JSON Schema that the entity adheres to. + + + This is for human use only, and not to be used by either clients or servers as a way to validate the entity. + + Extensions to the entity. Use this to add custom properties to the entity. From 1d375491d14c374ab473ce3120e448ce2f8e450e Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 18 Oct 2024 16:36:04 +0200 Subject: [PATCH 16/50] feat: :sparkles: Add Interaction Controls Extension --- app/changelog/page.mdx | 1 + app/extensions/interaction-controls/page.mdx | 108 +++++++++++++++++++ app/extensions/likes/page.mdx | 13 ++- components/Navigation.tsx | 4 + 4 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 app/extensions/interaction-controls/page.mdx diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index 3e65512..dde3e1e 100644 --- a/app/changelog/page.mdx +++ b/app/changelog/page.mdx @@ -21,6 +21,7 @@ This page lists changes since Working Draft 3. {{ className: 'lead' }} - Switched from ISO 8601 to [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) for timestamps. - In most cases, the two are interchangeable, but RFC 3339 is more strict. Most implementations should not need to change anything. - Add optional `$schema` field to [Entities](/entities). +- Added [Interaction Controls Extensions](/extensions/interaction-controls) ## Since WD 3 diff --git a/app/extensions/interaction-controls/page.mdx b/app/extensions/interaction-controls/page.mdx new file mode 100644 index 0000000..baf6cc9 --- /dev/null +++ b/app/extensions/interaction-controls/page.mdx @@ -0,0 +1,108 @@ +export const metadata = { + title: "Interaction Controls Extension", + description: "Allows users to control who can interact with their Notes" +} + +# Interaction Controls + +Often, it is desirable to post a Note, but control who is allowed to interact with it (e.g. send replies, like, dislike, etc.). This has traditionally not been possible in most federated networks: the Interaction Controls extension adds this possibility. + +## Usage + +The entity defined in this document must be inserted in the `pub.versia:interaction_controls` key of a [Note](/entities/note)'s extensions field. + +```jsonc {{ title: "Example Usage" }} +{ + "id": "456df8ed-daf1-4062-abab-491071c7b8dd", + "type": "Note", + "uri": "https://versia.social/notes/456df8ed-daf1-4062-abab-491071c7b8dd", + "created_at": "2024-04-09T01:38:51.743Z", + "content": { + "text/plain": { + "content": "Hello, world :happy_face:!" + } + }, + "extensions": { // [!code focus:9] + "pub.versia:interaction_controls": { + "reply": { + "allowed": ["followers"], + }, + } + } +} +``` + +## Entity Definition + + + + + + Describes permissions for a specific interaction. + + ```typescript + type InteractionGroup = | + "everyone" | + "followers" | + "followed" | + "group" | + "mutuals"; + + type InteractionPermissions = { + allowed?: InteractionGroup[]; + disallowed?: InteractionGroup[]; + } + ``` + + Permissions can either be whitelist (`allowed` property) or blacklist (`disallowed` property). Both options are mutually exclusive. + + In order of priority: + - `everyone`: Includes every single User in the federation. + - `followers`: Includes every follower of the author. + - `following`: Includes every User that the author follows. + - `mutuals`: Includes every mutual of the author (that is, every User that is both a follower and followed by the author). + - `group`: Includes every User in the [Group](/entities/group) that this Note was posted to, if any. If Note is not posted to a [Group](/entities/group), this value has no effect. + + Permission groups are evaluated from highest to lowest priority: if two groups conflict each other, the group with the highest priority must be used. + + + + + + ```jsonc {{ title: "Example"}} + { + "reply": { + "allowed": [ + "group" + ], + }, + "pub.versia:likes#Like": { + "disallowed": [ + "everyone" + ] + } + } + ``` + + + +## Usage + +### Interaction Types + +The following interaction types are defined as part of the core Versia spec: + +- `reply`: Sending a Note with `replies_to` including this Note. +- `quote`: Sending a Note with `quotes` including this Note. + +Extensions **may** choose to register their own interaction types (such as `pub.versia:likes#Like` for the [Like Extension](/extensions/likes)). The naming scheme for interaction types is identical to [Extensions](/extensions)'s `type` property, but with a hashtag (`#`) in place of a forward slash (`/`). + +### Handling Permission Errors + +Implementations that find a user attempting to create an interaction they are not allowed to **MUST** return a `403 Forbidden` HTTP status code when processing the Note during federation. The Note **must** also be discarded. + +It is important for implementations to backfill any related [Collections](/structures/collection) (e.g. user followers) in order to not incorrectly reject Notes based off of outdated data. + + + To avoid server load from constant Collection refreshing, implementations **could** only refetch associated Collections when forbidden interactions are detected, then recalculate permissions again. + \ No newline at end of file diff --git a/app/extensions/likes/page.mdx b/app/extensions/likes/page.mdx index ee49ea4..6682831 100644 --- a/app/extensions/likes/page.mdx +++ b/app/extensions/likes/page.mdx @@ -104,4 +104,15 @@ The Likes extension adds the following collections to the [User](/entities/user) "pub.versia:likes/Likes": "https://example.com/users/6e0204a2-746c-4972-8602-c4f37fc63bbe/likes", "pub.versia:likes/Dislikes": "https://example.com/users/6e0204a2-746c-4972-8602-c4f37fc63bbe/dislikes" } -} \ No newline at end of file +} +``` + +## Interaction Types + + + This section only applies to implementors of the [Interaction Controls Extension](/extensions/interaction-controls). + + +This extension registers the following interaction types: +- `pub.versia:likes#Like`, for liking a Note +- `pub.versia:likes#Dislike`, for disliking a Note \ No newline at end of file diff --git a/components/Navigation.tsx b/components/Navigation.tsx index 062725f..9c00fd9 100644 --- a/components/Navigation.tsx +++ b/components/Navigation.tsx @@ -295,6 +295,10 @@ export const navigation: NavGroup[] = [ title: "Instance Messaging", href: "/extensions/instance-messaging", }, + { + title: "Interaction Controls", + href: "/extensions/interaction-controls", + }, { title: "Likes", href: "/extensions/likes" }, { title: "Migration", href: "/extensions/migration" }, { title: "Polls", href: "/extensions/polls" }, From c26029681b1b0c0dfca2e158252f0881fec80ad8 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 18 Oct 2024 16:43:35 +0200 Subject: [PATCH 17/50] feat: :sparkles: Register more interaction types in the relevant extensions --- app/extensions/polls/page.mdx | 11 ++++++++++- app/extensions/reactions/page.mdx | 11 ++++++++++- app/extensions/share/page.mdx | 11 ++++++++++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/app/extensions/polls/page.mdx b/app/extensions/polls/page.mdx index e7be043..71e4bdb 100644 --- a/app/extensions/polls/page.mdx +++ b/app/extensions/polls/page.mdx @@ -125,4 +125,13 @@ If a vote is cast to a poll that is closed, the vote should be rejected with a ` ``` -
\ No newline at end of file + + +## Interaction Types + + + This section only applies to implementors of the [Interaction Controls Extension](/extensions/interaction-controls). + + +This extension registers the following interaction types: +- `pub.versia:polls#Vote`, for voting on a Poll attached to a Note. \ No newline at end of file diff --git a/app/extensions/reactions/page.mdx b/app/extensions/reactions/page.mdx index 58c885f..9d7b856 100644 --- a/app/extensions/reactions/page.mdx +++ b/app/extensions/reactions/page.mdx @@ -91,4 +91,13 @@ The Reactions Extension extends the [Note](/entities/note) entity with the follo ``` - \ No newline at end of file + + +## Interaction Types + + + This section only applies to implementors of the [Interaction Controls Extension](/extensions/interaction-controls). + + +This extension registers the following interaction types: +- `pub.versia:reactions#React`, for adding a Reaction to a Note. \ No newline at end of file diff --git a/app/extensions/share/page.mdx b/app/extensions/share/page.mdx index 59c8396..7bfde0d 100644 --- a/app/extensions/share/page.mdx +++ b/app/extensions/share/page.mdx @@ -44,4 +44,13 @@ When a user shares a note, the note's original author **must** receive the entit ``` - \ No newline at end of file + + +## Interaction Types + + + This section only applies to implementors of the [Interaction Controls Extension](/extensions/interaction-controls). + + +This extension registers the following interaction types: +- `pub.versia:share#Share`, for sharing a Note. \ No newline at end of file From b429c2f2e9bb02d41369cd97526af34be276a69d Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 18 Oct 2024 19:00:15 +0200 Subject: [PATCH 18/50] feat: :sparkles: Add "mentioned" interaction group --- app/extensions/interaction-controls/page.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/app/extensions/interaction-controls/page.mdx b/app/extensions/interaction-controls/page.mdx index baf6cc9..9ea730e 100644 --- a/app/extensions/interaction-controls/page.mdx +++ b/app/extensions/interaction-controls/page.mdx @@ -58,6 +58,7 @@ The entity defined in this document must be inserted in the `pub.versia:interact In order of priority: - `everyone`: Includes every single User in the federation. + - `mentioned`: Includes every mentioned User. - `followers`: Includes every follower of the author. - `following`: Includes every User that the author follows. - `mutuals`: Includes every mutual of the author (that is, every User that is both a follower and followed by the author). From 35e7119dc51127429432a86c2e9ac1e42ea0f64e Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Mon, 28 Oct 2024 14:19:30 +0100 Subject: [PATCH 19/50] feat: :sparkles: Write document on Principles --- app/philosophy/principles/page.mdx | 33 ++++++++++++++++++++++++++++++ components/Navigation.tsx | 4 ++++ 2 files changed, 37 insertions(+) create mode 100644 app/philosophy/principles/page.mdx diff --git a/app/philosophy/principles/page.mdx b/app/philosophy/principles/page.mdx new file mode 100644 index 0000000..0c497a6 --- /dev/null +++ b/app/philosophy/principles/page.mdx @@ -0,0 +1,33 @@ +# Principles + +When designing basically anything, it is very important to define its principles: many projects have failed because they accidentally strayed from their reason to exist. To not repeat the same mistakes, we need to define the core principles of the Versia Protocol. + +## Self-description + +Entities should contain all the data necessary for their processing (and only theirs) in a single JSON object. This object should also be roughly understandable by a human, and should be able to be serialized and deserialized without loss of information. + +This means that headers, transport mechanisms, + +## Determinism + +There must always be **one** canonical way of doing any single thing. There must always be **one** way to represent any single piece of data. There should be no ambiguity. + +## Simplicity over Functionality + +It's better to make something simple and easier to implement than something that supports every single edge case. This is not to say that edge cases should be ignored, but that they should be considered carefully. + +In general, **simplicity is preferred over functionality**. Extensions can potentially add fringe functionality back: however, if the core is too complex, it will be hard to add extensions. + +When in doubt, **leave it out**. + +### Client-facing vs Developer-facing + +Client-facing features (such as avatars, emoji reactions, quote posts, etc.) are usually "simpler" than the underlying federation mechanisms: as such, they should be prioritized and may contain more complexity than the underlying mechanisms. + +Developer-facing features (e.g. shared inboxes, reply backfilling, etc.) should be as simple as possible, as they are the building blocks of the client-facing features. When considering complexity, **client use-cases are more important than developer use-cases**. + +## Branching + +There should be **as little branching as possible**. This is reminiscent of the "one canonical way" principle: if there are multiple ways to do something, or a thing can be processed multiple ways, it should be simplified. + +If there is a need for branching, nesting should be avoided: branches should be as flat as possible. \ No newline at end of file diff --git a/components/Navigation.tsx b/components/Navigation.tsx index 9c00fd9..370a3a3 100644 --- a/components/Navigation.tsx +++ b/components/Navigation.tsx @@ -257,6 +257,10 @@ export const navigation: NavGroup[] = [ { title: "Extensions", href: "/extensions" }, ], }, + { + title: "Philosophy", + links: [{ title: "Principles", href: "/philosophy/principles" }], + }, { title: "Federation", links: [ From 1907c09653e01924c6d936ff4f83ce2d613553a1 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Mon, 28 Oct 2024 14:43:39 +0100 Subject: [PATCH 20/50] chore: :arrow_up: Upgrade dependencies --- bun.lockb | Bin 198696 -> 171976 bytes package.json | 30 +++++++++++++++--------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/bun.lockb b/bun.lockb index 4099437e14c5340e53767c29ff213836afd53879..ab87089d7edde867fb2a260ad5bd64ec17b4c752 100755 GIT binary patch delta 42024 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 Date: Mon, 28 Oct 2024 14:45:15 +0100 Subject: [PATCH 21/50] fix: :memo: Complete unfinished sentence --- app/philosophy/principles/page.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/philosophy/principles/page.mdx b/app/philosophy/principles/page.mdx index 0c497a6..0842424 100644 --- a/app/philosophy/principles/page.mdx +++ b/app/philosophy/principles/page.mdx @@ -6,7 +6,7 @@ When designing basically anything, it is very important to define its principles Entities should contain all the data necessary for their processing (and only theirs) in a single JSON object. This object should also be roughly understandable by a human, and should be able to be serialized and deserialized without loss of information. -This means that headers, transport mechanisms, +This means that headers, transport mechanisms, encoding and other such things should be separate from the data itself. This is to ensure that the data can be processed by any system, regardless of the transport mechanism. ## Determinism From d4a4554623d418b1c2bbff2f10eace9f72155f01 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Sat, 2 Nov 2024 16:05:39 +0100 Subject: [PATCH 22/50] chore: :arrow_up: Upgrade dependencies --- bun.lockb | Bin 171976 -> 172000 bytes package.json | 12 ++++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bun.lockb b/bun.lockb index ab87089d7edde867fb2a260ad5bd64ec17b4c752..4e4c32247228930c9d4df3972261f682ad2888d7 100755 GIT binary patch delta 7595 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 QH7tqz8aWYp4ZHsT0L-(}AOHXW delta 7470 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 Date: Sat, 2 Nov 2024 16:21:24 +0100 Subject: [PATCH 23/50] ci: :green_heart: Set build Node version to 22.11.0 --- .node-version | 1 + 1 file changed, 1 insertion(+) create mode 100644 .node-version diff --git a/.node-version b/.node-version new file mode 100644 index 0000000..fdb2eaa --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +22.11.0 \ No newline at end of file From 3babd7a5a3e63a94358f6fe78078c590437c02c9 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Sat, 2 Nov 2024 16:24:22 +0100 Subject: [PATCH 24/50] fix: :bug: Use proper React version overrides --- bun.lockb | Bin 172000 -> 171132 bytes package.json | 4 ++++ 2 files changed, 4 insertions(+) diff --git a/bun.lockb b/bun.lockb index 4e4c32247228930c9d4df3972261f682ad2888d7..77c51be78a168bb19d00a7132547ba4f77fe6599 100755 GIT binary patch delta 27733 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 BZ|(p9 delta 28204 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 Zvp2SMA@5{LKZm@0>${Vzr8}SVe*m5KK~n$# diff --git a/package.json b/package.json index 3e263a5..8fd689f 100644 --- a/package.json +++ b/package.json @@ -55,5 +55,9 @@ "@shikijs/transformers": "^1.22.2", "sharp": "^0.33.5" }, + "overrides": { + "react": "^19.0.0-rc-cae764ce-20241025", + "react-dom": "^19.0.0-rc-cae764ce-20241025" + }, "trustedDependencies": ["@biomejs/biome", "sharp"] } From b59b6b8ebbfd79c9cff297769fb605c4a4529bc8 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Sun, 3 Nov 2024 12:19:21 +0100 Subject: [PATCH 25/50] refactor: :recycle: Add URI Collections and change all appropriate Collections to use them --- app/changelog/page.mdx | 2 + app/entities/group/page.mdx | 4 +- app/entities/user/page.mdx | 10 ++-- app/extensions/interaction-controls/page.mdx | 2 +- app/extensions/likes/page.mdx | 4 +- app/extensions/reactions/page.mdx | 2 +- app/federation/page.mdx | 2 +- app/structures/collection/page.mdx | 57 ++++++++++++++++++++ 8 files changed, 71 insertions(+), 12 deletions(-) diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index dde3e1e..746644d 100644 --- a/app/changelog/page.mdx +++ b/app/changelog/page.mdx @@ -22,6 +22,8 @@ This page lists changes since Working Draft 3. {{ className: 'lead' }} - In most cases, the two are interchangeable, but RFC 3339 is more strict. Most implementations should not need to change anything. - Add optional `$schema` field to [Entities](/entities). - Added [Interaction Controls Extensions](/extensions/interaction-controls) +- Added [URI Collections](/structures/collection#uri-collection) + - Changed all Collections that can contain remote entities to use URI Collections (eg. [User](/entities/user) `collections.followers`). ## Since WD 3 diff --git a/app/entities/group/page.mdx b/app/entities/group/page.mdx index ec9e4cc..7d19d25 100644 --- a/app/entities/group/page.mdx +++ b/app/entities/group/page.mdx @@ -25,10 +25,10 @@ Refer to [Note](/entities/note#entity-definition)'s `group` property for how not Text only (`text/plain`, `text/html`, etc). - URI of the group's members list. [Collection](/structures/collection) of [Users](/entities/user). + URI of the group's members list. [URI Collection](/structures/collection#uri-collection) of [Users](/entities/user). - URI of the group's associated notes. [Collection](/structures/collection) of [Notes](/entities/note). + URI of the group's associated notes. [URI Collection](/structures/collection#uri-collection) of [Notes](/entities/note). diff --git a/app/entities/user/page.mdx b/app/entities/user/page.mdx index f7a6ab8..bb4773d 100644 --- a/app/entities/user/page.mdx +++ b/app/entities/user/page.mdx @@ -114,19 +114,19 @@ Instance **must** be the host of the instance the user is on (hostname with opti } ``` - All URIs must resolve to a [Collection](/structures/collection) of the appropriate entities. Extensions may add additional collections. + All URIs must resolve to either a [Collection](/structures/collection) or a [URI Collection](/structures/collection#uri-collection) of the appropriate entities. Extensions may add additional collections. ### Outbox - The user's federation outbox. Refer to the [federation documentation](/federation). + The user's federation outbox. Refer to the [federation documentation](/federation). [Collection](/structures/collection) of [Note](/entities/note) entities. ### Followers - User's followers. [Collection](/structures/collection) of [User](/entities/user) entities. + User's followers. [URI Collection](/structures/collection#uri-collection) of [User](/entities/user) entities. ### Following - Users that the user follows. [Collection](/structures/collection) of [User](/entities/user) entities. + Users that the user follows. [URI Collection](/structures/collection#uri-collection) of [User](/entities/user) entities. ### Featured - [Notes](/entities/note) that the user wants to feature (also known as "pin") on their profile. [Collection](/structures/collection) of [Note](/entities/note) entities. + [Notes](/entities/note) that the user wants to feature (also known as "pin") on their profile. [Collection](/structures/collection) of [Note](/entities/note) entities. Only notes authored by the user can be featured. diff --git a/app/extensions/interaction-controls/page.mdx b/app/extensions/interaction-controls/page.mdx index 9ea730e..682a9c1 100644 --- a/app/extensions/interaction-controls/page.mdx +++ b/app/extensions/interaction-controls/page.mdx @@ -102,7 +102,7 @@ Extensions **may** choose to register their own interaction types (such as `pub. Implementations that find a user attempting to create an interaction they are not allowed to **MUST** return a `403 Forbidden` HTTP status code when processing the Note during federation. The Note **must** also be discarded. -It is important for implementations to backfill any related [Collections](/structures/collection) (e.g. user followers) in order to not incorrectly reject Notes based off of outdated data. +It is important for implementations to backfill any related [Collections](/structures/collection)/[URI Collections](/structures/collection#uri-collection) (e.g. user followers) in order to not incorrectly reject Notes based off of outdated data. To avoid server load from constant Collection refreshing, implementations **could** only refetch associated Collections when forbidden interactions are detected, then recalculate permissions again. diff --git a/app/extensions/likes/page.mdx b/app/extensions/likes/page.mdx index 6682831..20a36ff 100644 --- a/app/extensions/likes/page.mdx +++ b/app/extensions/likes/page.mdx @@ -92,8 +92,8 @@ To undo a like or dislike, a [Delete](/entities/delete) entity should be used. T The Likes extension adds the following collections to the [User](/entities/user) entity: -- `likes`: A [Collection](/structures/collection) of all the notes the user has liked. -- `dislikes`: A [Collection](/structures/collection) of all the notes the user has disliked. +- `likes`: A [URI Collection](/structures/collection#uri-collection) of all the notes the user has liked. +- `dislikes`: A [URI Collection](/structures/collection#uri-collection) of all the notes the user has disliked. ```jsonc { diff --git a/app/extensions/reactions/page.mdx b/app/extensions/reactions/page.mdx index 9d7b856..687c861 100644 --- a/app/extensions/reactions/page.mdx +++ b/app/extensions/reactions/page.mdx @@ -58,7 +58,7 @@ The Reactions Extension extends the [Note](/entities/note) entity with the follo - URI to a [Collection](/structures/collection) of the [Reactions](#entity-definition) attached to the note. + URI to a [URI Collection](/structures/collection#uri-collection) of the [Reactions](#entity-definition) attached to the note. diff --git a/app/federation/page.mdx b/app/federation/page.mdx index 6378dc7..9364a26 100644 --- a/app/federation/page.mdx +++ b/app/federation/page.mdx @@ -39,6 +39,6 @@ Shared inboxes are defined in the [Instance Metadata](/entities/instance-metadat ## Outboxes -In addition to inboxes, every user has an outbox (e.g., `/users/3/outbox`). The outbox is simply a collection of all the messages that a user has sent. When a user sends a message to another user, a copy of that message is accessible in the sender's outbox. +In addition to inboxes, every user has an outbox (e.g., `/users/3/outbox`). The outbox is simply a [Collection](/structures/collection) of all the messages that a user has sent. When a user sends a message to another user, a copy of that message is accessible in the sender's outbox. Outboxes are very useful for "backfilling" data when a new instance joins the network. By resolving the outboxes of all new users it encounters, a new instance can quickly catch up on all old messages. \ No newline at end of file diff --git a/app/structures/collection/page.mdx b/app/structures/collection/page.mdx index 12ee97f..9140a24 100644 --- a/app/structures/collection/page.mdx +++ b/app/structures/collection/page.mdx @@ -75,5 +75,62 @@ Pages should be limited to a reasonable number of entities, such as 20 or 80. } ``` + + + +## URI Collection + +URI Collections are identical to regular collections, but they contain only URIs instead of full entities. They are useful for cases when remote entities need to be included in a collection, as those are typically not stored in implementation databases. {{ className: 'lead' }} + + + + + + Author of the collection. Usually the user who owns the collection. [Can be set to `null` to represent the instance](/entities/instance-metadata#the-null-author). + + + URI to the first page of the collection. Query parameters are allowed. + + + URI to the last page of the collection. Query parameters are allowed. + + If the collection only has one page, this should be the same as `first`. + + + Total number of entities in the collection, across all pages. + + + URI to the next page of the collection. Query parameters are allowed. + + If there is no next page, this should be `null`. + + + URI to the previous page of the collection. Query parameters are allowed. + + If there is no previous page, this should be `null`. + + + Collection contents. Must be an array of URIs. + + + + + + + ```jsonc {{ 'title': 'Example URI Collection' }} + { + "author": "https://versia.social/users/018ec082-0ae1-761c-b2c5-22275a611771", + "first": "https://versia.social/users/018ec082-0ae1-761c-b2c5-22275a611771/followers?page=1", + "last": "https://versia.social/users/018ec082-0ae1-761c-b2c5-22275a611771/followers?page=3", + "total": 46, + "next": "https://versia.social/users/018ec082-0ae1-761c-b2c5-22275a611771/followers?page=2", + "previous": null, + "items": [ + "https://versia.social/users/f8b0d4b4-d354-4798-bbc5-c2ba8acabfe3", + "https://social.bob.com/u/2B27E62snga763" + ] + } + ``` + \ No newline at end of file From e97b86f9830b02b522bf161eef783b1fd26dba78 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Sun, 3 Nov 2024 12:43:27 +0100 Subject: [PATCH 26/50] feat: :sparkles: Add collections field to Notes --- app/changelog/page.mdx | 2 + app/entities/note/page.mdx | 29 ++++++++++++ app/extensions/custom-emojis/page.mdx | 4 ++ app/extensions/interaction-controls/page.mdx | 4 ++ app/extensions/likes/page.mdx | 19 ++++++++ app/extensions/polls/page.mdx | 4 ++ app/extensions/reactions/page.mdx | 50 +++++--------------- app/extensions/share/page.mdx | 17 +++++++ app/structures/collection/page.mdx | 4 ++ 9 files changed, 95 insertions(+), 38 deletions(-) diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index 746644d..70a0db6 100644 --- a/app/changelog/page.mdx +++ b/app/changelog/page.mdx @@ -24,6 +24,8 @@ This page lists changes since Working Draft 3. {{ className: 'lead' }} - Added [Interaction Controls Extensions](/extensions/interaction-controls) - Added [URI Collections](/structures/collection#uri-collection) - Changed all Collections that can contain remote entities to use URI Collections (eg. [User](/entities/user) `collections.followers`). +- Add `collections` field to [Notes](/entities/note). + - [Likes Extension](/extensions/likes), [Reactions Extension](/extensions/reactions) and [Share Extension](/extensions/share) now use this field, instead of a custom field in `extensions`. ## Since WD 3 diff --git a/app/entities/note/page.mdx b/app/entities/note/page.mdx index 7a3f363..79f71a5 100644 --- a/app/entities/note/page.mdx +++ b/app/entities/note/page.mdx @@ -36,6 +36,28 @@ Notes represent a piece of content on a Versia instance. They can be posted by [ | "messaging"; // Like Discord, Element (Matrix), Signal ``` + + Collections related to the note. Must contain at least `replies` and `quotes`. + + ```typescript + type URI = string; + + type NoteCollections = { + replies: URI; + quotes: URI; + // Same format as type on Extensions + [key: ExtensionsKey]: URI; + } + ``` + + All URIs must resolve to either a [Collection](/structures/collection) or a [URI Collection](/structures/collection#uri-collection) of the appropriate entities. Extensions may add additional collections. + + ### Replies + All replies to this note (have this note as their `replies_to`). [URI Collection](/structures/collection#uri-collection) of [Note](/entities/note) entities. + + ### Quotes + All quotes of this note (have this note as their `quotes`). [URI Collection](/structures/collection#uri-collection) of [Note](/entities/note) entities. + The content of the note. Must be text format (`text/html`, `text/markdown`, etc). Must not be remote. @@ -126,6 +148,13 @@ Notes represent a piece of content on a Versia instance. They can be posted by [ ], "author": "https://versia.social/users/018eb863-753f-76ff-83d6-fd590de7740a", "category": "microblog", + "collections": { + "replies": "https://versia.social/objects/01902e09-0f8b-72de-8ee3-9afc0cf5eae1/replies", + "quotes": "https://versia.social/objects/01902e09-0f8b-72de-8ee3-9afc0cf5eae1/quotes", + "pub.versia:likes/Likes": "https://versia.social/objects/01902e09-0f8b-72de-8ee3-9afc0cf5eae1/likes", + "pub.versia:likes/Dislikes": "https://versia.social/objects/01902e09-0f8b-72de-8ee3-9afc0cf5eae1/dislikes", + "pub.versia:reactions/Reactions": "https://versia.social/objects/01902e09-0f8b-72de-8ee3-9afc0cf5eae1/reactions" + }, "content": { "text/html": { "content": "

In the next versia-fe update: account settings, finally!

" diff --git a/app/extensions/custom-emojis/page.mdx b/app/extensions/custom-emojis/page.mdx index cf491ed..c9cf810 100644 --- a/app/extensions/custom-emojis/page.mdx +++ b/app/extensions/custom-emojis/page.mdx @@ -87,6 +87,10 @@ Custom Emojis can be added to any entity with text content. The extension ID is "type": "Note", "uri": "https://versia.social/notes/456df8ed-daf1-4062-abab-491071c7b8dd", "created_at": "2024-04-09T01:38:51.743Z", + "collections": { + "replies": "https://versia.social/notes/456df8ed-daf1-4062-abab-491071c7b8dd/replies", + "quotes": "https://versia.social/notes/456df8ed-daf1-4062-abab-491071c7b8dd/quotes" + }, "content": { "text/plain": { "content": "Hello, world :happy_face:!" diff --git a/app/extensions/interaction-controls/page.mdx b/app/extensions/interaction-controls/page.mdx index 682a9c1..12931da 100644 --- a/app/extensions/interaction-controls/page.mdx +++ b/app/extensions/interaction-controls/page.mdx @@ -17,6 +17,10 @@ The entity defined in this document must be inserted in the `pub.versia:interact "type": "Note", "uri": "https://versia.social/notes/456df8ed-daf1-4062-abab-491071c7b8dd", "created_at": "2024-04-09T01:38:51.743Z", + "collections": { + "replies": "https://versia.social/notes/456df8ed-daf1-4062-abab-491071c7b8dd/replies", + "quotes": "https://versia.social/notes/456df8ed-daf1-4062-abab-491071c7b8dd/quotes" + }, "content": { "text/plain": { "content": "Hello, world :happy_face:!" diff --git a/app/extensions/likes/page.mdx b/app/extensions/likes/page.mdx index 20a36ff..569360e 100644 --- a/app/extensions/likes/page.mdx +++ b/app/extensions/likes/page.mdx @@ -107,6 +107,25 @@ The Likes extension adds the following collections to the [User](/entities/user) } ``` +## Note Collections + +The Likes extension adds the following collections to the [Note](/entities/note) entity: + +- `likes`: A [URI Collection](/structures/collection#uri-collection) of all the likes the note has received. +- `dislikes`: A [URI Collection](/structures/collection#uri-collection) of all the dislikes the note has received. + +```jsonc +{ + "type": "Note", + ... + "collections": { + ... + "pub.versia:likes/Likes": "https://example.com/notes/fmKZ763jzIU8/likes", + "pub.versia:likes/Dislikes": "https://example.com/notes/fmKZ763jzIU8/dislikes" + } +} +``` + ## Interaction Types diff --git a/app/extensions/polls/page.mdx b/app/extensions/polls/page.mdx index 71e4bdb..71e8209 100644 --- a/app/extensions/polls/page.mdx +++ b/app/extensions/polls/page.mdx @@ -45,6 +45,10 @@ Note that there is no `question` field: the question should be included in the ` "created_at": "2024-06-19T01:07:44.139Z", "author": "https://versia.social/users/018eb863-753f-76ff-83d6-fd590de7740a", "category": "microblog", + "collections": { + "replies": "https://versia.social/notes/01902e09-0f8b-72de-8ee3-9afc0cf5eae1/replies", + "quotes": "https://versia.social/notes/01902e09-0f8b-72de-8ee3-9afc0cf5eae1/quotes" + }, "content": { "text/plain": { "content": "What is your favourite color?" diff --git a/app/extensions/reactions/page.mdx b/app/extensions/reactions/page.mdx index 687c861..035dccc 100644 --- a/app/extensions/reactions/page.mdx +++ b/app/extensions/reactions/page.mdx @@ -50,48 +50,22 @@ User reactions are (like every other entity) federated to all followers, and can -## Extensions to Note +## Note Collections -The Reactions Extension extends the [Note](/entities/note) entity with the following fields: +The Likes extension adds the following collections to the [Note](/entities/note) entity: - - - - - URI to a [URI Collection](/structures/collection#uri-collection) of the [Reactions](#entity-definition) attached to the note. - - - +- `reactions`: A [URI Collection](/structures/collection#uri-collection) of all the reactions to the note. - - - ```jsonc {{ title: "Example Note" }} - { - "id": "01902e09-0f8b-72de-8ee3-9afc0cf5eae1", - "type": "Note", // [!code focus] - "uri": "https://versia.social/notes/01902e09-0f8b-72de-8ee3-9afc0cf5eae1", - "created_at": "2024-06-19T01:07:44.139Z", - "author": "https://versia.social/users/018eb863-753f-76ff-83d6-fd590de7740a", - "category": "microblog", - "content": { - "text/plain": { - "content": "Bababooey." - } - }, - "extensions": { // [!code focus:5] - "pub.versia:reactions": { - "reactions": "https://versia.social/notes/01902e09-0f8b-72de-8ee3-9afc0cf5eae1/reactions" - } - }, - "group": "public", - "is_sensitive": false, - "mentions": [], +```jsonc +{ + "type": "Note", + ... + "collections": { + ... + "pub.versia:reactions/Reactions": "https://example.com/publications/f08a124e-fe90-439e-8be4-15a428a72a19/reactions" } - - ``` - - - +} +``` ## Interaction Types diff --git a/app/extensions/share/page.mdx b/app/extensions/share/page.mdx index 7bfde0d..7e2e328 100644 --- a/app/extensions/share/page.mdx +++ b/app/extensions/share/page.mdx @@ -46,6 +46,23 @@ When a user shares a note, the note's original author **must** receive the entit +## Note Collections + +The Share extension adds the following collections to the [Note](/entities/note) entity: + +- `shares`: A [URI Collection](/structures/collection#uri-collection) of all the shares of the note. + +```jsonc +{ + "type": "Note", + ... + "collections": { + ... + "pub.versia:share/Shares": "https://example.com/notes/fmKZ763jzIU8/shares" + } +} +``` + ## Interaction Types diff --git a/app/structures/collection/page.mdx b/app/structures/collection/page.mdx index 9140a24..8af34c0 100644 --- a/app/structures/collection/page.mdx +++ b/app/structures/collection/page.mdx @@ -65,6 +65,10 @@ Pages should be limited to a reasonable number of entities, such as 20 or 80. "type": "Note", "uri": "https://versia.social/notes/456df8ed-daf1-4062-abab-491071c7b8dd", "created_at": "2024-04-09T01:38:51.743Z", + "collections": { + "replies": "https://versia.social/notes/456df8ed-daf1-4062-abab-491071c7b8dd/replies", + "quotes": "https://versia.social/notes/456df8ed-daf1-4062-abab-491071c7b8dd/quotes" + }, "content": { "text/plain": { "content": "Hello, world!" From 1fe84674defef433aff9234a470e42cee98ad081 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Mon, 4 Nov 2024 11:41:21 +0100 Subject: [PATCH 27/50] ci: :construction_worker: Add Codeberg mirror CI --- .github/workflows/mirror.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .github/workflows/mirror.yml diff --git a/.github/workflows/mirror.yml b/.github/workflows/mirror.yml new file mode 100644 index 0000000..1dba954 --- /dev/null +++ b/.github/workflows/mirror.yml @@ -0,0 +1,8 @@ +name: Mirror to Codeberg +on: [push] + +jobs: + mirror: + name: Mirror + uses: versia-pub/.github/.github/workflows/mirror.yml@main + secrets: inherit From 10b53282470343176a13c64e81a5bb24c37dab97 Mon Sep 17 00:00:00 2001 From: April John <30842467+CutestNekoAqua@users.noreply.github.com> Date: Tue, 19 Nov 2024 19:19:16 +0000 Subject: [PATCH 28/50] fix: update Versia Links --- app/links/page.mdx | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/app/links/page.mdx b/app/links/page.mdx index c52940e..7d57ec5 100644 --- a/app/links/page.mdx +++ b/app/links/page.mdx @@ -18,20 +18,22 @@ Versia Links are a way to reference entities in the Versia Protocol, in a way th An IANA registration for the `versia://` scheme will be requested in the future. - - Instance host, including the port if it is not the default (i.e. `443` for HTTPS). - Action to take on the entity. Can have multiple slashes as a way to segment the action. + Links that reference instance-specific content (like Entities) **must** reference a Instance. Possible actions: - - `users/:username`: Open a user profile. - - `notes/:id`: Open a note. - - `groups/:id`: Open a group. - - `reply/:id`: Open the composer to reply to a note. - - `quote/:id`: Open the composer to quote a note. - - `share/:id`: Share a note. + - `users/:instance/:id`: Open a user profile. + - `notes/:instance/:id`: Open a note. + - `groups/:instance/:id`: Open a group. + - `reply/:instance/:id`: Open the composer to reply to a note. + - `quote/:instance/:id`: Open the composer to quote a note. + - `share/:instance/:id`: Share a note. + - `compose/:text`: Compose a new note. Text passed at the end will be added in the note compose field. Used for "Share with Versia" buttons on websites. + + + Instance hosting the referenced content, including the port if it is not the default (i.e. `443` for HTTPS). @@ -60,4 +62,6 @@ The default client ("frontend") on a Versia instance **should** also display Ver - Notes - Groups -Clients **should** ask users to confirm any action that is not a simple view action, such as replying to a note or sharing a note. \ No newline at end of file +This **could** be used for easier following of users from remote instances. + +Clients **should** ask users to confirm any action that is not a simple view action, such as replying to a note or sharing a note. From aba8ff170b8cb2861877a196b3b7b7e6f4764e0c Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Sun, 24 Nov 2024 17:58:46 +0100 Subject: [PATCH 29/50] chore: :arrow_up: Upgrade dependencies --- bun.lockb | Bin 171132 -> 173332 bytes package.json | 30 +++++++++++++++--------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/bun.lockb b/bun.lockb index 77c51be78a168bb19d00a7132547ba4f77fe6599..3436d11d15b272a0762d4102e0ae2836707ad3aa 100755 GIT binary patch delta 28395 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 delta 27120 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 H!omLm89Uya diff --git a/package.json b/package.json index 8fd689f..7ec632a 100644 --- a/package.json +++ b/package.json @@ -11,16 +11,16 @@ "uuid": "bun --print 'crypto.randomUUID()'" }, "dependencies": { - "@algolia/autocomplete-core": "^1.17.6", + "@algolia/autocomplete-core": "^1.17.7", "@headlessui/react": "^2.2.0", "@headlessui/tailwindcss": "^0.2.1", "@mdx-js/loader": "^3.1.0", "@mdx-js/react": "^3.1.0", - "@next/mdx": "^15.0.2", + "@next/mdx": "^15.0.3", "@sindresorhus/slugify": "^2.2.1", "@tailwindcss/typography": "^0.5.15", "@types/mdx": "^2.0.13", - "@types/node": "^22.8.6", + "@types/node": "^22.9.3", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "@types/react-highlight-words": "^0.20.0", @@ -29,21 +29,21 @@ "clsx": "^2.1.1", "fast-glob": "^3.3.2", "flexsearch": "^0.7.43", - "framer-motion": "^11.11.11", + "framer-motion": "^11.11.17", "mdast-util-to-string": "^4.0.0", "mdx-annotations": "^0.1.4", - "next": "^15.0.2", - "next-themes": "^0.3.0", - "react": "^19.0.0-rc-cae764ce-20241025", - "react-dom": "^19.0.0-rc-cae764ce-20241025", + "next": "^15.0.3", + "next-themes": "^0.4.3", + "react": "^19.0.0-rc-91061073-20241121", + "react-dom": "^19.0.0-rc-91061073-20241121", "react-highlight-words": "^0.20.0", "remark": "^15.0.1", "remark-gfm": "^4.0.0", "remark-mdx": "^3.1.0", - "shiki": "^1.22.2", + "shiki": "^1.23.1", "simple-functional-loader": "^1.2.1", - "tailwindcss": "^3.4.14", - "typescript": "^5.6.3", + "tailwindcss": "^3.4.15", + "typescript": "^5.7.2", "unist-util-filter": "^5.0.1", "unist-util-visit": "^5.0.0", "zustand": "^5.0.1" @@ -51,13 +51,13 @@ "devDependencies": { "@biomejs/biome": "^1.9.4", "@iconify-icon/react": "^2.1.0", - "@next/bundle-analyzer": "^15.0.2", - "@shikijs/transformers": "^1.22.2", + "@next/bundle-analyzer": "^15.0.3", + "@shikijs/transformers": "^1.23.1", "sharp": "^0.33.5" }, "overrides": { - "react": "^19.0.0-rc-cae764ce-20241025", - "react-dom": "^19.0.0-rc-cae764ce-20241025" + "react": "^19.0.0-rc-91061073-20241121", + "react-dom": "^19.0.0-rc-91061073-20241121" }, "trustedDependencies": ["@biomejs/biome", "sharp"] } From a88272c6667d3e8282b160eccd7832a44aebc262 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Sun, 24 Nov 2024 18:03:25 +0100 Subject: [PATCH 30/50] feat: :sparkles: Allow uppercase letters in usernames, make them case-insensitive --- app/changelog/page.mdx | 2 ++ app/entities/user/page.mdx | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index 70a0db6..2bdb596 100644 --- a/app/changelog/page.mdx +++ b/app/changelog/page.mdx @@ -26,6 +26,8 @@ This page lists changes since Working Draft 3. {{ className: 'lead' }} - Changed all Collections that can contain remote entities to use URI Collections (eg. [User](/entities/user) `collections.followers`). - Add `collections` field to [Notes](/entities/note). - [Likes Extension](/extensions/likes), [Reactions Extension](/extensions/reactions) and [Share Extension](/extensions/share) now use this field, instead of a custom field in `extensions`. +- Allowed uppercase characters in [User](/entities/user) `username`. + - These are now case-insensitive. ## Since WD 3 diff --git a/app/entities/user/page.mdx b/app/entities/user/page.mdx index bb4773d..9330692 100644 --- a/app/entities/user/page.mdx +++ b/app/entities/user/page.mdx @@ -23,7 +23,7 @@ For example: @018ec082-0ae1-761c-b2c5-22275a611771@versia.social ``` -This is similar to an email address or an ActivityPub address. +This is similar to an email address or an ActivityPub address. Usernames are case-insensitive. ### Identifier @@ -65,7 +65,7 @@ Instance **must** be the host of the instance the user is on (hostname with opti Alpha-numeric username. Must be unique within the instance. **Must** be treated as changeable by the user. - Can only contain the following characters: `a-z` (lowercase), `0-9`, `_` and `-`. Should be limited to reasonable lengths. + Can only contain the following characters: `a-z`, `A-Z` (case-insensitive), `0-9`, `_` and `-`. Should be limited to reasonable lengths. A header image for the user's profile. Also known as a cover photo or a banner. Must be an image format (`image/*`). From 963672a5694bd8ed6e5d9d1e4a7b01dbabd4f5b7 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Sat, 7 Dec 2024 10:52:27 +0100 Subject: [PATCH 31/50] fix: :bug: Use beta.versia.social instead of social.lysand.org --- app/page.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/page.tsx b/app/page.tsx index c26510b..ee1889b 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -125,7 +125,7 @@ const Page: FC = () => { { name: "Versia", icon: "bx:server", - url: "https://social.lysand.org/@jessew", + url: "https://beta.versia.social/@jessew", }, { name: "Matrix", @@ -163,7 +163,7 @@ const Page: FC = () => { { name: "Versia", icon: "bx:server", - url: "https://social.lysand.org/@aprl", + url: "https://beta.versia.social/@aprl", }, { name: "Matrix", From 83a00503a66b1d31e918dd116a64eb424dd598b5 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Tue, 10 Dec 2024 11:51:42 +0100 Subject: [PATCH 32/50] fix: :bug: Update examples in Versia Links --- app/links/page.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/links/page.mdx b/app/links/page.mdx index 7d57ec5..387d72b 100644 --- a/app/links/page.mdx +++ b/app/links/page.mdx @@ -40,15 +40,15 @@ Versia Links are a way to reference entities in the Versia Protocol, in a way th ``` {{ title: "Viewing a user profile" }} - web+versia://bob.social/users/alice + web+versia://users/bob.social/alice ``` ``` {{ title: "Viewing a note" }} - web+versia://jimbob.com/notes/01902e09-0f8b-72de-8ee3-9afc0cf5eae1 + web+versia://notes/jimbob.com/01902e09-0f8b-72de-8ee3-9afc0cf5eae1 ``` ``` {{ title: "Replying to a note" }} - web+versia://bob.social/reply/01902e09-0f8b-72de-8ee3-9afc0cf5eae1 + web+versia://reply/bob.social/01902e09-0f8b-72de-8ee3-9afc0cf5eae1 ``` From aad708c3611c5fa2d4d3b9e5dfe58e903689dc2a Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Tue, 10 Dec 2024 11:53:00 +0100 Subject: [PATCH 33/50] chore: :arrow_up: Upgrade dependencies --- bun.lockb | Bin 173332 -> 175732 bytes package.json | 32 ++++++++++++++++---------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/bun.lockb b/bun.lockb index 3436d11d15b272a0762d4102e0ae2836707ad3aa..4323f787a9659d4a1c5449293208a55a3137c522 100755 GIT binary patch delta 27960 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 delta 26646 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 diff --git a/package.json b/package.json index 7ec632a..e7a5b88 100644 --- a/package.json +++ b/package.json @@ -11,48 +11,48 @@ "uuid": "bun --print 'crypto.randomUUID()'" }, "dependencies": { - "@algolia/autocomplete-core": "^1.17.7", + "@algolia/autocomplete-core": "^1.17.8", "@headlessui/react": "^2.2.0", "@headlessui/tailwindcss": "^0.2.1", "@mdx-js/loader": "^3.1.0", "@mdx-js/react": "^3.1.0", - "@next/mdx": "^15.0.3", + "@next/mdx": "^15.0.4", "@sindresorhus/slugify": "^2.2.1", "@tailwindcss/typography": "^0.5.15", "@types/mdx": "^2.0.13", - "@types/node": "^22.9.3", - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", + "@types/node": "^22.10.1", + "@types/react": "^19.0.1", + "@types/react-dom": "^19.0.2", "@types/react-highlight-words": "^0.20.0", "acorn": "^8.14.0", "autoprefixer": "^10.4.20", "clsx": "^2.1.1", "fast-glob": "^3.3.2", "flexsearch": "^0.7.43", - "framer-motion": "^11.11.17", + "framer-motion": "^11.13.4", "mdast-util-to-string": "^4.0.0", "mdx-annotations": "^0.1.4", - "next": "^15.0.3", - "next-themes": "^0.4.3", - "react": "^19.0.0-rc-91061073-20241121", - "react-dom": "^19.0.0-rc-91061073-20241121", + "next": "^15.0.4", + "next-themes": "^0.4.4", + "react": "^19.0.0", + "react-dom": "^19.0.0", "react-highlight-words": "^0.20.0", "remark": "^15.0.1", "remark-gfm": "^4.0.0", "remark-mdx": "^3.1.0", - "shiki": "^1.23.1", + "shiki": "^1.24.2", "simple-functional-loader": "^1.2.1", - "tailwindcss": "^3.4.15", + "tailwindcss": "^3.4.16", "typescript": "^5.7.2", "unist-util-filter": "^5.0.1", "unist-util-visit": "^5.0.0", - "zustand": "^5.0.1" + "zustand": "^5.0.2" }, "devDependencies": { "@biomejs/biome": "^1.9.4", - "@iconify-icon/react": "^2.1.0", - "@next/bundle-analyzer": "^15.0.3", - "@shikijs/transformers": "^1.23.1", + "@iconify-icon/react": "^2.2.0", + "@next/bundle-analyzer": "^15.0.4", + "@shikijs/transformers": "^1.24.2", "sharp": "^0.33.5" }, "overrides": { From 7055b898429f3836a2ea0574f873c0ffde6d2540 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Tue, 10 Dec 2024 16:17:07 +0100 Subject: [PATCH 34/50] feat: :sparkles: Properly document Groups federation --- app/changelog/page.mdx | 1 + app/entities/group/page.mdx | 196 ++++++++++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+) diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index 2bdb596..32ac559 100644 --- a/app/changelog/page.mdx +++ b/app/changelog/page.mdx @@ -17,6 +17,7 @@ This page lists changes since Working Draft 3. {{ className: 'lead' }} - `X-Signed-By` to `Versia-Signed-By` - Removed the nonce from the [signature system](/signatures), replaced with `Versia-Signed-At` (timestamps). - Standardize rate limits with [IETF draft draft-polli-ratelimit-headers-02](https://www.ietf.org/archive/id/draft-polli-ratelimit-headers-02.html). +- Properly documented [Group](/entities/group) federation and subscribing. - Added [Versia Links](/links). - Switched from ISO 8601 to [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) for timestamps. - In most cases, the two are interchangeable, but RFC 3339 is more strict. Most implementations should not need to change anything. diff --git a/app/entities/group/page.mdx b/app/entities/group/page.mdx index 7d19d25..2be98a1 100644 --- a/app/entities/group/page.mdx +++ b/app/entities/group/page.mdx @@ -24,6 +24,15 @@ Refer to [Note](/entities/note#entity-definition)'s `group` property for how not Text only (`text/plain`, `text/html`, etc). + + Whether the group is open to all users or requires approval to join. + + + **This is meant as a UI hint** and does not guarantee that group subscriptions will be accepted or rejected. + + It is similar to a [User](/entities/user)'s `manually_approves_followers` field. + + URI of the group's members list. [URI Collection](/structures/collection#uri-collection) of [Users](/entities/user). @@ -50,9 +59,196 @@ Refer to [Note](/entities/note#entity-definition)'s `group` property for how not "content": "A group for fans of the Woozy emoji." } }, + "open": false, "members": "https://example.com/groups/ed480922-b095-4f09-9da5-c995be8f5960/members", } ``` + + + +## Subscribing to Groups + +[Users](/entities/user) may "subscribe" to a Group in order to receive all [Notes](/entities/note) posted to it. The mechanism by which federation is handled is described at [the end of this document](#federation). + +First, a [User](/entities/user) must send a `GroupSubscribe` activity to the group. The group will then respond with either a `GroupSubscribeAccept` or a `GroupSubscribeReject` activity. + +If the group accepts the subscription, the user will receive all notes posted to the group. If the group rejects the subscription, the user will not receive any notes posted to the group. + +### GroupSubscribe + +Indicates that a [User](/entities/user) wishes to subscribe to a group. + + + + + + This entity does not have a URI. + + + URI of the [User](/entities/user) subscribing to the group. + + + URI of the group to subscribe to. + + + + + + + ```jsonc {{ title: "Example GroupSubscribe" }} + { + "type": "GroupSubscribe", + "id": "9a7e9345-4e4a-4d5a-8301-4dbbfe777ca0", + "subscriber": "https://bob.social/users/e9277471-8aa1-4d40-a3d0-0878e818ccdc", + "group": "https://example.com/groups/ed480922-b095-4f09-9da5-c995be8f5960", + "created_at": "2021-01-01T00:00:00Z" + } + ``` + + + + +### GroupUnsubscribe + +Indicates that a [User](/entities/user) wishes to unsubscribe from a group. + + + + + + This entity does not have a URI. + + + URI of the [User](/entities/user) unsubscribing from the group. + + + URI of the group to unsubscribe from. + + + + + + + ```jsonc {{ title: "Example GroupUnsubscribe" }} + { + "type": "GroupUnsubscribe", + "id": "9a7e9345-4e4a-4d5a-8301-4dbbfe777ca0", + "subscriber": "https://bob.social/users/e9277471-8aa1-4d40-a3d0-0878e818ccdc", + "group": "https://example.com/groups/ed480922-b095-4f09-9da5-c995be8f5960", + "created_at": "2021-01-01T00:00:00Z" + } + ``` + + + + +### GroupSubscribeAccept + +Indicates that a [Group](#entity-definition) has accepted a [User](/entities/user)'s subscription request. Should be signed by the instance hosting the group. + + + + + + This entity does not have a URI. + + + URI of the [User](/entities/user) subscribing to the group. + + + URI of the group that accepted the subscription. + + + + + + + ```jsonc {{ title: "Example GroupSubscribeAccept" }} + { + "type": "GroupSubscribeAccept", + "id": "9a7e9345-4e4a-4d5a-8301-4dbbfe777ca0", + "subscriber": "https://bob.social/users/e9277471-8aa1-4d40-a3d0-0878e818ccdc", + "group": "https://example.com/groups/ed480922-b095-4f09-9da5-c995be8f5960", + "created_at": "2021-01-01T00:00:00Z" + } + ``` + + + + +### GroupSubscribeReject + +Indicates that a [Group](#entity-definition) has rejected a [User](/entities/user)'s subscription request. Should be signed by the instance hosting the group. + + + + + + This entity does not have a URI. + + + URI of the [User](/entities/user) subscribing to the group. + + + URI of the group that rejected the subscription. + + + + + + + ```jsonc {{ title: "Example GroupSubscribeReject" }} + { + "type": "GroupSubscribeReject", + "id": "9a7e9345-4e4a-4d5a-8301-4dbbfe777ca0", + "subscriber": "https://bob.social/users/e9277471-8aa1-4d40-a3d0-0878e818ccdc", + "group": "https://example.com/groups/ed480922-b095-4f09-9da5-c995be8f5960", + "created_at": "2021-01-01T00:00:00Z" + } + ``` + + + + +## Federation + +Group federation represents a particularly challenging problem, as it requires a way to make sure every single [Note](/entities/note) posted to it is delivered to every single member of the group. + +All [Notes](/entities/note) posted to a group (using the `group` field) must be sent to its instance's [shared inbox](/federation#inboxes). Groups do not have an inbox of their own. + +Once this is done, the group's instance must then federate this [Note](/entities/note) to every member of the group. However, this cannot be done the "normal way", as the group's instance does not have the private key to [sign](/signatures) the [Note](/entities/note). + +### GroupFederate + +The `GroupFederate` entity allows a group to federate a note to all of its members, without needing to sign the note itself. It contains a URI to the note being federated, which must be fetched by the receiving instances. This entity is signed by the group's instance. + + + + + + This entity does not have a URI. + + + URI of the note to federate. + + + URI of the group federating the note. + + + + + + + ```jsonc {{ title: "Example GroupFederate" }} + { + "type": "GroupFederate", + "id": "9a7e9345-4e4a-4d5a-8301-4dbbfe777ca0", + "note": "https://example.com/notes/ed480922-b095-4f09-9da5-c995be8f5960", + "group": "https://example.com/groups/ed480922-b095-4f09-9da5-c995be8f5960", + "created_at": "2021-01-01T00:00:00Z" + } + ``` + \ No newline at end of file From 8bb062e88729ae1999eda50e4a79ace77a8d6e42 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Tue, 10 Dec 2024 16:31:07 +0100 Subject: [PATCH 35/50] fix: :label: Fix several typing issues from React 19 --- components/Code.tsx | 13 +++++++++---- components/Heading.tsx | 7 ++++--- components/Search.tsx | 1 + 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/components/Code.tsx b/components/Code.tsx index b9bc831..d50d33c 100644 --- a/components/Code.tsx +++ b/components/Code.tsx @@ -144,7 +144,8 @@ function CodePanel({ label?: string; code?: string; }) { - const child = Children.only(children); + // biome-ignore lint/suspicious/noExplicitAny: + const child = Children.only(children) as ReactNode & { props: any }; if (isValidElement(child)) { tag = child.props.tag ?? tag; @@ -205,7 +206,10 @@ function CodeGroupHeader({ )} > {getPanelTitle( - isValidElement(child) ? child.props : {}, + isValidElement(child) + ? // biome-ignore lint/suspicious/noExplicitAny: + (child.props as any) + : {}, )} ))} @@ -238,7 +242,7 @@ function CodeGroupPanels({ function usePreventLayoutShift() { const positionRef = useRef(null); - const rafRef = useRef(); + const rafRef = useRef(undefined); useEffect(() => { return () => { @@ -322,7 +326,8 @@ export function CodeGroup({ }: ComponentPropsWithoutRef & { title: string }) { const languages = Children.map(children, (child) => - getPanelTitle(isValidElement(child) ? child.props : {}), + // biome-ignore lint/suspicious/noExplicitAny: + getPanelTitle(isValidElement(child) ? (child.props as any) : {}), ) ?? []; const tabGroupProps = useTabGroupProps(languages); const hasTabs = Children.count(children) > 1; diff --git a/components/Heading.tsx b/components/Heading.tsx index e9f31b2..d439a1c 100644 --- a/components/Heading.tsx +++ b/components/Heading.tsx @@ -5,6 +5,7 @@ import Link from "next/link"; import { type ComponentPropsWithoutRef, type ReactNode, + type RefObject, useEffect, useRef, } from "react"; @@ -87,7 +88,7 @@ export function Heading({ }) { level = level ?? (2 as Level); const Component = `h${level}` as "h2" | "h3"; - const ref = useRef(null); + const ref = useRef(null); const registerHeading = useSectionStore((s) => s.registerHeading); const inView = useInView(ref, { @@ -96,10 +97,10 @@ export function Heading({ }); useEffect(() => { - if (level === 2) { + if (level === 2 && ref.current) { registerHeading({ id: props.id, - ref, + ref: ref as RefObject, offsetRem: tag || label ? 8 : 6, }); } diff --git a/components/Search.tsx b/components/Search.tsx index 90ef092..d2db96d 100644 --- a/components/Search.tsx +++ b/components/Search.tsx @@ -164,6 +164,7 @@ function LoadingIcon(props: ComponentPropsWithoutRef<"svg">) { function HighlightQuery({ text, query }: { text: string; query: string }) { return ( + // @ts-expect-error types not properly updated to react 19 Date: Tue, 10 Dec 2024 17:39:57 +0100 Subject: [PATCH 36/50] refactor: :memo: Use the term "transient entity" where appropriate --- app/changelog/page.mdx | 1 + app/entities/delete/page.mdx | 4 ++-- app/entities/follow-accept/page.mdx | 2 +- app/entities/follow-reject/page.mdx | 2 +- app/entities/follow/page.mdx | 2 +- app/entities/group/page.mdx | 10 +++++----- app/entities/page.mdx | 4 +++- app/entities/unfollow/page.mdx | 2 +- app/extensions/migration/page.mdx | 2 +- app/extensions/reports/page.mdx | 2 +- app/introduction/page.mdx | 1 + 11 files changed, 18 insertions(+), 14 deletions(-) diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index 32ac559..bc745c0 100644 --- a/app/changelog/page.mdx +++ b/app/changelog/page.mdx @@ -11,6 +11,7 @@ This page lists changes since Working Draft 3. {{ className: 'lead' }} ## Since WD 4 - Removed URI from [Report](/extensions/reports), and replaced `reason` with `tags`. +- Docs now use the term "Transient Entity" where appropriate. - Mandated Unix-style `\n` line endings in all text fields. - Renamed the following headers, as per [RFC 6648](https://tools.ietf.org/html/rfc6648): - `X-Signature` to `Versia-Signature` diff --git a/app/entities/delete/page.mdx b/app/entities/delete/page.mdx index b8521df..61d3893 100644 --- a/app/entities/delete/page.mdx +++ b/app/entities/delete/page.mdx @@ -5,7 +5,7 @@ export const metadata = { # Delete -Signals the deletion of an entity. {{ className: 'lead' }} +Signals the deletion of an entity. It is a **transient entity**. {{ className: 'lead' }} ## Authorization @@ -21,7 +21,7 @@ Having the authorization is defined as: - This entity does not have a URI. + This is a **Transient Entity** and does not have a URI. URI of the `User` who is deleting the entity. [Can be set to `null` to represent the instance](/entities/instance-metadata#the-null-author). diff --git a/app/entities/follow-accept/page.mdx b/app/entities/follow-accept/page.mdx index 1748d3d..8336474 100644 --- a/app/entities/follow-accept/page.mdx +++ b/app/entities/follow-accept/page.mdx @@ -15,7 +15,7 @@ export const metadata = { - This entity does not have a URI. + This is a **Transient Entity** and does not have a URI. URI of the `User` considered the 'followee', i.e. the user who is being followed. diff --git a/app/entities/follow-reject/page.mdx b/app/entities/follow-reject/page.mdx index bfba74b..a65a26c 100644 --- a/app/entities/follow-reject/page.mdx +++ b/app/entities/follow-reject/page.mdx @@ -25,7 +25,7 @@ But it can also be used when Bob is already following Alice, in the case that: - This entity does not have a URI. + This is a **Transient Entity** and does not have a URI. URI of the `User` considered the 'followee', i.e. the user who is being followed. diff --git a/app/entities/follow/page.mdx b/app/entities/follow/page.mdx index 179200b..26ff12b 100644 --- a/app/entities/follow/page.mdx +++ b/app/entities/follow/page.mdx @@ -57,7 +57,7 @@ Once a follow relationship is established, the **followee**'s instance should se - This entity does not have a URI. + This is a **Transient Entity** and does not have a URI. URI of the `User` considered the 'follower'. diff --git a/app/entities/group/page.mdx b/app/entities/group/page.mdx index 2be98a1..e9cab0e 100644 --- a/app/entities/group/page.mdx +++ b/app/entities/group/page.mdx @@ -83,7 +83,7 @@ Indicates that a [User](/entities/user) wishes to subscribe to a group. - This entity does not have a URI. + This is a **Transient Entity** and does not have a URI. URI of the [User](/entities/user) subscribing to the group. @@ -117,7 +117,7 @@ Indicates that a [User](/entities/user) wishes to unsubscribe from a group. - This entity does not have a URI. + This is a **Transient Entity** and does not have a URI. URI of the [User](/entities/user) unsubscribing from the group. @@ -151,7 +151,7 @@ Indicates that a [Group](#entity-definition) has accepted a [User](/entities/use - This entity does not have a URI. + This is a **Transient Entity** and does not have a URI. URI of the [User](/entities/user) subscribing to the group. @@ -185,7 +185,7 @@ Indicates that a [Group](#entity-definition) has rejected a [User](/entities/use - This entity does not have a URI. + This is a **Transient Entity** and does not have a URI. URI of the [User](/entities/user) subscribing to the group. @@ -227,7 +227,7 @@ The `GroupFederate` entity allows a group to federate a note to all of its membe - This entity does not have a URI. + This is a **Transient Entity** and does not have a URI. URI of the note to federate. diff --git a/app/entities/page.mdx b/app/entities/page.mdx index 0ae1ef8..431e246 100644 --- a/app/entities/page.mdx +++ b/app/entities/page.mdx @@ -34,7 +34,9 @@ Any field in an entity not marked as `required` may be omitted or set to `null`. URI of the entity. Should be unique and resolve to the entity. Must be an absolute URI. - **Some entity types may not need a URI. This will be specified in the entity's documentation.** + + **Transient Entities** do not require a URI. + URL of any JSON Schema that the entity adheres to. diff --git a/app/entities/unfollow/page.mdx b/app/entities/unfollow/page.mdx index fe51cff..078db5f 100644 --- a/app/entities/unfollow/page.mdx +++ b/app/entities/unfollow/page.mdx @@ -30,7 +30,7 @@ Sometimes, [Users](/entities/user) want to unsubscribe from each other to stop s - This entity does not have a URI. + This is a **Transient Entity** and does not have a URI. URI of the `User` considered the 'follower', i.e. the user who is unsubscribing from the followee. diff --git a/app/extensions/migration/page.mdx b/app/extensions/migration/page.mdx index 32e5e19..8e2f5a0 100644 --- a/app/extensions/migration/page.mdx +++ b/app/extensions/migration/page.mdx @@ -34,7 +34,7 @@ Migration happens in three steps: - This entity does not have a URI. + This is a **Transient Entity** and does not have a URI. Must be `pub.versia:migration/Migration`. diff --git a/app/extensions/reports/page.mdx b/app/extensions/reports/page.mdx index 13f49e5..68751a7 100644 --- a/app/extensions/reports/page.mdx +++ b/app/extensions/reports/page.mdx @@ -15,7 +15,7 @@ When an instance receives a report, it *should* be reviewed by a moderator or ad - This entity does not have a URI. + This is a **Transient Entity** and does not have a URI. Must be `pub.versia:reports/Report`. diff --git a/app/introduction/page.mdx b/app/introduction/page.mdx index dc51f80..e9cd248 100644 --- a/app/introduction/page.mdx +++ b/app/introduction/page.mdx @@ -35,6 +35,7 @@ The words **MUST**, **MUST NOT**, **SHOULD**, **SHOULD NOT**, and **MAY** are us The Versia Protocol uses the following terms: - **Entity**: A generic term for any JSON object in the protocol, such as a [User](./entities/user), a [Note](./entities/note), or a [Like](./extensions/likes). Entities are uniquely identified by their `id` property. + - **Transient Entity**: A type of **Entity** that is not meant to be stored permanently or referenced by other entities. - **Implementation**: A software application that implements the Versia Protocol. - **Instance**: An application deploying an **Implementation**. - Using the same nomenclature, an ActivityPub Implementation would be `Mastodon`, and an Instance would be `mastodon.social`. From 46297d538c3641a43a9f20f744b227a234c7a168 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Tue, 10 Dec 2024 17:44:51 +0100 Subject: [PATCH 37/50] fix: :memo: Add more information on what a transient entity is --- app/entities/delete/page.mdx | 4 ++-- app/entities/follow-accept/page.mdx | 2 +- app/entities/follow-reject/page.mdx | 2 +- app/entities/follow/page.mdx | 2 +- app/entities/group/page.mdx | 10 +++++----- app/entities/page.mdx | 8 +++++++- app/entities/unfollow/page.mdx | 2 +- app/extensions/migration/page.mdx | 2 +- app/extensions/reports/page.mdx | 2 +- app/introduction/page.mdx | 2 +- 10 files changed, 21 insertions(+), 15 deletions(-) diff --git a/app/entities/delete/page.mdx b/app/entities/delete/page.mdx index 61d3893..edb75a1 100644 --- a/app/entities/delete/page.mdx +++ b/app/entities/delete/page.mdx @@ -5,7 +5,7 @@ export const metadata = { # Delete -Signals the deletion of an entity. It is a **transient entity**. {{ className: 'lead' }} +Signals the deletion of an entity. It is a [**Transient Entity**](/entities#transient-entities). {{ className: 'lead' }} ## Authorization @@ -21,7 +21,7 @@ Having the authorization is defined as: - This is a **Transient Entity** and does not have a URI. + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. URI of the `User` who is deleting the entity. [Can be set to `null` to represent the instance](/entities/instance-metadata#the-null-author). diff --git a/app/entities/follow-accept/page.mdx b/app/entities/follow-accept/page.mdx index 8336474..620bb96 100644 --- a/app/entities/follow-accept/page.mdx +++ b/app/entities/follow-accept/page.mdx @@ -15,7 +15,7 @@ export const metadata = { - This is a **Transient Entity** and does not have a URI. + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. URI of the `User` considered the 'followee', i.e. the user who is being followed. diff --git a/app/entities/follow-reject/page.mdx b/app/entities/follow-reject/page.mdx index a65a26c..c87435c 100644 --- a/app/entities/follow-reject/page.mdx +++ b/app/entities/follow-reject/page.mdx @@ -25,7 +25,7 @@ But it can also be used when Bob is already following Alice, in the case that: - This is a **Transient Entity** and does not have a URI. + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. URI of the `User` considered the 'followee', i.e. the user who is being followed. diff --git a/app/entities/follow/page.mdx b/app/entities/follow/page.mdx index 26ff12b..e72d25e 100644 --- a/app/entities/follow/page.mdx +++ b/app/entities/follow/page.mdx @@ -57,7 +57,7 @@ Once a follow relationship is established, the **followee**'s instance should se - This is a **Transient Entity** and does not have a URI. + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. URI of the `User` considered the 'follower'. diff --git a/app/entities/group/page.mdx b/app/entities/group/page.mdx index e9cab0e..df8d46d 100644 --- a/app/entities/group/page.mdx +++ b/app/entities/group/page.mdx @@ -83,7 +83,7 @@ Indicates that a [User](/entities/user) wishes to subscribe to a group. - This is a **Transient Entity** and does not have a URI. + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. URI of the [User](/entities/user) subscribing to the group. @@ -117,7 +117,7 @@ Indicates that a [User](/entities/user) wishes to unsubscribe from a group. - This is a **Transient Entity** and does not have a URI. + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. URI of the [User](/entities/user) unsubscribing from the group. @@ -151,7 +151,7 @@ Indicates that a [Group](#entity-definition) has accepted a [User](/entities/use - This is a **Transient Entity** and does not have a URI. + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. URI of the [User](/entities/user) subscribing to the group. @@ -185,7 +185,7 @@ Indicates that a [Group](#entity-definition) has rejected a [User](/entities/use - This is a **Transient Entity** and does not have a URI. + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. URI of the [User](/entities/user) subscribing to the group. @@ -227,7 +227,7 @@ The `GroupFederate` entity allows a group to federate a note to all of its membe - This is a **Transient Entity** and does not have a URI. + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. URI of the note to federate. diff --git a/app/entities/page.mdx b/app/entities/page.mdx index 431e246..ec6fe15 100644 --- a/app/entities/page.mdx +++ b/app/entities/page.mdx @@ -35,7 +35,7 @@ Any field in an entity not marked as `required` may be omitted or set to `null`. URI of the entity. Should be unique and resolve to the entity. Must be an absolute URI. - **Transient Entities** do not require a URI. + [**Transient Entities**](/entities#transient-entities) do not require a URI. @@ -86,6 +86,12 @@ Any field in an entity not marked as `required` may be omitted or set to `null`. +## Transient Entities + +Some entities are transient, meaning they do not have a URI. These entities are used for actions that do not require a permanent record, such as deletions or migrations. + +Implementations **must not** rely on other implementations to store transient entities in their database. + ## Serialization When serialized to a string, the JSON representation of an entity must follow the following rules: diff --git a/app/entities/unfollow/page.mdx b/app/entities/unfollow/page.mdx index 078db5f..ab836fa 100644 --- a/app/entities/unfollow/page.mdx +++ b/app/entities/unfollow/page.mdx @@ -30,7 +30,7 @@ Sometimes, [Users](/entities/user) want to unsubscribe from each other to stop s - This is a **Transient Entity** and does not have a URI. + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. URI of the `User` considered the 'follower', i.e. the user who is unsubscribing from the followee. diff --git a/app/extensions/migration/page.mdx b/app/extensions/migration/page.mdx index 8e2f5a0..d775427 100644 --- a/app/extensions/migration/page.mdx +++ b/app/extensions/migration/page.mdx @@ -34,7 +34,7 @@ Migration happens in three steps: - This is a **Transient Entity** and does not have a URI. + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. Must be `pub.versia:migration/Migration`. diff --git a/app/extensions/reports/page.mdx b/app/extensions/reports/page.mdx index 68751a7..e119796 100644 --- a/app/extensions/reports/page.mdx +++ b/app/extensions/reports/page.mdx @@ -15,7 +15,7 @@ When an instance receives a report, it *should* be reviewed by a moderator or ad - This is a **Transient Entity** and does not have a URI. + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. Must be `pub.versia:reports/Report`. diff --git a/app/introduction/page.mdx b/app/introduction/page.mdx index e9cd248..6274e6b 100644 --- a/app/introduction/page.mdx +++ b/app/introduction/page.mdx @@ -35,7 +35,7 @@ The words **MUST**, **MUST NOT**, **SHOULD**, **SHOULD NOT**, and **MAY** are us The Versia Protocol uses the following terms: - **Entity**: A generic term for any JSON object in the protocol, such as a [User](./entities/user), a [Note](./entities/note), or a [Like](./extensions/likes). Entities are uniquely identified by their `id` property. - - **Transient Entity**: A type of **Entity** that is not meant to be stored permanently or referenced by other entities. + - [**Transient Entity**](/entities#transient-entities): A type of **Entity** that is not meant to be stored permanently or referenced by other entities. - **Implementation**: A software application that implements the Versia Protocol. - **Instance**: An application deploying an **Implementation**. - Using the same nomenclature, an ActivityPub Implementation would be `Mastodon`, and an Instance would be `mastodon.social`. From fe451d018cdad1652eb8349ffeafc86e3df989b2 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Wed, 11 Dec 2024 12:27:08 +0100 Subject: [PATCH 38/50] refactor: :recycle: Move Groups to an extension --- app/changelog/page.mdx | 4 ++- app/entities/note/page.mdx | 8 +++-- .../group => extensions/groups}/page.mdx | 34 ++++++++++++++----- app/extensions/interaction-controls/page.mdx | 2 +- app/extensions/page.mdx | 2 +- components/Navigation.tsx | 2 +- 6 files changed, 38 insertions(+), 14 deletions(-) rename app/{entities/group => extensions/groups}/page.mdx (88%) diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index bc745c0..162a632 100644 --- a/app/changelog/page.mdx +++ b/app/changelog/page.mdx @@ -18,7 +18,9 @@ This page lists changes since Working Draft 3. {{ className: 'lead' }} - `X-Signed-By` to `Versia-Signed-By` - Removed the nonce from the [signature system](/signatures), replaced with `Versia-Signed-At` (timestamps). - Standardize rate limits with [IETF draft draft-polli-ratelimit-headers-02](https://www.ietf.org/archive/id/draft-polli-ratelimit-headers-02.html). -- Properly documented [Group](/entities/group) federation and subscribing. +- Properly documented [Group](/extensions/groups) federation and subscribing. +- Moved [Groups](/extensions/groups) to an extension, as they were getting too complex for the core protocol. + - The [Note](/entities/note) `group` field documentation has been updated to reflect this. - Added [Versia Links](/links). - Switched from ISO 8601 to [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) for timestamps. - In most cases, the two are interchangeable, but RFC 3339 is more strict. Most implementations should not need to change anything. diff --git a/app/entities/note/page.mdx b/app/entities/note/page.mdx index 79f71a5..f86e22f 100644 --- a/app/entities/note/page.mdx +++ b/app/entities/note/page.mdx @@ -73,11 +73,15 @@ Notes represent a piece of content on a Versia instance. They can be posted by [ ``` - URI of a [Group](/entities/group) that the note is only visible in, or one of the following strings: + URI of a [Group](/extensions/groups) that the note is only visible in, or one of the following strings: - `public`: The note is visible to anyone. - `followers`: The note is visible only to the author's followers. - If not provided, the note is only visible to the author and those mentioned in the note. + If not provided, the note is only visible to the author and those mentioned in the note. If missing, the note is only visible to any mentioned users. + + + If the implementation does not support the [Groups Extension](/extensions/groups), any value other than `public` or `followers` should be treated as `null`. + Whether the note contains "sensitive content". This can be used with `subject` as a "content warning" feature. diff --git a/app/entities/group/page.mdx b/app/extensions/groups/page.mdx similarity index 88% rename from app/entities/group/page.mdx rename to app/extensions/groups/page.mdx index df8d46d..e0fdca8 100644 --- a/app/entities/group/page.mdx +++ b/app/extensions/groups/page.mdx @@ -1,9 +1,9 @@ export const metadata = { - title: 'Groups', + title: 'Groups Extension', description: 'Groups are a way to organize users and notes into communities.' } -# Groups +# Groups Extension Groups are a way to organize users and notes into communities. They can be used for any purpose, such as forums, blogs, image galleries, video sharing, audio sharing, and messaging. They are similar to Discord's channels or Matrix's rooms. {{ className: 'lead' }} @@ -14,6 +14,9 @@ Refer to [Note](/entities/note#entity-definition)'s `group` property for how not + + Must be `pub.versia:groups/Group`. + Group name/title. @@ -46,7 +49,7 @@ Refer to [Note](/entities/note#entity-definition)'s `group` property for how not ```jsonc {{ title: "Example Group" }} { - "type": "Group", + "type": "pub.versia:groups/Group", "id": "ed480922-b095-4f09-9da5-c995be8f5960", "uri": "https://example.com/groups/ed480922-b095-4f09-9da5-c995be8f5960", "name": { @@ -82,6 +85,9 @@ Indicates that a [User](/entities/user) wishes to subscribe to a group. + + Must be `pub.versia:groups/Subscribe`. + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. @@ -98,7 +104,7 @@ Indicates that a [User](/entities/user) wishes to subscribe to a group. ```jsonc {{ title: "Example GroupSubscribe" }} { - "type": "GroupSubscribe", + "type": "pub.versia:groups/Subscribe", "id": "9a7e9345-4e4a-4d5a-8301-4dbbfe777ca0", "subscriber": "https://bob.social/users/e9277471-8aa1-4d40-a3d0-0878e818ccdc", "group": "https://example.com/groups/ed480922-b095-4f09-9da5-c995be8f5960", @@ -116,6 +122,9 @@ Indicates that a [User](/entities/user) wishes to unsubscribe from a group. + + Must be `pub.versia:groups/Unsubscribe`. + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. @@ -132,7 +141,7 @@ Indicates that a [User](/entities/user) wishes to unsubscribe from a group. ```jsonc {{ title: "Example GroupUnsubscribe" }} { - "type": "GroupUnsubscribe", + "type": "pub.versia:groups/Unsubscribe", "id": "9a7e9345-4e4a-4d5a-8301-4dbbfe777ca0", "subscriber": "https://bob.social/users/e9277471-8aa1-4d40-a3d0-0878e818ccdc", "group": "https://example.com/groups/ed480922-b095-4f09-9da5-c995be8f5960", @@ -150,6 +159,9 @@ Indicates that a [Group](#entity-definition) has accepted a [User](/entities/use + + Must be `pub.versia:groups/SubscribeAccept`. + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. @@ -166,7 +178,7 @@ Indicates that a [Group](#entity-definition) has accepted a [User](/entities/use ```jsonc {{ title: "Example GroupSubscribeAccept" }} { - "type": "GroupSubscribeAccept", + "type": "pub.versia:groups/SubscribeAccept", "id": "9a7e9345-4e4a-4d5a-8301-4dbbfe777ca0", "subscriber": "https://bob.social/users/e9277471-8aa1-4d40-a3d0-0878e818ccdc", "group": "https://example.com/groups/ed480922-b095-4f09-9da5-c995be8f5960", @@ -184,6 +196,9 @@ Indicates that a [Group](#entity-definition) has rejected a [User](/entities/use + + Must be `pub.versia:groups/SubscribeReject`. + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. @@ -200,7 +215,7 @@ Indicates that a [Group](#entity-definition) has rejected a [User](/entities/use ```jsonc {{ title: "Example GroupSubscribeReject" }} { - "type": "GroupSubscribeReject", + "type": "pub.versia:groups/SubscribeReject", "id": "9a7e9345-4e4a-4d5a-8301-4dbbfe777ca0", "subscriber": "https://bob.social/users/e9277471-8aa1-4d40-a3d0-0878e818ccdc", "group": "https://example.com/groups/ed480922-b095-4f09-9da5-c995be8f5960", @@ -226,6 +241,9 @@ The `GroupFederate` entity allows a group to federate a note to all of its membe + + Must be `pub.versia:groups/Federate`. + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. @@ -242,7 +260,7 @@ The `GroupFederate` entity allows a group to federate a note to all of its membe ```jsonc {{ title: "Example GroupFederate" }} { - "type": "GroupFederate", + "type": "pub.versia:groups/Federate", "id": "9a7e9345-4e4a-4d5a-8301-4dbbfe777ca0", "note": "https://example.com/notes/ed480922-b095-4f09-9da5-c995be8f5960", "group": "https://example.com/groups/ed480922-b095-4f09-9da5-c995be8f5960", diff --git a/app/extensions/interaction-controls/page.mdx b/app/extensions/interaction-controls/page.mdx index 12931da..5e8eae0 100644 --- a/app/extensions/interaction-controls/page.mdx +++ b/app/extensions/interaction-controls/page.mdx @@ -66,7 +66,7 @@ The entity defined in this document must be inserted in the `pub.versia:interact - `followers`: Includes every follower of the author. - `following`: Includes every User that the author follows. - `mutuals`: Includes every mutual of the author (that is, every User that is both a follower and followed by the author). - - `group`: Includes every User in the [Group](/entities/group) that this Note was posted to, if any. If Note is not posted to a [Group](/entities/group), this value has no effect. + - `group`: Includes every User in the [Group](/extensions/groups) that this Note was posted to, if any. If Note is not posted to a [Group](/extensions/groups), this value has no effect. Permission groups are evaluated from highest to lowest priority: if two groups conflict each other, the group with the highest priority must be used. diff --git a/app/extensions/page.mdx b/app/extensions/page.mdx index 54b6b6e..36e126b 100644 --- a/app/extensions/page.mdx +++ b/app/extensions/page.mdx @@ -59,7 +59,7 @@ Extensions can be found in two places: an [Entity](/entities#entity-definition)' ```jsonc {{ title: "Example Entity Extension" }} { - "type": "Group", + "type": "pub.versia:groups/Group", "id": "ed480922-b095-4f09-9da5-c995be8f5960", "uri": "https://example.com/groups/ed480922-b095-4f09-9da5-c995be8f5960", "name": null, diff --git a/components/Navigation.tsx b/components/Navigation.tsx index 370a3a3..d66a944 100644 --- a/components/Navigation.tsx +++ b/components/Navigation.tsx @@ -284,7 +284,6 @@ export const navigation: NavGroup[] = [ { title: "Follow", href: "/entities/follow" }, { title: "FollowAccept", href: "/entities/follow-accept" }, { title: "FollowReject", href: "/entities/follow-reject" }, - { title: "Group", href: "/entities/group" }, { title: "Notes", href: "/entities/note" }, { title: "InstanceMetadata", href: "/entities/instance-metadata" }, { title: "Unfollow", href: "/entities/unfollow" }, @@ -295,6 +294,7 @@ export const navigation: NavGroup[] = [ title: "Extensions", links: [ { title: "Custom Emojis", href: "/extensions/custom-emojis" }, + { title: "Groups", href: "/extensions/groups" }, { title: "Instance Messaging", href: "/extensions/instance-messaging", From 32aa7cf1644eb23a0b4c44813641276b78cda19f Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Tue, 17 Dec 2024 16:48:57 +0100 Subject: [PATCH 39/50] docs: :memo: Feature more information on SPKI key encoding --- app/entities/instance-metadata/page.mdx | 2 +- app/entities/user/page.mdx | 2 +- app/signatures/page.mdx | 24 ++++++++++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/app/entities/instance-metadata/page.mdx b/app/entities/instance-metadata/page.mdx index af52fd5..ca8c233 100644 --- a/app/entities/instance-metadata/page.mdx +++ b/app/entities/instance-metadata/page.mdx @@ -74,7 +74,7 @@ Check the entity's documentation page to see if it supports this (it will be not ``` - `algorithm`: Algorithm used for the public key. Can only be `ed25519` for now. - - `key`: Instance public key, in SPKI-encoded base64 (from raw bytes, not a PEM format). + - `key`: Instance public key, in [SPKI-encoded base64](/signatures#exporting-the-public-key). URI to [Collection](/structures/collection) of instance moderators. diff --git a/app/entities/user/page.mdx b/app/entities/user/page.mdx index 9330692..a7dac8d 100644 --- a/app/entities/user/page.mdx +++ b/app/entities/user/page.mdx @@ -74,7 +74,7 @@ Instance **must** be the host of the instance the user is on (hostname with opti The user's public key. Must follow the [Versia Public Key](/signatures) format. `actor` may be a URI to another user's profile, in which case this key may allow the other user act on behalf of this user (see [delegation](/federation/delegation)). - `algorithm`: Must be `ed25519` for now. - - `key`: The public key in SPKI-encoded base64 (from raw bytes, not a PEM format). Must be the key associated with the `actor` URI. + - `key`: The public key in [SPKI-encoded base64](/signatures#exporting-the-public-key). Must be the key associated with the `actor` URI. - `actor`: URI to a user's profile, most often the user's own profile. ```typescript diff --git a/app/signatures/page.mdx b/app/signatures/page.mdx index 9121c57..b1359f8 100644 --- a/app/signatures/page.mdx +++ b/app/signatures/page.mdx @@ -156,3 +156,27 @@ if (!isVerified) { return new Response("Signature verification failed", { status: 401 }); } ``` + +## Exporting the Public Key + +Public keys are always encoded using `base64` and must be in SPKI format. You will need to look up the appropriate method for your cryptographic library to convert the key to this format. + + + This is **not** the same as the key's raw bytes. + + This is also not related to the commonly used "PEM" format. + + +```typescript {{ title: "Example using TypeScript and the WebCrypto API" }} +/** + * Using Node.js's Buffer API for brevity + * If using another runtime, you may need to use a different method to convert to/from Base64 + */ +const spkiEncodedPublicKey = await crypto.subtle.exportKey( + "spki", + /* Your public key */ + publicKey, +); + +const base64PublicKey = Buffer.from(publicKey).toString("base64"); +``` \ No newline at end of file From 66a63315029f18e984b6c7ffd01a6422fd985d0b Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Tue, 24 Dec 2024 13:14:39 +0100 Subject: [PATCH 40/50] feat: :sparkles: Support timezone in Vanity extension --- app/changelog/page.mdx | 1 + app/extensions/vanity/page.mdx | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index 162a632..ac5a2fa 100644 --- a/app/changelog/page.mdx +++ b/app/changelog/page.mdx @@ -32,6 +32,7 @@ This page lists changes since Working Draft 3. {{ className: 'lead' }} - [Likes Extension](/extensions/likes), [Reactions Extension](/extensions/reactions) and [Share Extension](/extensions/share) now use this field, instead of a custom field in `extensions`. - Allowed uppercase characters in [User](/entities/user) `username`. - These are now case-insensitive. +- Added `timezone` field to [Vanity Extension](/extensions/vanity). ## Since WD 3 diff --git a/app/extensions/vanity/page.mdx b/app/extensions/vanity/page.mdx index c6da43f..f63d45e 100644 --- a/app/extensions/vanity/page.mdx +++ b/app/extensions/vanity/page.mdx @@ -69,6 +69,9 @@ All properties are optional. Location does not need to be precise, and can be as simple as `+46+002/` (France) or `+48.52+002.20/` (Paris, France). + + User's timezone. Should be a valid [IANA timezone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) string. + Versia profiles that should be considered aliases of this profile. @@ -124,6 +127,7 @@ All properties are optional. }, "birthday": "1998-04-12", "location": "+40.6894-074.0447/", + "timezone": "America/New_York", "aliases": [ "https://burger.social/accounts/349ee237-c672-41c1-aadc-677e185f795a", "https://versia.social/users/f565ef02-035d-4974-ba5e-f62a8558331d" From 54f18bb3c82a6d1d0775906e973f1fcb77795e1d Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Tue, 24 Dec 2024 13:15:39 +0100 Subject: [PATCH 41/50] chore: :arrow_up: Upgrade dependencies --- bun.lockb | Bin 175732 -> 176548 bytes package.json | 18 +++++++++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bun.lockb b/bun.lockb index 4323f787a9659d4a1c5449293208a55a3137c522..f71a82a09a33b9796ffba90986ce630c254facbf 100755 GIT binary patch delta 22141 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≀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 diff --git a/package.json b/package.json index e7a5b88..397efe7 100644 --- a/package.json +++ b/package.json @@ -16,12 +16,12 @@ "@headlessui/tailwindcss": "^0.2.1", "@mdx-js/loader": "^3.1.0", "@mdx-js/react": "^3.1.0", - "@next/mdx": "^15.0.4", + "@next/mdx": "^15.1.2", "@sindresorhus/slugify": "^2.2.1", "@tailwindcss/typography": "^0.5.15", "@types/mdx": "^2.0.13", - "@types/node": "^22.10.1", - "@types/react": "^19.0.1", + "@types/node": "^22.10.2", + "@types/react": "^19.0.2", "@types/react-dom": "^19.0.2", "@types/react-highlight-words": "^0.20.0", "acorn": "^8.14.0", @@ -29,10 +29,10 @@ "clsx": "^2.1.1", "fast-glob": "^3.3.2", "flexsearch": "^0.7.43", - "framer-motion": "^11.13.4", + "framer-motion": "^11.15.0", "mdast-util-to-string": "^4.0.0", "mdx-annotations": "^0.1.4", - "next": "^15.0.4", + "next": "^15.1.2", "next-themes": "^0.4.4", "react": "^19.0.0", "react-dom": "^19.0.0", @@ -40,9 +40,9 @@ "remark": "^15.0.1", "remark-gfm": "^4.0.0", "remark-mdx": "^3.1.0", - "shiki": "^1.24.2", + "shiki": "^1.24.4", "simple-functional-loader": "^1.2.1", - "tailwindcss": "^3.4.16", + "tailwindcss": "^3.4.17", "typescript": "^5.7.2", "unist-util-filter": "^5.0.1", "unist-util-visit": "^5.0.0", @@ -51,8 +51,8 @@ "devDependencies": { "@biomejs/biome": "^1.9.4", "@iconify-icon/react": "^2.2.0", - "@next/bundle-analyzer": "^15.0.4", - "@shikijs/transformers": "^1.24.2", + "@next/bundle-analyzer": "^15.1.2", + "@shikijs/transformers": "^1.24.4", "sharp": "^0.33.5" }, "overrides": { From f27f206e2da89aa4aea7d0b334cf181decb24bc0 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Tue, 24 Dec 2024 13:34:22 +0100 Subject: [PATCH 42/50] docs: :memo: Add more project info to front page --- app/page.tsx | 54 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/app/page.tsx b/app/page.tsx index ee1889b..bd63a56 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,3 +1,4 @@ +import { Guide } from "@/components/Guides"; import { Resource, type ResourceType } from "@/components/Resources"; import { TeamMember } from "@/components/Team"; import { wrapper } from "@/components/mdx"; @@ -48,9 +49,9 @@ const Page: FC = () => { icon: "tabler:database", }, { - name: "In-depth security docs", + name: "Tested in production :)", description: - "Docs provide lots of information on how to program a secure instance.", + "We know it works well, because we use it in our own projects.", icon: "tabler:shield", }, { @@ -98,7 +99,52 @@ const Page: FC = () => { ))} -

Team

+

Try it out

+ +

+ Use the reference implementation,{" "} + Versia Server! It's a microblogging server + with a focus on feeling like current Fediverse platforms, + like Sharkey and Mastodon. +

+ + + +

Try a Versia instance

+ +

+ If you want to try out Versia without setting up your own + instance, you can use one of the following public instances: +

+
+ +

People

+ +

+ You can ask Jesse for help with anything + Versia-related, or if you just want to chat! +

{ { name: "Signal", icon: "simple-icons:signal", - url: "https://signal.me/#eu/mdX6iV0ayndNmJst43sNtlw3eFXgHSm7if4Y/mwYT1+qFDzl1PFAeroW+RpHGaRu", + url: "https://signal.me/#eu/Qw6gQXvEfcNrgEFgl-KjOBFiF6-3gWSSghgcpSj9dSedVFIPny5NYazioN5t7E24", }, { name: "Email", From 9db7cfccda70f4e33801817c37be3fd59c004f71 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Tue, 24 Dec 2024 14:01:09 +0100 Subject: [PATCH 43/50] feat: :sparkles: Add unique ID to every property on docs --- app/entities/delete/page.mdx | 2 +- app/entities/follow-accept/page.mdx | 2 +- app/entities/follow-reject/page.mdx | 2 +- app/entities/follow/page.mdx | 2 +- app/entities/instance-metadata/page.mdx | 2 +- app/entities/note/page.mdx | 2 +- app/entities/page.mdx | 2 +- app/entities/unfollow/page.mdx | 2 +- app/entities/user/page.mdx | 2 +- app/extensions/custom-emojis/page.mdx | 4 +- app/extensions/groups/page.mdx | 12 +-- app/extensions/instance-messaging/page.mdx | 2 +- app/extensions/interaction-controls/page.mdx | 2 +- app/extensions/likes/page.mdx | 4 +- app/extensions/migration/page.mdx | 4 +- app/extensions/page.mdx | 4 +- app/extensions/polls/page.mdx | 4 +- app/extensions/reactions/page.mdx | 2 +- app/extensions/reports/page.mdx | 2 +- app/extensions/share/page.mdx | 2 +- app/extensions/vanity/page.mdx | 2 +- app/extensions/websockets/page.mdx | 2 +- app/federation/http/page.mdx | 4 +- app/links/page.mdx | 2 +- app/structures/collection/page.mdx | 4 +- app/structures/content-format/page.mdx | 2 +- components/Property.tsx | 105 +++++++++++++++++++ components/mdx.tsx | 79 +------------- 28 files changed, 144 insertions(+), 116 deletions(-) create mode 100644 components/Property.tsx diff --git a/app/entities/delete/page.mdx b/app/entities/delete/page.mdx index edb75a1..ba9b3f6 100644 --- a/app/entities/delete/page.mdx +++ b/app/entities/delete/page.mdx @@ -19,7 +19,7 @@ Having the authorization is defined as: - + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. diff --git a/app/entities/follow-accept/page.mdx b/app/entities/follow-accept/page.mdx index 620bb96..103b4b0 100644 --- a/app/entities/follow-accept/page.mdx +++ b/app/entities/follow-accept/page.mdx @@ -13,7 +13,7 @@ export const metadata = { - + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. diff --git a/app/entities/follow-reject/page.mdx b/app/entities/follow-reject/page.mdx index c87435c..7492789 100644 --- a/app/entities/follow-reject/page.mdx +++ b/app/entities/follow-reject/page.mdx @@ -23,7 +23,7 @@ But it can also be used when Bob is already following Alice, in the case that: - + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. diff --git a/app/entities/follow/page.mdx b/app/entities/follow/page.mdx index e72d25e..7287542 100644 --- a/app/entities/follow/page.mdx +++ b/app/entities/follow/page.mdx @@ -55,7 +55,7 @@ Once a follow relationship is established, the **followee**'s instance should se - + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. diff --git a/app/entities/instance-metadata/page.mdx b/app/entities/instance-metadata/page.mdx index ca8c233..4232622 100644 --- a/app/entities/instance-metadata/page.mdx +++ b/app/entities/instance-metadata/page.mdx @@ -17,7 +17,7 @@ Check the entity's documentation page to see if it supports this (it will be not - + This entity does not have an ID. diff --git a/app/entities/note/page.mdx b/app/entities/note/page.mdx index f86e22f..2227f4c 100644 --- a/app/entities/note/page.mdx +++ b/app/entities/note/page.mdx @@ -15,7 +15,7 @@ Notes represent a piece of content on a Versia instance. They can be posted by [ - + Media attachments to the note. May be any format. **Must** be remote. diff --git a/app/entities/page.mdx b/app/entities/page.mdx index ec6fe15..b4bb253 100644 --- a/app/entities/page.mdx +++ b/app/entities/page.mdx @@ -17,7 +17,7 @@ Any field in an entity not marked as `required` may be omitted or set to `null`. - + Unique identifier for the entity. Must be unique within the instance. Can be any string. Max of 512 UTF-8 characters. diff --git a/app/entities/unfollow/page.mdx b/app/entities/unfollow/page.mdx index ab836fa..a155516 100644 --- a/app/entities/unfollow/page.mdx +++ b/app/entities/unfollow/page.mdx @@ -28,7 +28,7 @@ Sometimes, [Users](/entities/user) want to unsubscribe from each other to stop s - + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. diff --git a/app/entities/user/page.mdx b/app/entities/user/page.mdx index a7dac8d..f3141d1 100644 --- a/app/entities/user/page.mdx +++ b/app/entities/user/page.mdx @@ -42,7 +42,7 @@ Instance **must** be the host of the instance the user is on (hostname with opti - + The user's avatar. Must be an image format (`image/*`). diff --git a/app/extensions/custom-emojis/page.mdx b/app/extensions/custom-emojis/page.mdx index c9cf810..f6d3a18 100644 --- a/app/extensions/custom-emojis/page.mdx +++ b/app/extensions/custom-emojis/page.mdx @@ -11,7 +11,7 @@ The Custom Emojis extension adds support for adding personalized emojis to feder - + Emoji name, surrounded by identification characters (for example, colons: `:happy_face:`). @@ -72,7 +72,7 @@ Custom Emojis can be added to any entity with text content. The extension ID is - + [Custom emojis](/extensions/custom-emoji#structure-definition) to be added to the note. diff --git a/app/extensions/groups/page.mdx b/app/extensions/groups/page.mdx index e0fdca8..5a41f78 100644 --- a/app/extensions/groups/page.mdx +++ b/app/extensions/groups/page.mdx @@ -13,7 +13,7 @@ Refer to [Note](/entities/note#entity-definition)'s `group` property for how not - + Must be `pub.versia:groups/Group`. @@ -84,7 +84,7 @@ Indicates that a [User](/entities/user) wishes to subscribe to a group. - + Must be `pub.versia:groups/Subscribe`. @@ -121,7 +121,7 @@ Indicates that a [User](/entities/user) wishes to unsubscribe from a group. - + Must be `pub.versia:groups/Unsubscribe`. @@ -158,7 +158,7 @@ Indicates that a [Group](#entity-definition) has accepted a [User](/entities/use - + Must be `pub.versia:groups/SubscribeAccept`. @@ -195,7 +195,7 @@ Indicates that a [Group](#entity-definition) has rejected a [User](/entities/use - + Must be `pub.versia:groups/SubscribeReject`. @@ -240,7 +240,7 @@ The `GroupFederate` entity allows a group to federate a note to all of its membe - + Must be `pub.versia:groups/Federate`. diff --git a/app/extensions/instance-messaging/page.mdx b/app/extensions/instance-messaging/page.mdx index 1f44b81..794d1a7 100644 --- a/app/extensions/instance-messaging/page.mdx +++ b/app/extensions/instance-messaging/page.mdx @@ -29,7 +29,7 @@ This extension adds the following metadata to instances: - + The endpoint to send federation debug messages to. diff --git a/app/extensions/interaction-controls/page.mdx b/app/extensions/interaction-controls/page.mdx index 5e8eae0..96bbeea 100644 --- a/app/extensions/interaction-controls/page.mdx +++ b/app/extensions/interaction-controls/page.mdx @@ -40,7 +40,7 @@ The entity defined in this document must be inserted in the `pub.versia:interact - + Describes permissions for a specific interaction. diff --git a/app/extensions/likes/page.mdx b/app/extensions/likes/page.mdx index 569360e..403e6e7 100644 --- a/app/extensions/likes/page.mdx +++ b/app/extensions/likes/page.mdx @@ -18,7 +18,7 @@ Likes are a way for users to show appreciation for a note, like Twitter's "heart - + Must be `pub.versia:likes/Like`. @@ -55,7 +55,7 @@ Dislikes are a way for users to show disapproval for a note, like YouTube's "dis - + Must be `pub.versia:likes/Dislike`. diff --git a/app/extensions/migration/page.mdx b/app/extensions/migration/page.mdx index d775427..b52376b 100644 --- a/app/extensions/migration/page.mdx +++ b/app/extensions/migration/page.mdx @@ -32,7 +32,7 @@ Migration happens in three steps: - + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. @@ -69,7 +69,7 @@ The following extensions to [User](/entities/user) are used by the migration ext - + If this user has migrated from another instance, this property **MUST** be set to the URI of the user on the previous instance. diff --git a/app/extensions/page.mdx b/app/extensions/page.mdx index 36e126b..d3ba1f3 100644 --- a/app/extensions/page.mdx +++ b/app/extensions/page.mdx @@ -44,7 +44,7 @@ Extensions can be found in two places: an [Entity](/entities#entity-definition)' - + Custom extensions to the entity. @@ -85,7 +85,7 @@ Extensions can be found in two places: an [Entity](/entities#entity-definition)' - + The extension type. [Must follow naming conventions](#naming). diff --git a/app/extensions/polls/page.mdx b/app/extensions/polls/page.mdx index 71e8209..cb671a7 100644 --- a/app/extensions/polls/page.mdx +++ b/app/extensions/polls/page.mdx @@ -19,7 +19,7 @@ Note that there is no `question` field: the question should be included in the ` - + Array of options for the poll. Each option is a [ContentFormat](/structures/content-format) that can contain the same properties as a Note's `content` (e.g. [Custom Emojis](/extensions/custom-emojis) or HTML hyperlinks). @@ -98,7 +98,7 @@ If a vote is cast to a poll that is closed, the vote should be rejected with a ` - + Must be `pub.versia:polls/Vote`. diff --git a/app/extensions/reactions/page.mdx b/app/extensions/reactions/page.mdx index 035dccc..eaad613 100644 --- a/app/extensions/reactions/page.mdx +++ b/app/extensions/reactions/page.mdx @@ -15,7 +15,7 @@ User reactions are (like every other entity) federated to all followers, and can - + Must be `pub.versia:reactions/Reaction`. diff --git a/app/extensions/reports/page.mdx b/app/extensions/reports/page.mdx index e119796..a1bf22e 100644 --- a/app/extensions/reports/page.mdx +++ b/app/extensions/reports/page.mdx @@ -13,7 +13,7 @@ When an instance receives a report, it *should* be reviewed by a moderator or ad - + This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. diff --git a/app/extensions/share/page.mdx b/app/extensions/share/page.mdx index 7e2e328..fa38799 100644 --- a/app/extensions/share/page.mdx +++ b/app/extensions/share/page.mdx @@ -17,7 +17,7 @@ When a user shares a note, the note's original author **must** receive the entit - + Must be `pub.versia:share/Share`. diff --git a/app/extensions/vanity/page.mdx b/app/extensions/vanity/page.mdx index f63d45e..07e48d8 100644 --- a/app/extensions/vanity/page.mdx +++ b/app/extensions/vanity/page.mdx @@ -14,7 +14,7 @@ All properties are optional. - + Overlay images to be placed on top of the user's avatar, like this: [example overlay from Discord](https://cdn.discordapp.com/avatar-decoration-presets/a_949a575b693c81ced8f56a7579d0969f.png). diff --git a/app/extensions/websockets/page.mdx b/app/extensions/websockets/page.mdx index b2f21a5..ab29a30 100644 --- a/app/extensions/websockets/page.mdx +++ b/app/extensions/websockets/page.mdx @@ -22,7 +22,7 @@ Messages sent over the WebSocket connection are JSON objects. - + Same as the `Versia-Signature` header in HTTP requests. diff --git a/app/federation/http/page.mdx b/app/federation/http/page.mdx index 47f4dc0..bb421ad 100644 --- a/app/federation/http/page.mdx +++ b/app/federation/http/page.mdx @@ -14,7 +14,7 @@ ALL kinds of HTTP requests/responses between instances **MUST** include a [Signa - + Must include `application/json`. @@ -61,7 +61,7 @@ IETF draft [draft-polli-ratelimit-headers-02](https://www.ietf.org/archive/id/dr - + Must include `application/json; charset=utf-8`. diff --git a/app/links/page.mdx b/app/links/page.mdx index 387d72b..2d76b78 100644 --- a/app/links/page.mdx +++ b/app/links/page.mdx @@ -12,7 +12,7 @@ Versia Links are a way to reference entities in the Versia Protocol, in a way th - + Must be `web+versia://` so that browsers and applications can recognize it. diff --git a/app/structures/collection/page.mdx b/app/structures/collection/page.mdx index 8af34c0..841b87a 100644 --- a/app/structures/collection/page.mdx +++ b/app/structures/collection/page.mdx @@ -17,7 +17,7 @@ Pages should be limited to a reasonable number of entities, such as 20 or 80. - + Author of the collection. Usually the user who owns the collection. [Can be set to `null` to represent the instance](/entities/instance-metadata#the-null-author). @@ -88,7 +88,7 @@ URI Collections are identical to regular collections, but they contain only URIs - + Author of the collection. Usually the user who owns the collection. [Can be set to `null` to represent the instance](/entities/instance-metadata#the-null-author). diff --git a/app/structures/content-format/page.mdx b/app/structures/content-format/page.mdx index 21226d5..b294f93 100644 --- a/app/structures/content-format/page.mdx +++ b/app/structures/content-format/page.mdx @@ -71,7 +71,7 @@ It is a good idea to provide at least two versions of an image (if possible): on - + Structure data. If `Content-Type` is a binary format, this field should be a URI to the binary data. Otherwise, it should be the content itself. Refer to the `remote` property for more information. diff --git a/components/Property.tsx b/components/Property.tsx new file mode 100644 index 0000000..045bfb9 --- /dev/null +++ b/components/Property.tsx @@ -0,0 +1,105 @@ +"use client"; + +import Link from "next/link"; +import { type ReactNode, createContext, useContext } from "react"; + +export const PropertyContext = createContext<{ + name: string; +}>({ + name: "", +}); + +export function Properties({ + children, + name, +}: { children: ReactNode; name: string }) { + return ( +
+
    + + {children} + +
+
+ ); +} + +const numberTypeTooltips = { + f64: "64-bit floating-point number", + i64: "64-bit signed integer", + u64: "64-bit unsigned integer", +}; + +export function Property({ + name, + children, + type, + typeLink, + numberType, + required, +}: { + name: string; + children: ReactNode; + type?: string; + typeLink?: string; + numberType?: "f64" | "i64" | "u64"; + required?: boolean; +}) { + const { name: contextName } = useContext(PropertyContext); + + const idFormat = (name: string) => + name + .toLowerCase() + .replace(/[^a-z0-9]/g, "-") + .replace(/-+/g, "-") + .replace(/^-|-$/g, ""); + + return ( +
  • +
    +
    Name
    +
    + {name} +
    + {required && ( + <> +
    Required
    +
    + Required +
    + + )} + {numberType && ( + <> +
    Type
    +
    + {numberType} +
    + + )} + {type && ( + <> +
    Type
    +
    + {typeLink ? ( + {type} + ) : ( + type + )} +
    + + )} +
    Description
    +
    + {children} +
    +
    +
  • + ); +} diff --git a/components/mdx.tsx b/components/mdx.tsx index 5b925a0..09debe9 100644 --- a/components/mdx.tsx +++ b/components/mdx.tsx @@ -9,6 +9,7 @@ export const a = Link; // biome-ignore lint/performance/noBarrelFile: export { Button } from "./Button"; export { CodeGroup, Code as code, Pre as pre } from "./Code"; +export { Property, Properties } from "./Property"; export function wrapper({ children }: { children: ReactNode }) { return ( @@ -80,81 +81,3 @@ export function Col({
    ); } - -export function Properties({ children }: { children: ReactNode }) { - return ( -
    -
      - {children} -
    -
    - ); -} - -const numberTypeTooltips = { - f64: "64-bit floating-point number", - i64: "64-bit signed integer", - u64: "64-bit unsigned integer", -}; - -export function Property({ - name, - children, - type, - typeLink, - numberType, - required, -}: { - name: string; - children: ReactNode; - type?: string; - typeLink?: string; - numberType?: "f64" | "i64" | "u64"; - required?: boolean; -}) { - return ( -
  • -
    -
    Name
    -
    - {name} -
    - {required && ( - <> -
    Required
    -
    - Required -
    - - )} - {numberType && ( - <> -
    Type
    -
    - {numberType} -
    - - )} - {type && ( - <> -
    Type
    -
    - {typeLink ? ( - {type} - ) : ( - type - )} -
    - - )} -
    Description
    -
    - {children} -
    -
    -
  • - ); -} From 90e360d713cc65cee791b39d186cb82908de1783 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Tue, 24 Dec 2024 14:15:32 +0100 Subject: [PATCH 44/50] feat: :sparkles: Add ability to copy href of any property --- components/Heading.tsx | 2 +- components/Property.tsx | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/components/Heading.tsx b/components/Heading.tsx index d439a1c..c2c7082 100644 --- a/components/Heading.tsx +++ b/components/Heading.tsx @@ -14,7 +14,7 @@ import { remToPx } from "../lib/remToPx"; import { useSectionStore } from "./SectionProvider"; import { Tag } from "./Tag"; -function AnchorIcon(props: ComponentPropsWithoutRef<"svg">) { +export function AnchorIcon(props: ComponentPropsWithoutRef<"svg">) { return ( +
  • + +
    + +
    +
    Name
    From f3a87926932df45bb18ec639d45429e7e863e4c6 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Wed, 1 Jan 2025 00:44:04 +0100 Subject: [PATCH 45/50] feat: :memo: Add federation example docs --- app/federation/example/page.mdx | 174 ++++++++++++++++++++++++++++++++ components/Navigation.tsx | 1 + mdx/rehype.mjs | 1 + 3 files changed, 176 insertions(+) create mode 100644 app/federation/example/page.mdx diff --git a/app/federation/example/page.mdx b/app/federation/example/page.mdx new file mode 100644 index 0000000..0709a03 --- /dev/null +++ b/app/federation/example/page.mdx @@ -0,0 +1,174 @@ +export const metadata = { + title: 'Federation Example', + description: + 'A description of how a typical federation flow might look like', +} + +# Example + +This page describes a typical federation flow between two servers, `a.social` and `b.social`, in several different contexts. {{ className: 'lead' }} + + + All examples, domains, names and timestamps are **fictional** and are used **for illustrative purposes only**. + + Some details have been slightly simplified for clarity. + + +## Sending a Note + +`@alice` on `a.social` creates a note with the following content: + +```markdown +Hello, @joe@b.social! How are you doing today? +``` + +`@alice` has mentioned `@joe@b.social` in the note. + +### Resolving the Mention + +`a.social` resolves the mention by querying `b.social` for the user `joe` using WebFinger. + +```bash {{ title: "cURL example" }} +curl https://b.social/.well-known/webfinger?resource=acct:joe@b.social -H "Accept: application/json" +``` + +`b.social` responds with the following JSON: + +```json +{ + "subject": "acct:joe@b.social", + "links": [ + { // [!code focus:5] + "rel": "self", + "type": "application/json", + "href": "https://b.social/users/joe" + } + ] +} +``` + + + In a real Versia implementation, usernames would **not** be included in user profile's URL, as they can be changed. Instead, the `id` could be used. + + This is done for simplicity in this example. + + +### Fetching the User + +`a.social` fetches the user profile of `joe` from `b.social` using the URL provided in the WebFinger response. + +```bash +curl https://b.social/users/joe \ + -H "Accept: application/json" \ + -H "User-Agent: CoolServer/1.0 (https://coolserver.com)" \ + # The request is signed by a.social's instance private key + -H "Versia-Signature: /CjB2L9bcvRg+uP19B4/rqy7Ji9/cqMFPlL3GVCIndnQjYyOpBzJEAl9weDnXm7Jrqa3y6sBC+EYWKThO2r9Bw==" \ + -H "Versia-Signed-By: https://a.social/users/alice" \ + -H "Versia-Signed-At: 1729241687" +``` + +`b.social` responds with the following JSON: + +```json +{ + "id": "bde22zi3ca8762", // [!code focus:10] + "type": "User", + "uri": "https://b.social/users/joe", + "created_at": "2024-10-13T18:48:19Z", + "avatar": { + "image/webp": { + "content": "https://cdn.b.social/avatars/joe.webp", + "remote": true + } + }, + "collections": { + "featured": "https://b.social/users/joe/featured", + "followers": "https://b.social/users/joe/followers", + "following": "https://b.social/users/joe/following", + "outbox": "https://b.social/users/joe/outbox" + }, // [!code focus:9] + "display_name": "Joe Swanson (Winter Arc :gigachad:)", + "inbox": "https://b.social/inbox", + "public_key": { + "actor": "https://b.social/users/joe", + "algorithm": "ed25519", + "key": "MCowBQYDK2VwAyEAOSCcfsde0Ya3vf/P6lzgK0pA8qCISqneaze3omLlQCQ=" + }, + "username": "joe", + "extensions": { + "pub.versia:custom_emojis": { + "emojis": [ + { + "name": ":gigachad:", + "content": { + "image/png": { + "content": "https://cdn.b.social/emojis/gigachad.png", + "remote": true + } + } + } + ] + } + }, +} +``` + +`a.social` now has the user profile of `joe` and can display the note with the correct user information. + +### Serializing the Note + +Finally, `a.social` serializes the note to send it to `joe`. + +```json +{ + "id": "782addd9-c051-4eea-8ba4-23d561d0c5bb", // [!code focus:6] + "type": "Note", + "uri": "https://a.social/notes/782addd9-c051-4eea-8ba4-23d561d0c5bb", + "created_at": "2024-12-01T12:19:06Z", + "author": "https://a.social/users/alice", + "category": "microblog", + "collections": { + "replies": "https://a.social/notes/782addd9-c051-4eea-8ba4-23d561d0c5bb/replies", + "quotes": "https://a.social/notes/782addd9-c051-4eea-8ba4-23d561d0c5bb/quotes" + }, // [!code focus:11] + "content": { + "text/html": { + "content": "Hello, @joe@b.social! How are you doing today?", + "remote": false, + }, + "text/plain": { + "content": "Hello, @joe@b.social! How are you doing today?", + "remote": false, + } + }, + "group": "public", + "mentions": [ // [!code focus:3] + "https://b.social/users/joe" + ] +} +``` + +It is now time for `a.social` to send the note to `joe`. + +### Sending the Note + +`a.social` sends the note to `joe`'s inbox at `b.social`. + +```bash +curl -X POST https://b.social/inbox \ + -H "Content-Type: application/json; charset=utf-8" \ + -H "Accept: application/json" \ + -H "User-Agent: CoolerServer/1.0 (https://coolerserver.com)" \ + # The request is signed by Alice's private key + -H "Versia-Signature: 9BrfplAPVH6OEqlV5eX7MazaZAInSCPODZcBEvMliBi/OwfbCAsezlb0O9jUX9ZcbBA68ThA4WUgS9V+42rfAQ==" \ + -H "Versia-Signed-By: https://a.social/users/alice" \ + -H "Versia-Signed-At: 1733051946" +``` + +`b.social` responds with a `202 Accepted` status code. + +### Displaying the Note + +The software on `b.social` processes the note and shows it to `joe` using whatever interface it has. + +`joe` can now see the note from `@alice` on `a.social` and respond to it. \ No newline at end of file diff --git a/components/Navigation.tsx b/components/Navigation.tsx index d66a944..06c3c10 100644 --- a/components/Navigation.tsx +++ b/components/Navigation.tsx @@ -268,6 +268,7 @@ export const navigation: NavGroup[] = [ { title: "Validation", href: "/federation/validation" }, { title: "Discovery", href: "/federation/discovery" }, { title: "Delegation", href: "/federation/delegation" }, + { title: "Example", href: "/federation/example" }, ], }, { diff --git a/mdx/rehype.mjs b/mdx/rehype.mjs index bba9407..e736adf 100644 --- a/mdx/rehype.mjs +++ b/mdx/rehype.mjs @@ -31,6 +31,7 @@ const highlighter = await createHighlighter({ "html", "json5", "jsonc", + "markdown", "bash", "php", "python", From bdfab8357c4a56b09a593fcfe0215355149516dd Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Wed, 1 Jan 2025 00:44:42 +0100 Subject: [PATCH 46/50] chore: :arrow_up: Upgrade dependencies --- bun.lockb | Bin 176548 -> 176548 bytes package.json | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bun.lockb b/bun.lockb index f71a82a09a33b9796ffba90986ce630c254facbf..d402df3bac7158bd66a103db50114326bc9af1cb 100755 GIT binary patch delta 2348 zcmY+D2~<0V!f$FS|PU2VC@ zKWuLCi0J2CO*g$m&nQz`&+7zyZM)X|V3E=>EqAKk;zRR&dBG|c*3VYzy~?TM3PuKu zb{bz{&8c)$P=&870uN1%vD@4fx<{xbi5+7>1~-CFrHjK#S4s^TX0&qm@-|OT*OD83 z`z$E;dAFQu<6B;I6=ch=ddD1TEaG4YVMq%ZA%xz;fA*(!7Mtc#6}LK-Iz^XkcRtKK znLLQM=o&E~29N@x{A2S8D=kiC=afj!cZx{!Vp&z<*Kr+E^6xKfk!cH+n1k z!5vo?xx-DIB)(@aDu1?7BFacV{Yzgc`(NUgv5|nRUfIAS04F&s}54y(@NFukZvB>`Y>w^q83{$6dr!Dx}n8doT6WTPB?sIo%gkX`iT#x ztNO(z(ue-Rdiy;~9?*=&OB0F*f7-MEL&vVfv}*Zzkzd)U!Cgs5WyvH}xO-b+aQKzL zMe>@Py;T*yj7^1BD(7HP{GPWHXU)&m_a`ph+Ir?xdC2O|LbSgc+V}2m4a@QFh4*%U z);;aCx>vDFl(^yy0;g$Tboo_*a~#SVs_Dz*5{6!pSWyO@!j$@?zF%e z2G6rUtt3PD-pHZy;K1Ry--q`LZWyi1kETV8s zuqIhC{NMFjhC!*+mn<|MX>Z)yG&Q}1*W7$8{C=S2?T6>0&XlUYP`Pi)M$0UMVhaBV z?~KfH!akEV8Dmrvk4&o_^4cI)EZ5s9e&tq&p9T*c{khhxS8Vx|m60f1m}XkHKqTW7 zmZV&ATW&4Wt-JQ8Q8S=nbASlV7A&17vI*@1#8^!L zL7M=<1OuGD1M)uYMMn5(tV-vDtX z7|uX)Gz%#lFXaUf_Y25sbix^A(fqV5^2AZ-0B4BPpQjH9%n=MpR~u>n0jNS3QZj zzN@AcVd}+P2xlfb3WRJdtM<-P(F21JvLwh@1YL6V1!g8}0d5G~a$<3xkz;4OTFD@1 zEIBqS9Tr5Qjz1r*3)yyzRL)FNCuqn{MK^z2xejx~)f#e;P--kUniQ42ln>C#ZdQ>R zvQc!h73yQmp{{wy6SLzqWIdn

    wvt*Uff|Y0q+AtIMf7l^VN~o0^1>eEA{KaojbL z6oGR%;om_+ZrJgLwC_7p1`mj{BuEE07pli8ErFNBgB2~W^Z&4C`xKDEnOXk`LMjNo zuw!oF#T%tFgq#@@d}ddH$_~Ev*hw}JCiI@+f))cI7dyT*&%u6w><%C-!Uawr*#jXj zL4xw%;-NRVE{^E{0)vuELzty$Mp`;IIR@R4H*PU8wkEqlLMNHB6^nPqn3C-ZtQvw! zfziyF2(^DTGqn%%O&aui9kjHtnTAW~lNgN!2?|Ic%|CiSd7Cmiw0|}MZdDjUG$0p+ z!VzP=u_LoYvKOReZBIxbZ}NsmXR`f5aI4t_+2u(L&&8OsrZoIECW-dM7fIF%aEe5g zfzOdNWZ;Yc`OW^5*PsksN5apj^`$xM9tUnwj9dYUKsR)CwS pUuALuPMtIJXtWO>)5n<2W%!q-+Dsxnez&CTG;S)}aT@oc{2yboHIM)R delta 2436 zcmY+^2~-o;8UWy#X=F(-fC?laLRiBV*?i!WAgibqq$mPnr3hgSI|#^~E z)bO+K<*zbCsR6E=wv2vQIqldY#lm5E5$ayj5dib5qKdIffQSqQrS6Bm}y5y){ ziODT{i~}sHY~A{Ae=gn?shfFWh#9fqmF@e$$koGm>rL50J+n5!>xm^TYGC2`+vURL zTHBr5ati+PDRcc&9VEpBWi79j1|mi_e&aW7K?hI%Ow#_fqVD17fy#9G*MHr73P^&yI6Sw0wZrZyY9_RFBJ)v zMPZu&J1D8KaOu0Ts47ETe9zQf$?2=G%z?HlCN9fp_3rc6)iq|gPX}Leb`q98<6E4hGz*sU@OIah#nU4# zXWNq{lUpC+a#h34{q6FPee}9yOr<}!t;c#E(T|z^b~=puJ1((bTpb2f27~jp0~1ww z>Xn(jtG4ykGrY!`B3+l@4+nFcY{|z}9X8PmCwmDU{m@fxDAA;?%I$EN9r?ic^@7y- zNS)!K+IXb%RY+sQv@jB9vn^~yJ(TQr{Jf!RL|6W0+C=fEMMY{!*h&D%jZH8? z(S|arWtPS}cX6fQGjh5^_J@15yld|VQ(RMY2z>XQ(UU$?p`$%Dbb~3$H-XO`yF-LK zctPa)(TsWcDf{=byEEL4dhp+c4213*ON)txARo}K%@D+Voa)vhyk?y!wJy;>6o8~D z_IA?Bm$0a0iKXT2ne3Xgh$bpALB7$EKwk`2cmDXfcoCIL;I1;5%@pa}TXTRxkwexW z)C5Q#kS>v~lH1M8LFEw;B_M$c`QCGHzb`?B4+IY+{Sd`W;!flRRHlGz1hSt$xXW;C zDHD}NAksjrP4gJXn&0vMixL9f8_`-hXSUsO+{dS)q69=#!pD9nXc|9|f(iu)76@Xu zSkq-cmy3!e5FC*6+mGhy+@S76#U6+Z5QegXwtSlAp-z+z0s8!8 ztw87`jHjA+>=smf{UV~n!Kz*g^8Ig@j=o1FN&KJ%qgtlx+ktpg{OB?+r##v(hP&=%K}pUNa~j}dh!URa9RR*DIqAWr!hzjW1mjxvecKs8abvR&M7|?Sto#+>zYSJSShm)q(35uqL z`9_CAP@nFPX(fnd2r3g`jHnAn_c{GlN+!Xmd=QKJ3;0&id~X&iF+sth!JrJ)JMbI?JG$m&}63p?l=W-AV(LINTxp+uW$XmFZ#0u=)w zqFoduEXx{sk4T|n1w`~_X{jl1UT(k=fvAah|Eai`Sl@7e=y6}eF~v<9>#gGoAHad; zuqpe81-KZ5r3IL%VhTZz+*fx)Z@OZgbdMnh1Douim{3gF#sZkQ10*bf1ksvaeiF1} zr$rk_Nl*ghu_m9JoLEP`j(|NEZc zB%-^XvVHwbo_!@AQT}qt?TbeUGOMR@naC^-Hf<_E_9$&IrNjoFVi!~+O579Gh#mI- DYu Date: Wed, 1 Jan 2025 01:03:50 +0100 Subject: [PATCH 47/50] feat: :sparkles: Add Plausible to site --- app/layout.tsx | 1 + public/pl.js | 1 + 2 files changed, 2 insertions(+) create mode 100644 public/pl.js diff --git a/app/layout.tsx b/app/layout.tsx index a5797ef..6646be6 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -46,6 +46,7 @@ export default async function RootLayout({ +