From 3117b376c9f563c437560790f11826d6163d8ae2 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Mon, 21 Apr 2025 17:47:18 +0200 Subject: [PATCH 01/25] fix: :bug: Begin v0.6 draft --- components/Header.tsx | 4 ++-- components/Logo.tsx | 4 ++-- components/Navigation.tsx | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/Header.tsx b/components/Header.tsx index d05d77b..ef7f488 100644 --- a/components/Header.tsx +++ b/components/Header.tsx @@ -52,7 +52,7 @@ export const Header = forwardRef, { className?: string }>( className={clsx( className, // Add bg-construction bg-opacity-10 [background-size:57px_57px] classes to make it striped - "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 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 bg-construction bg-opacity-10 [background-size:57px_57px]", !isInsideMobileNavigation && "backdrop-blur-sm lg:left-72 xl:left-80 dark:backdrop-blur", isInsideMobileNavigation @@ -95,7 +95,7 @@ export const Header = forwardRef, { className?: string }>(
- +
diff --git a/components/Logo.tsx b/components/Logo.tsx index 13dd43d..2ec778a 100644 --- a/components/Logo.tsx +++ b/components/Logo.tsx @@ -1,7 +1,7 @@ import clsx from "clsx"; import type { ComponentPropsWithoutRef } from "react"; // Uncomment this on dev branches -// import { Badge } from "./Metadata"; +import { Badge } from "./Metadata"; export function Logo(props: ComponentPropsWithoutRef<"div">) { return ( @@ -18,7 +18,7 @@ export function Logo(props: ComponentPropsWithoutRef<"div">) { className="h-full rounded-sm" /> - Versia Protocol {/* Dev */} + Versia Protocol Dev ); diff --git a/components/Navigation.tsx b/components/Navigation.tsx index 06c3c10..a3c4d6d 100644 --- a/components/Navigation.tsx +++ b/components/Navigation.tsx @@ -334,7 +334,7 @@ export function Navigation(props: ComponentPropsWithoutRef<"nav">) { variant="filled" className="w-full" > - Working Draft 5 + Working Draft 6 From 89a8b1836fcae8a93dc7d54fb37ae922badb17ce Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Mon, 21 Apr 2025 18:02:33 +0200 Subject: [PATCH 02/25] docs: :memo: Updated changelog to include upcoming v0.6 changes --- app/changelog/page.mdx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index ac5a2fa..f904380 100644 --- a/app/changelog/page.mdx +++ b/app/changelog/page.mdx @@ -8,6 +8,15 @@ export const metadata = { This page lists changes since Working Draft 3. {{ className: 'lead' }} +## Since WD 5 + +- Added a new `content-type` for Versia entities: `application/vnd.versia+json`. +- Removed per-User keypairs: now, only the instance keypair is used for signing. +- Modified how URIs and references to other entities are handled: + - The `uri` field has been removed from all entities. + - Every field that used to be a URI now uses that entity's `id` field. + - New endpoints have been defined under `/_versia/v0.6/` to fetch entities by their `id`. + ## Since WD 4 - Removed URI from [Report](/extensions/reports), and replaced `reason` with `tags`. From 975d1c9baaa0d771338354f93787f7f2a5f15e73 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Mon, 21 Apr 2025 18:17:45 +0200 Subject: [PATCH 03/25] refactor: :alien: Update all entity example to conform to new reference format --- app/entities/delete/page.mdx | 5 ++-- app/entities/follow-accept/page.mdx | 4 ++-- app/entities/follow-reject/page.mdx | 4 ++-- app/entities/follow/page.mdx | 4 ++-- app/entities/instance-metadata/page.mdx | 3 --- app/entities/note/page.mdx | 10 +------- app/entities/page.mdx | 6 ++--- app/entities/unfollow/page.mdx | 4 ++-- app/entities/user/page.mdx | 12 +--------- app/extensions/custom-emojis/page.mdx | 5 ---- app/extensions/groups/page.mdx | 24 +++++++++---------- app/extensions/instance-messaging/page.mdx | 7 +----- app/extensions/interaction-controls/page.mdx | 5 ---- app/extensions/likes/page.mdx | 10 ++++---- app/extensions/migration/page.mdx | 8 +++---- app/extensions/page.mdx | 5 +--- app/extensions/polls/page.mdx | 12 +++------- app/extensions/reactions/page.mdx | 5 ++-- app/extensions/reports/page.mdx | 6 ++--- app/extensions/share/page.mdx | 5 ++-- app/extensions/vanity/page.mdx | 4 ++-- app/federation/example/page.mdx | 25 +++++--------------- app/structures/collection/page.mdx | 10 +++----- 23 files changed, 56 insertions(+), 127 deletions(-) diff --git a/app/entities/delete/page.mdx b/app/entities/delete/page.mdx index ba9b3f6..e5307ff 100644 --- a/app/entities/delete/page.mdx +++ b/app/entities/delete/page.mdx @@ -42,9 +42,8 @@ Having the authorization is defined as: "type": "Delete", "id": "9b3212b8-529c-435a-8798-09ebbc17ca74", "created_at": "2021-01-01T00:00:00.000Z", - "author": "https://example.com/users/6e0204a2-746c-4972-8602-c4f37fc63bbe", - "deleted_type": "Note", - "deleted": "https://example.com/notes/02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" + "author": "6e0204a2-746c-4972-8602-c4f37fc63bbe", + "deleted": "02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" } ``` diff --git a/app/entities/follow-accept/page.mdx b/app/entities/follow-accept/page.mdx index 103b4b0..6aa8d94 100644 --- a/app/entities/follow-accept/page.mdx +++ b/app/entities/follow-accept/page.mdx @@ -32,9 +32,9 @@ export const metadata = { { "type": "FollowAccept", "id": "3e7e4750-afd4-4d99-a256-02f0710a0520", - "author": "https://example.com/users/6e0204a2-746c-4972-8602-c4f37fc63bbe", + "author": "6e0204a2-746c-4972-8602-c4f37fc63bbe", "created_at": "2021-01-01T00:00:00.000Z", - "follower": "https://example.com/users/02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" + "follower": "example.com:02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" } ``` diff --git a/app/entities/follow-reject/page.mdx b/app/entities/follow-reject/page.mdx index 7492789..3b2ae3b 100644 --- a/app/entities/follow-reject/page.mdx +++ b/app/entities/follow-reject/page.mdx @@ -42,9 +42,9 @@ But it can also be used when Bob is already following Alice, in the case that: { "type": "FollowReject", "id": "3e7e4750-afd4-4d99-a256-02f0710a0520", - "author": "https://example.com/users/6e0204a2-746c-4972-8602-c4f37fc63bbe", + "author": "6e0204a2-746c-4972-8602-c4f37fc63bbe", "created_at": "2021-01-01T00:00:00.000Z", - "follower": "https://example.com/users/02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" + "follower": "example.com:02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" } ``` diff --git a/app/entities/follow/page.mdx b/app/entities/follow/page.mdx index 7287542..c64cc64 100644 --- a/app/entities/follow/page.mdx +++ b/app/entities/follow/page.mdx @@ -74,9 +74,9 @@ Once a follow relationship is established, the **followee**'s instance should se { "type": "Follow", "id": "3e7e4750-afd4-4d99-a256-02f0710a0520", - "author": "https://example.com/users/6e0204a2-746c-4972-8602-c4f37fc63bbe", + "author": "6e0204a2-746c-4972-8602-c4f37fc63bbe", "created_at": "2021-01-01T00:00:00.000Z", - "followee": "https://example.com/users/02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" + "followee": "example.com:02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" } ``` diff --git a/app/entities/instance-metadata/page.mdx b/app/entities/instance-metadata/page.mdx index 4232622..caa53bc 100644 --- a/app/entities/instance-metadata/page.mdx +++ b/app/entities/instance-metadata/page.mdx @@ -123,9 +123,6 @@ Check the entity's documentation page to see if it supports this (it will be not }, "description": "Server for Jim's Jolly Jimjams, a social network for fans of Jimjams.", "host": "social.jimjams.com", - "shared_inbox": "https://social.jimjams.com/inbox", - "moderators": "https://social.jimjams.com/moderators", - "admins": "https://social.jimjams.com/admins", "logo": { "image/png": { "content": "https://social.jimjams.com/files/logo.png" diff --git a/app/entities/note/page.mdx b/app/entities/note/page.mdx index 2227f4c..ed3cf04 100644 --- a/app/entities/note/page.mdx +++ b/app/entities/note/page.mdx @@ -123,7 +123,6 @@ Notes represent a piece of content on a Versia instance. They can be posted by [ { "id": "01902e09-0f8b-72de-8ee3-9afc0cf5eae1", "type": "Note", - "uri": "https://versia.social/objects/01902e09-0f8b-72de-8ee3-9afc0cf5eae1", "created_at": "2024-06-19T01:07:44.139Z", "attachments": [ // [!code focus:100] { @@ -150,15 +149,8 @@ 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", + "author": "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/entities/page.mdx b/app/entities/page.mdx index b4bb253..e7c8e8e 100644 --- a/app/entities/page.mdx +++ b/app/entities/page.mdx @@ -59,9 +59,8 @@ Any field in an entity not marked as `required` may be omitted or set to `null`. "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_type": "Note", - "deleted": "https://bongo.social/notes/54059ce2-9332-46fa-bf6a-598b5493b81b", + "author": "63a00ab3-39b1-49eb-b88e-ed65d2361f3e", + "deleted": "54059ce2-9332-46fa-bf6a-598b5493b81b", } ``` @@ -70,7 +69,6 @@ Any field in an entity not marked as `required` may be omitted or set to `null`. "id": "f0aacf0b-df7a-4ee5-a2ba-6c4acafd8642", "type": "org.space:Zlorbs/Zlorb", "created_at": "2023-04-13T08:00:00Z", - "uri": "https://space.org/zlorbs/f0aacf0b-df7a-4ee5-a2ba-6c4acafd8642", "extensions": { // [!code focus:100] "org.space:zlorbs": { "zlorb_type": "giant", diff --git a/app/entities/unfollow/page.mdx b/app/entities/unfollow/page.mdx index a155516..1c6000f 100644 --- a/app/entities/unfollow/page.mdx +++ b/app/entities/unfollow/page.mdx @@ -47,9 +47,9 @@ Sometimes, [Users](/entities/user) want to unsubscribe from each other to stop s { "type": "Unfollow", "id": "3e7e4750-afd4-4d99-a256-02f0710a0520", - "author": "https://example.com/users/6e0204a2-746c-4972-8602-c4f37fc63bbe", + "author": "6e0204a2-746c-4972-8602-c4f37fc63bbe", "created_at": "2021-01-01T00:00:00.000Z", - "followee": "https://example.com/users/02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" + "followee": "example.com:02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" } ``` diff --git a/app/entities/user/page.mdx b/app/entities/user/page.mdx index f3141d1..f069ba7 100644 --- a/app/entities/user/page.mdx +++ b/app/entities/user/page.mdx @@ -137,7 +137,6 @@ Instance **must** be the host of the instance the user is on (hostname with opti { "id": "018ec082-0ae1-761c-b2c5-22275a611771", "type": "User", - "uri": "https://versia.social/users/018ec082-0ae1-761c-b2c5-22275a611771", "created_at": "2024-04-09T01:38:51.743Z", "avatar": { // [!code focus:100] "image/png": { @@ -152,14 +151,6 @@ Instance **must** be the host of the instance the user is on (hostname with opti "content": "🌸🌸🌸" } }, - "collections": { - "featured": "https://versia.social/users/018ec082-0ae1-761c-b2c5-22275a611771/featured", - "followers": "https://versia.social/users/018ec082-0ae1-761c-b2c5-22275a611771/followers", - "following": "https://versia.social/users/018ec082-0ae1-761c-b2c5-22275a611771/following", - "pub.versia:likes/Dislikes": "https://versia.social/users/018ec082-0ae1-761c-b2c5-22275a611771/dislikes", - "pub.versia:likes/Likes": "https://versia.social/users/018ec082-0ae1-761c-b2c5-22275a611771/likes", - "outbox": "https://versia.social/users/018ec082-0ae1-761c-b2c5-22275a611771/outbox", - }, "display_name": "April The Pink (limited Sand Edition)", "extensions": { "pub.versia:custom_emojis": { @@ -181,11 +172,10 @@ Instance **must** be the host of the instance the user is on (hostname with opti } ], "header": null, - "inbox": "https://versia.social/users/018ec082-0ae1-761c-b2c5-22275a611771/inbox", "indexable": false, "manually_approves_followers": false, "public_key": { - "actor": "https://versia.social/users/018ec082-0ae1-761c-b2c5-22275a611771", + "actor": "018ec082-0ae1-761c-b2c5-22275a611771", "algorithm": "ed25519", "key": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" }, diff --git a/app/extensions/custom-emojis/page.mdx b/app/extensions/custom-emojis/page.mdx index f6d3a18..2af353a 100644 --- a/app/extensions/custom-emojis/page.mdx +++ b/app/extensions/custom-emojis/page.mdx @@ -85,12 +85,7 @@ Custom Emojis can be added to any entity with text content. The extension ID is { "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", - "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/groups/page.mdx b/app/extensions/groups/page.mdx index 5a41f78..5a96a17 100644 --- a/app/extensions/groups/page.mdx +++ b/app/extensions/groups/page.mdx @@ -51,7 +51,6 @@ Refer to [Note](/entities/note#entity-definition)'s `group` property for how not { "type": "pub.versia:groups/Group", "id": "ed480922-b095-4f09-9da5-c995be8f5960", - "uri": "https://example.com/groups/ed480922-b095-4f09-9da5-c995be8f5960", "name": { "text/html": { "content": "The Woozy fan club" @@ -62,8 +61,7 @@ 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", + "open": false } ``` @@ -106,8 +104,8 @@ Indicates that a [User](/entities/user) wishes to subscribe to a group. { "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", + "subscriber": "e9277471-8aa1-4d40-a3d0-0878e818ccdc", + "group": "example.com:ed480922-b095-4f09-9da5-c995be8f5960", "created_at": "2021-01-01T00:00:00Z" } ``` @@ -143,8 +141,8 @@ Indicates that a [User](/entities/user) wishes to unsubscribe from a group. { "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", + "subscriber": "e9277471-8aa1-4d40-a3d0-0878e818ccdc", + "group": "example.com:ed480922-b095-4f09-9da5-c995be8f5960", "created_at": "2021-01-01T00:00:00Z" } ``` @@ -180,8 +178,8 @@ Indicates that a [Group](#entity-definition) has accepted a [User](/entities/use { "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", + "subscriber": "e9277471-8aa1-4d40-a3d0-0878e818ccdc", + "group": "example.com:ed480922-b095-4f09-9da5-c995be8f5960", "created_at": "2021-01-01T00:00:00Z" } ``` @@ -217,8 +215,8 @@ Indicates that a [Group](#entity-definition) has rejected a [User](/entities/use { "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", + "subscriber": "e9277471-8aa1-4d40-a3d0-0878e818ccdc", + "group": "example.com:ed480922-b095-4f09-9da5-c995be8f5960", "created_at": "2021-01-01T00:00:00Z" } ``` @@ -262,8 +260,8 @@ The `GroupFederate` entity allows a group to federate a note to all of its membe { "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", + "note": "c5aa65fa-0356-4029-b61c-6b237e5d1393", + "group": "example.com:ed480922-b095-4f09-9da5-c995be8f5960", "created_at": "2021-01-01T00:00:00Z" } ``` diff --git a/app/extensions/instance-messaging/page.mdx b/app/extensions/instance-messaging/page.mdx index 794d1a7..54692f1 100644 --- a/app/extensions/instance-messaging/page.mdx +++ b/app/extensions/instance-messaging/page.mdx @@ -74,12 +74,7 @@ This extension adds the following metadata to instances: ] }, "host": "jane.org", - "created_at": "2021-07-01T00:00:00Z", - "extensions": { // [!code focus:5] - "pub.versia:instance_messaging": { - "endpoint": "https://jane.org/api/reports", - }, - } + "created_at": "2021-07-01T00:00:00Z" } ``` diff --git a/app/extensions/interaction-controls/page.mdx b/app/extensions/interaction-controls/page.mdx index 96bbeea..b1d27bc 100644 --- a/app/extensions/interaction-controls/page.mdx +++ b/app/extensions/interaction-controls/page.mdx @@ -15,12 +15,7 @@ The entity defined in this document must be inserted in the `pub.versia:interact { "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", - "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 403e6e7..c979ce9 100644 --- a/app/extensions/likes/page.mdx +++ b/app/extensions/likes/page.mdx @@ -38,9 +38,8 @@ Likes are a way for users to show appreciation for a note, like Twitter's "heart "id": "3e7e4750-afd4-4d99-a256-02f0710a0520", "type": "pub.versia:likes/Like", "created_at": "2021-01-01T00:00:00.000Z", - "author": "https://example.com/users/6e0204a2-746c-4972-8602-c4f37fc63bbe", - "uri": "https://example.com/likes/3e7e4750-afd4-4d99-a256-02f0710a0520", - "liked": "https://otherexample.org/notes/fmKZ763jzIU8" + "author": "6e0204a2-746c-4972-8602-c4f37fc63bbe", + "liked": "otherexample.org:fmKZ763jzIU8" } ``` @@ -75,9 +74,8 @@ Dislikes are a way for users to show disapproval for a note, like YouTube's "dis "id": "3e7e4750-afd4-4d99-a256-02f0710a0520", "type": "pub.versia:likes/Dislike", "created_at": "2021-01-01T00:00:00.000Z", - "author": "https://example.com/users/6e0204a2-746c-4972-8602-c4f37fc63bbe", - "uri": "https://example.com/dislikes/3e7e4750-afd4-4d99-a256-02f0710a0520", - "disliked": "https://otherexample.org/notes/fmKZ763jzIU8" + "author": "6e0204a2-746c-4972-8602-c4f37fc63bbe", + "disliked": "otherexample.org:fmKZ763jzIU8" } ``` diff --git a/app/extensions/migration/page.mdx b/app/extensions/migration/page.mdx index b52376b..36975e2 100644 --- a/app/extensions/migration/page.mdx +++ b/app/extensions/migration/page.mdx @@ -54,9 +54,9 @@ Migration happens in three steps: { "id": "016f3de2-ad63-4e06-999e-1e6b41c981c5", "type": "pub.versia:migration/Migration", - "author": "https://example.com/users/44df6e02-ef43-47e0-aff2-47041f3d09ed", + "author": "44df6e02-ef43-47e0-aff2-47041f3d09ed", "created_at": "2021-01-01T00:00:00.000Z", - "destination": "https://otherinstance.social/users/73e999a0-53d0-40a3-a5cc-be0408004726", + "destination": "otherinstance.social:73e999a0-53d0-40a3-a5cc-be0408004726", } ``` @@ -88,8 +88,8 @@ The following extensions to [User](/entities/user) are used by the migration ext // ... "extensions": { // [!code focus:100] "pub.versia:migration": { - "previous": "https://oldinstance.social/users/44df6e02-ef43-47e0-aff2-47041f3d09ed", - // "new": "https://newinstance.social/users/73e999a0-53d0-40a3-a5cc-be0408004726", + "previous": "oldinstance.social:44df6e02-ef43-47e0-aff2-47041f3d09ed", + // "new": "newinstance.social:73e999a0-53d0-40a3-a5cc-be0408004726", } } } diff --git a/app/extensions/page.mdx b/app/extensions/page.mdx index d3ba1f3..eab0c9a 100644 --- a/app/extensions/page.mdx +++ b/app/extensions/page.mdx @@ -61,10 +61,8 @@ Extensions can be found in two places: an [Entity](/entities#entity-definition)' { "type": "pub.versia:groups/Group", "id": "ed480922-b095-4f09-9da5-c995be8f5960", - "uri": "https://example.com/groups/ed480922-b095-4f09-9da5-c995be8f5960", "name": null, "description": null, - "members": "https://example.com/groups/ed480922-b095-4f09-9da5-c995be8f5960/members", "extensions": { // [!code focus:100] "com.example:gps": { "location": { @@ -102,8 +100,7 @@ Extensions can be found in two places: an [Entity](/entities#entity-definition)' { "type": "com.example:poll/Poll", "id": "6f27bc77-58ee-4c9b-b804-8cc1c1182fa9", - "uri": "https://example.com/actions/6f27bc77-58ee-4c9b-b804-8cc1c1182fa9", - "author": "https://example.com/users/6e0204a2-746c-4972-8602-c4f37fc63bbe", + "author": "6e0204a2-746c-4972-8602-c4f37fc63bbe", "created_at": "2021-01-01T00:00:00.000Z", "question": "What is your favourite colour?", "options": [ diff --git a/app/extensions/polls/page.mdx b/app/extensions/polls/page.mdx index cb671a7..ae91bdf 100644 --- a/app/extensions/polls/page.mdx +++ b/app/extensions/polls/page.mdx @@ -41,14 +41,9 @@ Note that there is no `question` field: the question should be included in the ` { "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", + "author": "versia.social: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?" @@ -120,10 +115,9 @@ If a vote is cast to a poll that is closed, the vote should be rejected with a ` { "id": "6f27bc77-58ee-4c9b-b804-8cc1c1182fa9", "type": "pub.versia:polls/Vote", // [!code focus] - "uri": "https://example.com/actions/6f27bc77-58ee-4c9b-b804-8cc1c1182fa9", "created_at": "2021-01-01T00:00:00.000Z", - "author": "https://example.com/users/6e0204a2-746c-4972-8602-c4f37fc63bbe", // [!code focus:3] - "poll": "https://example.com/notes/f08a124e-fe90-439e-8be4-15a428a72a19", + "author": "6e0204a2-746c-4972-8602-c4f37fc63bbe", // [!code focus:3] + "poll": "example.com:f08a124e-fe90-439e-8be4-15a428a72a19", "option": 1 } ``` diff --git a/app/extensions/reactions/page.mdx b/app/extensions/reactions/page.mdx index eaad613..e1b31d4 100644 --- a/app/extensions/reactions/page.mdx +++ b/app/extensions/reactions/page.mdx @@ -39,10 +39,9 @@ User reactions are (like every other entity) federated to all followers, and can { "id": "6f27bc77-58ee-4c9b-b804-8cc1c1182fa9", "type": "pub.versia:reactions/Reaction", // [!code focus] - "uri": "https://example.com/actions/6f27bc77-58ee-4c9b-b804-8cc1c1182fa9", "created_at": "2021-01-01T00:00:00.000Z", - "author": "https://example.com/users/6e0204a2-746c-4972-8602-c4f37fc63bbe", // [!code focus:3] - "object": "https://example.com/publications/f08a124e-fe90-439e-8be4-15a428a72a19", + "author": "6e0204a2-746c-4972-8602-c4f37fc63bbe", // [!code focus:3] + "object": "example.com:f08a124e-fe90-439e-8be4-15a428a72a19", "content": "πŸ˜€", } ``` diff --git a/app/extensions/reports/page.mdx b/app/extensions/reports/page.mdx index a1bf22e..96ddfa2 100644 --- a/app/extensions/reports/page.mdx +++ b/app/extensions/reports/page.mdx @@ -41,10 +41,10 @@ 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", + "author": "6f3001a1-641b-4763-a9c4-a089852eec84", "reported": [ - "https://test.com/publications/46f936a3-9a1e-4b02-8cde-0902a89769fa", - "https://test.com/publications/213d7c56-fb9b-4646-a4d2-7d70aa7d106a" + "test.com:46f936a3-9a1e-4b02-8cde-0902a89769fa", + "test.com:213d7c56-fb9b-4646-a4d2-7d70aa7d106a" ], "tags": [ "spam", diff --git a/app/extensions/share/page.mdx b/app/extensions/share/page.mdx index fa38799..7b047f5 100644 --- a/app/extensions/share/page.mdx +++ b/app/extensions/share/page.mdx @@ -37,9 +37,8 @@ When a user shares a note, the note's original author **must** receive the entit "id": "3e7e4750-afd4-4d99-a256-02f0710a0520", "type": "pub.versia:share/Share", "created_at": "2021-01-01T00:00:00.000Z", - "author": "https://example.com/users/6e0204a2-746c-4972-8602-c4f37fc63bbe", - "uri": "https://example.com/shares/3e7e4750-afd4-4d99-a256-02f0710a0520", - "shared": "https://otherexample.org/notes/fmKZ763jzIU8" + "author": "6e0204a2-746c-4972-8602-c4f37fc63bbe", + "shared": "otherexample.org:fmKZ763jzIU8" } ``` diff --git a/app/extensions/vanity/page.mdx b/app/extensions/vanity/page.mdx index 07e48d8..de6e6a9 100644 --- a/app/extensions/vanity/page.mdx +++ b/app/extensions/vanity/page.mdx @@ -129,8 +129,8 @@ All properties are optional. "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" + "burger.social:349ee237-c672-41c1-aadc-677e185f795a", + "versia.social:f565ef02-035d-4974-ba5e-f62a8558331d" ] } } diff --git a/app/federation/example/page.mdx b/app/federation/example/page.mdx index 0709a03..03be385 100644 --- a/app/federation/example/page.mdx +++ b/app/federation/example/page.mdx @@ -73,24 +73,16 @@ curl https://b.social/users/joe \ { "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] + }, // [!code focus:8] "display_name": "Joe Swanson (Winter Arc :gigachad:)", - "inbox": "https://b.social/inbox", "public_key": { - "actor": "https://b.social/users/joe", + "actor": "b.social:bde22zi3ca8762", "algorithm": "ed25519", "key": "MCowBQYDK2VwAyEAOSCcfsde0Ya3vf/P6lzgK0pA8qCISqneaze3omLlQCQ=" }, @@ -123,17 +115,12 @@ Finally, `a.social` serializes the note to send it to `joe`. { "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] + "author": "alice", + "category": "microblog", // [!code focus:11] "content": { "text/html": { - "content": "Hello, @joe@b.social! How are you doing today?", + "content": "Hello, @joe@b.social! How are you doing today?", "remote": false, }, "text/plain": { @@ -143,7 +130,7 @@ Finally, `a.social` serializes the note to send it to `joe`. }, "group": "public", "mentions": [ // [!code focus:3] - "https://b.social/users/joe" + "b.social:bde22zi3ca8762" ] } ``` diff --git a/app/structures/collection/page.mdx b/app/structures/collection/page.mdx index 841b87a..387b6f1 100644 --- a/app/structures/collection/page.mdx +++ b/app/structures/collection/page.mdx @@ -123,15 +123,11 @@ URI Collections are identical to regular collections, but they contain only 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", + "author": "018ec082-0ae1-761c-b2c5-22275a611771", "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" + "versia.social:f8b0d4b4-d354-4798-bbc5-c2ba8acabfe3", + "social.bob.com:2B27E62snga763" ] } ``` From 72039874abe6b3fb9691b48533bd73ab7eaf675a Mon Sep 17 00:00:00 2001 From: natri0 Date: Mon, 21 Apr 2025 17:23:22 +0000 Subject: [PATCH 04/25] =?UTF-8?q?feat:=20=E2=9C=A8=20Move=20Delegation=20t?= =?UTF-8?q?o=20an=20extension?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also adds a MDX component. --- app/changelog/page.mdx | 4 ++ app/extensions/delegation/page.mdx | 78 ++++++++++++++++++++++++++++++ app/federation/delegation/page.mdx | 25 ---------- components/Navigation.tsx | 2 +- components/mdx.tsx | 42 ++++++++++++++++ 5 files changed, 125 insertions(+), 26 deletions(-) create mode 100644 app/extensions/delegation/page.mdx delete mode 100644 app/federation/delegation/page.mdx diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index ac5a2fa..3c35d17 100644 --- a/app/changelog/page.mdx +++ b/app/changelog/page.mdx @@ -8,6 +8,10 @@ export const metadata = { This page lists changes since Working Draft 3. {{ className: 'lead' }} +## Since WD 5 + +- Moved [Delegation](/extensions/delegation) to an extension + ## Since WD 4 - Removed URI from [Report](/extensions/reports), and replaced `reason` with `tags`. diff --git a/app/extensions/delegation/page.mdx b/app/extensions/delegation/page.mdx new file mode 100644 index 0000000..3e9a17a --- /dev/null +++ b/app/extensions/delegation/page.mdx @@ -0,0 +1,78 @@ +export const metadata = { + title: 'Delegation Extension', + description: 'Lets users perform actions on other accounts\' behalf.' +} + +# Delegation Extension + +Delegation is used to authorize actions on behalf of another user. {{ className: 'lead '}} + +## Vocabulary + +- **Delegator**: The user that is delegating actions to another user. (The user that owns the key) +- **Delegate**: The user that is being delegated actions. (The user that the key is pointing to) + +## Implementation Details + +Any actions or entities created by the **delegate** should be attributed to the **delegator** user in clients transparently to end-users (e.g. showing the **delegator** user's name and avatar). This allows for a form of "consensual impersonation" that is authorized by the **delegators** and **delegates**. + +This is useful as a way to centralize all of a user's many "alt accounts" into a single, unified feed. + + + If an instance encounters an action from a User that has a Delegator listed, but that Delegator does not allow the User to perform actions on their behalf, the actions **MUST** be shown as the User's own. + + Also, if a User has a Delegator listed, but that Delegator does not allow the User to perform actions on their behalf, instances **SHOULD** mark the User with a warning about possible impersonation or fraud. + + +## Extension Definition + + + + + The Delegation extension uses an ID of `pub.versia:delegation`. + + If the extension is present, exactly **one** of the fields **MUST** be specified: + + + If this user performs actions on behalf on another user, **MUST** have a reference to that user. + + + If other users perform actions on behalf of this user, **MUST** have a list of references to all such users. + + + + + + + ```jsonc {{ title: "Example Delegator" }} + { + // ... + "type": "User", + "id": "73cb1728-75d7-4080-8d28-4adf49bb0a0d", + // ... + "extensions": { // [!code focus:5] + "pub.versia:delegation": { + "delegator": "versia.example.com:bfb6bb39-bb08-4226-91ac-8adebc3da046" + } + } + } + ``` + + ```jsonc {{ title: "Example Delegates List" }} + { + // ... + "type": "User", + "id": "bfb6bb39-bb08-4226-91ac-8adebc3da046", + // ... + "extensions": { // [!code focus:7] + "pub.versia:delegation": { + "allowed_delegates": [ + "versia.social:73cb1728-75d7-4080-8d28-4adf49bb0a0d" + ] + } + } + } + ``` + + + diff --git a/app/federation/delegation/page.mdx b/app/federation/delegation/page.mdx deleted file mode 100644 index 43d4e8c..0000000 --- a/app/federation/delegation/page.mdx +++ /dev/null @@ -1,25 +0,0 @@ -export const metadata = { - title: 'Delegation', - description: 'Delegation is used to authorize actions on behalf of another user', -} - -# Delegation - -Delegation is used to authorize actions on behalf of another user. {{ className: 'lead' }} - -## Vocabulary - -- **Delegator**: The user that is delegating actions to another user. (The user that owns the key) -- **Delegate**: The user that is being delegated actions. (The user that the key is pointing to) - -## The `actor` Field on Public Keys - -[Users](/entities/user)'s `public_key` property contains a field called `actor`. This field contains the URI to the **delegator** user, which is used to authorize actions on behalf of the **delegate** user. - -This means that the **delegator** user can sign requests with their private key, and any implementations should consider the **delegate** user as equivalent to the **delegator** user. - -## Implementation Details - -Any actions or entities created by the **delegate** should be attributed to the **delegator** user in clients transparently to end-users (e.g. showing the **delegator** user's name and avatar). This allows for a form of "consensual impersonation" that is authorized by the **delegators** and **delegates**. - -This is useful as a way to centralize all of a user's many "alt accounts" into a single, unified feed. \ No newline at end of file diff --git a/components/Navigation.tsx b/components/Navigation.tsx index a3c4d6d..9a53fe1 100644 --- a/components/Navigation.tsx +++ b/components/Navigation.tsx @@ -267,7 +267,6 @@ export const navigation: NavGroup[] = [ { title: "HTTP", href: "/federation/http" }, { title: "Validation", href: "/federation/validation" }, { title: "Discovery", href: "/federation/discovery" }, - { title: "Delegation", href: "/federation/delegation" }, { title: "Example", href: "/federation/example" }, ], }, @@ -295,6 +294,7 @@ export const navigation: NavGroup[] = [ title: "Extensions", links: [ { title: "Custom Emojis", href: "/extensions/custom-emojis" }, + { title: "Delegation", href: "/extensions/delegation" }, { title: "Groups", href: "/extensions/groups" }, { title: "Instance Messaging", diff --git a/components/mdx.tsx b/components/mdx.tsx index 09debe9..a71ea0f 100644 --- a/components/mdx.tsx +++ b/components/mdx.tsx @@ -44,6 +44,37 @@ function InfoIcon(props: ComponentPropsWithoutRef<"svg">) { ); } +function WarningIcon(props: ComponentPropsWithoutRef<"svg">) { + return ( + + ); +} + export function Note({ children }: { children: ReactNode }) { return (
@@ -55,6 +86,17 @@ export function Note({ children }: { children: ReactNode }) { ); } +export function Warning({ children }: { children: ReactNode }) { + return ( +
+ +
+ {children} +
+
+ ); +} + export function Row({ children }: { children: ReactNode }) { return (
From 71064dea2c206e827b619392bd017648eb649472 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Thu, 1 May 2025 20:09:59 +0200 Subject: [PATCH 05/25] feat: :sparkles: Document basics of S2S Federation API, and some endpoints --- app/api/basics/page.mdx | 27 +++++++ app/api/endpoints/page.mdx | 150 +++++++++++++++++++++++++++++++++++ app/api/errors/page.mdx | 0 app/api/html/page.mdx | 0 app/api/rate-limits/page.mdx | 0 components/Navigation.tsx | 10 +++ 6 files changed, 187 insertions(+) create mode 100644 app/api/basics/page.mdx create mode 100644 app/api/endpoints/page.mdx create mode 100644 app/api/errors/page.mdx create mode 100644 app/api/html/page.mdx create mode 100644 app/api/rate-limits/page.mdx diff --git a/app/api/basics/page.mdx b/app/api/basics/page.mdx new file mode 100644 index 0000000..851029f --- /dev/null +++ b/app/api/basics/page.mdx @@ -0,0 +1,27 @@ +export const metadata = { + title: "API", + description: "Defines the server-to-server API for Versia's federation.", +} + +# API + +Versia defines a very simple API for server-to-server communication, mainly fetching and sending entities. It is clearly namespaced and versioned, to avoid confusion with implementations' existing HTTP APIs. {{ className: "lead" }} + +## API Versioning + +Every Versia API endpoint is prefixed with `/.versia/vX/`, where `X` is the version of the API. The current version is `0.6`, so the current API prefix is `/.versia/v0.6/`. This versioning is used to avoid breaking changes in the future, and to allow for backwards compatibility. + + + Implementations have no obligations to support more than one Versia version. It is recommended to always support the latest version, as it helps avoid bogging down the network with old versions. + + +## Signatures + +- All API requests **MUST** be signed, unless otherwise specified. This includes `POST` and `GET` requests. +- All API responses **MUST** be signed, unless otherwise specified. + +The signature mechanism is defined in the [Signatures](/signatures) document. + +## Encoding + +"URL-encoding" is the mechanism used to encode data containing special characters in URLs. When this specification refers to "URL-encoding", it means the encoding defined in [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986#section-2.1). \ No newline at end of file diff --git a/app/api/endpoints/page.mdx b/app/api/endpoints/page.mdx new file mode 100644 index 0000000..c88012f --- /dev/null +++ b/app/api/endpoints/page.mdx @@ -0,0 +1,150 @@ +export const metadata = { + title: "API Endpoints", + description: "Explains all endpoints in Versia's federation API.", +} + +# Endpoints + +## Instance metadata + + + This endpoint is exempt from the signature requirement. No signatures are required for requests or responses to it. + + + + + + + + Must be `/.versia/v0.6/instance`. + + + Must be `GET`. + + + Must be the instance's metadata, as defined in the [Instance Metadata](/entities/instance-metadata) document. + + + + + + + ```http {{ 'title': 'Example request' }} + GET /.versia/v0.6/instance + Host: b.social + Accept: application/vnd.versia+json + ``` + + ```http {{ 'title': 'Example response' }} + HTTP/1.1 200 OK + Content-Type: application/vnd.versia+json + + { + "type": "InstanceMetadata", + "name": "Bob!!", + // ... + } + ``` + + + + +## Entity data + + + + + + Must be `/.versia/v0.6/entities/{entity_type}/{id}`. + + - `{entity_type}`: The type of the entity to fetch, URL-encoded. + - `{id}`: The ID of the entity to fetch, URL-encoded. + + Example: `GET /.versia/v0.6/entities/pub.versia%3Agroups%2FGroup/1234` fetches the [Group](/extensions/groups) entity with ID `1234`. + + + Must be `GET`. + + + Must be the entity's data as JSON, as defined in its [Entity](/entities) definition document. + + + + + + + ```http {{ 'title': 'Example request' }} + GET /.versia/v0.6/entities/user/1234 + Host: b.social + Accept: application/vnd.versia+json + ``` + + ```http {{ 'title': 'Example response' }} + HTTP/1.1 200 OK + Content-Type: application/vnd.versia+json + + { + "type": "User", + "id": "1234", + // ... + } + ``` + + + +## Entity collections + + + + + + Must be `/.versia/v0.6/entities/{entity_type}/{id}/collections/{collection_type}`. + + - `{entity_type}`: The type of the entity to fetch, URL-encoded. + - `{id}`: The ID of the entity to fetch, URL-encoded. + - `{collection_type}`: The type of the collection to fetch, URL-encoded. + + Example: `GET /.versia/v0.6/entities/User/1234/collections/followers` fetches the followers of the user with ID `1234`. + + + Must be `GET`. + + + Must be either a [Collection](/structures/collection) or a [URICollection](/structures/collection#uri-collection) as JSON. + + + + + + + ```http {{ 'title': 'Example request' }} + GET /.versia/v0.6/entities/user/1234/collections/followers + Host: b.social + Accept: application/vnd.versia+json + ``` + + ```http {{ 'title': 'Example response' }} + HTTP/1.1 200 OK + Content-Type: application/vnd.versia+json + + { + "type": "Followers", + "id": "1234", + // ... + } + ``` + + + +### Pagination + +Collections MUST support pagination, using the following URI parameters: + +- `offset`: The number of items to skip before returning the first item. This is a zero-based index. +- `limit`: The maximum number of items to return. This is a one-based index. Implementations MUST support a minimum of `1` and a maximum of `40` items. + +```http {{ 'title': 'Example paginated collection request' }} +GET /.versia/v0.6/entities/user/1234/collections/followers?offset=10&limit=20 +Host: b.social +Accept: application/vnd.versia+json +``` diff --git a/app/api/errors/page.mdx b/app/api/errors/page.mdx new file mode 100644 index 0000000..e69de29 diff --git a/app/api/html/page.mdx b/app/api/html/page.mdx new file mode 100644 index 0000000..e69de29 diff --git a/app/api/rate-limits/page.mdx b/app/api/rate-limits/page.mdx new file mode 100644 index 0000000..e69de29 diff --git a/components/Navigation.tsx b/components/Navigation.tsx index 9a53fe1..5ef4a98 100644 --- a/components/Navigation.tsx +++ b/components/Navigation.tsx @@ -270,6 +270,16 @@ export const navigation: NavGroup[] = [ { title: "Example", href: "/federation/example" }, ], }, + { + title: "API", + links: [ + { title: "Basics", href: "/api/basics" }, + { title: "Endpoints", href: "/api/endpoints" }, + { title: "Rate Limits", href: "/api/rate-limits" }, + { title: "Errors", href: "/api/errors" }, + { title: "HTML Redirects", href: "/api/html" }, + ], + }, { title: "Structures", links: [ From 51c53824adcafaefd0a2471492456acc2a4ab17e Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 2 May 2025 15:31:04 +0200 Subject: [PATCH 06/25] feat: :sparkles: Document inbox endpoint --- app/api/basics/page.mdx | 29 ++++++++++++++++++++++++++++- app/api/endpoints/page.mdx | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/app/api/basics/page.mdx b/app/api/basics/page.mdx index 851029f..deb0f5a 100644 --- a/app/api/basics/page.mdx +++ b/app/api/basics/page.mdx @@ -11,6 +11,8 @@ Versia defines a very simple API for server-to-server communication, mainly fetc Every Versia API endpoint is prefixed with `/.versia/vX/`, where `X` is the version of the API. The current version is `0.6`, so the current API prefix is `/.versia/v0.6/`. This versioning is used to avoid breaking changes in the future, and to allow for backwards compatibility. +Requests not encrypted with TLS (aka HTTPS) **MUST NOT** be sent or responded to. All implementations are required to use TLS 1.2 or higher, and to support HTTP/2. + Implementations have no obligations to support more than one Versia version. It is recommended to always support the latest version, as it helps avoid bogging down the network with old versions. @@ -24,4 +26,29 @@ The signature mechanism is defined in the [Signatures](/signatures) document. ## Encoding -"URL-encoding" is the mechanism used to encode data containing special characters in URLs. When this specification refers to "URL-encoding", it means the encoding defined in [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986#section-2.1). \ No newline at end of file +"URL-encoding" is the mechanism used to encode data containing special characters in URLs. When this specification refers to "URL-encoding", it means the encoding defined in [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986#section-2.1). + +## Redirects + +API endpoints **MUST NOT** redirect to other endpoints, with the following exceptions: +- HTTP to HTTPS redirects (upgrading insecure requests). +- When the request does not have an `Accept: application/vnd.versia+json` header, the server **MAY** redirect to an HTML representation of the resource. + +This is forbidden: + +```http +GET /.versia/v0.6/entities/user/1234 +Host: example.com + +HTTP/1.1 301 Moved Permanently +Location: https://example.com/users/1234 +``` + +This is allowed: +```http +GET /.versia/v0.6/entities/user/1234 +Host: example.com + +HTTP/1.1 301 Moved Permanently +Location: https://example.com/.versia/v0.6/entities/user/1234 +``` \ No newline at end of file diff --git a/app/api/endpoints/page.mdx b/app/api/endpoints/page.mdx index c88012f..ba90209 100644 --- a/app/api/endpoints/page.mdx +++ b/app/api/endpoints/page.mdx @@ -148,3 +148,39 @@ GET /.versia/v0.6/entities/user/1234/collections/followers?offset=10&limit=20 Host: b.social Accept: application/vnd.versia+json ``` + +## Inbox + +The inbox endpoint is used for other instances to send entities to this instance. It is a single endpoint that can receive messages for every user (also known as a shared inbox). + +The delivery mechanism is described further in the [Federation](/federation) document. + + + + + + Must be `/.versia/v0.6/inbox`. + + + Must be `POST`. + + + + + + + ```http {{ 'title': 'Example request' }} + POST /.versia/v0.6/inbox + Host: b.social + Accept: application/vnd.versia+json + Content-Type: application/vnd.versia+json + + { + "type": "Note", + "id": "1234", + ... + } + ``` + + + \ No newline at end of file From d886b83e62e2ece58bc0874c70a32803d30ae2a1 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Mon, 5 May 2025 14:08:20 +0200 Subject: [PATCH 07/25] refactor: :memo: Update all extension to remove now-useless fields --- app/entities/delete/page.mdx | 8 ++- app/entities/follow-accept/page.mdx | 7 +- app/entities/follow-reject/page.mdx | 7 +- app/entities/follow/page.mdx | 7 +- app/entities/instance-metadata/page.mdx | 33 ++++------ app/entities/note/page.mdx | 31 +++------ app/entities/page.mdx | 18 +++--- app/entities/unfollow/page.mdx | 7 +- app/entities/user/page.mdx | 68 ++++---------------- app/extensions/custom-emojis/page.mdx | 6 +- app/extensions/delegation/page.mdx | 7 +- app/extensions/groups/page.mdx | 58 ++++++++++------- app/extensions/instance-messaging/page.mdx | 63 ++++-------------- app/extensions/interaction-controls/page.mdx | 2 +- app/extensions/likes/page.mdx | 32 ++------- app/extensions/migration/page.mdx | 7 +- app/extensions/page.mdx | 4 +- app/extensions/reactions/page.mdx | 13 +--- app/extensions/reports/page.mdx | 7 +- app/extensions/share/page.mdx | 13 +--- app/extensions/websockets/page.mdx | 57 ---------------- app/federation/discovery/page.mdx | 8 +-- app/federation/example/page.mdx | 23 +++---- app/federation/http/page.mdx | 15 +++-- app/federation/page.mdx | 16 ++--- app/signatures/page.mdx | 16 ++--- app/structures/collection/page.mdx | 43 ------------- 27 files changed, 166 insertions(+), 410 deletions(-) delete mode 100644 app/extensions/websockets/page.mdx diff --git a/app/entities/delete/page.mdx b/app/entities/delete/page.mdx index e5307ff..773058b 100644 --- a/app/entities/delete/page.mdx +++ b/app/entities/delete/page.mdx @@ -17,12 +17,13 @@ Having the authorization is defined as: ## Entity Definition + + This entity is a [**Transient Entity**](/entities#transient-entities). + + - - 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). @@ -43,6 +44,7 @@ Having the authorization is defined as: "id": "9b3212b8-529c-435a-8798-09ebbc17ca74", "created_at": "2021-01-01T00:00:00.000Z", "author": "6e0204a2-746c-4972-8602-c4f37fc63bbe", + "deleted_type": "Note", "deleted": "02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" } ``` diff --git a/app/entities/follow-accept/page.mdx b/app/entities/follow-accept/page.mdx index 6aa8d94..a9d404b 100644 --- a/app/entities/follow-accept/page.mdx +++ b/app/entities/follow-accept/page.mdx @@ -11,12 +11,13 @@ export const metadata = { ## Entity Definition + + This entity is a [**Transient Entity**](/entities#transient-entities). + + - - 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 3b2ae3b..db8d6df 100644 --- a/app/entities/follow-reject/page.mdx +++ b/app/entities/follow-reject/page.mdx @@ -21,12 +21,13 @@ But it can also be used when Bob is already following Alice, in the case that: ## Entity Definition + + This entity is a [**Transient Entity**](/entities#transient-entities). + + - - 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 c64cc64..6a188bb 100644 --- a/app/entities/follow/page.mdx +++ b/app/entities/follow/page.mdx @@ -53,12 +53,13 @@ Once a follow relationship is established, the **followee**'s instance should se ## Entity Definition + + This entity is a [**Transient Entity**](/entities#transient-entities). + + - - 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/instance-metadata/page.mdx b/app/entities/instance-metadata/page.mdx index caa53bc..bcdf3c5 100644 --- a/app/entities/instance-metadata/page.mdx +++ b/app/entities/instance-metadata/page.mdx @@ -9,7 +9,7 @@ Contains metadata about a Versia instance, such as capabilities and endpoints. { ## The `null` Author -On some entities that have an `author` field, the `author` can be `null` to represent the instance itself as the author (like ActivityPub's Server Actors). In this case, the instance's public key should be used to verify the entity. To know which instance's public key to use, the entity signature should be used. +On some entities that have an `author` field, the `author` can be `null` to represent the instance itself as the author (like ActivityPub's Server Actors). Check the entity's documentation page to see if it supports this (it will be noted in the `author` field). @@ -21,9 +21,6 @@ Check the entity's documentation page to see if it supports this (it will be not This entity does not have an ID. - - This entity does not have a URI. - Friendly name of the instance, for humans. @@ -60,9 +57,6 @@ Check the entity's documentation page to see if it supports this (it will be not Hostname of the instance. Includes the port if it is not the default (i.e. `443` for HTTPS). - - URI to the instance's shared inbox, if supported. - Public key of the instance. @@ -76,20 +70,6 @@ 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](/signatures#exporting-the-public-key). - - URI to [Collection](/structures/collection) of instance moderators. - - - This is for human consumption (such as moderator contact), not for any kind of protocol authorization. - - - - URI to [Collection](/structures/collection) of instance administrators. - - - This is for human consumption (such as admin contact), not for any kind of protocol authorization. - - Logo of the instance. Must be an image format (`image/*`). @@ -144,4 +124,13 @@ Check the entity's documentation page to see if it supports this (it will be not ``` - \ No newline at end of file + + +### Collections + +The following [Collections](/structures/collection) are available: + +- `moderators`: [Collection](/structures/collection) of instance moderators ([Users](/entities/user)). +- `admins`: [Collection](/structures/collection) of instance administrators ([Users](/entities/user)). + +These can be fetched using the [Federation API](/api/endpoints#entity-collections) \ No newline at end of file diff --git a/app/entities/note/page.mdx b/app/entities/note/page.mdx index ed3cf04..2a2e060 100644 --- a/app/entities/note/page.mdx +++ b/app/entities/note/page.mdx @@ -36,28 +36,6 @@ 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. @@ -178,3 +156,12 @@ Notes represent a piece of content on a Versia instance. They can be posted by [ + +### Collections + +The following [Collections](/structures/collection) are available: + +- `replies`: [URI Collection](/structures/collection#uri-collection) of [Note](/entities/note) entities that are replies to this note. +- `quotes`: [URI Collection](/structures/collection#uri-collection) of [Note](/entities/note) entities that quote this note. + +These can be fetched using the [Federation API](/api/endpoints#entity-collections) \ No newline at end of file diff --git a/app/entities/page.mdx b/app/entities/page.mdx index e7c8e8e..7b756f7 100644 --- a/app/entities/page.mdx +++ b/app/entities/page.mdx @@ -19,7 +19,12 @@ 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. + Unique identifier for the entity. Must be unique within the instance. Can be any string with the following character sets: + + - `a-z` + - `A-Z` + - `0-9` + - `-`, `_` Type of the entity. Custom types must follow [Extension Naming](/extensions#naming). @@ -31,13 +36,6 @@ Any field in an entity not marked as `required` may be omitted or set to `null`. Handling of dates that are valid but obviously incorrect (e.g. in the future) is left to the Implementation's discretion. - - URI of the entity. Should be unique and resolve to the entity. Must be an absolute URI. - - - [**Transient Entities**](/entities#transient-entities) do not require a URI. - - URL of any JSON Schema that the entity adheres to. @@ -86,7 +84,7 @@ 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. +Some entities are transient, meaning they cannot be refetched using the [Federation API](/api/endpoints). 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. @@ -95,5 +93,5 @@ Implementations **must not** rely on other implementations to store transient en When serialized to a string, the JSON representation of an entity must follow the following rules: - Keys must be sorted lexicographically. - 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 be **signed** using the the [instance's private key](/entities/instance-metadata). - Must use Unix-style `\n` line endings (LF). \ No newline at end of file diff --git a/app/entities/unfollow/page.mdx b/app/entities/unfollow/page.mdx index 1c6000f..3e1be6b 100644 --- a/app/entities/unfollow/page.mdx +++ b/app/entities/unfollow/page.mdx @@ -26,12 +26,13 @@ Sometimes, [Users](/entities/user) want to unsubscribe from each other to stop s ## Entity Definition + + This entity is a [**Transient Entity**](/entities#transient-entities). + + - - 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/entities/user/page.mdx b/app/entities/user/page.mdx index f069ba7..94a078e 100644 --- a/app/entities/user/page.mdx +++ b/app/entities/user/page.mdx @@ -70,64 +70,12 @@ Instance **must** be the host of the instance the user is on (hostname with opti A header image for the user's profile. Also known as a cover photo or a banner. Must be an image format (`image/*`). - - 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](/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 - type URI = string; - - type PublicKey = { - actor: URI; - algorithm: string; - key: string; - } - ``` - If `true`, the user must approve any new followers manually. If `false`, followers are automatically approved. This does not affect federation, and is meant to be used for clients to display correct UI. Defaults to `false`. User consent to be indexed by search engines. If `false`, the user's profile should not be indexed. Defaults to `true`. - - The user's federation inbox. Refer to the [federation documentation](/federation). - - Some instances may also have a shared inbox. Refer to [Instance Metadata](/entities/instance-metadata) for more information. - - - Collections related to the user. Must contain at least `outbox`, `followers`, `following`, and `featured`. - - ```typescript - type URI = string; - - type UserCollections = { - outbox: URI; - followers: URI; - following: URI; - featured: 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. - - ### Outbox - The user's federation outbox. Refer to the [federation documentation](/federation). [Collection](/structures/collection) of [Note](/entities/note) entities. - - ### Followers - User's followers. [URI Collection](/structures/collection#uri-collection) of [User](/entities/user) entities. - - ### Following - 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. Only notes authored by the user can be featured. - @@ -174,14 +122,20 @@ Instance **must** be the host of the instance the user is on (hostname with opti "header": null, "indexable": false, "manually_approves_followers": false, - "public_key": { - "actor": "018ec082-0ae1-761c-b2c5-22275a611771", - "algorithm": "ed25519", - "key": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - }, "username": "aprl" } ``` + +### Collections + +The following [Collections](/structures/collection) are available: + +- `outbox`: [Collection](/structures/collection) of notes authored by the user. +- `followers`: [URI Collection](/structures/collection#uri-collection) of users that follow the user. +- `following`: [URI Collection](/structures/collection#uri-collection) of users that the user follows. +- `featured`: [Collection](/structures/collection) of notes that the user wants to feature on their profile ("pinned" notes). + +These can be fetched using the [Federation API](/api/endpoints#entity-collections) \ No newline at end of file diff --git a/app/extensions/custom-emojis/page.mdx b/app/extensions/custom-emojis/page.mdx index 2af353a..25a6072 100644 --- a/app/extensions/custom-emojis/page.mdx +++ b/app/extensions/custom-emojis/page.mdx @@ -15,7 +15,11 @@ The Custom Emojis extension adds support for adding personalized emojis to feder Emoji name, surrounded by identification characters (for example, colons: `:happy_face:`). - Name must match the regex `^[a-zA-Z0-9_-]+$`. + The following characters are allowed: + - `a-z` + - `A-Z` + - `0-9` + - `_`, `-` Identification characters must not match the name regex (must not be alphanumeric/underscore/hyphen). There may only be two identification characters, one at the beginning and one at the end. diff --git a/app/extensions/delegation/page.mdx b/app/extensions/delegation/page.mdx index 3e9a17a..3ec8480 100644 --- a/app/extensions/delegation/page.mdx +++ b/app/extensions/delegation/page.mdx @@ -26,13 +26,12 @@ This is useful as a way to centralize all of a user's many "alt accounts" into a ## Extension Definition +The Delegation extension uses an ID of `pub.versia:delegation`. + +If the extension is present, exactly **one** of the fields **MUST** be specified: - The Delegation extension uses an ID of `pub.versia:delegation`. - - If the extension is present, exactly **one** of the fields **MUST** be specified: - If this user performs actions on behalf on another user, **MUST** have a reference to that user. diff --git a/app/extensions/groups/page.mdx b/app/extensions/groups/page.mdx index 5a96a17..4cf9e5b 100644 --- a/app/extensions/groups/page.mdx +++ b/app/extensions/groups/page.mdx @@ -36,12 +36,6 @@ Refer to [Note](/entities/note#entity-definition)'s `group` property for how not 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). - - - URI of the group's associated notes. [URI Collection](/structures/collection#uri-collection) of [Notes](/entities/note). - @@ -68,6 +62,15 @@ Refer to [Note](/entities/note#entity-definition)'s `group` property for how not +### Collections + +The following [Collections](/structures/collection) are available: + +- `members`: [URI Collection](/structures/collection#uri-collection) of [Users](/entities/user) that are members of the group. +- `notes`: [URI Collection](/structures/collection#uri-collection) of [Notes](/entities/note) that are associated with the group. + +These can be fetched using the [Federation API](/api/endpoints#entity-collections) + ## 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). @@ -80,15 +83,16 @@ If the group accepts the subscription, the user will receive all notes posted to Indicates that a [User](/entities/user) wishes to subscribe to a group. + + This entity is a [**Transient Entity**](/entities#transient-entities). + + Must be `pub.versia:groups/Subscribe`. - - 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,15 +121,16 @@ Indicates that a [User](/entities/user) wishes to subscribe to a group. Indicates that a [User](/entities/user) wishes to unsubscribe from a group. + + This entity is a [**Transient Entity**](/entities#transient-entities). + + Must be `pub.versia:groups/Unsubscribe`. - - This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. - URI of the [User](/entities/user) unsubscribing from the group. @@ -152,7 +157,11 @@ Indicates that a [User](/entities/user) wishes to unsubscribe from a group. ### 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. +Indicates that a [Group](#entity-definition) has accepted a [User](/entities/user)'s subscription request. Should be sent by the instance hosting the group. + + + This entity is a [**Transient Entity**](/entities#transient-entities). + @@ -160,9 +169,6 @@ 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. - URI of the [User](/entities/user) subscribing to the group. @@ -189,7 +195,11 @@ Indicates that a [Group](#entity-definition) has accepted a [User](/entities/use ### 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. +Indicates that a [Group](#entity-definition) has rejected a [User](/entities/user)'s subscription request. Should be sent by the instance hosting the group. + + + This entity is a [**Transient Entity**](/entities#transient-entities). + @@ -197,9 +207,6 @@ 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. - URI of the [User](/entities/user) subscribing to the group. @@ -228,13 +235,17 @@ Indicates that a [Group](#entity-definition) has rejected a [User](/entities/use 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. +All [Notes](/entities/note) posted to a group (using the `group` field) must be sent to its instance's [inbox](/api/endpoints#inbox). 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. +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 sent by the group's instance. + + + This entity is a [**Transient Entity**](/entities#transient-entities). + @@ -242,9 +253,6 @@ 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. - URI of the note to federate. diff --git a/app/extensions/instance-messaging/page.mdx b/app/extensions/instance-messaging/page.mdx index 54692f1..9a13a4b 100644 --- a/app/extensions/instance-messaging/page.mdx +++ b/app/extensions/instance-messaging/page.mdx @@ -23,60 +23,21 @@ For example, let's consider the following scenario: In this scenario, `jane.org` has no way of knowing what went wrong, as `joe.social` does not provide any feedback. -## Instance Metadata Extensions -This extension adds the following metadata to instances: +## Sending Messages - - - - - The endpoint to send federation debug messages to. +To send a federation debug message, instances **should** make a `POST` request to the `/.versia/v0.6/messaging` endpoint with a simple text body containing a helpful message. - ### Sending Messages +No signatures are required (either on the request or response), and no response body is expected. - To send a federation debug message, instances **should** make a `POST` request to the appropriate endpoint with a simple text body containing a helpful message. +```text {{ "title": "Helpful Message" }} +Validation failed for https://jane.org/users/nkGEd8eI98. +Reasons: + - `username` must be alphanumeric. Found invalid character `@`. +``` - ```text {{ "title": "Helpful Message" }} - Validation failed for https://jane.org/users/nkGEd8eI98. - Reasons: - - `username` must be alphanumeric. Found invalid character `@`. - ``` +Do not send useless messages, such as: - Do not send useless messages, such as: - - ```text {{ "title": "Unhelpful Message" }} - Federation failed. - ``` - - - - - - - ```jsonc {{ "title": "Example Instance Metadata" }} - { - "type": "InstanceMetadata", - "name": "Jane.org", - "software": { - "name": "Versia Server", - "version": "0.7.0" - }, - "compatibility": { - "versions": [ - "0.5.0" - ], - "extensions": [ - "pub.versia:reactions", - "pub.versia:polls", - "pub.versia:reports", - "pub.versia:instance_messaging" - ] - }, - "host": "jane.org", - "created_at": "2021-07-01T00:00:00Z" - } - ``` - - - \ No newline at end of file +```text {{ "title": "Unhelpful Message" }} +Federation failed. +``` \ No newline at end of file diff --git a/app/extensions/interaction-controls/page.mdx b/app/extensions/interaction-controls/page.mdx index b1d27bc..afd30b4 100644 --- a/app/extensions/interaction-controls/page.mdx +++ b/app/extensions/interaction-controls/page.mdx @@ -99,7 +99,7 @@ Extensions **may** choose to register their own interaction types (such as `pub. ### 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. +Implementations that find a user attempting to create an interaction they are not allowed to **MAY** return a `403 Forbidden` HTTP status code when processing the Note during federation, or use the [Instance Messaging](/extensions/instance-messaging) extension. The Note **must** be discarded. 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. diff --git a/app/extensions/likes/page.mdx b/app/extensions/likes/page.mdx index c979ce9..4614aac 100644 --- a/app/extensions/likes/page.mdx +++ b/app/extensions/likes/page.mdx @@ -90,39 +90,15 @@ 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 [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 -{ - "type": "User", - ... - "collections": { - ... - "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" - } -} -``` +- `pub.versia:likes/Likes`: [URI Collection](/structures/collection#uri-collection) of all the notes the user has liked. +- `pub.versia:likes/Dislikes`: [URI Collection](/structures/collection#uri-collection) of all the notes the user has disliked. ## 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" - } -} -``` +- `pub.versia:likes/Likes`: [URI Collection](/structures/collection#uri-collection) of all the likes the note has received. +- `pub.versia:likes/Dislikes`: [URI Collection](/structures/collection#uri-collection) of all the dislikes the note has received. ## Interaction Types diff --git a/app/extensions/migration/page.mdx b/app/extensions/migration/page.mdx index 36975e2..47f6d5b 100644 --- a/app/extensions/migration/page.mdx +++ b/app/extensions/migration/page.mdx @@ -30,12 +30,13 @@ Migration happens in three steps: ## Entity Definition + + This entity is a [**Transient Entity**](/entities#transient-entities). + + - - 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/page.mdx b/app/extensions/page.mdx index eab0c9a..f84e12a 100644 --- a/app/extensions/page.mdx +++ b/app/extensions/page.mdx @@ -7,7 +7,7 @@ export const metadata = { Versia provides a set of core entities and structures to build a barebones social network. However, it is not possible nor desirable to cover every use case. This is where extensions come in, allowing parts of the system to be extended or replaced with custom functionality. {{ className: 'lead' }} -By design, extensions can be mitchmatched in any combination, without requiring any changes to the core system. This allows for a high degree of customization and flexibility. Implementations that do not support a particular extension can simply ignore it without any issues. +By design, extensions can be implemented in any combination, without requiring any changes to the core system. This allows for a high degree of customization and flexibility. Implementations that do not support a particular extension can simply ignore it without any issues. Extensions **should** be standardized and publicly documented. @@ -90,7 +90,7 @@ Extensions can be found in two places: an [Entity](/entities#entity-definition)' Other properties of the custom entity. These are specific to the extension, and should be documented by the extension author. - Note that `id`, `uri` and `created_at` are still required for custom entities, unless the extension author specifies otherwise. + Note that `id` and `created_at` are still required for custom entities, unless the extension author specifies otherwise. diff --git a/app/extensions/reactions/page.mdx b/app/extensions/reactions/page.mdx index e1b31d4..8691324 100644 --- a/app/extensions/reactions/page.mdx +++ b/app/extensions/reactions/page.mdx @@ -53,18 +53,7 @@ User reactions are (like every other entity) federated to all followers, and can The Likes extension adds the following collections to the [Note](/entities/note) entity: -- `reactions`: A [URI Collection](/structures/collection#uri-collection) of all the reactions to the note. - -```jsonc -{ - "type": "Note", - ... - "collections": { - ... - "pub.versia:reactions/Reactions": "https://example.com/publications/f08a124e-fe90-439e-8be4-15a428a72a19/reactions" - } -} -``` +- `pub.versia:reactions/Reactions`: [URI Collection](/structures/collection#uri-collection) of all the reactions to the note. ## Interaction Types diff --git a/app/extensions/reports/page.mdx b/app/extensions/reports/page.mdx index 96ddfa2..6465730 100644 --- a/app/extensions/reports/page.mdx +++ b/app/extensions/reports/page.mdx @@ -11,12 +11,13 @@ When an instance receives a report, it *should* be reviewed by a moderator or ad ## Entity Definition + + This entity is a [**Transient Entity**](/entities#transient-entities). + + - - This is a [**Transient Entity**](/entities#transient-entities) and does not have a URI. - Must be `pub.versia:reports/Report`. diff --git a/app/extensions/share/page.mdx b/app/extensions/share/page.mdx index 7b047f5..9c80fad 100644 --- a/app/extensions/share/page.mdx +++ b/app/extensions/share/page.mdx @@ -49,18 +49,7 @@ When a user shares a note, the note's original author **must** receive the entit 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" - } -} -``` +- `pub.versia:share/Shares`: [URI Collection](/structures/collection#uri-collection) of all the shares of the note. ## Interaction Types diff --git a/app/extensions/websockets/page.mdx b/app/extensions/websockets/page.mdx deleted file mode 100644 index ab29a30..0000000 --- a/app/extensions/websockets/page.mdx +++ /dev/null @@ -1,57 +0,0 @@ -export const metadata = { - title: 'WebSocket Extension', - description: - 'The WebSocket extension adds support for real-time communication between instances.', -} - -# WebSockets Extension - - - This document is **provided for informative purposes** and should not be used in a production environment. It is subject to change. - - If internal testing proves unsuccessful at solving the problems with the HTTP delivery method, this document may be abandoned. - - -Typically, communication between Versia instances is done via HTTP. However, HTTP suffers from some limitations, such as high latency and heavy overhead for small messages, making it less suitable for exchanging large amounts of entities at acceptable speeds. {{ className: 'lead' }} - -This extension aims to address these limitations by adding support for the exchange of entities using WebSockets. - -## Message Format - -Messages sent over the WebSocket connection are JSON objects. - - - - - - Same as the `Versia-Signature` header in HTTP requests. - - - Same as the `Versia-Signed-At` 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. - - - - - - - ```jsonc {{ 'title': 'Example Message' }} - { - "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\"}" - } - ``` - - - - -## Connection Establishment - -... \ No newline at end of file diff --git a/app/federation/discovery/page.mdx b/app/federation/discovery/page.mdx index a1baf1e..b56a945 100644 --- a/app/federation/discovery/page.mdx +++ b/app/federation/discovery/page.mdx @@ -49,17 +49,17 @@ Accept: application/jrd+json ## Instance Discovery -Instaance metadata can be accessed by making a `GET` request to the instance's Versia metadata endpoint, which is located at `/.well-known/versia`. This endpoint does not need any signatures in the output. +Instaance metadata can be accessed by making a `GET` request to the instance's Versia metadata endpoint, documented in the [Endpoints](/api/endpoints#instance-metadata) document. ### Example -To discover the metadata of the instance `versia.social`, an instance would make a `GET` request to `https://versia.social/.well-known/versia`. +To discover the metadata of the instance `versia.social`, an instance would make a `GET` request to `https://versia.social/.versia/v0.6/instance`. This endpoint will return an [InstanceMetadata](/entities/instance-metadata) entity. ```http {{ 'title': 'Example Request' }} -GET /.well-known/versia HTTP/1.1 -Accept: application/json +GET /.versia/v0.6/instance HTTP/1.1 +Accept: application/vnd.versia+json ``` ```jsonc {{ 'title': 'Example Response' }} diff --git a/app/federation/example/page.mdx b/app/federation/example/page.mdx index 03be385..34e2d25 100644 --- a/app/federation/example/page.mdx +++ b/app/federation/example/page.mdx @@ -40,8 +40,8 @@ curl https://b.social/.well-known/webfinger?resource=acct:joe@b.social -H "Accep "links": [ { // [!code focus:5] "rel": "self", - "type": "application/json", - "href": "https://b.social/users/joe" + "type": "application/vnd.versia+json", + "href": "https://b.social/.versia/entities/User/joe" } ] } @@ -58,12 +58,12 @@ curl https://b.social/.well-known/webfinger?resource=acct:joe@b.social -H "Accep `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" \ +curl https://b.social/.versia/entities/User/joe \ + -H "Accept: application/vnd.versia+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-By: a.social" \ -H "Versia-Signed-At: 1729241687" ``` @@ -79,13 +79,8 @@ curl https://b.social/users/joe \ "content": "https://cdn.b.social/avatars/joe.webp", "remote": true } - }, // [!code focus:8] + }, // [!code focus:3] "display_name": "Joe Swanson (Winter Arc :gigachad:)", - "public_key": { - "actor": "b.social:bde22zi3ca8762", - "algorithm": "ed25519", - "key": "MCowBQYDK2VwAyEAOSCcfsde0Ya3vf/P6lzgK0pA8qCISqneaze3omLlQCQ=" - }, "username": "joe", "extensions": { "pub.versia:custom_emojis": { @@ -142,13 +137,13 @@ It is now time for `a.social` to send the note to `joe`. `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" \ +curl -X POST https://b.social/.versia/v0.6/inbox \ + -H "Content-Type: application/vnd.versia+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-By: a.social" \ -H "Versia-Signed-At: 1733051946" ``` diff --git a/app/federation/http/page.mdx b/app/federation/http/page.mdx index bb421ad..dd94545 100644 --- a/app/federation/http/page.mdx +++ b/app/federation/http/page.mdx @@ -16,10 +16,10 @@ ALL kinds of HTTP requests/responses between instances **MUST** include a [Signa - Must include `application/json`. + Must include `application/vnd.versia+json`, unless specified otherwise. - Must include `application/json; charset=utf-8`, if the request has a body. + Must include `application/vnd.versia+json; charset=utf-8`, if the request has a body. See [Signatures](/signatures) for more information. @@ -37,11 +37,12 @@ ALL kinds of HTTP requests/responses between instances **MUST** include a [Signa ```http {{ 'title': 'Example Request' }} - POST https://bob.com/users/1/inbox HTTP/1.1 + POST https://bob.com/.versia/v0.6/inbox HTTP/1.1 + # This specific endpoint returns plain JSON Accept: application/json User-Agent: CoolServer/1.0 (https://coolserver.com) Versia-Signature: /CjB2L9bcvRg+uP19B4/rqy7Ji9/cqMFPlL3GVCIndnQjYyOpBzJEAl9weDnXm7Jrqa3y6sBC+EYWKThO2r9Bw== - Versia-Signed-By: https://example.com/users/1 + Versia-Signed-By: example.com Versia-Signed-At: 1729241687 ``` @@ -63,7 +64,7 @@ IETF draft [draft-polli-ratelimit-headers-02](https://www.ietf.org/archive/id/dr - Must include `application/json; charset=utf-8`. + Must include `application/vnd.versia+json; charset=utf-8`, unless specified otherwise. See [Signatures](/signatures) for more information. @@ -79,9 +80,9 @@ IETF draft [draft-polli-ratelimit-headers-02](https://www.ietf.org/archive/id/dr ```http {{ 'title': 'Example Response' }} HTTP/1.1 200 OK - Content-Type: application/json; charset=utf-8 + Content-Type: application/vnd.versia+json; charset=utf-8 Versia-Signature: /CjB2L9bcvRg+uP19B4/rqy7Ji9/cqMFPlL3GVCIndnQjYyOpBzJEAl9weDnXm7Jrqa3y6sBC+EYWKThO2r9Bw==+7BvnWKITyGyTwHbb6fVYwRx1I - Versia-Signed-By: https://example.com/users/1 + Versia-Signed-By: example.com Versia-Signed-At: 1729241717 ``` diff --git a/app/federation/page.mdx b/app/federation/page.mdx index 9364a26..0072096 100644 --- a/app/federation/page.mdx +++ b/app/federation/page.mdx @@ -21,24 +21,22 @@ Federation is built on the [HyperText Transfer Protocol (HTTP)](https://tools.ie ## Inboxes -Ever [User](/entities/user) has a personal HTTP endpoint called an inbox (e.g., `/users/3/inbox`). This endpoint is used to send and receive messages between users and instances. Messages are sent as JSON payloads over HTTP `POST` requests. + + See the [Inbox Endpoint](/api/endpoints#inbox) for more information on the inbox endpoint. + + +Ever [Instance](/entities/instance-metadata) has a personal HTTP endpoint called an inbox (`/.versia/v0.6/inbox`). This endpoint is used to send and receive messages between users and instances. Messages are sent as JSON payloads over HTTP `POST` requests. Let's consider the following example: > Alice, on the instance `alice.example`, sends a message to Bob on the instance `bob.example`. -To perform this action, Alice's instance sends a `POST` request to Bob's inbox endpoint, which can be found by checking the `inbox` field in Bob's [User](/entities/user) entity. This request contains the [Note](/entities/note) entity that Alice wants to send to Bob, with [the appropriate metadata](/federation/http) to ensure the message is valid. +To perform this action, Alice's instance sends a `POST` request to Bob's instance's inbox endpoint. This request contains the [Note](/entities/note) entity that Alice wants to send to Bob, with [the appropriate metadata](/federation/http) to ensure the message is valid. Bob's instance receives the message and processes it according to the rules defined in the [Validation](/federation/validation) document. -### Shared Inboxes - -In addition to personal inboxes, instances can also have shared inboxes. Shared inboxes are a single per-instance endpoint that can receive messages for multiple users. This is useful for instances that want to reduce the number of HTTP requests they need to handle. - -Shared inboxes are defined in the [Instance Metadata](/entities/instance-metadata) entity. If supported, they should be used in place of personal inboxes. - ## Outboxes -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. +In addition to inboxes, every user has an outbox (at `/.versia/v0.6/entities/User//collections/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/signatures/page.mdx b/app/signatures/page.mdx index d3b700d..20aab26 100644 --- a/app/signatures/page.mdx +++ b/app/signatures/page.mdx @@ -18,7 +18,7 @@ Versia uses cryptographic signatures to ensure the integrity and authenticity of A signature consists of a series of headers in an HTTP request. The following headers are used: - **`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-By`**: Hostname of the instance that signed the request. This **MUST** be a hostname reachable over HTTPS (including port number if applicable), and **MUST NOT** be a URL. - **`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: @@ -61,14 +61,14 @@ To verify a signature, the instance must: The following example is written in TypeScript using the WebCrypto API. -`@bob`, from `bob.com`, wants to sign a request to `alice.com`. The request is a `POST` to `/notes`, with the following body: +`@bob`, from `bob.com`, wants to sign a request to `alice.com`. The request is a `POST` to `/.versia/v0.6/inbox`, with the following body: ```json { "content": "Hello, world!" } ``` -Bob can be found at `https://bob.com/users/bf44e6ad-7c0a-4560-9938-cf3fd4066511`. His ed25519 private key, encoded in Base64 PKCS8, is `MC4CAQAwBQYDK2VwBCIEILrNXhbWxC/MhKQDsJOAAF1FH/R+Am5G/eZKnqNum5ro`. +Bob can be found at `https://bob.com/.versia/v0.6/entities/User/bf44e6ad-7c0a-4560-9938-cf3fd4066511`. His instance's ed25519 private key, encoded in Base64 PKCS8, is `MC4CAQAwBQYDK2VwBCIEILrNXhbWxC/MhKQDsJOAAF1FH/R+Am5G/eZKnqNum5ro`. Here's how Bob would sign the request: ```typescript @@ -97,7 +97,7 @@ const digest = await crypto.subtle.digest( ); const stringToSign = - `post /notes ${timestamp} ${Buffer.from(digest).toString("base64")}`; + `post /.versia/v0.6/inbox ${timestamp} ${Buffer.from(digest).toString("base64")}`; const signature = await crypto.subtle.sign( "Ed25519", @@ -113,19 +113,19 @@ To send the request, Bob would use the following code: ```typescript const headers = new Headers(); -headers.set("Versia-Signed-By", "https://bob.com/users/bf44e6ad-7c0a-4560-9938-cf3fd4066511"); +headers.set("Versia-Signed-By", "bob.com"); 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", { +const response = await fetch("https://alice.com/.versia/v0.6/inbox", { method: "POST", headers, body: content, }); ``` -On Alice's side, she would verify the signature using Bob's public key. Here, we assume that Alice has Bob's public key stored in a variable called `publicKey` (during real federation, this would be fetched from Bob's profile). +On Alice's side, she would verify the signature using Bob's instance's public key. Here, we assume that Alice has Bob's instance's public key stored in a variable called `publicKey` (during real federation, this would be fetched from the instance's [metadata endpoint](/api/endpoints#instance-metadata)). ```typescript const method = request.method.toLowerCase(); @@ -165,7 +165,7 @@ Public keys are always encoded using `base64` and must be in SPKI format. You wi This is **not** the same as the key's raw bytes. - This is also not related to the commonly used "PEM" format. + This is also not the commonly used "PEM" format. ```typescript {{ title: "Example using TypeScript and the WebCrypto API" }} diff --git a/app/structures/collection/page.mdx b/app/structures/collection/page.mdx index 387b6f1..6a8ac54 100644 --- a/app/structures/collection/page.mdx +++ b/app/structures/collection/page.mdx @@ -7,8 +7,6 @@ export const metadata = { Collections are a way to represent paginated groups of entities. They are used everywhere lists of entities can be found, such as a user's outbox. {{ className: 'lead' }} -Pages should be limited to a reasonable number of entities, such as 20 or 80. - As Collections are independent and not part of a larger entity (like [ContentFormat](/structures/content-format)), they should have a valid [Signature](/signatures). @@ -21,28 +19,9 @@ 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). - - 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 entities. @@ -54,11 +33,7 @@ Pages should be limited to a reasonable number of entities, such as 20 or 80. ```jsonc {{ 'title': 'Example Collection' }} { "author": "https://versia.social/users/018ec082-0ae1-761c-b2c5-22275a611771", - "first": "https://versia.social/users/018ec082-0ae1-761c-b2c5-22275a611771/outbox?page=1", - "last": "https://versia.social/users/018ec082-0ae1-761c-b2c5-22275a611771/outbox?page=3", "total": 46, - "next": "https://versia.social/users/018ec082-0ae1-761c-b2c5-22275a611771/outbox?page=2", - "previous": null, "items": [ { "id": "456df8ed-daf1-4062-abab-491071c7b8dd", @@ -92,27 +67,9 @@ 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). - - 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. From bcdf0ec25113e78f0b942a58832c34f46acfcced Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Mon, 5 May 2025 14:33:22 +0200 Subject: [PATCH 08/25] refactor: :memo: Use References nomenclature instead of URI --- app/entities/delete/page.mdx | 8 ++--- app/entities/follow-accept/page.mdx | 8 ++--- app/entities/follow-reject/page.mdx | 8 ++--- app/entities/follow/page.mdx | 8 ++--- app/entities/note/page.mdx | 20 ++++++------ app/entities/unfollow/page.mdx | 8 ++--- app/extensions/groups/page.mdx | 40 ++++++++++++------------ app/extensions/likes/page.mdx | 16 +++++----- app/extensions/migration/page.mdx | 16 +++++----- app/extensions/polls/page.mdx | 8 ++--- app/extensions/reactions/page.mdx | 8 ++--- app/extensions/reports/page.mdx | 8 ++--- app/extensions/share/page.mdx | 8 ++--- app/extensions/vanity/page.mdx | 4 +-- app/structures/collection/page.mdx | 12 ++++---- app/types/page.mdx | 47 +++++++++++++++++++++++++++++ 16 files changed, 137 insertions(+), 90 deletions(-) diff --git a/app/entities/delete/page.mdx b/app/entities/delete/page.mdx index 773058b..0c69ef8 100644 --- a/app/entities/delete/page.mdx +++ b/app/entities/delete/page.mdx @@ -24,14 +24,14 @@ Having the authorization is defined as: - - URI of the `User` who is deleting the entity. [Can be set to `null` to represent the instance](/entities/instance-metadata#the-null-author). + + [Reference](/types#reference) to the `User` who is deleting the entity. [Can be set to `null` to represent the instance](/entities/instance-metadata#the-null-author). Type of the entity being deleted. - - URI of the entity being deleted. + + [Reference](/types#reference) to the entity being deleted. diff --git a/app/entities/follow-accept/page.mdx b/app/entities/follow-accept/page.mdx index a9d404b..1d0957d 100644 --- a/app/entities/follow-accept/page.mdx +++ b/app/entities/follow-accept/page.mdx @@ -18,11 +18,11 @@ export const metadata = { - - URI of the `User` considered the 'followee', i.e. the user who is being followed. + + [Reference](/types#reference) to the `User` considered the 'followee', i.e. the user who is being followed. - - URI of the `User` considered the 'follower', i.e. the user who is trying to follow the author. + + [Reference](/types#reference) to the `User` considered the 'follower', i.e. the user who is trying to follow the author. diff --git a/app/entities/follow-reject/page.mdx b/app/entities/follow-reject/page.mdx index db8d6df..5a0091d 100644 --- a/app/entities/follow-reject/page.mdx +++ b/app/entities/follow-reject/page.mdx @@ -28,11 +28,11 @@ But it can also be used when Bob is already following Alice, in the case that: - - URI of the `User` considered the 'followee', i.e. the user who is being followed. + + [Reference](/types#reference) to the `User` considered the 'followee', i.e. the user who is being followed. - - URI of the `User` considered the 'follower', i.e. the user who is trying to follow the author. + + [Reference](/types#reference) to the `User` considered the 'follower', i.e. the user who is trying to follow the author. diff --git a/app/entities/follow/page.mdx b/app/entities/follow/page.mdx index 6a188bb..0ddee2d 100644 --- a/app/entities/follow/page.mdx +++ b/app/entities/follow/page.mdx @@ -60,11 +60,11 @@ Once a follow relationship is established, the **followee**'s instance should se - - URI of the `User` considered the 'follower'. + + [Reference](/types#reference) to the `User` considered the 'follower'. - - URI of the `User` that is being followed. + + [Reference](/types#reference) to the `User` that is being followed. diff --git a/app/entities/note/page.mdx b/app/entities/note/page.mdx index 2a2e060..af7098a 100644 --- a/app/entities/note/page.mdx +++ b/app/entities/note/page.mdx @@ -19,8 +19,8 @@ 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. - - URI of the `User` considered the author of the note. + + [Reference](/types#reference) to the `User` considered the author of the note. Category of the note. Useful for clients to render notes differently depending on their intended purpose. @@ -50,8 +50,8 @@ Notes represent a piece of content on a Versia instance. They can be posted by [ } ``` - - URI of a [Group](/extensions/groups) that the note is only visible in, or one of the following strings: + + [Reference](/types#reference) to 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. @@ -64,8 +64,8 @@ Notes represent a piece of content on a Versia instance. They can be posted by [ Whether the note contains "sensitive content". This can be used with `subject` as a "content warning" feature. - - URIs of [Users](/entities/user) that should be notified of the note. Similar to Twitter's `@` mentions. The note may also contain mentions in the content, however only the mentions in this field should trigger notifications. + + [References](/types#reference) to [Users](/entities/user) that should be notified of the note. Similar to Twitter's `@` mentions. The note may also contain mentions in the content, however only the mentions in this field should trigger notifications. Previews for any links in the publication. This is to avoid the [stampeding mastodon problem](https://github.com/mastodon/mastodon/issues/23662) where a link preview is fetched by every instance that sees the publication, creating an accidental DDOS attack. @@ -84,11 +84,11 @@ Notes represent a piece of content on a Versia instance. They can be posted by [ Implementations should make sure not to trust the previews, as they could be faked by malicious remote instances. This is not a very good attack vector, but it is still possible to redirect users to malicious links. - - URI of the note that this note is quoting, if any. Quoting is similar to replying, but does not notify the author of the quoted note. Inspired by Twitter's "quote tweet" feature. + + [Reference](/types#reference) to the note that this note is quoting, if any. Quoting is similar to replying, but does not notify the author of the quoted note. Inspired by Twitter's "quote tweet" feature. - - URI of the note that this note is a reply to, if any. + + [Reference](/types#reference) to the note that this note is a reply to, if any. 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`). diff --git a/app/entities/unfollow/page.mdx b/app/entities/unfollow/page.mdx index 3e1be6b..d033348 100644 --- a/app/entities/unfollow/page.mdx +++ b/app/entities/unfollow/page.mdx @@ -33,11 +33,11 @@ Sometimes, [Users](/entities/user) want to unsubscribe from each other to stop s - - URI of the `User` considered the 'follower', i.e. the user who is unsubscribing from the followee. + + [Reference](/types#reference) to the `User` considered the 'follower', i.e. the user who is unsubscribing from the followee. - - URI of the `User` considered the 'followee', i.e. the user who is being unsubscribed from. + + [Reference](/types#reference) to the `User` considered the 'followee', i.e. the user who is being unsubscribed from. diff --git a/app/extensions/groups/page.mdx b/app/extensions/groups/page.mdx index 4cf9e5b..54c710b 100644 --- a/app/extensions/groups/page.mdx +++ b/app/extensions/groups/page.mdx @@ -93,11 +93,11 @@ Indicates that a [User](/entities/user) wishes to subscribe to a group. Must be `pub.versia:groups/Subscribe`. - - URI of the [User](/entities/user) subscribing to the group. + + [Reference](/types#reference) to the [User](/entities/user) subscribing to the group. - - URI of the group to subscribe to. + + [Reference](/types#reference) to the group to subscribe to. @@ -131,11 +131,11 @@ Indicates that a [User](/entities/user) wishes to unsubscribe from a group. Must be `pub.versia:groups/Unsubscribe`. - - URI of the [User](/entities/user) unsubscribing from the group. + + [Reference](/types#reference) to the [User](/entities/user) unsubscribing from the group. - - URI of the group to unsubscribe from. + + [Reference](/types#reference) to the group to unsubscribe from. @@ -169,11 +169,11 @@ Indicates that a [Group](#entity-definition) has accepted a [User](/entities/use Must be `pub.versia:groups/SubscribeAccept`. - - URI of the [User](/entities/user) subscribing to the group. + + [Reference](/types#reference) to the [User](/entities/user) subscribing to the group. - - URI of the group that accepted the subscription. + + [Reference](/types#reference) to the group that accepted the subscription. @@ -207,11 +207,11 @@ Indicates that a [Group](#entity-definition) has rejected a [User](/entities/use Must be `pub.versia:groups/SubscribeReject`. - - URI of the [User](/entities/user) subscribing to the group. + + [Reference](/types#reference) to the [User](/entities/user) subscribing to the group. - - URI of the group that rejected the subscription. + + [Reference](/types#reference) to the group that rejected the subscription. @@ -253,11 +253,11 @@ The `GroupFederate` entity allows a group to federate a note to all of its membe Must be `pub.versia:groups/Federate`. - - URI of the note to federate. + + [Reference](/types#reference) to the note to federate. - - URI of the group federating the note. + + [Reference](/types#reference) to the group federating the note. diff --git a/app/extensions/likes/page.mdx b/app/extensions/likes/page.mdx index 4614aac..546aa30 100644 --- a/app/extensions/likes/page.mdx +++ b/app/extensions/likes/page.mdx @@ -22,11 +22,11 @@ Likes are a way for users to show appreciation for a note, like Twitter's "heart Must be `pub.versia:likes/Like`. - - Creator of the Like. + + [Reference](/types#reference) to the creator of the Like. - - URI of the note being liked. Must link to a [Note](/entities/note). + + [Reference](/types#reference) to the note being liked. @@ -58,11 +58,11 @@ Dislikes are a way for users to show disapproval for a note, like YouTube's "dis Must be `pub.versia:likes/Dislike`. - - Creator of the Dislike. + + [Reference](/types#reference) to the creator of the Dislike. - - URI of the note being disliked. Must link to a [Note](/entities/note). + + [Reference](/types#reference) to the note being disliked. diff --git a/app/extensions/migration/page.mdx b/app/extensions/migration/page.mdx index 47f6d5b..50cc11b 100644 --- a/app/extensions/migration/page.mdx +++ b/app/extensions/migration/page.mdx @@ -40,11 +40,11 @@ Migration happens in three steps: Must be `pub.versia:migration/Migration`. - - URI of the [User](/entities/user) who is migrating. + + [Reference](/types#reference) to the [User](/entities/user) who is migrating. - - URI of the destination [User](/entities/user) on the new instance. + + [Reference](/types#reference) to the destination [User](/entities/user) on the new instance. @@ -71,11 +71,11 @@ 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. + + If this user has migrated from another instance, this property **MUST** be a [Reference](/types#reference) to the user on the previous instance. - - If this user has migrated to another instance, this property **MUST** be set to the URI of the user on the new instance. + + If this user has migrated to another instance, this property **MUST** be a [Reference](/types#reference) to the URI of the user on the new instance. diff --git a/app/extensions/polls/page.mdx b/app/extensions/polls/page.mdx index ae91bdf..f9e30dc 100644 --- a/app/extensions/polls/page.mdx +++ b/app/extensions/polls/page.mdx @@ -97,11 +97,11 @@ If a vote is cast to a poll that is closed, the vote should be rejected with a ` Must be `pub.versia:polls/Vote`. - - URI to the user who cast the vote. + + [Reference](/types#reference) of the user who cast the vote. - - URI to the poll that the user voted on. Must link to a [Note](/entities/note) with a valid poll. + + [Reference](/types#reference) to the note with poll that the user voted on. Index of the option that the user voted for. This should be a valid index into the `options` array of the poll. diff --git a/app/extensions/reactions/page.mdx b/app/extensions/reactions/page.mdx index 8691324..311a8ee 100644 --- a/app/extensions/reactions/page.mdx +++ b/app/extensions/reactions/page.mdx @@ -19,11 +19,11 @@ User reactions are (like every other entity) federated to all followers, and can Must be `pub.versia:reactions/Reaction`. - - URI of the [User](/entities/user) that is reacting. + + [Reference](/types#reference) to the [User](/entities/user) that is reacting. - - URI of the [Note](/entities/note) attached to the reaction. + + [Reference](/types#reference) to the [Note](/entities/note) attached to the reaction. Emoji content of reaction. May also be arbitrary text, or [Custom Emoji](/extensions/custom-emojis) if supported. diff --git a/app/extensions/reports/page.mdx b/app/extensions/reports/page.mdx index 6465730..ac4ed8c 100644 --- a/app/extensions/reports/page.mdx +++ b/app/extensions/reports/page.mdx @@ -21,11 +21,11 @@ When an instance receives a report, it *should* be reviewed by a moderator or ad Must be `pub.versia:reports/Report`. - - URI of the reporting [User](/entities/user). Optional if the report is anonymous. + + [Reference](/types#reference) to the reporting [User](/entities/user). Optional if the report is anonymous. - - URIs of the content being reported. + + [References](/types#reference) to the content being reported. Report tags. Should be concise and clear, such as `spam`, `harassment`, `misinformation`, etc. Used for categorization. diff --git a/app/extensions/share/page.mdx b/app/extensions/share/page.mdx index 9c80fad..02b862b 100644 --- a/app/extensions/share/page.mdx +++ b/app/extensions/share/page.mdx @@ -21,11 +21,11 @@ When a user shares a note, the note's original author **must** receive the entit Must be `pub.versia:share/Share`. - - Creator of the Share. + + [Reference](/types#reference) to the creator of the Share. - - URI of the note being shared. Must link to a [Note](/entities/note). + + [Reference](/types#reference) to the note being shared. diff --git a/app/extensions/vanity/page.mdx b/app/extensions/vanity/page.mdx index de6e6a9..626e3f1 100644 --- a/app/extensions/vanity/page.mdx +++ b/app/extensions/vanity/page.mdx @@ -72,8 +72,8 @@ All properties are optional. 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. + + [References](/types#reference) to Versia profiles that should be considered aliases (or "alt accounts") of this profile. diff --git a/app/structures/collection/page.mdx b/app/structures/collection/page.mdx index 6a8ac54..391c668 100644 --- a/app/structures/collection/page.mdx +++ b/app/structures/collection/page.mdx @@ -16,8 +16,8 @@ Collections are a way to represent paginated groups of entities. They are used e - - 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). + + [Reference](/types#reference) to the 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). Total number of entities in the collection, across all pages. @@ -64,14 +64,14 @@ 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). + + [Reference](/types#reference) to the 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). Total number of entities in the collection, across all pages. - - Collection contents. Must be an array of URIs. + + Collection contents. Must be an array of [References](/types#reference). diff --git a/app/types/page.mdx b/app/types/page.mdx index d35e6fa..ffe1230 100644 --- a/app/types/page.mdx +++ b/app/types/page.mdx @@ -1,3 +1,50 @@ +## Reference + +```typescript +type Hostname = string; +type Id = Entity["id"]; + +type Reference = `${Hostname}:${Id}` | `${Id}`; +``` + +A **reference** is a way to refer to any entity within the Versia network. It is a string composed of the following parts: + +- The entity's instance's hostname. Optional if that same instance is the creator of the entity. + - Punycode encoding is used for internationalized domain names (IDNs). + - Example: `example.com`, `example.com:3000`, `xn--ls8h.xn--ls8h`. +- A colon (`:`) separator, if the hostname is present. +- The entity's unique identifier. This is the `id` property of the entity. + + + If the hostname is an IPv6 address, it must be enclosed in square brackets. + + For example: `[2001:db8::1]:3000`. + + + +### Examples + +These two examples are equivalent if the instance is `example.com`: + +```jsonc +{ + "type": "Follow", + "id": "3e7e4750-afd4-4d99-a256-02f0710a0520", + "author": "6e0204a2-746c-4972-8602-c4f37fc63bbe", // [!code focus] + "created_at": "2021-01-01T00:00:00.000Z", + "followee": "test.org:02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" +} +``` + +```jsonc +{ + "type": "Follow", + "id": "3e7e4750-afd4-4d99-a256-02f0710a0520", + "author": "example.com:6e0204a2-746c-4972-8602-c4f37fc63bbe", // [!code focus] + "created_at": "2021-01-01T00:00:00.000Z", + "followee": "test.org:02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" +} +``` ## RFC3339 From 71c691fe08d22ced99162ba6834d3e3c1413dee6 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Mon, 5 May 2025 14:35:19 +0200 Subject: [PATCH 09/25] chore: :memo: Update changelog --- app/changelog/page.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index 969fba6..2d5061f 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' }} - The `uri` field has been removed from all entities. - Every field that used to be a URI now uses that entity's `id` field. - New endpoints have been defined under `/_versia/v0.6/` to fetch entities by their `id`. +- Added [References](/types#reference) as a way to refer to other entities. ## Since WD 4 From e56b1c407d11fe41798bdc6a9ec0a9eaa723dcab Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Tue, 13 May 2025 14:56:06 +0200 Subject: [PATCH 10/25] fix: :memo: Fix incorrect path in changelog --- app/changelog/page.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index 2d5061f..a777015 100644 --- a/app/changelog/page.mdx +++ b/app/changelog/page.mdx @@ -16,7 +16,7 @@ This page lists changes since Working Draft 3. {{ className: 'lead' }} - Modified how URIs and references to other entities are handled: - The `uri` field has been removed from all entities. - Every field that used to be a URI now uses that entity's `id` field. - - New endpoints have been defined under `/_versia/v0.6/` to fetch entities by their `id`. + - New endpoints have been defined under `/.versia/v0.6/` to fetch entities by their `id`. - Added [References](/types#reference) as a way to refer to other entities. ## Since WD 4 From e138e9e7c319c31cd0d5da68be218fd8065d050c Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Tue, 13 May 2025 15:04:30 +0200 Subject: [PATCH 11/25] refactor: :fire: Remove `id` property from transient entities --- app/entities/delete/page.mdx | 1 - app/entities/follow-accept/page.mdx | 1 - app/entities/follow-reject/page.mdx | 1 - app/entities/follow/page.mdx | 1 - app/entities/page.mdx | 14 ++++++++------ app/entities/unfollow/page.mdx | 1 - app/extensions/groups/page.mdx | 5 ----- app/extensions/migration/page.mdx | 1 - app/extensions/reports/page.mdx | 1 - app/types/page.mdx | 2 -- 10 files changed, 8 insertions(+), 20 deletions(-) diff --git a/app/entities/delete/page.mdx b/app/entities/delete/page.mdx index 0c69ef8..551d036 100644 --- a/app/entities/delete/page.mdx +++ b/app/entities/delete/page.mdx @@ -41,7 +41,6 @@ Having the authorization is defined as: ```jsonc {{ title: 'Example Delete' }} { "type": "Delete", - "id": "9b3212b8-529c-435a-8798-09ebbc17ca74", "created_at": "2021-01-01T00:00:00.000Z", "author": "6e0204a2-746c-4972-8602-c4f37fc63bbe", "deleted_type": "Note", diff --git a/app/entities/follow-accept/page.mdx b/app/entities/follow-accept/page.mdx index 1d0957d..1e7f0f5 100644 --- a/app/entities/follow-accept/page.mdx +++ b/app/entities/follow-accept/page.mdx @@ -32,7 +32,6 @@ export const metadata = { ```jsonc {{ title: 'Example FollowAccept' }} { "type": "FollowAccept", - "id": "3e7e4750-afd4-4d99-a256-02f0710a0520", "author": "6e0204a2-746c-4972-8602-c4f37fc63bbe", "created_at": "2021-01-01T00:00:00.000Z", "follower": "example.com:02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" diff --git a/app/entities/follow-reject/page.mdx b/app/entities/follow-reject/page.mdx index 5a0091d..abf9710 100644 --- a/app/entities/follow-reject/page.mdx +++ b/app/entities/follow-reject/page.mdx @@ -42,7 +42,6 @@ But it can also be used when Bob is already following Alice, in the case that: ```jsonc {{ title: 'Example FollowReject' }} { "type": "FollowReject", - "id": "3e7e4750-afd4-4d99-a256-02f0710a0520", "author": "6e0204a2-746c-4972-8602-c4f37fc63bbe", "created_at": "2021-01-01T00:00:00.000Z", "follower": "example.com:02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" diff --git a/app/entities/follow/page.mdx b/app/entities/follow/page.mdx index 0ddee2d..be4e1f9 100644 --- a/app/entities/follow/page.mdx +++ b/app/entities/follow/page.mdx @@ -74,7 +74,6 @@ Once a follow relationship is established, the **followee**'s instance should se ```jsonc {{ title: 'Example Follow' }} { "type": "Follow", - "id": "3e7e4750-afd4-4d99-a256-02f0710a0520", "author": "6e0204a2-746c-4972-8602-c4f37fc63bbe", "created_at": "2021-01-01T00:00:00.000Z", "followee": "example.com:02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" diff --git a/app/entities/page.mdx b/app/entities/page.mdx index 7b756f7..2df932c 100644 --- a/app/entities/page.mdx +++ b/app/entities/page.mdx @@ -25,6 +25,8 @@ Any field in an entity not marked as `required` may be omitted or set to `null`. - `A-Z` - `0-9` - `-`, `_` + + Not present on [Transient Entities](#transient-entities). Type of the entity. Custom types must follow [Extension Naming](/extensions#naming). @@ -54,11 +56,11 @@ Any field in an entity not marked as `required` may be omitted or set to `null`. ```jsonc {{ 'title': 'Example Entity' }} { - "id": "9a8928b6-2526-4979-aab1-ef2f88cd5700", - "type": "Delete", - "created_at": "2022-01-01T12:00:00Z", - "author": "63a00ab3-39b1-49eb-b88e-ed65d2361f3e", - "deleted": "54059ce2-9332-46fa-bf6a-598b5493b81b", + "id": "3e7e4750-afd4-4d99-a256-02f0710a0520", + "type": "pub.versia:likes/Like", + "created_at": "2021-01-01T00:00:00.000Z", + "author": "6e0204a2-746c-4972-8602-c4f37fc63bbe", + "liked": "otherexample.org:fmKZ763jzIU8" } ``` @@ -84,7 +86,7 @@ Any field in an entity not marked as `required` may be omitted or set to `null`. ## Transient Entities -Some entities are transient, meaning they cannot be refetched using the [Federation API](/api/endpoints). These entities are used for actions that do not require a permanent record, such as deletions or migrations. +Some entities are transient, meaning they cannot be refetched using the [Federation API](/api/endpoints). These entities are used for actions that do not require a permanent record, such as deletions or migrations. Transient Entities do not have an `id` field. Implementations **must not** rely on other implementations to store transient entities in their database. diff --git a/app/entities/unfollow/page.mdx b/app/entities/unfollow/page.mdx index d033348..d735321 100644 --- a/app/entities/unfollow/page.mdx +++ b/app/entities/unfollow/page.mdx @@ -47,7 +47,6 @@ Sometimes, [Users](/entities/user) want to unsubscribe from each other to stop s ```jsonc {{ title: 'Example Unfollow' }} { "type": "Unfollow", - "id": "3e7e4750-afd4-4d99-a256-02f0710a0520", "author": "6e0204a2-746c-4972-8602-c4f37fc63bbe", "created_at": "2021-01-01T00:00:00.000Z", "followee": "example.com:02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" diff --git a/app/extensions/groups/page.mdx b/app/extensions/groups/page.mdx index 54c710b..818af8d 100644 --- a/app/extensions/groups/page.mdx +++ b/app/extensions/groups/page.mdx @@ -107,7 +107,6 @@ Indicates that a [User](/entities/user) wishes to subscribe to a group. ```jsonc {{ title: "Example GroupSubscribe" }} { "type": "pub.versia:groups/Subscribe", - "id": "9a7e9345-4e4a-4d5a-8301-4dbbfe777ca0", "subscriber": "e9277471-8aa1-4d40-a3d0-0878e818ccdc", "group": "example.com:ed480922-b095-4f09-9da5-c995be8f5960", "created_at": "2021-01-01T00:00:00Z" @@ -145,7 +144,6 @@ Indicates that a [User](/entities/user) wishes to unsubscribe from a group. ```jsonc {{ title: "Example GroupUnsubscribe" }} { "type": "pub.versia:groups/Unsubscribe", - "id": "9a7e9345-4e4a-4d5a-8301-4dbbfe777ca0", "subscriber": "e9277471-8aa1-4d40-a3d0-0878e818ccdc", "group": "example.com:ed480922-b095-4f09-9da5-c995be8f5960", "created_at": "2021-01-01T00:00:00Z" @@ -183,7 +181,6 @@ Indicates that a [Group](#entity-definition) has accepted a [User](/entities/use ```jsonc {{ title: "Example GroupSubscribeAccept" }} { "type": "pub.versia:groups/SubscribeAccept", - "id": "9a7e9345-4e4a-4d5a-8301-4dbbfe777ca0", "subscriber": "e9277471-8aa1-4d40-a3d0-0878e818ccdc", "group": "example.com:ed480922-b095-4f09-9da5-c995be8f5960", "created_at": "2021-01-01T00:00:00Z" @@ -221,7 +218,6 @@ Indicates that a [Group](#entity-definition) has rejected a [User](/entities/use ```jsonc {{ title: "Example GroupSubscribeReject" }} { "type": "pub.versia:groups/SubscribeReject", - "id": "9a7e9345-4e4a-4d5a-8301-4dbbfe777ca0", "subscriber": "e9277471-8aa1-4d40-a3d0-0878e818ccdc", "group": "example.com:ed480922-b095-4f09-9da5-c995be8f5960", "created_at": "2021-01-01T00:00:00Z" @@ -267,7 +263,6 @@ The `GroupFederate` entity allows a group to federate a note to all of its membe ```jsonc {{ title: "Example GroupFederate" }} { "type": "pub.versia:groups/Federate", - "id": "9a7e9345-4e4a-4d5a-8301-4dbbfe777ca0", "note": "c5aa65fa-0356-4029-b61c-6b237e5d1393", "group": "example.com:ed480922-b095-4f09-9da5-c995be8f5960", "created_at": "2021-01-01T00:00:00Z" diff --git a/app/extensions/migration/page.mdx b/app/extensions/migration/page.mdx index 50cc11b..4b917ff 100644 --- a/app/extensions/migration/page.mdx +++ b/app/extensions/migration/page.mdx @@ -53,7 +53,6 @@ Migration happens in three steps: ```json {{ title: "Example Entity" }} { - "id": "016f3de2-ad63-4e06-999e-1e6b41c981c5", "type": "pub.versia:migration/Migration", "author": "44df6e02-ef43-47e0-aff2-47041f3d09ed", "created_at": "2021-01-01T00:00:00.000Z", diff --git a/app/extensions/reports/page.mdx b/app/extensions/reports/page.mdx index ac4ed8c..d24b53d 100644 --- a/app/extensions/reports/page.mdx +++ b/app/extensions/reports/page.mdx @@ -40,7 +40,6 @@ When an instance receives a report, it *should* be reviewed by a moderator or ad ```jsonc {{ title: "Example Report" }} { - "id": "6f3001a1-641b-4763-a9c4-a089852eec84", "type": "pub.versia:reports/Report", "author": "6f3001a1-641b-4763-a9c4-a089852eec84", "reported": [ diff --git a/app/types/page.mdx b/app/types/page.mdx index ffe1230..f0126d6 100644 --- a/app/types/page.mdx +++ b/app/types/page.mdx @@ -29,7 +29,6 @@ These two examples are equivalent if the instance is `example.com`: ```jsonc { "type": "Follow", - "id": "3e7e4750-afd4-4d99-a256-02f0710a0520", "author": "6e0204a2-746c-4972-8602-c4f37fc63bbe", // [!code focus] "created_at": "2021-01-01T00:00:00.000Z", "followee": "test.org:02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" @@ -39,7 +38,6 @@ These two examples are equivalent if the instance is `example.com`: ```jsonc { "type": "Follow", - "id": "3e7e4750-afd4-4d99-a256-02f0710a0520", "author": "example.com:6e0204a2-746c-4972-8602-c4f37fc63bbe", // [!code focus] "created_at": "2021-01-01T00:00:00.000Z", "followee": "test.org:02e1e3b2-cb1f-4e4a-b82e-98866bee5de7" From c6c5945bef341fc69eb53ff91406e4a03a68c58a Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Tue, 13 May 2025 15:31:35 +0200 Subject: [PATCH 12/25] refactor: :memo: Use new Versia content-type everywhere --- app/api/endpoints/page.mdx | 8 ++++---- app/federation/discovery/page.mdx | 6 +++--- app/signatures/page.mdx | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/api/endpoints/page.mdx b/app/api/endpoints/page.mdx index ba90209..ca7bc92 100644 --- a/app/api/endpoints/page.mdx +++ b/app/api/endpoints/page.mdx @@ -37,7 +37,7 @@ export const metadata = { ```http {{ 'title': 'Example response' }} HTTP/1.1 200 OK - Content-Type: application/vnd.versia+json + Content-Type: application/vnd.versia+json; charset=utf-8 { "type": "InstanceMetadata", @@ -81,7 +81,7 @@ export const metadata = { ```http {{ 'title': 'Example response' }} HTTP/1.1 200 OK - Content-Type: application/vnd.versia+json + Content-Type: application/vnd.versia+json; charset=utf-8 { "type": "User", @@ -125,7 +125,7 @@ export const metadata = { ```http {{ 'title': 'Example response' }} HTTP/1.1 200 OK - Content-Type: application/vnd.versia+json + Content-Type: application/vnd.versia+json; charset=utf-8 { "type": "Followers", @@ -173,7 +173,7 @@ The delivery mechanism is described further in the [Federation](/federation) doc POST /.versia/v0.6/inbox Host: b.social Accept: application/vnd.versia+json - Content-Type: application/vnd.versia+json + Content-Type: application/vnd.versia+json; charset=utf-8 { "type": "Note", diff --git a/app/federation/discovery/page.mdx b/app/federation/discovery/page.mdx index b56a945..f67b931 100644 --- a/app/federation/discovery/page.mdx +++ b/app/federation/discovery/page.mdx @@ -24,7 +24,7 @@ Accept: application/jrd+json { "subject": "acct:george@versia.social", // [!code focus:6] "aliases": [ - "https://versia.social/users/018ec082-0ae1-761c-b2c5-22275a611771", + "https://versia.social/.versia/v0.6/entities/User/018ec082-0ae1-761c-b2c5-22275a611771", "https://versia.social/@george" ], "links": [ @@ -35,8 +35,8 @@ Accept: application/jrd+json }, { // [!code focus:5] "rel": "self", - "type": "application/json", - "href": "https://versia.social/users/018ec082-0ae1-761c-b2c5-22275a611771" + "type": "application/vnd.versia+json", + "href": "https://versia.social/.versia/v0.6/entities/User/018ec082-0ae1-761c-b2c5-22275a611771" }, { "rel": "http://webfinger.net/rel/avatar", diff --git a/app/signatures/page.mdx b/app/signatures/page.mdx index 20aab26..e1b4b49 100644 --- a/app/signatures/page.mdx +++ b/app/signatures/page.mdx @@ -116,7 +116,7 @@ const headers = new Headers(); headers.set("Versia-Signed-By", "bob.com"); headers.set("Versia-Signed-At", timestamp); headers.set("Versia-Signature", base64Signature); -headers.set("Content-Type", "application/json"); +headers.set("Content-Type", "application/vnd.versia+json; charset=utf-8"); const response = await fetch("https://alice.com/.versia/v0.6/inbox", { method: "POST", From 2995c813bf5b98554a252c43e4fdfecd9267f92b Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Wed, 28 May 2025 16:33:26 +0200 Subject: [PATCH 13/25] fix: :pencil2: Typo fix --- app/extensions/reactions/page.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/extensions/reactions/page.mdx b/app/extensions/reactions/page.mdx index 311a8ee..110f569 100644 --- a/app/extensions/reactions/page.mdx +++ b/app/extensions/reactions/page.mdx @@ -51,7 +51,7 @@ User reactions are (like every other entity) federated to all followers, and can ## Note Collections -The Likes extension adds the following collections to the [Note](/entities/note) entity: +The Reactions extension adds the following collections to the [Note](/entities/note) entity: - `pub.versia:reactions/Reactions`: [URI Collection](/structures/collection#uri-collection) of all the reactions to the note. From b2f98c131177137824a2ce230fd901ca565d1db4 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Sat, 7 Jun 2025 20:33:49 +0200 Subject: [PATCH 14/25] chore: :arrow_up: Upgrade dependencies --- bun.lock | 191 +++++++++++++++++++++++++-------------------------- package.json | 34 ++++----- 2 files changed, 112 insertions(+), 113 deletions(-) diff --git a/bun.lock b/bun.lock index 1d48e42..aa1cf01 100644 --- a/bun.lock +++ b/bun.lock @@ -4,28 +4,28 @@ "": { "name": "@versia-pub/docs", "dependencies": { - "@algolia/autocomplete-core": "^1.19.1", - "@headlessui/react": "^2.2.3", + "@algolia/autocomplete-core": "^1.19.2", + "@headlessui/react": "^2.2.4", "@headlessui/tailwindcss": "^0.2.2", "@mdx-js/loader": "^3.1.0", "@mdx-js/react": "^3.1.0", - "@next/mdx": "^15.3.2", + "@next/mdx": "^15.3.3", "@sindresorhus/slugify": "^2.2.1", - "@tailwindcss/postcss": "^4.1.6", + "@tailwindcss/postcss": "^4.1.8", "@tailwindcss/typography": "^0.5.16", "@types/mdx": "^2.0.13", - "@types/node": "^22.15.18", - "@types/react": "^19.1.4", - "@types/react-dom": "^19.1.5", + "@types/node": "^22.15.30", + "@types/react": "^19.1.6", + "@types/react-dom": "^19.1.6", "@types/react-highlight-words": "^0.20.0", "acorn": "^8.14.1", "clsx": "^2.1.1", "fast-glob": "^3.3.3", - "flexsearch": "^0.8.166", - "framer-motion": "^12.11.3", + "flexsearch": "^0.8.205", + "framer-motion": "^12.16.0", "mdast-util-to-string": "^4.0.0", "mdx-annotations": "^0.1.4", - "next": "^15.3.2", + "next": "^15.3.3", "next-themes": "^0.4.6", "react": "^19.1.0", "react-dom": "^19.1.0", @@ -33,34 +33,35 @@ "remark": "^15.0.1", "remark-gfm": "^4.0.1", "remark-mdx": "^3.1.0", - "shiki": "^3.4.1", + "shiki": "^3.6.0", "simple-functional-loader": "^1.2.1", - "tailwindcss": "^4.1.6", + "tailwindcss": "^4.1.8", "typescript": "^5.8.3", "unist-util-filter": "^5.0.1", "unist-util-visit": "^5.0.0", "uwuifier": "^4.2.2", - "zustand": "^5.0.4", + "zustand": "^5.0.5", }, "devDependencies": { "@biomejs/biome": "^1.9.4", "@iconify-icon/react": "^3.0.0", - "@next/bundle-analyzer": "^15.3.2", - "@shikijs/transformers": "^3.4.1", - "sharp": "^0.34.1", + "@next/bundle-analyzer": "^15.3.3", + "@shikijs/transformers": "^3.6.0", + "sharp": "^0.34.2", }, }, }, "trustedDependencies": [ + "@tailwindcss/oxide", "sharp", "@biomejs/biome", ], "packages": { - "@algolia/autocomplete-core": ["@algolia/autocomplete-core@1.19.1", "", { "dependencies": { "@algolia/autocomplete-plugin-algolia-insights": "1.19.1", "@algolia/autocomplete-shared": "1.19.1" } }, "sha512-MeZZN1NSPgfp2zhiaCyAW02jOWMftCJ06qoeEVEQ8v+kMlXL15SUYBpQwj7Gd+nV46KHqDrW+g5EGqhCsX6zWg=="], + "@algolia/autocomplete-core": ["@algolia/autocomplete-core@1.19.2", "", { "dependencies": { "@algolia/autocomplete-plugin-algolia-insights": "1.19.2", "@algolia/autocomplete-shared": "1.19.2" } }, "sha512-mKv7RyuAzXvwmq+0XRK8HqZXt9iZ5Kkm2huLjgn5JoCPtDy+oh9yxUMfDDaVCw0oyzZ1isdJBc7l9nuCyyR7Nw=="], - "@algolia/autocomplete-plugin-algolia-insights": ["@algolia/autocomplete-plugin-algolia-insights@1.19.1", "", { "dependencies": { "@algolia/autocomplete-shared": "1.19.1" }, "peerDependencies": { "search-insights": ">= 1 < 3" } }, "sha512-TPVerIGKbfOwd69ZNrriI6voKRwwj6Vmy4tD12/3RCh8zdvDOdRvc7LxeKPtgwJzavZkfH7nK9pb+4E+PCdgdg=="], + "@algolia/autocomplete-plugin-algolia-insights": ["@algolia/autocomplete-plugin-algolia-insights@1.19.2", "", { "dependencies": { "@algolia/autocomplete-shared": "1.19.2" }, "peerDependencies": { "search-insights": ">= 1 < 3" } }, "sha512-TjxbcC/r4vwmnZaPwrHtkXNeqvlpdyR+oR9Wi2XyfORkiGkLTVhX2j+O9SaCCINbKoDfc+c2PB8NjfOnz7+oKg=="], - "@algolia/autocomplete-shared": ["@algolia/autocomplete-shared@1.19.1", "", { "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", "algoliasearch": ">= 4.9.1 < 6" } }, "sha512-/GcOv70emuVdSHBAERW7/r4czMzJROkgLOl45+ugyxK79RzSkXV2esY638qSo6mzC7EVwglSJ8BQ0kAVKVxMjA=="], + "@algolia/autocomplete-shared": ["@algolia/autocomplete-shared@1.19.2", "", { "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", "algoliasearch": ">= 4.9.1 < 6" } }, "sha512-jEazxZTVD2nLrC+wYlVHQgpBoBB5KPStrJxLzsIFl6Kqd1AlG9sIAGl39V5tECLpIQzB3Qa2T6ZPJ1ChkwMK/w=="], "@algolia/client-abtesting": ["@algolia/client-abtesting@5.23.4", "", { "dependencies": { "@algolia/client-common": "5.23.4", "@algolia/requester-browser-xhr": "5.23.4", "@algolia/requester-fetch": "5.23.4", "@algolia/requester-node-http": "5.23.4" } }, "sha512-WIMT2Kxy+FFWXWQxIU8QgbTioL+SGE24zhpj0kipG4uQbzXwONaWt7ffaYLjfge3gcGSgJVv+1VlahVckafluQ=="], @@ -124,7 +125,7 @@ "@floating-ui/utils": ["@floating-ui/utils@0.2.9", "", {}, "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg=="], - "@headlessui/react": ["@headlessui/react@2.2.3", "", { "dependencies": { "@floating-ui/react": "^0.26.16", "@react-aria/focus": "^3.20.2", "@react-aria/interactions": "^3.25.0", "@tanstack/react-virtual": "^3.13.6", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, "sha512-hgOJGXPifPlOczIeSwX8OjLWRJ5XdYApZFf7DeCbCrO1PXHkPhNTRrA9ZwJsgAG7SON1i2JcvIreF/kbgtJeaQ=="], + "@headlessui/react": ["@headlessui/react@2.2.4", "", { "dependencies": { "@floating-ui/react": "^0.26.16", "@react-aria/focus": "^3.20.2", "@react-aria/interactions": "^3.25.0", "@tanstack/react-virtual": "^3.13.9", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, "sha512-lz+OGcAH1dK93rgSMzXmm1qKOJkBUqZf1L4M8TWLNplftQD3IkoEDdUFNfAn4ylsN6WOTVtWaLmvmaHOUk1dTA=="], "@headlessui/tailwindcss": ["@headlessui/tailwindcss@0.2.2", "", { "peerDependencies": { "tailwindcss": "^3.0 || ^4.0" } }, "sha512-xNe42KjdyA4kfUKLLPGzME9zkH7Q3rOZ5huFihWNWOQFxnItxPB3/67yBI8/qBfY8nwBRx5GHn4VprsoluVMGw=="], @@ -132,9 +133,9 @@ "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="], - "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.1", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.1.0" }, "os": "darwin", "cpu": "arm64" }, "sha512-pn44xgBtgpEbZsu+lWf2KNb6OAf70X68k+yk69Ic2Xz11zHR/w24/U49XT7AeRwJ0Px+mhALhU5LPci1Aymk7A=="], + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.1.0" }, "os": "darwin", "cpu": "arm64" }, "sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg=="], - "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.1", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.1.0" }, "os": "darwin", "cpu": "x64" }, "sha512-VfuYgG2r8BpYiOUN+BfYeFo69nP/MIwAtSJ7/Zpxc5QF3KS22z8Pvg3FkrSFJBPNQ7mmcUcYQFBmEQp7eu1F8Q=="], + "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.1.0" }, "os": "darwin", "cpu": "x64" }, "sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g=="], "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.1.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA=="], @@ -154,23 +155,25 @@ "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.1.0", "", { "os": "linux", "cpu": "x64" }, "sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A=="], - "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.1", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.1.0" }, "os": "linux", "cpu": "arm" }, "sha512-anKiszvACti2sGy9CirTlNyk7BjjZPiML1jt2ZkTdcvpLU1YH6CXwRAZCA2UmRXnhiIftXQ7+Oh62Ji25W72jA=="], + "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.1.0" }, "os": "linux", "cpu": "arm" }, "sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ=="], - "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.1", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.1.0" }, "os": "linux", "cpu": "arm64" }, "sha512-kX2c+vbvaXC6vly1RDf/IWNXxrlxLNpBVWkdpRq5Ka7OOKj6nr66etKy2IENf6FtOgklkg9ZdGpEu9kwdlcwOQ=="], + "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.1.0" }, "os": "linux", "cpu": "arm64" }, "sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q=="], - "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.1", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.1.0" }, "os": "linux", "cpu": "s390x" }, "sha512-7s0KX2tI9mZI2buRipKIw2X1ufdTeaRgwmRabt5bi9chYfhur+/C1OXg3TKg/eag1W+6CCWLVmSauV1owmRPxA=="], + "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.1.0" }, "os": "linux", "cpu": "s390x" }, "sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw=="], - "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.1", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.1.0" }, "os": "linux", "cpu": "x64" }, "sha512-wExv7SH9nmoBW3Wr2gvQopX1k8q2g5V5Iag8Zk6AVENsjwd+3adjwxtp3Dcu2QhOXr8W9NusBU6XcQUohBZ5MA=="], + "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.1.0" }, "os": "linux", "cpu": "x64" }, "sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ=="], - "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.1", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.1.0" }, "os": "linux", "cpu": "arm64" }, "sha512-DfvyxzHxw4WGdPiTF0SOHnm11Xv4aQexvqhRDAoD00MzHekAj9a/jADXeXYCDFH/DzYruwHbXU7uz+H+nWmSOQ=="], + "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.1.0" }, "os": "linux", "cpu": "arm64" }, "sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA=="], - "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.1", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.1.0" }, "os": "linux", "cpu": "x64" }, "sha512-pax/kTR407vNb9qaSIiWVnQplPcGU8LRIJpDT5o8PdAx5aAA7AS3X9PS8Isw1/WfqgQorPotjrZL3Pqh6C5EBg=="], + "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.1.0" }, "os": "linux", "cpu": "x64" }, "sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA=="], - "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.1", "", { "dependencies": { "@emnapi/runtime": "^1.4.0" }, "cpu": "none" }, "sha512-YDybQnYrLQfEpzGOQe7OKcyLUCML4YOXl428gOOzBgN6Gw0rv8dpsJ7PqTHxBnXnwXr8S1mYFSLSa727tpz0xg=="], + "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.2", "", { "dependencies": { "@emnapi/runtime": "^1.4.3" }, "cpu": "none" }, "sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ=="], - "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-WKf/NAZITnonBf3U1LfdjoMgNO5JYRSlhovhRhMxXVdvWYveM4kM3L8m35onYIdh75cOMCo1BexgVQcCDzyoWw=="], + "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-cfP/r9FdS63VA5k0xiqaNaEoGxBg9k7uE+RQGzuK9fHt7jib4zAVVseR9LsE4gJcNWgT6APKMNnCcnyOtmSEUQ=="], - "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.1", "", { "os": "win32", "cpu": "x64" }, "sha512-hw1iIAHpNE8q3uMIRCgGOeDoz9KtFNarFLQclLxr/LK1VBkj8nby18RjFvr6aP7USRYAjTZW6yisnBWMX571Tw=="], + "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLjGGvAbj0X/FXl8n1WbtQ6iVBpWU7JO94u/P2M4a8CFYsvQi4GW2mRy/JqkRx0qpBzaOdKJKw8uc930EX2AHw=="], + + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.2", "", { "os": "win32", "cpu": "x64" }, "sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw=="], "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], @@ -190,27 +193,27 @@ "@mdx-js/react": ["@mdx-js/react@3.1.0", "", { "dependencies": { "@types/mdx": "^2.0.0" }, "peerDependencies": { "@types/react": ">=16", "react": ">=16" } }, "sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ=="], - "@next/bundle-analyzer": ["@next/bundle-analyzer@15.3.2", "", { "dependencies": { "webpack-bundle-analyzer": "4.10.1" } }, "sha512-zY5O1PNKNxWEjaFX8gKzm77z2oL0cnj+m5aiqNBgay9LPLCDO13Cf+FJONeNq/nJjeXptwHFT9EMmTecF9U4Iw=="], + "@next/bundle-analyzer": ["@next/bundle-analyzer@15.3.3", "", { "dependencies": { "webpack-bundle-analyzer": "4.10.1" } }, "sha512-9gddnjACK6yOa5IkmeFyzcwZh2rscsb6ZspTd7tymPYKQM96fJuKjn9HrRtPNKiMm7ExKNadAJqREmHdBgHZ9A=="], - "@next/env": ["@next/env@15.3.2", "", {}, "sha512-xURk++7P7qR9JG1jJtLzPzf0qEvqCN0A/T3DXf8IPMKo9/6FfjxtEffRJIIew/bIL4T3C2jLLqBor8B/zVlx6g=="], + "@next/env": ["@next/env@15.3.3", "", {}, "sha512-OdiMrzCl2Xi0VTjiQQUK0Xh7bJHnOuET2s+3V+Y40WJBAXrJeGA3f+I8MZJ/YQ3mVGi5XGR1L66oFlgqXhQ4Vw=="], - "@next/mdx": ["@next/mdx@15.3.2", "", { "dependencies": { "source-map": "^0.7.0" }, "peerDependencies": { "@mdx-js/loader": ">=0.15.0", "@mdx-js/react": ">=0.15.0" }, "optionalPeers": ["@mdx-js/loader", "@mdx-js/react"] }, "sha512-D6lSSbVzn1EiPwrBKG5QzXClcgdqiNCL8a3/6oROinzgZnYSxbVmnfs0UrqygtGSOmgW7sdJJSEOy555DoAwvw=="], + "@next/mdx": ["@next/mdx@15.3.3", "", { "dependencies": { "source-map": "^0.7.0" }, "peerDependencies": { "@mdx-js/loader": ">=0.15.0", "@mdx-js/react": ">=0.15.0" }, "optionalPeers": ["@mdx-js/loader", "@mdx-js/react"] }, "sha512-kJI7E/353vsoGa2usU/P36gDSA0iVc9xqJFFiPgLrSgWlivkANTRXjrnNVmVpHZ6ETmiZP52fMuKwmT9/FSmNQ=="], - "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@15.3.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-2DR6kY/OGcokbnCsjHpNeQblqCZ85/1j6njYSkzRdpLn5At7OkSdmk7WyAmB9G0k25+VgqVZ/u356OSoQZ3z0g=="], + "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@15.3.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-WRJERLuH+O3oYB4yZNVahSVFmtxRNjNF1I1c34tYMoJb0Pve+7/RaLAJJizyYiFhjYNGHRAE1Ri2Fd23zgDqhg=="], - "@next/swc-darwin-x64": ["@next/swc-darwin-x64@15.3.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-ro/fdqaZWL6k1S/5CLv1I0DaZfDVJkWNaUU3un8Lg6m0YENWlDulmIWzV96Iou2wEYyEsZq51mwV8+XQXqMp3w=="], + "@next/swc-darwin-x64": ["@next/swc-darwin-x64@15.3.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-XHdzH/yBc55lu78k/XwtuFR/ZXUTcflpRXcsu0nKmF45U96jt1tsOZhVrn5YH+paw66zOANpOnFQ9i6/j+UYvw=="], - "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@15.3.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-covwwtZYhlbRWK2HlYX9835qXum4xYZ3E2Mra1mdQ+0ICGoMiw1+nVAn4d9Bo7R3JqSmK1grMq/va+0cdh7bJA=="], + "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@15.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-VZ3sYL2LXB8znNGcjhocikEkag/8xiLgnvQts41tq6i+wql63SMS1Q6N8RVXHw5pEUjiof+II3HkDd7GFcgkzw=="], - "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@15.3.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-KQkMEillvlW5Qk5mtGA/3Yz0/tzpNlSw6/3/ttsV1lNtMuOHcGii3zVeXZyi4EJmmLDKYcTcByV2wVsOhDt/zg=="], + "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@15.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-h6Y1fLU4RWAp1HPNJWDYBQ+e3G7sLckyBXhmH9ajn8l/RSMnhbuPBV/fXmy3muMcVwoJdHL+UtzRzs0nXOf9SA=="], - "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@15.3.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uRBo6THWei0chz+Y5j37qzx+BtoDRFIkDzZjlpCItBRXyMPIg079eIkOCl3aqr2tkxL4HFyJ4GHDes7W8HuAUg=="], + "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@15.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-jJ8HRiF3N8Zw6hGlytCj5BiHyG/K+fnTKVDEKvUCyiQ/0r5tgwO7OgaRiOjjRoIx2vwLR+Rz8hQoPrnmFbJdfw=="], - "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@15.3.2", "", { "os": "linux", "cpu": "x64" }, "sha512-+uxFlPuCNx/T9PdMClOqeE8USKzj8tVz37KflT3Kdbx/LOlZBRI2yxuIcmx1mPNK8DwSOMNCr4ureSet7eyC0w=="], + "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@15.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-HrUcTr4N+RgiiGn3jjeT6Oo208UT/7BuTr7K0mdKRBtTbT4v9zJqCDKO97DUqqoBK1qyzP1RwvrWTvU6EPh/Cw=="], - "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@15.3.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-LLTKmaI5cfD8dVzh5Vt7+OMo+AIOClEdIU/TSKbXXT2iScUTSxOGoBhfuv+FU8R9MLmrkIL1e2fBMkEEjYAtPQ=="], + "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@15.3.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-SxorONgi6K7ZUysMtRF3mIeHC5aA3IQLmKFQzU0OuhuUYwpOBc1ypaLJLP5Bf3M9k53KUUUj4vTPwzGvl/NwlQ=="], - "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@15.3.2", "", { "os": "win32", "cpu": "x64" }, "sha512-aW5B8wOPioJ4mBdMDXkt5f3j8pUr9W8AnlX0Df35uRWNT1Y6RIybxjnSUe+PhM+M1bwgyY8PHLmXZC6zT1o5tA=="], + "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@15.3.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4QZG6F8enl9/S2+yIiOiju0iCTFd93d8VC1q9LZS4p/Xuk81W2QDjCFeoogmrWWkAD59z8ZxepBQap2dKS5ruw=="], "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], @@ -234,19 +237,19 @@ "@react-types/shared": ["@react-types/shared@3.29.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-IDQYu/AHgZimObzCFdNl1LpZvQW/xcfLt3v20sorl5qRucDVj4S9os98sVTZ4IRIBjmS+MkjqpR5E70xan7ooA=="], - "@shikijs/core": ["@shikijs/core@3.4.1", "", { "dependencies": { "@shikijs/types": "3.4.1", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-GCqSd3KXRTKX1sViP7fIyyyf6do2QVg+fTd4IT00ucYCVSKiSN8HbFbfyjGsoZePNKWcQqXe4U4rrz2IVldG5A=="], + "@shikijs/core": ["@shikijs/core@3.6.0", "", { "dependencies": { "@shikijs/types": "3.6.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-9By7Xb3olEX0o6UeJyPLI1PE1scC4d3wcVepvtv2xbuN9/IThYN4Wcwh24rcFeASzPam11MCq8yQpwwzCgSBRw=="], - "@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.4.1", "", { "dependencies": { "@shikijs/types": "3.4.1", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-oGvRqN3Bsk+cGzmCb/5Kt/LfD7uyA8vCUUawyqmLti/AYNV7++zIZFEW8JwW5PrpPNWWx9RcZ/chnYLedzlVIQ=="], + "@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.6.0", "", { "dependencies": { "@shikijs/types": "3.6.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-7YnLhZG/TU05IHMG14QaLvTW/9WiK8SEYafceccHUSXs2Qr5vJibUwsDfXDLmRi0zHdzsxrGKpSX6hnqe0k8nA=="], - "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.4.1", "", { "dependencies": { "@shikijs/types": "3.4.1", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-p8I5KWgEDUcXRif9JjJUZtNeqCyxZ8xcslecDJMigsqSZfokwqQIsH4aGpdjzmDf8LIWvT+C3TCxnJQVaPmCbQ=="], + "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.6.0", "", { "dependencies": { "@shikijs/types": "3.6.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-nmOhIZ9yT3Grd+2plmW/d8+vZ2pcQmo/UnVwXMUXAKTXdi+LK0S08Ancrz5tQQPkxvjBalpMW2aKvwXfelauvA=="], - "@shikijs/langs": ["@shikijs/langs@3.4.1", "", { "dependencies": { "@shikijs/types": "3.4.1" } }, "sha512-v5A5ApJYcrcPLHcwAi0bViUU+Unh67UaXU9gGX3qfr2z3AqlqSZbC00W/3J4+tfGJASzwrWDro2R1er6SsCL1Q=="], + "@shikijs/langs": ["@shikijs/langs@3.6.0", "", { "dependencies": { "@shikijs/types": "3.6.0" } }, "sha512-IdZkQJaLBu1LCYCwkr30hNuSDfllOT8RWYVZK1tD2J03DkiagYKRxj/pDSl8Didml3xxuyzUjgtioInwEQM/TA=="], - "@shikijs/themes": ["@shikijs/themes@3.4.1", "", { "dependencies": { "@shikijs/types": "3.4.1" } }, "sha512-XOJgs55mVVMZtNVJx1NVmdcfXG9HIyZGh7qpCw/Ok5UMjWgkmb8z15TgcmF3ItvHItijiIMl9BLcNO/tFSGl1w=="], + "@shikijs/themes": ["@shikijs/themes@3.6.0", "", { "dependencies": { "@shikijs/types": "3.6.0" } }, "sha512-Fq2j4nWr1DF4drvmhqKq8x5vVQ27VncF8XZMBuHuQMZvUSS3NBgpqfwz/FoGe36+W6PvniZ1yDlg2d4kmYDU6w=="], - "@shikijs/transformers": ["@shikijs/transformers@3.4.1", "", { "dependencies": { "@shikijs/core": "3.4.1", "@shikijs/types": "3.4.1" } }, "sha512-Z3lbVQXHiXLC0bjDuGqsF3AAvvv4lQMoAXqIINZiOBgsk6CrnPZy0E2A+QUqv/MUaqp5qtYGsKDUJWbFE+buXw=="], + "@shikijs/transformers": ["@shikijs/transformers@3.6.0", "", { "dependencies": { "@shikijs/core": "3.6.0", "@shikijs/types": "3.6.0" } }, "sha512-PYkU54lYV0RCaUG8n2FNTF+YWiU3uPhcjLGq2x/C8lIrUX9GVnRb3bK+R5xtdFHbuctntATKm7ondp/H/dux9Q=="], - "@shikijs/types": ["@shikijs/types@3.4.1", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-4flT+pToGqRBb0UhGqXTV7rCqUS3fhc8z3S2Djc3E5USKhXwadeKGFVNB2rKXfohlrEozNJMtMiZaN8lfdj/ZQ=="], + "@shikijs/types": ["@shikijs/types@3.6.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-cLWFiToxYu0aAzJqhXTQsFiJRTFDAGl93IrMSBNaGSzs7ixkLfdG6pH11HipuWFGW5vyx4X47W8HDQ7eSrmBUg=="], "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], @@ -258,41 +261,41 @@ "@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="], - "@tailwindcss/node": ["@tailwindcss/node@4.1.6", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.29.2", "magic-string": "^0.30.17", "source-map-js": "^1.2.1", "tailwindcss": "4.1.6" } }, "sha512-ed6zQbgmKsjsVvodAS1q1Ld2BolEuxJOSyyNc+vhkjdmfNUDCmQnlXBfQkHrlzNmslxHsQU/bFmzcEbv4xXsLg=="], + "@tailwindcss/node": ["@tailwindcss/node@4.1.8", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.30.1", "magic-string": "^0.30.17", "source-map-js": "^1.2.1", "tailwindcss": "4.1.8" } }, "sha512-OWwBsbC9BFAJelmnNcrKuf+bka2ZxCE2A4Ft53Tkg4uoiE67r/PMEYwCsourC26E+kmxfwE0hVzMdxqeW+xu7Q=="], - "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.6", "", { "dependencies": { "detect-libc": "^2.0.4", "tar": "^7.4.3" }, "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.6", "@tailwindcss/oxide-darwin-arm64": "4.1.6", "@tailwindcss/oxide-darwin-x64": "4.1.6", "@tailwindcss/oxide-freebsd-x64": "4.1.6", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.6", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.6", "@tailwindcss/oxide-linux-arm64-musl": "4.1.6", "@tailwindcss/oxide-linux-x64-gnu": "4.1.6", "@tailwindcss/oxide-linux-x64-musl": "4.1.6", "@tailwindcss/oxide-wasm32-wasi": "4.1.6", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.6", "@tailwindcss/oxide-win32-x64-msvc": "4.1.6" } }, "sha512-0bpEBQiGx+227fW4G0fLQ8vuvyy5rsB1YIYNapTq3aRsJ9taF3f5cCaovDjN5pUGKKzcpMrZst/mhNaKAPOHOA=="], + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.8", "", { "dependencies": { "detect-libc": "^2.0.4", "tar": "^7.4.3" }, "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.8", "@tailwindcss/oxide-darwin-arm64": "4.1.8", "@tailwindcss/oxide-darwin-x64": "4.1.8", "@tailwindcss/oxide-freebsd-x64": "4.1.8", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.8", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.8", "@tailwindcss/oxide-linux-arm64-musl": "4.1.8", "@tailwindcss/oxide-linux-x64-gnu": "4.1.8", "@tailwindcss/oxide-linux-x64-musl": "4.1.8", "@tailwindcss/oxide-wasm32-wasi": "4.1.8", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.8", "@tailwindcss/oxide-win32-x64-msvc": "4.1.8" } }, "sha512-d7qvv9PsM5N3VNKhwVUhpK6r4h9wtLkJ6lz9ZY9aeZgrUWk1Z8VPyqyDT9MZlem7GTGseRQHkeB1j3tC7W1P+A=="], - "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.6", "", { "os": "android", "cpu": "arm64" }, "sha512-VHwwPiwXtdIvOvqT/0/FLH/pizTVu78FOnI9jQo64kSAikFSZT7K4pjyzoDpSMaveJTGyAKvDjuhxJxKfmvjiQ=="], + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.8", "", { "os": "android", "cpu": "arm64" }, "sha512-Fbz7qni62uKYceWYvUjRqhGfZKwhZDQhlrJKGtnZfuNtHFqa8wmr+Wn74CTWERiW2hn3mN5gTpOoxWKk0jRxjg=="], - "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-weINOCcqv1HVBIGptNrk7c6lWgSFFiQMcCpKM4tnVi5x8OY2v1FrV76jwLukfT6pL1hyajc06tyVmZFYXoxvhQ=="], + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RdRvedGsT0vwVVDztvyXhKpsU2ark/BjgG0huo4+2BluxdXo8NDgzl77qh0T1nUxmM11eXwR8jA39ibvSTbi7A=="], - "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-3FzekhHG0ww1zQjQ1lPoq0wPrAIVXAbUkWdWM8u5BnYFZgb9ja5ejBqyTgjpo5mfy0hFOoMnMuVDI+7CXhXZaQ=="], + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-t6PgxjEMLp5Ovf7uMb2OFmb3kqzVTPPakWpBIFzppk4JE4ix0yEtbtSjPbU8+PZETpaYMtXvss2Sdkx8Vs4XRw=="], - "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.6", "", { "os": "freebsd", "cpu": "x64" }, "sha512-4m5F5lpkBZhVQJq53oe5XgJ+aFYWdrgkMwViHjRsES3KEu2m1udR21B1I77RUqie0ZYNscFzY1v9aDssMBZ/1w=="], + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-g8C8eGEyhHTqwPStSwZNSrOlyx0bhK/V/+zX0Y+n7DoRUzyS8eMbVshVOLJTDDC+Qn9IJnilYbIKzpB9n4aBsg=="], - "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.6", "", { "os": "linux", "cpu": "arm" }, "sha512-qU0rHnA9P/ZoaDKouU1oGPxPWzDKtIfX7eOGi5jOWJKdxieUJdVV+CxWZOpDWlYTd4N3sFQvcnVLJWJ1cLP5TA=="], + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.8", "", { "os": "linux", "cpu": "arm" }, "sha512-Jmzr3FA4S2tHhaC6yCjac3rGf7hG9R6Gf2z9i9JFcuyy0u79HfQsh/thifbYTF2ic82KJovKKkIB6Z9TdNhCXQ=="], - "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-jXy3TSTrbfgyd3UxPQeXC3wm8DAgmigzar99Km9Sf6L2OFfn/k+u3VqmpgHQw5QNfCpPe43em6Q7V76Wx7ogIQ=="], + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-qq7jXtO1+UEtCmCeBBIRDrPFIVI4ilEQ97qgBGdwXAARrUqSn/L9fUrkb1XP/mvVtoVeR2bt/0L77xx53bPZ/Q=="], - "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-8kjivE5xW0qAQ9HX9reVFmZj3t+VmljDLVRJpVBEoTR+3bKMnvC7iLcoSGNIUJGOZy1mLVq7x/gerVg0T+IsYw=="], + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-O6b8QesPbJCRshsNApsOIpzKt3ztG35gfX9tEf4arD7mwNinsoCKxkj8TgEE0YRjmjtO3r9FlJnT/ENd9EVefQ=="], - "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.6", "", { "os": "linux", "cpu": "x64" }, "sha512-A4spQhwnWVpjWDLXnOW9PSinO2PTKJQNRmL/aIl2U/O+RARls8doDfs6R41+DAXK0ccacvRyDpR46aVQJJCoCg=="], + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.8", "", { "os": "linux", "cpu": "x64" }, "sha512-32iEXX/pXwikshNOGnERAFwFSfiltmijMIAbUhnNyjFr3tmWmMJWQKU2vNcFX0DACSXJ3ZWcSkzNbaKTdngH6g=="], - "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.6", "", { "os": "linux", "cpu": "x64" }, "sha512-YRee+6ZqdzgiQAHVSLfl3RYmqeeaWVCk796MhXhLQu2kJu2COHBkqlqsqKYx3p8Hmk5pGCQd2jTAoMWWFeyG2A=="], + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.8", "", { "os": "linux", "cpu": "x64" }, "sha512-s+VSSD+TfZeMEsCaFaHTaY5YNj3Dri8rST09gMvYQKwPphacRG7wbuQ5ZJMIJXN/puxPcg/nU+ucvWguPpvBDg=="], - "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.6", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@emnapi/wasi-threads": "^1.0.2", "@napi-rs/wasm-runtime": "^0.2.9", "@tybys/wasm-util": "^0.9.0", "tslib": "^2.8.0" }, "cpu": "none" }, "sha512-qAp4ooTYrBQ5pk5jgg54/U1rCJ/9FLYOkkQ/nTE+bVMseMfB6O7J8zb19YTpWuu4UdfRf5zzOrNKfl6T64MNrQ=="], + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.8", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@emnapi/wasi-threads": "^1.0.2", "@napi-rs/wasm-runtime": "^0.2.10", "@tybys/wasm-util": "^0.9.0", "tslib": "^2.8.0" }, "cpu": "none" }, "sha512-CXBPVFkpDjM67sS1psWohZ6g/2/cd+cq56vPxK4JeawelxwK4YECgl9Y9TjkE2qfF+9/s1tHHJqrC4SS6cVvSg=="], - "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-nqpDWk0Xr8ELO/nfRUDjk1pc9wDJ3ObeDdNMHLaymc4PJBWj11gdPCWZFKSK2AVKjJQC7J2EfmSmf47GN7OuLg=="], + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-7GmYk1n28teDHUjPlIx4Z6Z4hHEgvP5ZW2QS9ygnDAdI/myh3HTHjDqtSqgu1BpRoI4OiLx+fThAyA1JePoENA=="], - "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.6", "", { "os": "win32", "cpu": "x64" }, "sha512-5k9xF33xkfKpo9wCvYcegQ21VwIBU1/qEbYlVukfEIyQbEA47uK8AAwS7NVjNE3vHzcmxMYwd0l6L4pPjjm1rQ=="], + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.8", "", { "os": "win32", "cpu": "x64" }, "sha512-fou+U20j+Jl0EHwK92spoWISON2OBnCazIc038Xj2TdweYV33ZRkS9nwqiUi2d/Wba5xg5UoHfvynnb/UB49cQ=="], - "@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.6", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.6", "@tailwindcss/oxide": "4.1.6", "postcss": "^8.4.41", "tailwindcss": "4.1.6" } }, "sha512-ELq+gDMBuRXPJlpE3PEen+1MhnHAQQrh2zF0dI1NXOlEWfr2qWf2CQdr5jl9yANv8RErQaQ2l6nIFO9OSCVq/g=="], + "@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.8", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.8", "@tailwindcss/oxide": "4.1.8", "postcss": "^8.4.41", "tailwindcss": "4.1.8" } }, "sha512-vB/vlf7rIky+w94aWMw34bWW1ka6g6C3xIOdICKX2GC0VcLtL6fhlLiafF0DVIwa9V6EHz8kbWMkS2s2QvvNlw=="], "@tailwindcss/typography": ["@tailwindcss/typography@0.5.16", "", { "dependencies": { "lodash.castarray": "^4.4.0", "lodash.isplainobject": "^4.0.6", "lodash.merge": "^4.6.2", "postcss-selector-parser": "6.0.10" }, "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" } }, "sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA=="], - "@tanstack/react-virtual": ["@tanstack/react-virtual@3.13.6", "", { "dependencies": { "@tanstack/virtual-core": "3.13.6" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-WT7nWs8ximoQ0CDx/ngoFP7HbQF9Q2wQe4nh2NB+u2486eX3nZRE40P9g6ccCVq7ZfTSH5gFOuCoVH5DLNS/aA=="], + "@tanstack/react-virtual": ["@tanstack/react-virtual@3.13.9", "", { "dependencies": { "@tanstack/virtual-core": "3.13.9" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-SPWC8kwG/dWBf7Py7cfheAPOxuvIv4fFQ54PdmYbg7CpXfsKxkucak43Q0qKsxVthhUJQ1A7CIMAIplq4BjVwA=="], - "@tanstack/virtual-core": ["@tanstack/virtual-core@3.13.6", "", {}, "sha512-cnQUeWnhNP8tJ4WsGcYiX24Gjkc9ALstLbHcBj1t3E7EimN6n6kHH+DPV4PpDnuw00NApQp+ViojMj1GRdwYQg=="], + "@tanstack/virtual-core": ["@tanstack/virtual-core@3.13.9", "", {}, "sha512-3jztt0jpaoJO5TARe2WIHC1UQC3VMLAFUW5mmMo0yrkwtDB2AQP0+sh10BVUpWrnvHjSLvzFizydtEGLCJKFoQ=="], "@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="], @@ -308,11 +311,11 @@ "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], - "@types/node": ["@types/node@22.15.18", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-v1DKRfUdyW+jJhZNEI1PYy29S2YRxMV5AOO/x/SjKmW0acCIOqmbj6Haf9eHAhsPmrhlHSxEhv/1WszcLWV4cg=="], + "@types/node": ["@types/node@22.15.30", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-6Q7lr06bEHdlfplU6YRbgG1SFBdlsfNC4/lX+SkhiTs0cpJkOElmWls8PxDFv4yY/xKb8Y6SO0OmSX4wgqTZbA=="], - "@types/react": ["@types/react@19.1.4", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-EB1yiiYdvySuIITtD5lhW4yPyJ31RkJkkDw794LaQYrxCSaQV/47y5o1FMC4zF9ZyjUjzJMZwbovEnT5yHTW6g=="], + "@types/react": ["@types/react@19.1.6", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-JeG0rEWak0N6Itr6QUx+X60uQmN+5t3j9r/OVDtWzFXKaj6kD1BwJzOksD0FF6iWxZlbE1kB0q9vtnU2ekqa1Q=="], - "@types/react-dom": ["@types/react-dom@19.1.5", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-CMCjrWucUBZvohgZxkjd6S9h0nZxXjzus6yDfUb+xLxYM7VvjKNH1tQrE9GWLql1XoOP4/Ds3bwFqShHUYraGg=="], + "@types/react-dom": ["@types/react-dom@19.1.6", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw=="], "@types/react-highlight-words": ["@types/react-highlight-words@0.20.0", "", { "dependencies": { "@types/react": "*" } }, "sha512-Qm512TiOakvtNzHJ2+TNVHnLn5cJ2wLQV0+LrhuispVth6dRf5b8ydjq3Kc0thpZ7bz4s6RnG6meboAXHWRK+Q=="], @@ -382,7 +385,7 @@ "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], - "detect-libc": ["detect-libc@2.0.3", "", {}, "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="], + "detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="], "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], @@ -420,9 +423,9 @@ "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], - "flexsearch": ["flexsearch@0.8.166", "", {}, "sha512-X3GY9OfQyP1tjyy18PbGeFoxLNWlAedqv1dH/ikLS/6OYCGehX7LjJcR5Zuo0WSNqyqwbbhec1CucCwR+Rgfig=="], + "flexsearch": ["flexsearch@0.8.205", "", {}, "sha512-REFjMqy86DKkCTJ4gIE42c9MVm9t1vUWfEub/8taixYuhvyu4jd4XmFALk5VuKW4GH4VLav8A4BJboTsslHF1w=="], - "framer-motion": ["framer-motion@12.11.3", "", { "dependencies": { "motion-dom": "^12.11.2", "motion-utils": "^12.9.4", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-ksUtDFBZtrbQFt4bEMFrFgo7camhmXcLeuylKQxEYSd9czkZ4tZmFROxWczWeu51WqC2m91ifpvgGCBLd0uviQ=="], + "framer-motion": ["framer-motion@12.16.0", "", { "dependencies": { "motion-dom": "^12.16.0", "motion-utils": "^12.12.1", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-xryrmD4jSBQrS2IkMdcTmiS4aSKckbS7kLDCuhUn9110SQKG1w3zlq1RTqCblewg+ZYe+m3sdtzQA6cRwo5g8Q=="], "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], @@ -472,27 +475,27 @@ "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], - "lightningcss": ["lightningcss@1.29.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.29.2", "lightningcss-darwin-x64": "1.29.2", "lightningcss-freebsd-x64": "1.29.2", "lightningcss-linux-arm-gnueabihf": "1.29.2", "lightningcss-linux-arm64-gnu": "1.29.2", "lightningcss-linux-arm64-musl": "1.29.2", "lightningcss-linux-x64-gnu": "1.29.2", "lightningcss-linux-x64-musl": "1.29.2", "lightningcss-win32-arm64-msvc": "1.29.2", "lightningcss-win32-x64-msvc": "1.29.2" } }, "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA=="], + "lightningcss": ["lightningcss@1.30.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.30.1", "lightningcss-darwin-x64": "1.30.1", "lightningcss-freebsd-x64": "1.30.1", "lightningcss-linux-arm-gnueabihf": "1.30.1", "lightningcss-linux-arm64-gnu": "1.30.1", "lightningcss-linux-arm64-musl": "1.30.1", "lightningcss-linux-x64-gnu": "1.30.1", "lightningcss-linux-x64-musl": "1.30.1", "lightningcss-win32-arm64-msvc": "1.30.1", "lightningcss-win32-x64-msvc": "1.30.1" } }, "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg=="], - "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.29.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA=="], + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ=="], - "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.29.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w=="], + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA=="], - "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.29.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg=="], + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig=="], - "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.29.2", "", { "os": "linux", "cpu": "arm" }, "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg=="], + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.1", "", { "os": "linux", "cpu": "arm" }, "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q=="], - "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.29.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ=="], + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw=="], - "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.29.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ=="], + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ=="], - "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.29.2", "", { "os": "linux", "cpu": "x64" }, "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg=="], + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw=="], - "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.29.2", "", { "os": "linux", "cpu": "x64" }, "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w=="], + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ=="], - "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.29.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw=="], + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA=="], - "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.29.2", "", { "os": "win32", "cpu": "x64" }, "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA=="], + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.1", "", { "os": "win32", "cpu": "x64" }, "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg=="], "loader-utils": ["loader-utils@2.0.4", "", { "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", "json5": "^2.1.2" } }, "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw=="], @@ -626,9 +629,9 @@ "mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="], - "motion-dom": ["motion-dom@12.11.2", "", { "dependencies": { "motion-utils": "^12.9.4" } }, "sha512-wZ396XNNTI9GOkyrr80wFSbZc1JbIHSHTbLdririSbkEgahWWKmsHzsxyxqBBvuBU/iaQWVu1YCjdpXYNfo2yQ=="], + "motion-dom": ["motion-dom@12.16.0", "", { "dependencies": { "motion-utils": "^12.12.1" } }, "sha512-Z2nGwWrrdH4egLEtgYMCEN4V2qQt1qxlKy/uV7w691ztyA41Q5Rbn0KNGbsNVDZr9E8PD2IOQ3hSccRnB6xWzw=="], - "motion-utils": ["motion-utils@12.9.4", "", {}, "sha512-BW3I65zeM76CMsfh3kHid9ansEJk9Qvl+K5cu4DVHKGsI52n76OJ4z2CUJUV+Mn3uEP9k1JJA3tClG0ggSrRcg=="], + "motion-utils": ["motion-utils@12.12.1", "", {}, "sha512-f9qiqUHm7hWSLlNW8gS9pisnsN7CRFRD58vNjptKdsqFLpkVnX00TNeD6Q0d27V9KzT7ySFyK1TZ/DShfVOv6w=="], "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], @@ -636,7 +639,7 @@ "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], - "next": ["next@15.3.2", "", { "dependencies": { "@next/env": "15.3.2", "@swc/counter": "0.1.3", "@swc/helpers": "0.5.15", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "15.3.2", "@next/swc-darwin-x64": "15.3.2", "@next/swc-linux-arm64-gnu": "15.3.2", "@next/swc-linux-arm64-musl": "15.3.2", "@next/swc-linux-x64-gnu": "15.3.2", "@next/swc-linux-x64-musl": "15.3.2", "@next/swc-win32-arm64-msvc": "15.3.2", "@next/swc-win32-x64-msvc": "15.3.2", "sharp": "^0.34.1" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.41.2", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-CA3BatMyHkxZ48sgOCLdVHjFU36N7TF1HhqAHLFOkV6buwZnvMI84Cug8xD56B9mCuKrqXnLn94417GrZ/jjCQ=="], + "next": ["next@15.3.3", "", { "dependencies": { "@next/env": "15.3.3", "@swc/counter": "0.1.3", "@swc/helpers": "0.5.15", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "15.3.3", "@next/swc-darwin-x64": "15.3.3", "@next/swc-linux-arm64-gnu": "15.3.3", "@next/swc-linux-arm64-musl": "15.3.3", "@next/swc-linux-x64-gnu": "15.3.3", "@next/swc-linux-x64-musl": "15.3.3", "@next/swc-win32-arm64-msvc": "15.3.3", "@next/swc-win32-x64-msvc": "15.3.3", "sharp": "^0.34.1" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.41.2", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-JqNj29hHNmCLtNvd090SyRbXJiivQ+58XjCcrC50Crb5g5u2zi7Y2YivbsEfzk6AtVI80akdOQbaMZwWB1Hthw=="], "next-themes": ["next-themes@0.4.6", "", { "peerDependencies": { "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA=="], @@ -702,11 +705,11 @@ "search-insights": ["search-insights@2.17.3", "", {}, "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ=="], - "semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], + "semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], - "sharp": ["sharp@0.34.1", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.7.1" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.1", "@img/sharp-darwin-x64": "0.34.1", "@img/sharp-libvips-darwin-arm64": "1.1.0", "@img/sharp-libvips-darwin-x64": "1.1.0", "@img/sharp-libvips-linux-arm": "1.1.0", "@img/sharp-libvips-linux-arm64": "1.1.0", "@img/sharp-libvips-linux-ppc64": "1.1.0", "@img/sharp-libvips-linux-s390x": "1.1.0", "@img/sharp-libvips-linux-x64": "1.1.0", "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", "@img/sharp-libvips-linuxmusl-x64": "1.1.0", "@img/sharp-linux-arm": "0.34.1", "@img/sharp-linux-arm64": "0.34.1", "@img/sharp-linux-s390x": "0.34.1", "@img/sharp-linux-x64": "0.34.1", "@img/sharp-linuxmusl-arm64": "0.34.1", "@img/sharp-linuxmusl-x64": "0.34.1", "@img/sharp-wasm32": "0.34.1", "@img/sharp-win32-ia32": "0.34.1", "@img/sharp-win32-x64": "0.34.1" } }, "sha512-1j0w61+eVxu7DawFJtnfYcvSv6qPFvfTaqzTQ2BLknVhHTwGS8sc63ZBF4rzkWMBVKybo4S5OBtDdZahh2A1xg=="], + "sharp": ["sharp@0.34.2", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.4", "semver": "^7.7.2" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.2", "@img/sharp-darwin-x64": "0.34.2", "@img/sharp-libvips-darwin-arm64": "1.1.0", "@img/sharp-libvips-darwin-x64": "1.1.0", "@img/sharp-libvips-linux-arm": "1.1.0", "@img/sharp-libvips-linux-arm64": "1.1.0", "@img/sharp-libvips-linux-ppc64": "1.1.0", "@img/sharp-libvips-linux-s390x": "1.1.0", "@img/sharp-libvips-linux-x64": "1.1.0", "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", "@img/sharp-libvips-linuxmusl-x64": "1.1.0", "@img/sharp-linux-arm": "0.34.2", "@img/sharp-linux-arm64": "0.34.2", "@img/sharp-linux-s390x": "0.34.2", "@img/sharp-linux-x64": "0.34.2", "@img/sharp-linuxmusl-arm64": "0.34.2", "@img/sharp-linuxmusl-x64": "0.34.2", "@img/sharp-wasm32": "0.34.2", "@img/sharp-win32-arm64": "0.34.2", "@img/sharp-win32-ia32": "0.34.2", "@img/sharp-win32-x64": "0.34.2" } }, "sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg=="], - "shiki": ["shiki@3.4.1", "", { "dependencies": { "@shikijs/core": "3.4.1", "@shikijs/engine-javascript": "3.4.1", "@shikijs/engine-oniguruma": "3.4.1", "@shikijs/langs": "3.4.1", "@shikijs/themes": "3.4.1", "@shikijs/types": "3.4.1", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-PSnoczt+iWIOB4iRQ+XVPFtTuN1FcmuYzPgUBZTSv5pC6CozssIx2M4O5n4S9gJlUu9A3FxMU0ZPaHflky/6LA=="], + "shiki": ["shiki@3.6.0", "", { "dependencies": { "@shikijs/core": "3.6.0", "@shikijs/engine-javascript": "3.6.0", "@shikijs/engine-oniguruma": "3.6.0", "@shikijs/langs": "3.6.0", "@shikijs/themes": "3.6.0", "@shikijs/types": "3.6.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-tKn/Y0MGBTffQoklaATXmTqDU02zx8NYBGQ+F6gy87/YjKbizcLd+Cybh/0ZtOBX9r1NEnAy/GTRDKtOsc1L9w=="], "simple-functional-loader": ["simple-functional-loader@1.2.1", "", { "dependencies": { "loader-utils": "^2.0.0" } }, "sha512-GPDrxrQkE7ijm35QlfPFVp5hBHR6ZcaUq42TEDgf1U5iTL3IDLFvKAbHE/ODqpdfJJ7Xn4cr/slBn12jjNPkaQ=="], @@ -732,7 +735,7 @@ "tabbable": ["tabbable@6.2.0", "", {}, "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="], - "tailwindcss": ["tailwindcss@4.1.6", "", {}, "sha512-j0cGLTreM6u4OWzBeLBpycK0WIh8w7kSwcUsQZoGLHZ7xDTdM69lN64AgoIEEwFi0tnhs4wSykUa5YWxAzgFYg=="], + "tailwindcss": ["tailwindcss@4.1.8", "", {}, "sha512-kjeW8gjdxasbmFKpVGrGd5T4i40mV5J2Rasw48QARfYeQ8YS9x02ON9SFWax3Qf616rt4Cp3nVNIj6Hd1mP3og=="], "tapable": ["tapable@2.2.1", "", {}, "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="], @@ -784,19 +787,17 @@ "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], - "zustand": ["zustand@5.0.4", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-39VFTN5InDtMd28ZhjLyuTnlytDr9HfwO512Ai4I8ZABCoyAj4F1+sr7sD1jP/+p7k77Iko0Pb5NhgBFDCX0kQ=="], + "zustand": ["zustand@5.0.5", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-mILtRfKW9xM47hqxGIxCv12gXusoY/xTSHBYApXozR0HmQv299whhBeeAcRy+KrPPybzosvJBCOmVjq6x12fCg=="], "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], - "@tailwindcss/oxide/detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="], - "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.4.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA=="], - "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.9", "", { "dependencies": { "@emnapi/core": "^1.4.0", "@emnapi/runtime": "^1.4.0", "@tybys/wasm-util": "^0.9.0" }, "bundled": true }, "sha512-OKRBiajrrxB9ATokgEQoG87Z25c67pCpYcCwmXYX8PBftC9pBfN18gnm/fh1wurSLEKIAt+QRFLFCQISrb66Jg=="], + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.10", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.9.0" }, "bundled": true }, "sha512-bCsCyeZEwVErsGmyPNSzwfwFn4OdxBj0mmv6hOFucB/k81Ojdu68RbZdxYsRQUPc9l6SU5F/cG+bXgWs3oUgsQ=="], "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.9.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw=="], @@ -808,8 +809,6 @@ "estree-util-visit/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], - "lightningcss/detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="], - "mdx-annotations/unist-util-visit": ["unist-util-visit@4.1.2", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0", "unist-util-visit-parents": "^5.1.1" } }, "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg=="], "micromark-util-events-to-acorn/estree-util-visit": ["estree-util-visit@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/unist": "^3.0.0" } }, "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww=="], diff --git a/package.json b/package.json index bf19321..87ab747 100644 --- a/package.json +++ b/package.json @@ -11,28 +11,28 @@ "uuid": "bun --print 'crypto.randomUUID()'" }, "dependencies": { - "@algolia/autocomplete-core": "^1.19.1", - "@headlessui/react": "^2.2.3", + "@algolia/autocomplete-core": "^1.19.2", + "@headlessui/react": "^2.2.4", "@headlessui/tailwindcss": "^0.2.2", "@mdx-js/loader": "^3.1.0", "@mdx-js/react": "^3.1.0", - "@next/mdx": "^15.3.2", + "@next/mdx": "^15.3.3", "@sindresorhus/slugify": "^2.2.1", - "@tailwindcss/postcss": "^4.1.6", + "@tailwindcss/postcss": "^4.1.8", "@tailwindcss/typography": "^0.5.16", "@types/mdx": "^2.0.13", - "@types/node": "^22.15.18", - "@types/react": "^19.1.4", - "@types/react-dom": "^19.1.5", + "@types/node": "^22.15.30", + "@types/react": "^19.1.6", + "@types/react-dom": "^19.1.6", "@types/react-highlight-words": "^0.20.0", "acorn": "^8.14.1", "clsx": "^2.1.1", "fast-glob": "^3.3.3", - "flexsearch": "^0.8.166", - "framer-motion": "^12.11.3", + "flexsearch": "^0.8.205", + "framer-motion": "^12.16.0", "mdast-util-to-string": "^4.0.0", "mdx-annotations": "^0.1.4", - "next": "^15.3.2", + "next": "^15.3.3", "next-themes": "^0.4.6", "react": "^19.1.0", "react-dom": "^19.1.0", @@ -40,21 +40,21 @@ "remark": "^15.0.1", "remark-gfm": "^4.0.1", "remark-mdx": "^3.1.0", - "shiki": "^3.4.1", + "shiki": "^3.6.0", "simple-functional-loader": "^1.2.1", - "tailwindcss": "^4.1.6", + "tailwindcss": "^4.1.8", "typescript": "^5.8.3", "unist-util-filter": "^5.0.1", "unist-util-visit": "^5.0.0", "uwuifier": "^4.2.2", - "zustand": "^5.0.4" + "zustand": "^5.0.5" }, "devDependencies": { "@biomejs/biome": "^1.9.4", "@iconify-icon/react": "^3.0.0", - "@next/bundle-analyzer": "^15.3.2", - "@shikijs/transformers": "^3.4.1", - "sharp": "^0.34.1" + "@next/bundle-analyzer": "^15.3.3", + "@shikijs/transformers": "^3.6.0", + "sharp": "^0.34.2" }, - "trustedDependencies": ["@biomejs/biome", "sharp"] + "trustedDependencies": ["@biomejs/biome", "@tailwindcss/oxide", "sharp"] } From e6f7a27d3ec1d68cb45c1c00f149950125d4b3e5 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Sat, 7 Jun 2025 20:40:10 +0200 Subject: [PATCH 15/25] docs: :recycle: Removed usage of null author, mandate usage of `null` for unset fields --- app/changelog/page.mdx | 2 ++ app/entities/delete/page.mdx | 4 ++-- app/entities/instance-metadata/page.mdx | 6 ------ app/entities/page.mdx | 2 +- app/structures/collection/page.mdx | 8 ++++---- 5 files changed, 9 insertions(+), 13 deletions(-) diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index a777015..05c7f15 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' }} - Every field that used to be a URI now uses that entity's `id` field. - New endpoints have been defined under `/.versia/v0.6/` to fetch entities by their `id`. - Added [References](/types#reference) as a way to refer to other entities. +- Mandated the usage of `null` for optional fields that are not set, instead of omitting them. +- Changed usage of "`null` authors" to simply being an optional field. ## Since WD 4 diff --git a/app/entities/delete/page.mdx b/app/entities/delete/page.mdx index 551d036..8a3d292 100644 --- a/app/entities/delete/page.mdx +++ b/app/entities/delete/page.mdx @@ -24,8 +24,8 @@ Having the authorization is defined as: - - [Reference](/types#reference) to the `User` who is deleting the entity. [Can be set to `null` to represent the instance](/entities/instance-metadata#the-null-author). + + [Reference](/types#reference) to the `User` who is deleting the entity. Type of the entity being deleted. diff --git a/app/entities/instance-metadata/page.mdx b/app/entities/instance-metadata/page.mdx index bcdf3c5..4e5439f 100644 --- a/app/entities/instance-metadata/page.mdx +++ b/app/entities/instance-metadata/page.mdx @@ -7,12 +7,6 @@ export const metadata = { Contains metadata about a Versia instance, such as capabilities and endpoints. {{ className: 'lead' }} -## The `null` Author - -On some entities that have an `author` field, the `author` can be `null` to represent the instance itself as the author (like ActivityPub's Server Actors). - -Check the entity's documentation page to see if it supports this (it will be noted in the `author` field). - ## Entity Definition diff --git a/app/entities/page.mdx b/app/entities/page.mdx index 2df932c..aec10f8 100644 --- a/app/entities/page.mdx +++ b/app/entities/page.mdx @@ -12,7 +12,7 @@ Entities are the foundation of the Versia protocol. A similar concept to entitie An entity is a simple JSON object that represents a core data structure in Versia. Entities are used to represent various types of data, such as users, notes, and more. Each entity has a unique `id` property that is used to identify it within the instance. -Any field in an entity not marked as `required` may be omitted or set to `null`. +Any field in an entity not marked as `required` may be set to `null`. These fields **must not** be omitted: they must be present with a `null` value if not set. diff --git a/app/structures/collection/page.mdx b/app/structures/collection/page.mdx index 391c668..16172ed 100644 --- a/app/structures/collection/page.mdx +++ b/app/structures/collection/page.mdx @@ -16,8 +16,8 @@ Collections are a way to represent paginated groups of entities. They are used e - - [Reference](/types#reference) to the 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). + + [Reference](/types#reference) to the author of the collection. Usually the user who "owns" the collection. Total number of entities in the collection, across all pages. @@ -64,8 +64,8 @@ URI Collections are identical to regular collections, but they contain only URIs - - [Reference](/types#reference) to the 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). + + [Reference](/types#reference) to the author of the collection. Usually the user who owns the collection. Total number of entities in the collection, across all pages. From e9b5ccd76c3b717714e684c0ca00e08e71349885 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Sat, 7 Jun 2025 22:54:59 +0200 Subject: [PATCH 16/25] docs: :recycle: Rewrite various docs pages, add null fields everywhere they were missing, make some Note and User fields mandatory --- app/api/basics/page.mdx | 33 ++++- app/api/endpoints/page.mdx | 8 +- app/changelog/page.mdx | 7 ++ app/entities/delete/page.mdx | 4 +- app/entities/instance-metadata/page.mdx | 6 +- app/entities/note/page.mdx | 22 +++- app/entities/page.mdx | 23 ++-- app/entities/user/page.mdx | 12 +- app/extensions/custom-emojis/page.mdx | 17 ++- app/extensions/groups/page.mdx | 2 +- app/extensions/interaction-controls/page.mdx | 1 + app/extensions/page.mdx | 11 +- app/extensions/polls/page.mdx | 3 +- app/extensions/vanity/page.mdx | 50 ++++++-- app/federation/discovery/page.mdx | 9 +- app/federation/example/page.mdx | 60 ++++++++-- app/federation/http/page.mdx | 28 +++-- app/federation/page.mdx | 10 +- app/federation/validation/page.mdx | 8 +- app/introduction/page.mdx | 9 +- app/json/page.mdx | 119 +++++++++++++++++++ app/links/page.mdx | 6 +- app/page.tsx | 25 +--- app/philosophy/principles/page.mdx | 4 +- app/security/page.mdx | 5 +- app/signatures/page.mdx | 36 +++--- app/structures/collection/page.mdx | 1 + app/structures/content-format/page.mdx | 34 +++++- app/types/page.mdx | 1 - components/Libraries.tsx | 4 +- components/Navigation.tsx | 2 +- 31 files changed, 412 insertions(+), 148 deletions(-) create mode 100644 app/json/page.mdx diff --git a/app/api/basics/page.mdx b/app/api/basics/page.mdx index deb0f5a..621e55f 100644 --- a/app/api/basics/page.mdx +++ b/app/api/basics/page.mdx @@ -11,23 +11,44 @@ Versia defines a very simple API for server-to-server communication, mainly fetc Every Versia API endpoint is prefixed with `/.versia/vX/`, where `X` is the version of the API. The current version is `0.6`, so the current API prefix is `/.versia/v0.6/`. This versioning is used to avoid breaking changes in the future, and to allow for backwards compatibility. -Requests not encrypted with TLS (aka HTTPS) **MUST NOT** be sent or responded to. All implementations are required to use TLS 1.2 or higher, and to support HTTP/2. +Requests not encrypted with TLS (aka HTTPS) **must not** be sent or responded to. All implementations are required to use TLS 1.2 or higher, and to support HTTP/2. - Implementations have no obligations to support more than one Versia version. It is recommended to always support the latest version, as it helps avoid bogging down the network with old versions. + Implementations have no obligation to support more than one Versia version. It is recommended to always support the latest version, as it helps avoid bogging down the network with old versions. ## Signatures -- All API requests **MUST** be signed, unless otherwise specified. This includes `POST` and `GET` requests. -- All API responses **MUST** be signed, unless otherwise specified. - -The signature mechanism is defined in the [Signatures](/signatures) document. +API requests/responses between instances **must** include a [Signature](/signatures), signed with the [instance's private key](/entities/instance-metadata), as defined in [Signatures](/signatures). ## Encoding "URL-encoding" is the mechanism used to encode data containing special characters in URLs. When this specification refers to "URL-encoding", it means the encoding defined in [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986#section-2.1). +## Domain + +Versia defines a **domain** as the hostname of an instance, which is used to identify the instance in the network. It **must** be a valid hostname, and cannot include a port number (the HTTPS port is always 443). + +Defining a domain is very complicated, so please refer to the following examples: + +``` {{ "title": "Valid Domains" }} +example.com +test.localhost +sus.example.org +xn--ls8h.la +1.0.1.7.0.8.0.0.0.0.7.4.0.1.0.0.2.ip6.arpa # We know what you did +``` + +``` {{ "title": "Invalid Domains" }} +example.com:3000 # ❌️ Invalid: port number is not allowed +test..localhost # ❌️ Invalid: double dot is not allowed +example.com. # ❌️ Invalid: trailing dot is not allowed +test.org/ # ❌️ Invalid: trailing slash is not allowed +test.org/sus # ❌️ Invalid: path is not allowed +πŸ’©.la # ❌️ Invalid: IDNs must be Punycode encoded +https://bob.org # ❌️ Invalid: protocol is not allowed +``` + ## Redirects API endpoints **MUST NOT** redirect to other endpoints, with the following exceptions: diff --git a/app/api/endpoints/page.mdx b/app/api/endpoints/page.mdx index ca7bc92..33f1db0 100644 --- a/app/api/endpoints/page.mdx +++ b/app/api/endpoints/page.mdx @@ -22,7 +22,7 @@ export const metadata = { Must be `GET`. - Must be the instance's metadata, as defined in the [Instance Metadata](/entities/instance-metadata) document. + Instance's metadata, as defined in the [Instance Metadata](/entities/instance-metadata) document. @@ -66,7 +66,7 @@ export const metadata = { Must be `GET`. - Must be the entity's data as JSON, as defined in its [Entity](/entities) definition document. + Entity data as JSON, as defined in its [Entity](/entities) definition document. @@ -151,9 +151,9 @@ Accept: application/vnd.versia+json ## Inbox -The inbox endpoint is used for other instances to send entities to this instance. It is a single endpoint that can receive messages for every user (also known as a shared inbox). +The inbox endpoint is used for instances to send entities to each other. It is a single endpoint that can receive messages for every user (also known as a shared inbox). -The delivery mechanism is described further in the [Federation](/federation) document. +The delivery mechanism is described further in the [Federation](/federation#inboxes) document. diff --git a/app/changelog/page.mdx b/app/changelog/page.mdx index 05c7f15..2eed47b 100644 --- a/app/changelog/page.mdx +++ b/app/changelog/page.mdx @@ -20,6 +20,13 @@ This page lists changes since Working Draft 3. {{ className: 'lead' }} - Added [References](/types#reference) as a way to refer to other entities. - Mandated the usage of `null` for optional fields that are not set, instead of omitting them. - Changed usage of "`null` authors" to simply being an optional field. +- Added more guidelines on [JSON data handling](/json). +- Clarified the meaning of [Domain](/api/basics#domain) in the context of Versia. +- Changes to [Note](/entities/note): + - `is_sensitive`, `attachments`, `mentions` and `previews` are now required. +- Changes to [User](/entities/user): + - `fields`, `manually_approves_followers` and `indexable` are now required. +- Removed "short pronoun" from [Vanity Extension](/extensions/vanity) (union types are tricky to parse in strongly typed languages). ## Since WD 4 diff --git a/app/entities/delete/page.mdx b/app/entities/delete/page.mdx index 8a3d292..cf71d3f 100644 --- a/app/entities/delete/page.mdx +++ b/app/entities/delete/page.mdx @@ -5,14 +5,14 @@ export const metadata = { # Delete -Signals the deletion of an entity. It is a [**Transient Entity**](/entities#transient-entities). {{ className: 'lead' }} +Signals the deletion of an entity. {{ className: 'lead' }} ## Authorization Implementations **must** ensure that the author of the `Delete` entity has the authorization to delete the target entity. Having the authorization is defined as: -- The author is the creator of the target entity (including [delegation](/federation/delegation)). +- The author is the creator of the target entity (including [delegation](/extensions/delegation)). - The author is the instance. ## Entity Definition diff --git a/app/entities/instance-metadata/page.mdx b/app/entities/instance-metadata/page.mdx index 4e5439f..8fae58c 100644 --- a/app/entities/instance-metadata/page.mdx +++ b/app/entities/instance-metadata/page.mdx @@ -48,8 +48,8 @@ Contains metadata about a Versia instance, such as capabilities and endpoints. { Long description of the instance, for humans. Should be around 100-200 words. - - Hostname of the instance. Includes the port if it is not the default (i.e. `443` for HTTPS). + + Domain of the instance, used for federation. Public key of the instance. @@ -96,7 +96,7 @@ Contains metadata about a Versia instance, such as capabilities and endpoints. { ] }, "description": "Server for Jim's Jolly Jimjams, a social network for fans of Jimjams.", - "host": "social.jimjams.com", + "domain": "social.jimjams.com", "logo": { "image/png": { "content": "https://social.jimjams.com/files/logo.png" diff --git a/app/entities/note/page.mdx b/app/entities/note/page.mdx index af7098a..91c717b 100644 --- a/app/entities/note/page.mdx +++ b/app/entities/note/page.mdx @@ -16,7 +16,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. @@ -61,13 +61,13 @@ Notes represent a piece of content on a Versia instance. They can be posted by [ 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. - + [References](/types#reference) to [Users](/entities/user) that should be notified of the note. Similar to Twitter's `@` mentions. The note may also contain mentions in the content, however only the mentions in this field should trigger notifications. - + Previews for any links in the publication. This is to avoid the [stampeding mastodon problem](https://github.com/mastodon/mastodon/issues/23662) where a link preview is fetched by every instance that sees the publication, creating an accidental DDOS attack. ```typescript @@ -108,6 +108,9 @@ Notes represent a piece of content on a Versia instance. They can be posted by [ "content": "https://cdn.versia.social/29e810bf4707fef373d886af322089d5db300fce66e4e073efc26827f10825f6/image.webp", "remote": true, "thumbhash": "1QcSHQRnh493V4dIh4eXh1h4kJUI", + "description": null, + "fps": null, + "duration": null, "height": 960, "size": 221275, "hash": { @@ -120,6 +123,12 @@ Notes represent a piece of content on a Versia instance. They can be posted by [ "text/plain": { "content": "https://cdn.lysand.org/68c02dd11c179ef4d170b05393f6e72133dd0ad733f40d41b42363d8784e8d5d/fire.txt", "remote": true, + "description": null, + "thumbhash": null, + "width": null, + "height": null, + "fps": null, + "duration": null "size": 8, "hash": { "sha256": "68c02dd11c179ef4d170b05393f6e72133dd0ad733f40d41b42363d8784e8d5d" @@ -150,7 +159,10 @@ Notes represent a piece of content on a Versia instance. They can be posted by [ "group": "public", "is_sensitive": false, "mentions": [], - "subject": "Versia development" + "subject": "Versia development", + "previews": [], + "quotes": null, + "replies_to": null } ``` diff --git a/app/entities/page.mdx b/app/entities/page.mdx index aec10f8..3ffdcb4 100644 --- a/app/entities/page.mdx +++ b/app/entities/page.mdx @@ -6,9 +6,12 @@ export const metadata = { # Entities -Entities are the foundation of the Versia protocol. A similar concept to entities are the [ActivityStreams](https://www.w3.org/TR/activitystreams-core/) objects, which are used to represent activities in the [ActivityPub](https://www.w3.org/TR/activitypub/) protocol. {{ className: 'lead' }} +Entities are the foundation of the Versia protocol. They are similar to: {{ className: 'lead' }} -## Entity Definition +- [ActivityStreams](https://www.w3.org/TR/activitystreams-core/) objects +- [Matrix](https://matrix.org/) events. + +## Definition An entity is a simple JSON object that represents a core data structure in Versia. Entities are used to represent various types of data, such as users, notes, and more. Each entity has a unique `id` property that is used to identify it within the instance. @@ -31,11 +34,11 @@ Any field in an entity not marked as `required` may be set to `null`. These fiel Type of the entity. Custom types must follow [Extension Naming](/extensions#naming). - + 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. + Handling of dates that are valid but obviously incorrect (e.g. in the future) is left to the Implementation's discretion. Sending a [Note](/entities/note) created on `13-12-1337` is very funny, but don't be surprised if it is rejected. @@ -86,14 +89,6 @@ Any field in an entity not marked as `required` may be set to `null`. These fiel ## Transient Entities -Some entities are transient, meaning they cannot be refetched using the [Federation API](/api/endpoints). These entities are used for actions that do not require a permanent record, such as deletions or migrations. Transient Entities do not have an `id` field. - -Implementations **must not** rely on other implementations to store transient entities in their database. - -## Serialization +Some entities are **transient**, meaning they cannot be fetched using the [Federation API](/api/endpoints). These entities are used for actions that do not require a permanent record, such as deletions or migrations. Transient Entities do not have an `id` field. -When serialized to a string, the JSON representation of an entity must follow the following rules: -- Keys must be sorted lexicographically. -- Must use UTF-8 encoding. -- Must be **signed** using the the [instance's private key](/entities/instance-metadata). -- Must use Unix-style `\n` line endings (LF). \ No newline at end of file +Implementations **must not** rely on other implementations to store transient entities in their database. \ No newline at end of file diff --git a/app/entities/user/page.mdx b/app/entities/user/page.mdx index 94a078e..c5d6e1f 100644 --- a/app/entities/user/page.mdx +++ b/app/entities/user/page.mdx @@ -35,7 +35,7 @@ Usernames can be changed by the user, so it is recommended to use `id` for long- ### Instance -Instance **must** be the host of the instance the user is on (hostname with optional port). +Instance **must** be the [Domain](/api/basics#domain) that the user is on. ## Entity Definition @@ -52,7 +52,7 @@ Instance **must** be the host of the instance the user is on (hostname with opti Display name, as shown to other users. May contain emojis and any Unicode character. - + Custom key/value pairs. For example, metadata like socials or pronouns. Must be text format (`text/*`). ```typescript @@ -70,11 +70,11 @@ Instance **must** be the host of the instance the user is on (hostname with opti A header image for the user's profile. Also known as a cover photo or a banner. Must be an image format (`image/*`). - - If `true`, the user must approve any new followers manually. If `false`, followers are automatically approved. This does not affect federation, and is meant to be used for clients to display correct UI. Defaults to `false`. + + If `true`, the user must approve any new followers manually. If `false`, followers are automatically approved. This does not affect federation, and is meant to be used for clients to display correct UI. - - User consent to be indexed by search engines. If `false`, the user's profile should not be indexed. Defaults to `true`. + + User consent to be indexed by search engines. If `false`, the user's profile should not be indexed. diff --git a/app/extensions/custom-emojis/page.mdx b/app/extensions/custom-emojis/page.mdx index 25a6072..a1b1e45 100644 --- a/app/extensions/custom-emojis/page.mdx +++ b/app/extensions/custom-emojis/page.mdx @@ -39,6 +39,13 @@ The Custom Emojis extension adds support for adding personalized emojis to feder "content": "https://cdn.example.com/emojis/happy_face.webp", "remote": true, "description": "A happy emoji smiling.", + "size": null, + "hash": null, + "thumbhash": null, + "width": null, + "height": null, + "fps": null, + "duration": null } } } @@ -95,7 +102,8 @@ Custom Emojis can be added to any entity with text content. The extension ID is "content": "Hello, world :happy_face:!" } }, - "extensions": { // [!code focus:16] + ... + "extensions": { // [!code focus:23] "pub.versia:custom_emojis": { "emojis": [ { @@ -105,6 +113,13 @@ Custom Emojis can be added to any entity with text content. The extension ID is "content": "https://cdn.example.com/emojis/happy_face.webp", "remote": true, "description": "A happy emoji smiling.", + "size": null, + "hash": null, + "thumbhash": null, + "width": null, + "height": null, + "fps": null, + "duration": null } } } diff --git a/app/extensions/groups/page.mdx b/app/extensions/groups/page.mdx index 818af8d..bbfb469 100644 --- a/app/extensions/groups/page.mdx +++ b/app/extensions/groups/page.mdx @@ -27,7 +27,7 @@ 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. diff --git a/app/extensions/interaction-controls/page.mdx b/app/extensions/interaction-controls/page.mdx index afd30b4..f81bfcb 100644 --- a/app/extensions/interaction-controls/page.mdx +++ b/app/extensions/interaction-controls/page.mdx @@ -21,6 +21,7 @@ The entity defined in this document must be inserted in the `pub.versia:interact "content": "Hello, world :happy_face:!" } }, + ... "extensions": { // [!code focus:9] "pub.versia:interaction_controls": { "reply": { diff --git a/app/extensions/page.mdx b/app/extensions/page.mdx index f84e12a..8dd3c67 100644 --- a/app/extensions/page.mdx +++ b/app/extensions/page.mdx @@ -21,7 +21,7 @@ Extensions **must not** be designed in a way that makes them required to underst Versia extension names are composed of two parts: - The domain name of the extension author, in reverse order. Example: `pub.versia` -- The extension name, separated by a colon. `snake_case`. Example: `likes` +- The extension name, separated by a colon, in `snake_case`. Example: `likes` ``` {{ title: "Example Extension Name" }} pub.versia:likes @@ -30,7 +30,7 @@ pub.versia:likes ### Custom entities Custom entities are named in the same way, but with an additional part: -- The entity name, separated by a slash. `PascalCase`. Example: `Like` +- The entity name, separated by a slash, in `PascalCase`. Example: `Like` ``` {{ title: "Example Custom Entity Type" }} pub.versia:likes/Like @@ -49,9 +49,7 @@ Extensions can be found in two places: an [Entity](/entities#entity-definition)' Custom extensions to the entity. - `key`: The extension name. - - `value`: Extension data. Can be any JSON-serializable data. - - Extension data can be any JSON-serializable data. + - `value`: Extension data. Can be any JSON object, following [Versia JSON rules](/json). @@ -63,6 +61,7 @@ Extensions can be found in two places: an [Entity](/entities#entity-definition)' "id": "ed480922-b095-4f09-9da5-c995be8f5960", "name": null, "description": null, + "open": true, "extensions": { // [!code focus:100] "com.example:gps": { "location": { @@ -85,7 +84,7 @@ Extensions can be found in two places: an [Entity](/entities#entity-definition)' - The extension type. [Must follow naming conventions](#naming). + The extension type, [following naming conventions](#naming). Other properties of the custom entity. These are specific to the extension, and should be documented by the extension author. diff --git a/app/extensions/polls/page.mdx b/app/extensions/polls/page.mdx index f9e30dc..d07ef97 100644 --- a/app/extensions/polls/page.mdx +++ b/app/extensions/polls/page.mdx @@ -29,7 +29,7 @@ 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. - + RFC 3339 timestamp of when the poll ends and no more votes can be cast. If not present, the poll does not expire. @@ -49,6 +49,7 @@ Note that there is no `question` field: the question should be included in the ` "content": "What is your favourite color?" } }, + ... "extensions": { // [!code focus:28] "pub.versia:polls": { "options": [ diff --git a/app/extensions/vanity/page.mdx b/app/extensions/vanity/page.mdx index 626e3f1..1fde257 100644 --- a/app/extensions/vanity/page.mdx +++ b/app/extensions/vanity/page.mdx @@ -42,13 +42,10 @@ All properties are optional. Audio format (e.g. `audio/mpeg`). - An array of internationalized pronouns the user uses. Can be represented as a string or an object. + An array of internationalized pronouns the user uses. ```typescript - /* e.g. "he/him" */ - type ShortPronoun = string; - - interface LongPronoun { + interface Pronoun { subject: string; object: string; dependent_possessive: string; @@ -56,12 +53,11 @@ All properties are optional. reflexive: string; } - type Pronoun = ShortPronoun | LongPronoun; /* Example: en-US or fr */ type LanguageCode = string; ``` - + User's birthday. If year is left out or set to `0000`, implementations **SHOULD** not display the year. @@ -92,6 +88,14 @@ All properties are optional. "image/png": { "content": "https://cdn.example.com/ab5081cf-b11f-408f-92c2-7c246f290593/cat_ears.png", "remote": true, + "description": null, + "size": null, + "hash": null, + "thumbhash": null, + "width": null, + "height": null, + "fps": null, + "duration": null } } ], @@ -99,23 +103,53 @@ All properties are optional. "image/png": { "content": "https://cdn.example.com/d8c42be1-d0f7-43ef-b4ab-5f614e1beba4/rounded_square.jpeg", "remote": true, + "description": null, + "size": null, + "hash": null, + "thumbhash": null, + "width": null, + "height": null, + "fps": null, + "duration": null } }, "background": { "image/png": { "content": "https://cdn.example.com/6492ddcd-311e-4921-9567-41b497762b09/untitled-file-0019822.png", "remote": true, + "description": null, + "size": null, + "hash": null, + "thumbhash": null, + "width": null, + "height": null, + "fps": null, + "duration": null } }, "audio": { "audio/mpeg": { "content": "https://cdn.example.com/4da2f0d4-4728-4819-83e4-d614e4c5bebc/michael-jackson-thriller.mp3", "remote": true, + "description": null, + "size": null, + "hash": null, + "thumbhash": null, + "width": null, + "height": null, + "fps": null, + "duration": null } }, "pronouns": { "en-us": [ - "he/him", + { + "subject": "he", + "object": "him", + "dependent_possessive": "his", + "independent_possessive": "his", + "reflexive": "himself" + }, { "subject": "they", "object": "them", diff --git a/app/federation/discovery/page.mdx b/app/federation/discovery/page.mdx index f67b931..d317b52 100644 --- a/app/federation/discovery/page.mdx +++ b/app/federation/discovery/page.mdx @@ -49,7 +49,7 @@ Accept: application/jrd+json ## Instance Discovery -Instaance metadata can be accessed by making a `GET` request to the instance's Versia metadata endpoint, documented in the [Endpoints](/api/endpoints#instance-metadata) document. +Instance metadata can be accessed by making a `GET` request to the instance's Versia metadata endpoint, documented in the [Endpoints](/api/endpoints#instance-metadata) document. ### Example @@ -80,7 +80,10 @@ Accept: application/vnd.versia+json "pub.versia:reports" ] }, - "host": "versia.social", - "created_at": "2021-07-01T00:00:00Z" + "domain": "versia.social", + "created_at": "2021-07-01T00:00:00Z", + "description": null, + "logo": null, + "banner": null } ``` \ No newline at end of file diff --git a/app/federation/example/page.mdx b/app/federation/example/page.mdx index 34e2d25..ad4893b 100644 --- a/app/federation/example/page.mdx +++ b/app/federation/example/page.mdx @@ -50,7 +50,7 @@ curl https://b.social/.well-known/webfinger?resource=acct:joe@b.social -H "Accep 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. + This is done for brevity here. ### Fetching the User @@ -58,10 +58,10 @@ curl https://b.social/.well-known/webfinger?resource=acct:joe@b.social -H "Accep `a.social` fetches the user profile of `joe` from `b.social` using the URL provided in the WebFinger response. ```bash +# The request is signed by a.social's instance private key curl https://b.social/.versia/entities/User/joe \ -H "Accept: application/vnd.versia+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: a.social" \ -H "Versia-Signed-At: 1729241687" @@ -71,17 +71,30 @@ curl https://b.social/.versia/entities/User/joe \ ```json { - "id": "bde22zi3ca8762", // [!code focus:10] + "id": "bde22zi3ca8762", // [!code focus:3] "type": "User", "created_at": "2024-10-13T18:48:19Z", "avatar": { "image/webp": { "content": "https://cdn.b.social/avatars/joe.webp", - "remote": true + "remote": true, + "description": null, + "size": null, + "hash": null, + "thumbhash": null, + "width": null, + "height": null, + "fps": null, + "duration": null } }, // [!code focus:3] "display_name": "Joe Swanson (Winter Arc :gigachad:)", "username": "joe", + "bio": null, + "header": null, + "fields": [], + "manually_approves_followers": false, + "indexable": true, "extensions": { "pub.versia:custom_emojis": { "emojis": [ @@ -90,7 +103,15 @@ curl https://b.social/.versia/entities/User/joe \ "content": { "image/png": { "content": "https://cdn.b.social/emojis/gigachad.png", - "remote": true + "remote": true, + "description": null, + "size": null, + "hash": null, + "thumbhash": null, + "width": null, + "height": null, + "fps": null, + "duration": null } } } @@ -112,21 +133,44 @@ Finally, `a.social` serializes the note to send it to `joe`. "type": "Note", "created_at": "2024-12-01T12:19:06Z", "author": "alice", - "category": "microblog", // [!code focus:11] + "category": "microblog", "content": { - "text/html": { + "text/html": { // [!code focus:12] "content": "Hello, @joe@b.social! How are you doing today?", "remote": false, + "description": null, + "size": null, + "hash": null, + "thumbhash": null, + "width": null, + "height": null, + "fps": null, + "duration": null }, "text/plain": { "content": "Hello, @joe@b.social! How are you doing today?", "remote": false, + "description": null, + "size": null, + "hash": null, + "thumbhash": null, + "width": null, + "height": null, + "fps": null, + "duration": null } }, "group": "public", "mentions": [ // [!code focus:3] "b.social:bde22zi3ca8762" - ] + ], + "attachments": [], + "is_sensitive": false, + "previews": [], + "replies_to": null, + "quotes": null, + "subject": null, + "device": null, } ``` diff --git a/app/federation/http/page.mdx b/app/federation/http/page.mdx index dd94545..575d714 100644 --- a/app/federation/http/page.mdx +++ b/app/federation/http/page.mdx @@ -8,7 +8,7 @@ export const metadata = { Versia uses the HTTP protocol for all communications between instances. HTTP requests must conform to certain standards to ensure compatibility between different implementations, as well as to ensure the security and integrity of the data being exchanged. -ALL kinds of HTTP requests/responses between instances **MUST** include a [Signature](/signatures), signed with either the relevant [User](/entities/user)'s private key or the [instance's private key](/entities/instance-metadata). +HTTP requests/responses between instances **must** include a [Signature](/signatures), signed with the [instance's private key](/entities/instance-metadata), as defined in [Signatures](/signatures). ## Requests @@ -16,22 +16,26 @@ ALL kinds of HTTP requests/responses between instances **MUST** include a [Signa - Must include `application/vnd.versia+json`, unless specified otherwise. + Must be `application/vnd.versia+json`, unless specified otherwise. Basic `application/json` is **not** allowed. - Must include `application/vnd.versia+json; charset=utf-8`, if the request has a body. + Must be `application/vnd.versia+json; charset=utf-8` if the request has a body. - + See [Signatures](/signatures) for more information. - + See [Signatures](/signatures). - + See [Signatures](/signatures). - A string identifying the software making the request. + A string identifying the software making the request. Should contain the name of the software, its version, and a link to its homepage. + + ``` {{ 'title': 'Example User-Agent' }} + CoolServer/1.0 (https://coolserver.com) + ``` @@ -50,9 +54,9 @@ ALL kinds of HTTP requests/responses between instances **MUST** include a [Signa ## Rate limits -Implementations **MUST** respect the rate limits of remote instances. +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. +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. @@ -66,13 +70,13 @@ IETF draft [draft-polli-ratelimit-headers-02](https://www.ietf.org/archive/id/dr Must include `application/vnd.versia+json; charset=utf-8`, unless specified otherwise. - + See [Signatures](/signatures) for more information. - + See [Signatures](/signatures). - + See [Signatures](/signatures). diff --git a/app/federation/page.mdx b/app/federation/page.mdx index 0072096..13ca699 100644 --- a/app/federation/page.mdx +++ b/app/federation/page.mdx @@ -29,7 +29,7 @@ Ever [Instance](/entities/instance-metadata) has a personal HTTP endpoint called Let's consider the following example: -> Alice, on the instance `alice.example`, sends a message to Bob on the instance `bob.example`. +Alice, on the instance `alice.example`, sends a message to Bob on the instance `bob.example`. To perform this action, Alice's instance sends a `POST` request to Bob's instance's inbox endpoint. This request contains the [Note](/entities/note) entity that Alice wants to send to Bob, with [the appropriate metadata](/federation/http) to ensure the message is valid. @@ -39,4 +39,12 @@ Bob's instance receives the message and processes it according to the rules defi In addition to inboxes, every user has an outbox (at `/.versia/v0.6/entities/User//collections/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. + + Implementations **should** filter out entities that are not relevant to the request author when returning the outbox. + + For example, if Alice sends a [Note](/entities/note) to Bob on `direct` visibility: + - Alice's instance **should** return the [Note](/entities/note) in response to a request from Bob's instance. + - Alice's instance **should not** display the [Note](/entities/note) in her outbox in response to a request from Joe's instance. + + 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/federation/validation/page.mdx b/app/federation/validation/page.mdx index 493b04b..2739f39 100644 --- a/app/federation/validation/page.mdx +++ b/app/federation/validation/page.mdx @@ -6,7 +6,7 @@ export const metadata = { # Validation -Implementations **MUST** strictly validate all incoming data to ensure that it is well-formed and adheres to the Versia Protocol. If a request is invalid, the instance **MUST** return a `400 Bad Request` HTTP status code. +Implementations **MUST** strictly validate all incoming data to ensure that it is well-formed and adheres to the Versia Protocol. If a request is invalid, the instance **MUST** return a `422 Unprocessable Entity` HTTP status code. Remember that while *your* implementation may disallow or restrict some user input, other implementations may not. You **should not** apply those restrictions to data coming from other instances. @@ -16,13 +16,13 @@ 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 presence of **all required fields**, and the presence of `null` on optional fields. - 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. - Do not set arbitrary limits on the length of fields that other instances may send you. For example, a `bio` field should not be limited to 160 characters, even if your own implementation has such a limit. - - If you do set limits, they should be reasonable, well-documented and should allow Users to easily view the remote original, by, for example, linking to it. + - If you do set limits, they should be reasonable, well-documented and should allow Users to easily view the remote original, by, for example, linking to it. A limit of `100 000` characters for a `bio` field is acceptable, but a limit of `160` characters is not. - The **type**, **precision** and **scale** of all numeric fields. - For example, a `size` field on a `ContentFormat` structure should be a positive integer, not a negative number or a floating-point number. @@ -30,7 +30,7 @@ Things that should be validated include, but are not limited to: Using the same type with a higher bit count, for example using a u128 instead of a u64, is acceptable. Beware of performance impacts this may cause. -- The **validity** of all URLs and URIs (run them through your favorite URL parser, optionally fetch the linked URL). +- The **validity** of all URLs and URIs (run them through your favorite URL parser). - The **time** of all dates and times (people should not be born in the future, or in the year 0). It is your implementation's duty to reject data from other instances that does not adhere to the strict spec. **This is crucial to ensure the integrity of your instance and the network as a whole**. Allowing data that is technically valid but semantically incorrect can lead to the degradation of the entire Versia ecosystem. diff --git a/app/introduction/page.mdx b/app/introduction/page.mdx index 6274e6b..4df6f95 100644 --- a/app/introduction/page.mdx +++ b/app/introduction/page.mdx @@ -3,7 +3,7 @@ import { HeroPattern } from '@/components/HeroPattern' export const metadata = { title: 'Versia Documentation', - description: 'Introduction to the Versia Protocol, a communication medium for federated applications, leveraging the HTTP stack.', + description: 'Introduction to the Versia Protocol, a communication medium for federated applications, using the HTTP stack.', } export const sections = [ @@ -16,7 +16,7 @@ export const sections = [ # Versia Federation Protocol -The Versia Protocol is designed as a communication medium for federated applications, leveraging the HTTP stack. Its simplicity ensures ease of implementation and comprehension. {{ className: 'lead' }} +The Versia Protocol is designed as a communication medium for federated applications, using the HTTP stack. Its simplicity ensures ease of implementation and comprehension. {{ className: 'lead' }}

Thanks

diff --git a/app/philosophy/principles/page.mdx b/app/philosophy/principles/page.mdx index 0842424..7fba24e 100644 --- a/app/philosophy/principles/page.mdx +++ b/app/philosophy/principles/page.mdx @@ -28,6 +28,6 @@ Developer-facing features (e.g. shared inboxes, reply backfilling, etc.) should ## 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. +There should be **as little branching logic 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 +If there is a need for branching, nesting should be avoided: logic branches should be as flat as possible. \ No newline at end of file diff --git a/app/security/page.mdx b/app/security/page.mdx index 62cf1e6..4957a67 100644 --- a/app/security/page.mdx +++ b/app/security/page.mdx @@ -16,7 +16,7 @@ export const metadata = { Versia's security model is designed to ensure the integrity and authenticity of data, with a simple but robust system of cryptographic signatures. This system is designed to be easy to implement and understand, while still providing strong guarantees. -However, **it is of critical importance to understand the limitations of this system**. Versia's security model is designed to prevent impersonation attacks and data tampering, but it does not provide confidentiality. This means that while you can trust the data you receive, you should not assume that it is private. +However, **it is very important to understand the limitations of this system**. Versia's security model is designed to prevent impersonation attacks and data tampering, but it does not provide confidentiality. This means that while you can trust the data you receive, you should not assume that it is private. There are three main kinds of security that are commonly discussed in the context of cryptography: @@ -47,13 +47,12 @@ There are several reasons why confidentiality is not covered as part of this spe - Email - The Web - Twitter -- TCP Confidentiality is **several orders of magnitude more complex** than integrity and authenticity. It requires a completely different set of tools and assumptions, which are not feasible to reliably implement in a complex federated system (if you've ever seen `** Unable to decrypt: The sender's device has not sent us the keys for this message. **`, you know what we're talking about). Furthermore, adding more complex cryptography would make the specification significantly more complex, which would likely make it harder to implement for smaller developers with less resources. -Additionally, we would like to avoid re-creating what would essentially be a shoddier version of much stronger centralized platforms like [Signal](https://signal.org/). We feel, just like many others before us, that it is better to leave the confidentiality to the experts. +Additionally, we would like to avoid re-creating what would essentially be a shoddier version of much stronger centralized platforms like [Signal](https://signal.org/). We feel that it is better to leave the confidentiality to the experts. ## Conclusion diff --git a/app/signatures/page.mdx b/app/signatures/page.mdx index e1b4b49..9c8ba31 100644 --- a/app/signatures/page.mdx +++ b/app/signatures/page.mdx @@ -18,15 +18,15 @@ Versia uses cryptographic signatures to ensure the integrity and authenticity of A signature consists of a series of headers in an HTTP request. The following headers are used: - **`Versia-Signature`**: The signature itself, encoded in base64. -- **`Versia-Signed-By`**: Hostname of the instance that signed the request. This **MUST** be a hostname reachable over HTTPS (including port number if applicable), and **MUST NOT** be a URL. -- **`Versia-Signed-At`**: The current Unix timestamp, in seconds (no milliseconds), when the request was signed. Timezone must be UTC, like all Unix timestamps. +- **`Versia-Signed-By`**: [Domain](/api/basics#domain) of the instance authoring the request. +- **`Versia-Signed-At`**: The current Unix timestamp, in seconds (integer), 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 GET 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`. +Signatures must be put on: +- **All `POST` requests**. +- **All `GET` requests**. +- **All responses to `GET` requests** (for example, when fetching a user's profile). -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. +If a signature fails, is missing or is invalid, the instance **must** return a `401 Unauthorized` HTTP status code. If the signature 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 @@ -36,12 +36,12 @@ $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 Unix timestamp when the request was signed, in UTC seconds. +- `$0` is the HTTP method (e.g. `GET`, `POST`) in lowercase. If signing a *response*, use the method of the original request. +- `$1` is the request pathname, URL-encoded. +- `$2` is the Unix timestamp when the request was signed, in UTC seconds (integer). - `$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. +Sign this string using the instance's private key with the [Ed25519](https://en.wikipedia.org/wiki/EdDSA#Ed25519) algorithm. The resulting bytes **must** be encoded in base64. Example: ``` @@ -50,12 +50,12 @@ post /notes 1729243417 n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg= ### Verifying the Signature -To verify a signature, the instance must: +To verify a signature, the verifying instance must: - Recreate the string as described above. - 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. +- Decode the signature from base64 to the raw bytes. +- Perform a signature verification using the sender instance's public key. ### Example @@ -68,7 +68,7 @@ The following example is written in TypeScript using the WebCrypto API. } ``` -Bob can be found at `https://bob.com/.versia/v0.6/entities/User/bf44e6ad-7c0a-4560-9938-cf3fd4066511`. His instance's ed25519 private key, encoded in Base64 PKCS8, is `MC4CAQAwBQYDK2VwBCIEILrNXhbWxC/MhKQDsJOAAF1FH/R+Am5G/eZKnqNum5ro`. +Bob can be found at `https://bob.com/.versia/v0.6/entities/User/bf44e6ad-7c0a-4560-9938-cf3fd4066511`. His instance's ed25519 private key, encoded in Base64 [PKCS8](https://en.wikipedia.org/wiki/PKCS_8), is `MC4CAQAwBQYDK2VwBCIEILrNXhbWxC/MhKQDsJOAAF1FH/R+Am5G/eZKnqNum5ro`. Here's how Bob would sign the request: ```typescript @@ -131,7 +131,7 @@ On Alice's side, she would verify the signature using Bob's instance's public ke const method = request.method.toLowerCase(); const path = new URL(request.url).pathname; const signature = request.headers.get("Versia-Signature"); -const timestamp = request.headers.get("Versia-Signed-At"); +const timestamp = Number(request.headers.get("Versia-Signed-At")) * 1000; // Convert to milliseconds // Check if timestamp is within 5 minutes of the current time if (Math.abs(Date.now() - timestamp) > 300_000) { @@ -160,10 +160,10 @@ if (!isVerified) { ## 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. +Public keys are always encoded using `base64` and must be in [SPKI](https://en.wikipedia.org/wiki/Simple_public-key_infrastructure) 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 **not** merely the key's raw bytes encoded as base64. You must export the key in [SPKI](https://en.wikipedia.org/wiki/Simple_public-key_infrastructure) format, *then* encode it as base64. This is also not the commonly used "PEM" format. diff --git a/app/structures/collection/page.mdx b/app/structures/collection/page.mdx index 16172ed..e0e98ae 100644 --- a/app/structures/collection/page.mdx +++ b/app/structures/collection/page.mdx @@ -40,6 +40,7 @@ Collections are a way to represent paginated groups of entities. They are used e "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" diff --git a/app/structures/content-format/page.mdx b/app/structures/content-format/page.mdx index 66db689..a8b1d9d 100644 --- a/app/structures/content-format/page.mdx +++ b/app/structures/content-format/page.mdx @@ -127,7 +127,9 @@ It is a good idea to provide at least two versions of an image (if possible): on }, "thumbhash": "3OcRJYB4d3h/iIeHeEh3eIhw+j2w", "width": 1920, - "height": 1080 + "height": 1080, + "fps": null, + "duration": null } } ``` @@ -136,15 +138,39 @@ It is a good idea to provide at least two versions of an image (if possible): on { "text/plain": { "content": "The consequences of today are determined by the actions of the past. To change your future, alter your decisions today.", - "remote": false + "remote": false, + "description": null, + "size": null, + "hash": null, + "thumbhash": null, + "width": null, + "height": null, + "fps": null, + "duration": null }, "text/markdown": { "content": "> The consequences of today are determined by the actions of the past.\n> To change your future, alter your decisions today.", - "remote": false + "remote": false, + "description": null, + "size": null, + "hash": null, + "thumbhash": null, + "width": null, + "height": null, + "fps": null, + "duration": null }, "text/html": { "content": "

The consequences of today are determined by the actions of the past.

To change your future, alter your decisions today.

", - "remote": false + "remote": false, + "description": null, + "size": null, + "hash": null, + "thumbhash": null, + "width": null, + "height": null, + "fps": null, + "duration": null } } ``` diff --git a/app/types/page.mdx b/app/types/page.mdx index f0126d6..044c310 100644 --- a/app/types/page.mdx +++ b/app/types/page.mdx @@ -21,7 +21,6 @@ A **reference** is a way to refer to any entity within the Versia network. It is For example: `[2001:db8::1]:3000`. - ### Examples These two examples are equivalent if the instance is `example.com`: diff --git a/components/Libraries.tsx b/components/Libraries.tsx index 24f98e0..3f94ef7 100644 --- a/components/Libraries.tsx +++ b/components/Libraries.tsx @@ -6,8 +6,8 @@ import { Heading } from "./Heading"; const libraries = [ { - href: "https://github.com/versia-pub/api/tree/main/federation", - name: "@versia/federation", + href: "https://github.com/versia-pub/server/tree/main/packages/sdk", + name: "@versia/sdk", description: "Fully-featured federation toolkit with validation, signatures, parsing, and more.", logo: logoTypescript, diff --git a/components/Navigation.tsx b/components/Navigation.tsx index 5ef4a98..0c1e953 100644 --- a/components/Navigation.tsx +++ b/components/Navigation.tsx @@ -250,6 +250,7 @@ export const navigation: NavGroup[] = [ { title: "Introduction", href: "/introduction" }, { title: "SDKs", href: "/sdks" }, { title: "Entities", href: "/entities" }, + { title: "JSON", href: "/json" }, { title: "Signatures", href: "/signatures" }, { title: "Security", href: "/security" }, { title: "Federation", href: "/federation" }, @@ -321,7 +322,6 @@ export const navigation: NavGroup[] = [ { title: "Reports", href: "/extensions/reports" }, { title: "Share", href: "/extensions/share" }, { title: "Vanity", href: "/extensions/vanity" }, - { title: "WebSockets", href: "/extensions/websockets" }, ], }, ]; From 70177770b367b722bcd86dccd308b21b3e10e70a Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Sat, 7 Jun 2025 23:21:50 +0200 Subject: [PATCH 17/25] feat: :sparkles: Add link hover functionality --- bun.lock | 42 +++++++++ components/LinkPreview.tsx | 174 +++++++++++++++++++++++++++++++++++++ next.config.mjs | 5 ++ package.json | 2 + 4 files changed, 223 insertions(+) create mode 100644 components/LinkPreview.tsx diff --git a/bun.lock b/bun.lock index aa1cf01..f63f8a7 100644 --- a/bun.lock +++ b/bun.lock @@ -10,6 +10,7 @@ "@mdx-js/loader": "^3.1.0", "@mdx-js/react": "^3.1.0", "@next/mdx": "^15.3.3", + "@radix-ui/react-hover-card": "^1.1.14", "@sindresorhus/slugify": "^2.2.1", "@tailwindcss/postcss": "^4.1.8", "@tailwindcss/typography": "^0.5.16", @@ -27,6 +28,7 @@ "mdx-annotations": "^0.1.4", "next": "^15.3.3", "next-themes": "^0.4.6", + "qss": "^3.0.0", "react": "^19.1.0", "react-dom": "^19.1.0", "react-highlight-words": "^0.21.0", @@ -223,6 +225,44 @@ "@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="], + "@radix-ui/primitive": ["@radix-ui/primitive@1.1.2", "", {}, "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="], + + "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="], + + "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="], + + "@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="], + + "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ=="], + + "@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@1.1.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-popper": "1.2.7", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-CPYZ24Mhirm+g6D8jArmLzjYu4Eyg3TTUHswR26QgzXBHBe64BO/RHOJKzmF/Dxb4y4f9PKyJdwm/O/AhNkb+Q=="], + + "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.7", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ=="], + + "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="], + + "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA=="], + + "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], + + "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + + "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="], + + "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="], + + "@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="], + + "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="], + + "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="], + + "@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.1", "", { "dependencies": { "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w=="], + + "@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="], + + "@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="], + "@react-aria/focus": ["@react-aria/focus@3.20.2", "", { "dependencies": { "@react-aria/interactions": "^3.25.0", "@react-aria/utils": "^3.28.2", "@react-types/shared": "^3.29.0", "@swc/helpers": "^0.5.0", "clsx": "^2.0.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-Q3rouk/rzoF/3TuH6FzoAIKrl+kzZi9LHmr8S5EqLAOyP9TXIKG34x2j42dZsAhrw7TbF9gA8tBKwnCNH4ZV+Q=="], "@react-aria/interactions": ["@react-aria/interactions@3.25.0", "", { "dependencies": { "@react-aria/ssr": "^3.9.8", "@react-aria/utils": "^3.28.2", "@react-stately/flags": "^3.1.1", "@react-types/shared": "^3.29.0", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-GgIsDLlO8rDU/nFn6DfsbP9rfnzhm8QFjZkB9K9+r+MTSCn7bMntiWQgMM+5O6BiA8d7C7x4zuN4bZtc0RBdXQ=="], @@ -661,6 +701,8 @@ "property-information": ["property-information@7.0.0", "", {}, "sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg=="], + "qss": ["qss@3.0.0", "", {}, "sha512-ZHoCB3M/3Voev64zhLLUOKDtaEdJ/lymsJJ7R3KBusVZ2ovNiIB7XOq3Xh6V1a8O+Vho+g2B5YElq9zW7D8aQw=="], + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], "react": ["react@19.1.0", "", {}, "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg=="], diff --git a/components/LinkPreview.tsx b/components/LinkPreview.tsx new file mode 100644 index 0000000..eb11c7c --- /dev/null +++ b/components/LinkPreview.tsx @@ -0,0 +1,174 @@ +"use client"; +import * as HoverCardPrimitive from "@radix-ui/react-hover-card"; + +import { + AnimatePresence, + motion, + useMotionValue, + useSpring, +} from "framer-motion"; +import { encode } from "qss"; +import { + type MouseEvent as ReactMouseEvent, + type ReactNode, + useEffect, + useState, +} from "react"; + +import { createPortal } from "react-dom"; + +type LinkPreviewProps = { + children: ReactNode; + url: string; + className?: string; + width?: number; + height?: number; + quality?: number; + layout?: string; +} & ( + | { isStatic: true; imageSrc: string } + | { isStatic?: false; imageSrc?: never } +); + +export const LinkPreview = ({ + children, + url, + className, + width = 200, + height = 125, + isStatic = false, + imageSrc = "", +}: LinkPreviewProps) => { + let src: string; + + if (isStatic) { + src = imageSrc; + } else { + const params = encode({ + url, + screenshot: true, + meta: false, + embed: "screenshot.url", + colorScheme: "dark", + "viewport.isMobile": true, + "viewport.deviceScaleFactor": 1, + "viewport.width": width * 3, + "viewport.height": height * 3, + }); + src = `https://api.microlink.io/?${params}`; + } + + const [isOpen, setOpen] = useState(false); + + const [isMounted, setIsMounted] = useState(false); + + useEffect(() => { + setIsMounted(true); + }, []); + + const springConfig = { stiffness: 100, damping: 15 }; + const x = useMotionValue(0); + + const translateX = useSpring(x, springConfig); + + const handleMouseMove = ( + event: ReactMouseEvent, + ) => { + const targetRect = ( + event.target as HTMLAnchorElement + ).getBoundingClientRect(); + const eventOffsetX = event.clientX - targetRect.left; + const offsetFromCenter = (eventOffsetX - targetRect.width / 2) / 2; // Reduce the effect to make it subtle + x.set(offsetFromCenter); + }; + + const [isCurrentOrigin, setIsCurrentOrigin] = useState(true); + + useEffect(() => { + if (process && URL.canParse(url)) { + setIsCurrentOrigin(new URL(url).origin === window.location.origin); + } + }, [url]); + + return ( + <> + {isMounted + ? createPortal( +
+ +
, + document.body, + ) + : null} + { + setOpen(open); + }} + > + + {children} + + + + + + {isOpen && ( + + + {`Preview + + + )} + + + + + + ); +}; diff --git a/next.config.mjs b/next.config.mjs index 14c5c0d..64b6f60 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -17,6 +17,11 @@ const withMDX = nextMDX({ const nextConfig = { pageExtensions: ["js", "jsx", "ts", "tsx", "mdx"], output: "export", + images: { + domains: [ + "api.microlink.io", // Microlink Image Preview + ], + }, }; const withBundleAnalyzer = bundleAnalyzer({ diff --git a/package.json b/package.json index 87ab747..f72817d 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@mdx-js/loader": "^3.1.0", "@mdx-js/react": "^3.1.0", "@next/mdx": "^15.3.3", + "@radix-ui/react-hover-card": "^1.1.14", "@sindresorhus/slugify": "^2.2.1", "@tailwindcss/postcss": "^4.1.8", "@tailwindcss/typography": "^0.5.16", @@ -34,6 +35,7 @@ "mdx-annotations": "^0.1.4", "next": "^15.3.3", "next-themes": "^0.4.6", + "qss": "^3.0.0", "react": "^19.1.0", "react-dom": "^19.1.0", "react-highlight-words": "^0.21.0", From bf4384376ee3934f47b9798b10b864b977cf7fcc Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 15 Aug 2025 04:34:14 +0200 Subject: [PATCH 18/25] fix: :bug: Remove nonsensical sentence --- app/json/page.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/json/page.mdx b/app/json/page.mdx index 6679560..1465fbd 100644 --- a/app/json/page.mdx +++ b/app/json/page.mdx @@ -116,4 +116,4 @@ Numbers in JSON must be represented as decimal numbers. They can be integers or ### Optional Fields -Fields that are not marked as **required** may be set to `null`. These fields **must not** be omitted: they must be present with a `null` value if not set. \ No newline at end of file +Fields that are not marked as **required** may be set to `null`, or simply omitted. \ No newline at end of file From cdc1d6a6a22b310f9ed46734aff3c979cda3b93e Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 15 Aug 2025 04:53:12 +0200 Subject: [PATCH 19/25] chore: :arrow_up: Upgrade dependencies --- app/layout.tsx | 2 +- app/page.tsx | 8 +- app/providers.tsx | 2 +- biome.json | 97 ++++++---- bun.lock | 312 +++++++++++++++++--------------- components/Code.tsx | 11 +- components/Feedback.tsx | 1 - components/Footer.tsx | 3 +- components/GridPattern.tsx | 2 +- components/Guides.tsx | 6 +- components/Header.tsx | 6 +- components/MobileNavigation.tsx | 2 +- components/Navigation.tsx | 2 +- components/Property.tsx | 7 +- components/Resources.tsx | 3 +- components/Search.tsx | 3 +- components/SectionProvider.tsx | 4 +- components/mdx.tsx | 5 +- mdx/rehype.mjs | 1 - next.config.mjs | 3 +- package.json | 44 +++-- public/pl.js | 125 ++++++++++++- styles/tailwind.css | 8 +- 23 files changed, 411 insertions(+), 246 deletions(-) diff --git a/app/layout.tsx b/app/layout.tsx index 89d9395..c7d658f 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -6,8 +6,8 @@ import type { Section } from "../components/SectionProvider"; import { Providers } from "./providers"; import "@/styles/tailwind.css"; -import logo from "@/images/branding/logo.webp"; import type { ReactNode } from "react"; +import logo from "@/images/branding/logo.webp"; export const metadata: Metadata = { title: { diff --git a/app/page.tsx b/app/page.tsx index 25ef88c..f6b2d5b 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,11 +1,11 @@ +import type { Metadata } from "next"; +import Image from "next/image"; +import type { FC } from "react"; import { Guide } from "@/components/Guides"; +import { wrapper } from "@/components/mdx"; import { Resource, type ResourceType } from "@/components/Resources"; import { TeamMember } from "@/components/Team"; -import { wrapper } from "@/components/mdx"; import fastlyLogo from "@/images/logos/fastly.svg"; -import type { Metadata } from "next"; -import Image from "next/image"; -import type { FC } from "react"; export const metadata: Metadata = { title: "Versia Documentation", diff --git a/app/providers.tsx b/app/providers.tsx index db08246..26a03a1 100644 --- a/app/providers.tsx +++ b/app/providers.tsx @@ -1,8 +1,8 @@ "use client"; -import { uwuifyDocument } from "@/lib/uwuify"; import { ThemeProvider, useTheme } from "next-themes"; import { type ReactNode, useEffect } from "react"; +import { uwuifyDocument } from "@/lib/uwuify"; function ThemeWatcher() { const { resolvedTheme, setTheme } = useTheme(); diff --git a/biome.json b/biome.json index 074db76..3af7e22 100644 --- a/biome.json +++ b/biome.json @@ -1,30 +1,44 @@ { - "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", - "organizeImports": { - "enabled": true - }, + "$schema": "https://biomejs.dev/schemas/2.2.0/schema.json", + "assist": { "actions": { "source": { "organizeImports": "on" } } }, "linter": { "enabled": true, "rules": { - "all": true, + "suspicious": { + "noConsole": "off", + "noExplicitAny": "off", + "noDuplicateElseIf": "error", + "noDocumentCookie": "off", + "noReactSpecificProps": "off", + "noUnknownAtRules": "off" + }, + "performance": { + "noBarrelFile": "off", + "noNamespaceImport": "off", + "useTopLevelRegex": "off", + "noImgElement": "off" + }, "correctness": { - "noNodejsModules": "off", + "noUnknownFunction": "off", + "noUndeclaredVariables": "off", + "useHookAtTopLevel": "off", + "noUnusedVariables": "off", + "noUnusedImports": "off", + "noUndeclaredDependencies": "off", "useImportExtensions": "off", - "noUnknownFunction": "off" + "useJsxKeyInIterable": "off", + "useUniqueElementIds": "off" }, - "complexity": { - "noExcessiveCognitiveComplexity": "off" + "a11y": { + "noStaticElementInteractions": "off" }, - "suspicious": { - "noReactSpecificProps": "off" - }, - "performance": { - "useTopLevelRegex": "off" + "complexity": { + "noExcessiveCognitiveComplexity": "off", + "noImportantStyles": "off" }, "style": { "noDefaultExport": "off", "noParameterProperties": "off", - "noNamespaceImport": "off", "useFilenamingConvention": "off", "useNamingConvention": { "level": "warn", @@ -54,28 +68,22 @@ "PascalCase", "snake_case" ] - }, - { - "selector": { - "kind": "classMethod", - "scope": "any" - }, - "formats": ["camelCase", "PascalCase"] - }, - { - "selector": { - "kind": "functionParameter", - "scope": "any" - }, - "formats": ["snake_case", "camelCase"] } ] } - } + }, + "noParameterAssign": "error", + "useAsConstAssertion": "error", + "useDefaultParameterLast": "error", + "useEnumInitializers": "error", + "useSelfClosingElements": "error", + "useSingleVarDeclarator": "error", + "noUnusedTemplateLiteral": "error", + "useNumberNamespace": "error", + "noInferrableTypes": "error", + "noUselessElse": "error" }, - "nursery": { - "noDuplicateElseIf": "warn" - } + "nursery": {} } }, "formatter": { @@ -83,10 +91,27 @@ "indentStyle": "space", "indentWidth": 4 }, - "javascript": { - "globals": ["Bun"] + "overrides": [ + { + "includes": ["**/*.vue"], + "linter": { + "rules": { + "correctness": { + "noUnusedImports": "off" + }, + "style": { + "useImportType": "off" + } + } + } + } + ], + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true }, "files": { - "ignore": ["node_modules", ".next", ".output", "out", "public/pl.js"] + "includes": ["**", "!public"] } } diff --git a/bun.lock b/bun.lock index f63f8a7..83dae65 100644 --- a/bun.lock +++ b/bun.lock @@ -5,51 +5,51 @@ "name": "@versia-pub/docs", "dependencies": { "@algolia/autocomplete-core": "^1.19.2", - "@headlessui/react": "^2.2.4", + "@headlessui/react": "^2.2.7", "@headlessui/tailwindcss": "^0.2.2", "@mdx-js/loader": "^3.1.0", "@mdx-js/react": "^3.1.0", "@next/mdx": "^15.3.3", - "@radix-ui/react-hover-card": "^1.1.14", + "@radix-ui/react-hover-card": "^1.1.15", "@sindresorhus/slugify": "^2.2.1", - "@tailwindcss/postcss": "^4.1.8", + "@tailwindcss/postcss": "^4.1.12", "@tailwindcss/typography": "^0.5.16", "@types/mdx": "^2.0.13", - "@types/node": "^22.15.30", - "@types/react": "^19.1.6", - "@types/react-dom": "^19.1.6", + "@types/node": "^24.2.1", + "@types/react": "^19.1.10", + "@types/react-dom": "^19.1.7", "@types/react-highlight-words": "^0.20.0", - "acorn": "^8.14.1", + "acorn": "^8.15.0", "clsx": "^2.1.1", "fast-glob": "^3.3.3", "flexsearch": "^0.8.205", - "framer-motion": "^12.16.0", + "framer-motion": "^12.23.12", "mdast-util-to-string": "^4.0.0", "mdx-annotations": "^0.1.4", - "next": "^15.3.3", + "next": "15.3.3", "next-themes": "^0.4.6", "qss": "^3.0.0", - "react": "^19.1.0", - "react-dom": "^19.1.0", + "react": "^19.1.1", + "react-dom": "^19.1.1", "react-highlight-words": "^0.21.0", "remark": "^15.0.1", "remark-gfm": "^4.0.1", "remark-mdx": "^3.1.0", - "shiki": "^3.6.0", + "shiki": "^3.9.2", "simple-functional-loader": "^1.2.1", - "tailwindcss": "^4.1.8", - "typescript": "^5.8.3", + "tailwindcss": "^4.1.12", + "typescript": "^5.9.2", "unist-util-filter": "^5.0.1", "unist-util-visit": "^5.0.0", "uwuifier": "^4.2.2", - "zustand": "^5.0.5", + "zustand": "^5.0.7", }, "devDependencies": { - "@biomejs/biome": "^1.9.4", + "@biomejs/biome": "^2.2.0", "@iconify-icon/react": "^3.0.0", - "@next/bundle-analyzer": "^15.3.3", - "@shikijs/transformers": "^3.6.0", - "sharp": "^0.34.2", + "@next/bundle-analyzer": "^15.4.6", + "@shikijs/transformers": "^3.9.2", + "sharp": "^0.34.3", }, }, }, @@ -59,75 +59,75 @@ "@biomejs/biome", ], "packages": { + "@algolia/abtesting": ["@algolia/abtesting@1.1.0", "", { "dependencies": { "@algolia/client-common": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-sEyWjw28a/9iluA37KLGu8vjxEIlb60uxznfTUmXImy7H5NvbpSO6yYgmgH5KiD7j+zTUUihiST0jEP12IoXow=="], + "@algolia/autocomplete-core": ["@algolia/autocomplete-core@1.19.2", "", { "dependencies": { "@algolia/autocomplete-plugin-algolia-insights": "1.19.2", "@algolia/autocomplete-shared": "1.19.2" } }, "sha512-mKv7RyuAzXvwmq+0XRK8HqZXt9iZ5Kkm2huLjgn5JoCPtDy+oh9yxUMfDDaVCw0oyzZ1isdJBc7l9nuCyyR7Nw=="], "@algolia/autocomplete-plugin-algolia-insights": ["@algolia/autocomplete-plugin-algolia-insights@1.19.2", "", { "dependencies": { "@algolia/autocomplete-shared": "1.19.2" }, "peerDependencies": { "search-insights": ">= 1 < 3" } }, "sha512-TjxbcC/r4vwmnZaPwrHtkXNeqvlpdyR+oR9Wi2XyfORkiGkLTVhX2j+O9SaCCINbKoDfc+c2PB8NjfOnz7+oKg=="], "@algolia/autocomplete-shared": ["@algolia/autocomplete-shared@1.19.2", "", { "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", "algoliasearch": ">= 4.9.1 < 6" } }, "sha512-jEazxZTVD2nLrC+wYlVHQgpBoBB5KPStrJxLzsIFl6Kqd1AlG9sIAGl39V5tECLpIQzB3Qa2T6ZPJ1ChkwMK/w=="], - "@algolia/client-abtesting": ["@algolia/client-abtesting@5.23.4", "", { "dependencies": { "@algolia/client-common": "5.23.4", "@algolia/requester-browser-xhr": "5.23.4", "@algolia/requester-fetch": "5.23.4", "@algolia/requester-node-http": "5.23.4" } }, "sha512-WIMT2Kxy+FFWXWQxIU8QgbTioL+SGE24zhpj0kipG4uQbzXwONaWt7ffaYLjfge3gcGSgJVv+1VlahVckafluQ=="], + "@algolia/client-abtesting": ["@algolia/client-abtesting@5.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-uUdHxbfHdoppDVflCHMxRlj49/IllPwwQ2cQ8DLC4LXr3kY96AHBpW0dMyi6ygkn2MtFCc6BxXCzr668ZRhLBQ=="], - "@algolia/client-analytics": ["@algolia/client-analytics@5.23.4", "", { "dependencies": { "@algolia/client-common": "5.23.4", "@algolia/requester-browser-xhr": "5.23.4", "@algolia/requester-fetch": "5.23.4", "@algolia/requester-node-http": "5.23.4" } }, "sha512-4B9gChENsQA9kFmFlb+x3YhBz2Gx3vSsm81FHI1yJ3fn2zlxREHmfrjyqYoMunsU7BybT/o5Nb7ccCbm/vfseA=="], + "@algolia/client-analytics": ["@algolia/client-analytics@5.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-SunAgwa9CamLcRCPnPHx1V2uxdQwJGqb1crYrRWktWUdld0+B2KyakNEeVn5lln4VyeNtW17Ia7V7qBWyM/Skw=="], - "@algolia/client-common": ["@algolia/client-common@5.23.4", "", {}, "sha512-bsj0lwU2ytiWLtl7sPunr+oLe+0YJql9FozJln5BnIiqfKOaseSDdV42060vUy+D4373f2XBI009K/rm2IXYMA=="], + "@algolia/client-common": ["@algolia/client-common@5.35.0", "", {}, "sha512-ipE0IuvHu/bg7TjT2s+187kz/E3h5ssfTtjpg1LbWMgxlgiaZIgTTbyynM7NfpSJSKsgQvCQxWjGUO51WSCu7w=="], - "@algolia/client-insights": ["@algolia/client-insights@5.23.4", "", { "dependencies": { "@algolia/client-common": "5.23.4", "@algolia/requester-browser-xhr": "5.23.4", "@algolia/requester-fetch": "5.23.4", "@algolia/requester-node-http": "5.23.4" } }, "sha512-XSCtAYvJ/hnfDHfRVMbBH0dayR+2ofVZy3jf5qyifjguC6rwxDsSdQvXpT0QFVyG+h8UPGtDhMPoUIng4wIcZA=="], + "@algolia/client-insights": ["@algolia/client-insights@5.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-UNbCXcBpqtzUucxExwTSfAe8gknAJ485NfPN6o1ziHm6nnxx97piIbcBQ3edw823Tej2Wxu1C0xBY06KgeZ7gA=="], - "@algolia/client-personalization": ["@algolia/client-personalization@5.23.4", "", { "dependencies": { "@algolia/client-common": "5.23.4", "@algolia/requester-browser-xhr": "5.23.4", "@algolia/requester-fetch": "5.23.4", "@algolia/requester-node-http": "5.23.4" } }, "sha512-l/0QvqgRFFOf7BnKSJ3myd1WbDr86ftVaa3PQwlsNh7IpIHmvVcT83Bi5zlORozVGMwaKfyPZo6O48PZELsOeA=="], + "@algolia/client-personalization": ["@algolia/client-personalization@5.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-/KWjttZ6UCStt4QnWoDAJ12cKlQ+fkpMtyPmBgSS2WThJQdSV/4UWcqCUqGH7YLbwlj3JjNirCu3Y7uRTClxvA=="], - "@algolia/client-query-suggestions": ["@algolia/client-query-suggestions@5.23.4", "", { "dependencies": { "@algolia/client-common": "5.23.4", "@algolia/requester-browser-xhr": "5.23.4", "@algolia/requester-fetch": "5.23.4", "@algolia/requester-node-http": "5.23.4" } }, "sha512-TB0htrDgVacVGtPDyENoM6VIeYqR+pMsDovW94dfi2JoaRxfqu/tYmLpvgWcOknP6wLbr8bA+G7t/NiGksNAwQ=="], + "@algolia/client-query-suggestions": ["@algolia/client-query-suggestions@5.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-8oCuJCFf/71IYyvQQC+iu4kgViTODbXDk3m7yMctEncRSRV+u2RtDVlpGGfPlJQOrAY7OONwJlSHkmbbm2Kp/w=="], - "@algolia/client-search": ["@algolia/client-search@5.23.4", "", { "dependencies": { "@algolia/client-common": "5.23.4", "@algolia/requester-browser-xhr": "5.23.4", "@algolia/requester-fetch": "5.23.4", "@algolia/requester-node-http": "5.23.4" } }, "sha512-uBGo6KwUP6z+u6HZWRui8UJClS7fgUIAiYd1prUqCbkzDiCngTOzxaJbEvrdkK0hGCQtnPDiuNhC5MhtVNN4Eg=="], + "@algolia/client-search": ["@algolia/client-search@5.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-FfmdHTrXhIduWyyuko1YTcGLuicVbhUyRjO3HbXE4aP655yKZgdTIfMhZ/V5VY9bHuxv/fGEh3Od1Lvv2ODNTg=="], - "@algolia/ingestion": ["@algolia/ingestion@1.23.4", "", { "dependencies": { "@algolia/client-common": "5.23.4", "@algolia/requester-browser-xhr": "5.23.4", "@algolia/requester-fetch": "5.23.4", "@algolia/requester-node-http": "5.23.4" } }, "sha512-Si6rFuGnSeEUPU9QchYvbknvEIyCRK7nkeaPVQdZpABU7m4V/tsiWdHmjVodtx3h20VZivJdHeQO9XbHxBOcCw=="], + "@algolia/ingestion": ["@algolia/ingestion@1.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-gPzACem9IL1Co8mM1LKMhzn1aSJmp+Vp434An4C0OBY4uEJRcqsLN3uLBlY+bYvFg8C8ImwM9YRiKczJXRk0XA=="], - "@algolia/monitoring": ["@algolia/monitoring@1.23.4", "", { "dependencies": { "@algolia/client-common": "5.23.4", "@algolia/requester-browser-xhr": "5.23.4", "@algolia/requester-fetch": "5.23.4", "@algolia/requester-node-http": "5.23.4" } }, "sha512-EXGoVVTshraqPJgr5cMd1fq7Jm71Ew6MpGCEaxI5PErBpJAmKdtjRIzs6JOGKHRaWLi+jdbJPYc2y8RN4qcx5Q=="], + "@algolia/monitoring": ["@algolia/monitoring@1.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-w9MGFLB6ashI8BGcQoVt7iLgDIJNCn4OIu0Q0giE3M2ItNrssvb8C0xuwJQyTy1OFZnemG0EB1OvXhIHOvQwWw=="], - "@algolia/recommend": ["@algolia/recommend@5.23.4", "", { "dependencies": { "@algolia/client-common": "5.23.4", "@algolia/requester-browser-xhr": "5.23.4", "@algolia/requester-fetch": "5.23.4", "@algolia/requester-node-http": "5.23.4" } }, "sha512-1t6glwKVCkjvBNlng2itTf8fwaLSqkL4JaMENgR3WTGR8mmW2akocUy/ZYSQcG4TcR7qu4zW2UMGAwLoWoflgQ=="], + "@algolia/recommend": ["@algolia/recommend@5.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-AhrVgaaXAb8Ue0u2nuRWwugt0dL5UmRgS9LXe0Hhz493a8KFeZVUE56RGIV3hAa6tHzmAV7eIoqcWTQvxzlJeQ=="], - "@algolia/requester-browser-xhr": ["@algolia/requester-browser-xhr@5.23.4", "", { "dependencies": { "@algolia/client-common": "5.23.4" } }, "sha512-UUuizcgc5+VSY8hqzDFVdJ3Wcto03lpbFRGPgW12pHTlUQHUTADtIpIhkLLOZRCjXmCVhtr97Z+eR6LcRYXa3Q=="], + "@algolia/requester-browser-xhr": ["@algolia/requester-browser-xhr@5.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0" } }, "sha512-diY415KLJZ6x1Kbwl9u96Jsz0OstE3asjXtJ9pmk1d+5gPuQ5jQyEsgC+WmEXzlec3iuVszm8AzNYYaqw6B+Zw=="], - "@algolia/requester-fetch": ["@algolia/requester-fetch@5.23.4", "", { "dependencies": { "@algolia/client-common": "5.23.4" } }, "sha512-UhDg6elsek6NnV5z4VG1qMwR6vbp+rTMBEnl/v4hUyXQazU+CNdYkl++cpdmLwGI/7nXc28xtZiL90Es3I7viQ=="], + "@algolia/requester-fetch": ["@algolia/requester-fetch@5.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0" } }, "sha512-uydqnSmpAjrgo8bqhE9N1wgcB98psTRRQXcjc4izwMB7yRl9C8uuAQ/5YqRj04U0mMQ+fdu2fcNF6m9+Z1BzDQ=="], - "@algolia/requester-node-http": ["@algolia/requester-node-http@5.23.4", "", { "dependencies": { "@algolia/client-common": "5.23.4" } }, "sha512-jXGzGBRUS0oywQwnaCA6mMDJO7LoC3dYSLsyNfIqxDR4SNGLhtg3je0Y31lc24OA4nYyKAYgVLtjfrpcpsWShg=="], + "@algolia/requester-node-http": ["@algolia/requester-node-http@5.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0" } }, "sha512-RgLX78ojYOrThJHrIiPzT4HW3yfQa0D7K+MQ81rhxqaNyNBu4F1r+72LNHYH/Z+y9I1Mrjrd/c/Ue5zfDgAEjQ=="], "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], - "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="], - - "@biomejs/biome": ["@biomejs/biome@1.9.4", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "1.9.4", "@biomejs/cli-darwin-x64": "1.9.4", "@biomejs/cli-linux-arm64": "1.9.4", "@biomejs/cli-linux-arm64-musl": "1.9.4", "@biomejs/cli-linux-x64": "1.9.4", "@biomejs/cli-linux-x64-musl": "1.9.4", "@biomejs/cli-win32-arm64": "1.9.4", "@biomejs/cli-win32-x64": "1.9.4" }, "bin": { "biome": "bin/biome" } }, "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog=="], + "@biomejs/biome": ["@biomejs/biome@2.2.0", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.2.0", "@biomejs/cli-darwin-x64": "2.2.0", "@biomejs/cli-linux-arm64": "2.2.0", "@biomejs/cli-linux-arm64-musl": "2.2.0", "@biomejs/cli-linux-x64": "2.2.0", "@biomejs/cli-linux-x64-musl": "2.2.0", "@biomejs/cli-win32-arm64": "2.2.0", "@biomejs/cli-win32-x64": "2.2.0" }, "bin": { "biome": "bin/biome" } }, "sha512-3On3RSYLsX+n9KnoSgfoYlckYBoU6VRM22cw1gB4Y0OuUVSYd/O/2saOJMrA4HFfA1Ff0eacOvMN1yAAvHtzIw=="], - "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@1.9.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw=="], + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.2.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zKbwUUh+9uFmWfS8IFxmVD6XwqFcENjZvEyfOxHs1epjdH3wyyMQG80FGDsmauPwS2r5kXdEM0v/+dTIA9FXAg=="], - "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@1.9.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg=="], + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.2.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-+OmT4dsX2eTfhD5crUOPw3RPhaR+SKVspvGVmSdZ9y9O/AgL8pla6T4hOn1q+VAFBHuHhsdxDRJgFCSC7RaMOw=="], - "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g=="], + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.2.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-6eoRdF2yW5FnW9Lpeivh7Mayhq0KDdaDMYOJnH9aT02KuSIX5V1HmWJCQQPwIQbhDh68Zrcpl8inRlTEan0SXw=="], - "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA=="], + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.2.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-egKpOa+4FL9YO+SMUMLUvf543cprjevNc3CAgDNFLcjknuNMcZ0GLJYa3EGTCR2xIkIUJDVneBV3O9OcIlCEZQ=="], - "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg=="], + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.2.0", "", { "os": "linux", "cpu": "x64" }, "sha512-5UmQx/OZAfJfi25zAnAGHUMuOd+LOsliIt119x2soA2gLggQYrVPA+2kMUxR6Mw5M1deUF/AWWP2qpxgH7Nyfw=="], - "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg=="], + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.2.0", "", { "os": "linux", "cpu": "x64" }, "sha512-I5J85yWwUWpgJyC1CcytNSGusu2p9HjDnOPAFG4Y515hwRD0jpR9sT9/T1cKHtuCvEQ/sBvx+6zhz9l9wEJGAg=="], - "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@1.9.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg=="], + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.2.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-n9a1/f2CwIDmNMNkFs+JI0ZjFnMO0jdOyGNtihgUNFnlmd84yIYY2KMTBmMV58ZlVHjgmY5Y6E1hVTnSRieggA=="], - "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@1.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA=="], + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.2.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Nawu5nHjP/zPKTIryh2AavzTc/KEg4um/MxWdXW0A6P/RZOyIpa7+QSjeXwAwX/utJGaCoXRPWtF3m5U/bB3Ww=="], "@discoveryjs/json-ext": ["@discoveryjs/json-ext@0.5.7", "", {}, "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw=="], - "@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="], + "@emnapi/runtime": ["@emnapi/runtime@1.4.5", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg=="], - "@floating-ui/core": ["@floating-ui/core@1.6.9", "", { "dependencies": { "@floating-ui/utils": "^0.2.9" } }, "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw=="], + "@floating-ui/core": ["@floating-ui/core@1.7.3", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w=="], - "@floating-ui/dom": ["@floating-ui/dom@1.6.13", "", { "dependencies": { "@floating-ui/core": "^1.6.0", "@floating-ui/utils": "^0.2.9" } }, "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w=="], + "@floating-ui/dom": ["@floating-ui/dom@1.7.3", "", { "dependencies": { "@floating-ui/core": "^1.7.3", "@floating-ui/utils": "^0.2.10" } }, "sha512-uZA413QEpNuhtb3/iIKoYMSK07keHPYeXF02Zhd6e213j+d1NamLix/mCLxBUDW/Gx52sPH2m+chlUsyaBs/Ag=="], "@floating-ui/react": ["@floating-ui/react@0.26.28", "", { "dependencies": { "@floating-ui/react-dom": "^2.1.2", "@floating-ui/utils": "^0.2.8", "tabbable": "^6.0.0" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw=="], - "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.2", "", { "dependencies": { "@floating-ui/dom": "^1.0.0" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A=="], + "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.5", "", { "dependencies": { "@floating-ui/dom": "^1.7.3" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-HDO/1/1oH9fjj4eLgegrlH3dklZpHtUYYFiVwMUwfGvk9jWDRWqkklA2/NFScknrcNSspbV868WjXORvreDX+Q=="], - "@floating-ui/utils": ["@floating-ui/utils@0.2.9", "", {}, "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg=="], + "@floating-ui/utils": ["@floating-ui/utils@0.2.10", "", {}, "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="], - "@headlessui/react": ["@headlessui/react@2.2.4", "", { "dependencies": { "@floating-ui/react": "^0.26.16", "@react-aria/focus": "^3.20.2", "@react-aria/interactions": "^3.25.0", "@tanstack/react-virtual": "^3.13.9", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, "sha512-lz+OGcAH1dK93rgSMzXmm1qKOJkBUqZf1L4M8TWLNplftQD3IkoEDdUFNfAn4ylsN6WOTVtWaLmvmaHOUk1dTA=="], + "@headlessui/react": ["@headlessui/react@2.2.7", "", { "dependencies": { "@floating-ui/react": "^0.26.16", "@react-aria/focus": "^3.20.2", "@react-aria/interactions": "^3.25.0", "@tanstack/react-virtual": "^3.13.9", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, "sha512-WKdTymY8Y49H8/gUc/lIyYK1M+/6dq0Iywh4zTZVAaiTDprRfioxSgD0wnXTQTBpjpGJuTL1NO/mqEvc//5SSg=="], "@headlessui/tailwindcss": ["@headlessui/tailwindcss@0.2.2", "", { "peerDependencies": { "tailwindcss": "^3.0 || ^4.0" } }, "sha512-xNe42KjdyA4kfUKLLPGzME9zkH7Q3rOZ5huFihWNWOQFxnItxPB3/67yBI8/qBfY8nwBRx5GHn4VprsoluVMGw=="], @@ -135,59 +135,61 @@ "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="], - "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.1.0" }, "os": "darwin", "cpu": "arm64" }, "sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg=="], + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.3", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.0" }, "os": "darwin", "cpu": "arm64" }, "sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg=="], + + "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.3", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.0" }, "os": "darwin", "cpu": "x64" }, "sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA=="], - "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.1.0" }, "os": "darwin", "cpu": "x64" }, "sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g=="], + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ=="], - "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.1.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA=="], + "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg=="], - "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.1.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ=="], + "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.0", "", { "os": "linux", "cpu": "arm" }, "sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw=="], - "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.1.0", "", { "os": "linux", "cpu": "arm" }, "sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA=="], + "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA=="], - "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.1.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew=="], + "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ=="], - "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.1.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ=="], + "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw=="], - "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.1.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA=="], + "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.0", "", { "os": "linux", "cpu": "x64" }, "sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg=="], - "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.1.0", "", { "os": "linux", "cpu": "x64" }, "sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q=="], + "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q=="], - "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.1.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w=="], + "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.0", "", { "os": "linux", "cpu": "x64" }, "sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q=="], - "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.1.0", "", { "os": "linux", "cpu": "x64" }, "sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A=="], + "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.3", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.0" }, "os": "linux", "cpu": "arm" }, "sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A=="], - "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.1.0" }, "os": "linux", "cpu": "arm" }, "sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ=="], + "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.3", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.0" }, "os": "linux", "cpu": "arm64" }, "sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA=="], - "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.1.0" }, "os": "linux", "cpu": "arm64" }, "sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q=="], + "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.3", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.0" }, "os": "linux", "cpu": "ppc64" }, "sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA=="], - "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.1.0" }, "os": "linux", "cpu": "s390x" }, "sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw=="], + "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.3", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.0" }, "os": "linux", "cpu": "s390x" }, "sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ=="], - "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.1.0" }, "os": "linux", "cpu": "x64" }, "sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ=="], + "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.3", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.0" }, "os": "linux", "cpu": "x64" }, "sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ=="], - "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.1.0" }, "os": "linux", "cpu": "arm64" }, "sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA=="], + "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.3", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.0" }, "os": "linux", "cpu": "arm64" }, "sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ=="], - "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.1.0" }, "os": "linux", "cpu": "x64" }, "sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA=="], + "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.3", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.0" }, "os": "linux", "cpu": "x64" }, "sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ=="], - "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.2", "", { "dependencies": { "@emnapi/runtime": "^1.4.3" }, "cpu": "none" }, "sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ=="], + "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.3", "", { "dependencies": { "@emnapi/runtime": "^1.4.4" }, "cpu": "none" }, "sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg=="], - "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-cfP/r9FdS63VA5k0xiqaNaEoGxBg9k7uE+RQGzuK9fHt7jib4zAVVseR9LsE4gJcNWgT6APKMNnCcnyOtmSEUQ=="], + "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ=="], - "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLjGGvAbj0X/FXl8n1WbtQ6iVBpWU7JO94u/P2M4a8CFYsvQi4GW2mRy/JqkRx0qpBzaOdKJKw8uc930EX2AHw=="], + "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw=="], - "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.2", "", { "os": "win32", "cpu": "x64" }, "sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw=="], + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.3", "", { "os": "win32", "cpu": "x64" }, "sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g=="], "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], - "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="], + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], - "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], - "@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="], + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], - "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="], + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], - "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.30", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q=="], "@mdx-js/loader": ["@mdx-js/loader@3.1.0", "", { "dependencies": { "@mdx-js/mdx": "^3.0.0", "source-map": "^0.7.0" }, "peerDependencies": { "webpack": ">=5" }, "optionalPeers": ["webpack"] }, "sha512-xU/lwKdOyfXtQGqn3VnJjlDrmKXEvMi1mgYxVmukEUtVycIz1nh7oQ40bKTd4cA7rLStqu0740pnhGYxGoqsCg=="], @@ -195,11 +197,11 @@ "@mdx-js/react": ["@mdx-js/react@3.1.0", "", { "dependencies": { "@types/mdx": "^2.0.0" }, "peerDependencies": { "@types/react": ">=16", "react": ">=16" } }, "sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ=="], - "@next/bundle-analyzer": ["@next/bundle-analyzer@15.3.3", "", { "dependencies": { "webpack-bundle-analyzer": "4.10.1" } }, "sha512-9gddnjACK6yOa5IkmeFyzcwZh2rscsb6ZspTd7tymPYKQM96fJuKjn9HrRtPNKiMm7ExKNadAJqREmHdBgHZ9A=="], + "@next/bundle-analyzer": ["@next/bundle-analyzer@15.4.6", "", { "dependencies": { "webpack-bundle-analyzer": "4.10.1" } }, "sha512-LZWqTQgIpfhblT77VVc1r4qtHJY1pfZOAIx8zNtliU7L3pMjpNrG4rYWikJ7AyAI/RgYyt2sCVWqkeOZmFp7Zg=="], "@next/env": ["@next/env@15.3.3", "", {}, "sha512-OdiMrzCl2Xi0VTjiQQUK0Xh7bJHnOuET2s+3V+Y40WJBAXrJeGA3f+I8MZJ/YQ3mVGi5XGR1L66oFlgqXhQ4Vw=="], - "@next/mdx": ["@next/mdx@15.3.3", "", { "dependencies": { "source-map": "^0.7.0" }, "peerDependencies": { "@mdx-js/loader": ">=0.15.0", "@mdx-js/react": ">=0.15.0" }, "optionalPeers": ["@mdx-js/loader", "@mdx-js/react"] }, "sha512-kJI7E/353vsoGa2usU/P36gDSA0iVc9xqJFFiPgLrSgWlivkANTRXjrnNVmVpHZ6ETmiZP52fMuKwmT9/FSmNQ=="], + "@next/mdx": ["@next/mdx@15.4.6", "", { "dependencies": { "source-map": "^0.7.0" }, "peerDependencies": { "@mdx-js/loader": ">=0.15.0", "@mdx-js/react": ">=0.15.0" }, "optionalPeers": ["@mdx-js/loader", "@mdx-js/react"] }, "sha512-PpJcNWNDq3WctJI2LY7Jur6qTdWklZ3BmbBlS9zG9MvmphcU91MoF/udPmRS1huRSVibGGteXMELu8MXYxjU9g=="], "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@15.3.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-WRJERLuH+O3oYB4yZNVahSVFmtxRNjNF1I1c34tYMoJb0Pve+7/RaLAJJizyYiFhjYNGHRAE1Ri2Fd23zgDqhg=="], @@ -225,7 +227,7 @@ "@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="], - "@radix-ui/primitive": ["@radix-ui/primitive@1.1.2", "", {}, "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="], + "@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="], "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="], @@ -233,15 +235,15 @@ "@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="], - "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ=="], + "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="], - "@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@1.1.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-popper": "1.2.7", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-CPYZ24Mhirm+g6D8jArmLzjYu4Eyg3TTUHswR26QgzXBHBe64BO/RHOJKzmF/Dxb4y4f9PKyJdwm/O/AhNkb+Q=="], + "@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg=="], - "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.7", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ=="], + "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="], "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="], - "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA=="], + "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="], "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], @@ -263,33 +265,33 @@ "@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="], - "@react-aria/focus": ["@react-aria/focus@3.20.2", "", { "dependencies": { "@react-aria/interactions": "^3.25.0", "@react-aria/utils": "^3.28.2", "@react-types/shared": "^3.29.0", "@swc/helpers": "^0.5.0", "clsx": "^2.0.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-Q3rouk/rzoF/3TuH6FzoAIKrl+kzZi9LHmr8S5EqLAOyP9TXIKG34x2j42dZsAhrw7TbF9gA8tBKwnCNH4ZV+Q=="], + "@react-aria/focus": ["@react-aria/focus@3.21.0", "", { "dependencies": { "@react-aria/interactions": "^3.25.4", "@react-aria/utils": "^3.30.0", "@react-types/shared": "^3.31.0", "@swc/helpers": "^0.5.0", "clsx": "^2.0.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-7NEGtTPsBy52EZ/ToVKCu0HSelE3kq9qeis+2eEq90XSuJOMaDHUQrA7RC2Y89tlEwQB31bud/kKRi9Qme1dkA=="], - "@react-aria/interactions": ["@react-aria/interactions@3.25.0", "", { "dependencies": { "@react-aria/ssr": "^3.9.8", "@react-aria/utils": "^3.28.2", "@react-stately/flags": "^3.1.1", "@react-types/shared": "^3.29.0", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-GgIsDLlO8rDU/nFn6DfsbP9rfnzhm8QFjZkB9K9+r+MTSCn7bMntiWQgMM+5O6BiA8d7C7x4zuN4bZtc0RBdXQ=="], + "@react-aria/interactions": ["@react-aria/interactions@3.25.4", "", { "dependencies": { "@react-aria/ssr": "^3.9.10", "@react-aria/utils": "^3.30.0", "@react-stately/flags": "^3.1.2", "@react-types/shared": "^3.31.0", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-HBQMxgUPHrW8V63u9uGgBymkMfj6vdWbB0GgUJY49K9mBKMsypcHeWkWM6+bF7kxRO728/IK8bWDV6whDbqjHg=="], - "@react-aria/ssr": ["@react-aria/ssr@3.9.8", "", { "dependencies": { "@swc/helpers": "^0.5.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-lQDE/c9uTfBSDOjaZUJS8xP2jCKVk4zjQeIlCH90xaLhHDgbpCdns3xvFpJJujfj3nI4Ll9K7A+ONUBDCASOuw=="], + "@react-aria/ssr": ["@react-aria/ssr@3.9.10", "", { "dependencies": { "@swc/helpers": "^0.5.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ=="], - "@react-aria/utils": ["@react-aria/utils@3.28.2", "", { "dependencies": { "@react-aria/ssr": "^3.9.8", "@react-stately/flags": "^3.1.1", "@react-stately/utils": "^3.10.6", "@react-types/shared": "^3.29.0", "@swc/helpers": "^0.5.0", "clsx": "^2.0.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-J8CcLbvnQgiBn54eeEvQQbIOfBF3A1QizxMw9P4cl9MkeR03ug7RnjTIdJY/n2p7t59kLeAB3tqiczhcj+Oi5w=="], + "@react-aria/utils": ["@react-aria/utils@3.30.0", "", { "dependencies": { "@react-aria/ssr": "^3.9.10", "@react-stately/flags": "^3.1.2", "@react-stately/utils": "^3.10.8", "@react-types/shared": "^3.31.0", "@swc/helpers": "^0.5.0", "clsx": "^2.0.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-ydA6y5G1+gbem3Va2nczj/0G0W7/jUVo/cbN10WA5IizzWIwMP5qhFr7macgbKfHMkZ+YZC3oXnt2NNre5odKw=="], - "@react-stately/flags": ["@react-stately/flags@3.1.1", "", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-XPR5gi5LfrPdhxZzdIlJDz/B5cBf63l4q6/AzNqVWFKgd0QqY5LvWJftXkklaIUpKSJkIKQb8dphuZXDtkWNqg=="], + "@react-stately/flags": ["@react-stately/flags@3.1.2", "", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-2HjFcZx1MyQXoPqcBGALwWWmgFVUk2TuKVIQxCbRq7fPyWXIl6VHcakCLurdtYC2Iks7zizvz0Idv48MQ38DWg=="], - "@react-stately/utils": ["@react-stately/utils@3.10.6", "", { "dependencies": { "@swc/helpers": "^0.5.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-O76ip4InfTTzAJrg8OaZxKU4vvjMDOpfA/PGNOytiXwBbkct2ZeZwaimJ8Bt9W1bj5VsZ81/o/tW4BacbdDOMA=="], + "@react-stately/utils": ["@react-stately/utils@3.10.8", "", { "dependencies": { "@swc/helpers": "^0.5.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-SN3/h7SzRsusVQjQ4v10LaVsDc81jyyR0DD5HnsQitm/I5WDpaSr2nRHtyloPFU48jlql1XX/S04T2DLQM7Y3g=="], - "@react-types/shared": ["@react-types/shared@3.29.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-IDQYu/AHgZimObzCFdNl1LpZvQW/xcfLt3v20sorl5qRucDVj4S9os98sVTZ4IRIBjmS+MkjqpR5E70xan7ooA=="], + "@react-types/shared": ["@react-types/shared@3.31.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-ua5U6V66gDcbLZe4P2QeyNgPp4YWD1ymGA6j3n+s8CGExtrCPe64v+g4mvpT8Bnb985R96e4zFT61+m0YCwqMg=="], - "@shikijs/core": ["@shikijs/core@3.6.0", "", { "dependencies": { "@shikijs/types": "3.6.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-9By7Xb3olEX0o6UeJyPLI1PE1scC4d3wcVepvtv2xbuN9/IThYN4Wcwh24rcFeASzPam11MCq8yQpwwzCgSBRw=="], + "@shikijs/core": ["@shikijs/core@3.9.2", "", { "dependencies": { "@shikijs/types": "3.9.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-3q/mzmw09B2B6PgFNeiaN8pkNOixWS726IHmJEpjDAcneDPMQmUg2cweT9cWXY4XcyQS3i6mOOUgQz9RRUP6HA=="], - "@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.6.0", "", { "dependencies": { "@shikijs/types": "3.6.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-7YnLhZG/TU05IHMG14QaLvTW/9WiK8SEYafceccHUSXs2Qr5vJibUwsDfXDLmRi0zHdzsxrGKpSX6hnqe0k8nA=="], + "@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.9.2", "", { "dependencies": { "@shikijs/types": "3.9.2", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-kUTRVKPsB/28H5Ko6qEsyudBiWEDLst+Sfi+hwr59E0GLHV0h8RfgbQU7fdN5Lt9A8R1ulRiZyTvAizkROjwDA=="], - "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.6.0", "", { "dependencies": { "@shikijs/types": "3.6.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-nmOhIZ9yT3Grd+2plmW/d8+vZ2pcQmo/UnVwXMUXAKTXdi+LK0S08Ancrz5tQQPkxvjBalpMW2aKvwXfelauvA=="], + "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.9.2", "", { "dependencies": { "@shikijs/types": "3.9.2", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-Vn/w5oyQ6TUgTVDIC/BrpXwIlfK6V6kGWDVVz2eRkF2v13YoENUvaNwxMsQU/t6oCuZKzqp9vqtEtEzKl9VegA=="], - "@shikijs/langs": ["@shikijs/langs@3.6.0", "", { "dependencies": { "@shikijs/types": "3.6.0" } }, "sha512-IdZkQJaLBu1LCYCwkr30hNuSDfllOT8RWYVZK1tD2J03DkiagYKRxj/pDSl8Didml3xxuyzUjgtioInwEQM/TA=="], + "@shikijs/langs": ["@shikijs/langs@3.9.2", "", { "dependencies": { "@shikijs/types": "3.9.2" } }, "sha512-X1Q6wRRQXY7HqAuX3I8WjMscjeGjqXCg/Sve7J2GWFORXkSrXud23UECqTBIdCSNKJioFtmUGJQNKtlMMZMn0w=="], - "@shikijs/themes": ["@shikijs/themes@3.6.0", "", { "dependencies": { "@shikijs/types": "3.6.0" } }, "sha512-Fq2j4nWr1DF4drvmhqKq8x5vVQ27VncF8XZMBuHuQMZvUSS3NBgpqfwz/FoGe36+W6PvniZ1yDlg2d4kmYDU6w=="], + "@shikijs/themes": ["@shikijs/themes@3.9.2", "", { "dependencies": { "@shikijs/types": "3.9.2" } }, "sha512-6z5lBPBMRfLyyEsgf6uJDHPa6NAGVzFJqH4EAZ+03+7sedYir2yJBRu2uPZOKmj43GyhVHWHvyduLDAwJQfDjA=="], - "@shikijs/transformers": ["@shikijs/transformers@3.6.0", "", { "dependencies": { "@shikijs/core": "3.6.0", "@shikijs/types": "3.6.0" } }, "sha512-PYkU54lYV0RCaUG8n2FNTF+YWiU3uPhcjLGq2x/C8lIrUX9GVnRb3bK+R5xtdFHbuctntATKm7ondp/H/dux9Q=="], + "@shikijs/transformers": ["@shikijs/transformers@3.9.2", "", { "dependencies": { "@shikijs/core": "3.9.2", "@shikijs/types": "3.9.2" } }, "sha512-MW5hT4TyUp6bNAgTExRYLk1NNasVQMTCw1kgbxHcEC0O5cbepPWaB+1k+JzW9r3SP2/R8kiens8/3E6hGKfgsA=="], - "@shikijs/types": ["@shikijs/types@3.6.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-cLWFiToxYu0aAzJqhXTQsFiJRTFDAGl93IrMSBNaGSzs7ixkLfdG6pH11HipuWFGW5vyx4X47W8HDQ7eSrmBUg=="], + "@shikijs/types": ["@shikijs/types@3.9.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-/M5L0Uc2ljyn2jKvj4Yiah7ow/W+DJSglVafvWAJ/b8AZDeeRAdMu3c2riDzB7N42VD+jSnWxeP9AKtd4TfYVw=="], "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], @@ -301,45 +303,45 @@ "@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="], - "@tailwindcss/node": ["@tailwindcss/node@4.1.8", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.30.1", "magic-string": "^0.30.17", "source-map-js": "^1.2.1", "tailwindcss": "4.1.8" } }, "sha512-OWwBsbC9BFAJelmnNcrKuf+bka2ZxCE2A4Ft53Tkg4uoiE67r/PMEYwCsourC26E+kmxfwE0hVzMdxqeW+xu7Q=="], + "@tailwindcss/node": ["@tailwindcss/node@4.1.12", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.5.1", "lightningcss": "1.30.1", "magic-string": "^0.30.17", "source-map-js": "^1.2.1", "tailwindcss": "4.1.12" } }, "sha512-3hm9brwvQkZFe++SBt+oLjo4OLDtkvlE8q2WalaD/7QWaeM7KEJbAiY/LJZUaCs7Xa8aUu4xy3uoyX4q54UVdQ=="], - "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.8", "", { "dependencies": { "detect-libc": "^2.0.4", "tar": "^7.4.3" }, "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.8", "@tailwindcss/oxide-darwin-arm64": "4.1.8", "@tailwindcss/oxide-darwin-x64": "4.1.8", "@tailwindcss/oxide-freebsd-x64": "4.1.8", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.8", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.8", "@tailwindcss/oxide-linux-arm64-musl": "4.1.8", "@tailwindcss/oxide-linux-x64-gnu": "4.1.8", "@tailwindcss/oxide-linux-x64-musl": "4.1.8", "@tailwindcss/oxide-wasm32-wasi": "4.1.8", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.8", "@tailwindcss/oxide-win32-x64-msvc": "4.1.8" } }, "sha512-d7qvv9PsM5N3VNKhwVUhpK6r4h9wtLkJ6lz9ZY9aeZgrUWk1Z8VPyqyDT9MZlem7GTGseRQHkeB1j3tC7W1P+A=="], + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.12", "", { "dependencies": { "detect-libc": "^2.0.4", "tar": "^7.4.3" }, "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.12", "@tailwindcss/oxide-darwin-arm64": "4.1.12", "@tailwindcss/oxide-darwin-x64": "4.1.12", "@tailwindcss/oxide-freebsd-x64": "4.1.12", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.12", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.12", "@tailwindcss/oxide-linux-arm64-musl": "4.1.12", "@tailwindcss/oxide-linux-x64-gnu": "4.1.12", "@tailwindcss/oxide-linux-x64-musl": "4.1.12", "@tailwindcss/oxide-wasm32-wasi": "4.1.12", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.12", "@tailwindcss/oxide-win32-x64-msvc": "4.1.12" } }, "sha512-gM5EoKHW/ukmlEtphNwaGx45fGoEmP10v51t9unv55voWh6WrOL19hfuIdo2FjxIaZzw776/BUQg7Pck++cIVw=="], - "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.8", "", { "os": "android", "cpu": "arm64" }, "sha512-Fbz7qni62uKYceWYvUjRqhGfZKwhZDQhlrJKGtnZfuNtHFqa8wmr+Wn74CTWERiW2hn3mN5gTpOoxWKk0jRxjg=="], + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.12", "", { "os": "android", "cpu": "arm64" }, "sha512-oNY5pq+1gc4T6QVTsZKwZaGpBb2N1H1fsc1GD4o7yinFySqIuRZ2E4NvGasWc6PhYJwGK2+5YT1f9Tp80zUQZQ=="], - "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RdRvedGsT0vwVVDztvyXhKpsU2ark/BjgG0huo4+2BluxdXo8NDgzl77qh0T1nUxmM11eXwR8jA39ibvSTbi7A=="], + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-cq1qmq2HEtDV9HvZlTtrj671mCdGB93bVY6J29mwCyaMYCP/JaUBXxrQQQm7Qn33AXXASPUb2HFZlWiiHWFytw=="], - "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-t6PgxjEMLp5Ovf7uMb2OFmb3kqzVTPPakWpBIFzppk4JE4ix0yEtbtSjPbU8+PZETpaYMtXvss2Sdkx8Vs4XRw=="], + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-6UCsIeFUcBfpangqlXay9Ffty9XhFH1QuUFn0WV83W8lGdX8cD5/+2ONLluALJD5+yJ7k8mVtwy3zMZmzEfbLg=="], - "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-g8C8eGEyhHTqwPStSwZNSrOlyx0bhK/V/+zX0Y+n7DoRUzyS8eMbVshVOLJTDDC+Qn9IJnilYbIKzpB9n4aBsg=="], + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JOH/f7j6+nYXIrHobRYCtoArJdMJh5zy5lr0FV0Qu47MID/vqJAY3r/OElPzx1C/wdT1uS7cPq+xdYYelny1ww=="], - "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.8", "", { "os": "linux", "cpu": "arm" }, "sha512-Jmzr3FA4S2tHhaC6yCjac3rGf7hG9R6Gf2z9i9JFcuyy0u79HfQsh/thifbYTF2ic82KJovKKkIB6Z9TdNhCXQ=="], + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.12", "", { "os": "linux", "cpu": "arm" }, "sha512-v4Ghvi9AU1SYgGr3/j38PD8PEe6bRfTnNSUE3YCMIRrrNigCFtHZ2TCm8142X8fcSqHBZBceDx+JlFJEfNg5zQ=="], - "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-qq7jXtO1+UEtCmCeBBIRDrPFIVI4ilEQ97qgBGdwXAARrUqSn/L9fUrkb1XP/mvVtoVeR2bt/0L77xx53bPZ/Q=="], + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-YP5s1LmetL9UsvVAKusHSyPlzSRqYyRB0f+Kl/xcYQSPLEw/BvGfxzbH+ihUciePDjiXwHh+p+qbSP3SlJw+6g=="], - "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-O6b8QesPbJCRshsNApsOIpzKt3ztG35gfX9tEf4arD7mwNinsoCKxkj8TgEE0YRjmjtO3r9FlJnT/ENd9EVefQ=="], + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-V8pAM3s8gsrXcCv6kCHSuwyb/gPsd863iT+v1PGXC4fSL/OJqsKhfK//v8P+w9ThKIoqNbEnsZqNy+WDnwQqCA=="], - "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.8", "", { "os": "linux", "cpu": "x64" }, "sha512-32iEXX/pXwikshNOGnERAFwFSfiltmijMIAbUhnNyjFr3tmWmMJWQKU2vNcFX0DACSXJ3ZWcSkzNbaKTdngH6g=="], + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.12", "", { "os": "linux", "cpu": "x64" }, "sha512-xYfqYLjvm2UQ3TZggTGrwxjYaLB62b1Wiysw/YE3Yqbh86sOMoTn0feF98PonP7LtjsWOWcXEbGqDL7zv0uW8Q=="], - "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.8", "", { "os": "linux", "cpu": "x64" }, "sha512-s+VSSD+TfZeMEsCaFaHTaY5YNj3Dri8rST09gMvYQKwPphacRG7wbuQ5ZJMIJXN/puxPcg/nU+ucvWguPpvBDg=="], + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.12", "", { "os": "linux", "cpu": "x64" }, "sha512-ha0pHPamN+fWZY7GCzz5rKunlv9L5R8kdh+YNvP5awe3LtuXb5nRi/H27GeL2U+TdhDOptU7T6Is7mdwh5Ar3A=="], - "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.8", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@emnapi/wasi-threads": "^1.0.2", "@napi-rs/wasm-runtime": "^0.2.10", "@tybys/wasm-util": "^0.9.0", "tslib": "^2.8.0" }, "cpu": "none" }, "sha512-CXBPVFkpDjM67sS1psWohZ6g/2/cd+cq56vPxK4JeawelxwK4YECgl9Y9TjkE2qfF+9/s1tHHJqrC4SS6cVvSg=="], + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.12", "", { "dependencies": { "@emnapi/core": "^1.4.5", "@emnapi/runtime": "^1.4.5", "@emnapi/wasi-threads": "^1.0.4", "@napi-rs/wasm-runtime": "^0.2.12", "@tybys/wasm-util": "^0.10.0", "tslib": "^2.8.0" }, "cpu": "none" }, "sha512-4tSyu3dW+ktzdEpuk6g49KdEangu3eCYoqPhWNsZgUhyegEda3M9rG0/j1GV/JjVVsj+lG7jWAyrTlLzd/WEBg=="], - "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-7GmYk1n28teDHUjPlIx4Z6Z4hHEgvP5ZW2QS9ygnDAdI/myh3HTHjDqtSqgu1BpRoI4OiLx+fThAyA1JePoENA=="], + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-iGLyD/cVP724+FGtMWslhcFyg4xyYyM+5F4hGvKA7eifPkXHRAUDFaimu53fpNg9X8dfP75pXx/zFt/jlNF+lg=="], - "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.8", "", { "os": "win32", "cpu": "x64" }, "sha512-fou+U20j+Jl0EHwK92spoWISON2OBnCazIc038Xj2TdweYV33ZRkS9nwqiUi2d/Wba5xg5UoHfvynnb/UB49cQ=="], + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.12", "", { "os": "win32", "cpu": "x64" }, "sha512-NKIh5rzw6CpEodv/++r0hGLlfgT/gFN+5WNdZtvh6wpU2BpGNgdjvj6H2oFc8nCM839QM1YOhjpgbAONUb4IxA=="], - "@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.8", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.8", "@tailwindcss/oxide": "4.1.8", "postcss": "^8.4.41", "tailwindcss": "4.1.8" } }, "sha512-vB/vlf7rIky+w94aWMw34bWW1ka6g6C3xIOdICKX2GC0VcLtL6fhlLiafF0DVIwa9V6EHz8kbWMkS2s2QvvNlw=="], + "@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.12", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.12", "@tailwindcss/oxide": "4.1.12", "postcss": "^8.4.41", "tailwindcss": "4.1.12" } }, "sha512-5PpLYhCAwf9SJEeIsSmCDLgyVfdBhdBpzX1OJ87anT9IVR0Z9pjM0FNixCAUAHGnMBGB8K99SwAheXrT0Kh6QQ=="], "@tailwindcss/typography": ["@tailwindcss/typography@0.5.16", "", { "dependencies": { "lodash.castarray": "^4.4.0", "lodash.isplainobject": "^4.0.6", "lodash.merge": "^4.6.2", "postcss-selector-parser": "6.0.10" }, "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" } }, "sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA=="], - "@tanstack/react-virtual": ["@tanstack/react-virtual@3.13.9", "", { "dependencies": { "@tanstack/virtual-core": "3.13.9" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-SPWC8kwG/dWBf7Py7cfheAPOxuvIv4fFQ54PdmYbg7CpXfsKxkucak43Q0qKsxVthhUJQ1A7CIMAIplq4BjVwA=="], + "@tanstack/react-virtual": ["@tanstack/react-virtual@3.13.12", "", { "dependencies": { "@tanstack/virtual-core": "3.13.12" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Gd13QdxPSukP8ZrkbgS2RwoZseTTbQPLnQEn7HY/rqtM+8Zt95f7xKC7N0EsKs7aoz0WzZ+fditZux+F8EzYxA=="], - "@tanstack/virtual-core": ["@tanstack/virtual-core@3.13.9", "", {}, "sha512-3jztt0jpaoJO5TARe2WIHC1UQC3VMLAFUW5mmMo0yrkwtDB2AQP0+sh10BVUpWrnvHjSLvzFizydtEGLCJKFoQ=="], + "@tanstack/virtual-core": ["@tanstack/virtual-core@3.13.12", "", {}, "sha512-1YBOJfRHV4sXUmWsFSf5rQor4Ss82G8dQWLRbnk3GA4jeP8hQt1hxXh0tmflpC0dz3VgEv/1+qwPyLeWkQuPFA=="], "@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="], - "@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="], + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], "@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="], @@ -351,11 +353,11 @@ "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], - "@types/node": ["@types/node@22.15.30", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-6Q7lr06bEHdlfplU6YRbgG1SFBdlsfNC4/lX+SkhiTs0cpJkOElmWls8PxDFv4yY/xKb8Y6SO0OmSX4wgqTZbA=="], + "@types/node": ["@types/node@24.2.1", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ=="], - "@types/react": ["@types/react@19.1.6", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-JeG0rEWak0N6Itr6QUx+X60uQmN+5t3j9r/OVDtWzFXKaj6kD1BwJzOksD0FF6iWxZlbE1kB0q9vtnU2ekqa1Q=="], + "@types/react": ["@types/react@19.1.10", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg=="], - "@types/react-dom": ["@types/react-dom@19.1.6", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw=="], + "@types/react-dom": ["@types/react-dom@19.1.7", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw=="], "@types/react-highlight-words": ["@types/react-highlight-words@0.20.0", "", { "dependencies": { "@types/react": "*" } }, "sha512-Qm512TiOakvtNzHJ2+TNVHnLn5cJ2wLQV0+LrhuispVth6dRf5b8ydjq3Kc0thpZ7bz4s6RnG6meboAXHWRK+Q=="], @@ -363,13 +365,13 @@ "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], - "acorn": ["acorn@8.14.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg=="], + "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], "acorn-walk": ["acorn-walk@8.3.4", "", { "dependencies": { "acorn": "^8.11.0" } }, "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g=="], - "algoliasearch": ["algoliasearch@5.23.4", "", { "dependencies": { "@algolia/client-abtesting": "5.23.4", "@algolia/client-analytics": "5.23.4", "@algolia/client-common": "5.23.4", "@algolia/client-insights": "5.23.4", "@algolia/client-personalization": "5.23.4", "@algolia/client-query-suggestions": "5.23.4", "@algolia/client-search": "5.23.4", "@algolia/ingestion": "1.23.4", "@algolia/monitoring": "1.23.4", "@algolia/recommend": "5.23.4", "@algolia/requester-browser-xhr": "5.23.4", "@algolia/requester-fetch": "5.23.4", "@algolia/requester-node-http": "5.23.4" } }, "sha512-QzAKFHl3fm53s44VHrTdEo0TkpL3XVUYQpnZy1r6/EHvMAyIg+O4hwprzlsNmcCHTNyVcF2S13DAUn7XhkC6qg=="], + "algoliasearch": ["algoliasearch@5.35.0", "", { "dependencies": { "@algolia/abtesting": "1.1.0", "@algolia/client-abtesting": "5.35.0", "@algolia/client-analytics": "5.35.0", "@algolia/client-common": "5.35.0", "@algolia/client-insights": "5.35.0", "@algolia/client-personalization": "5.35.0", "@algolia/client-query-suggestions": "5.35.0", "@algolia/client-search": "5.35.0", "@algolia/ingestion": "1.35.0", "@algolia/monitoring": "1.35.0", "@algolia/recommend": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-Y+moNhsqgLmvJdgTsO4GZNgsaDWv8AOGAaPeIeHKlDn/XunoAqYbA+XNpBd1dW8GOXAUDyxC9Rxc7AV4kpFcIg=="], "astring": ["astring@1.9.0", "", { "bin": { "astring": "bin/astring" } }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="], @@ -381,7 +383,7 @@ "busboy": ["busboy@1.6.0", "", { "dependencies": { "streamsearch": "^1.1.0" } }, "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA=="], - "caniuse-lite": ["caniuse-lite@1.0.30001715", "", {}, "sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw=="], + "caniuse-lite": ["caniuse-lite@1.0.30001735", "", {}, "sha512-EV/laoX7Wq2J9TQlyIXRxTJqIw4sxfXS4OYgudGxBYRuTv0q7AM6yMEpU/Vo1I94thg9U6EZ2NfZx9GJq83u7w=="], "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], @@ -419,9 +421,9 @@ "debounce": ["debounce@1.2.1", "", {}, "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug=="], - "debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="], + "debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], - "decode-named-character-reference": ["decode-named-character-reference@1.1.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w=="], + "decode-named-character-reference": ["decode-named-character-reference@1.2.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q=="], "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], @@ -433,7 +435,7 @@ "emojis-list": ["emojis-list@3.0.0", "", {}, "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q=="], - "enhanced-resolve": ["enhanced-resolve@5.18.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg=="], + "enhanced-resolve": ["enhanced-resolve@5.18.3", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww=="], "esast-util-from-estree": ["esast-util-from-estree@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "devlop": "^1.0.0", "estree-util-visit": "^2.0.0", "unist-util-position-from-estree": "^2.0.0" } }, "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ=="], @@ -465,7 +467,7 @@ "flexsearch": ["flexsearch@0.8.205", "", {}, "sha512-REFjMqy86DKkCTJ4gIE42c9MVm9t1vUWfEub/8taixYuhvyu4jd4XmFALk5VuKW4GH4VLav8A4BJboTsslHF1w=="], - "framer-motion": ["framer-motion@12.16.0", "", { "dependencies": { "motion-dom": "^12.16.0", "motion-utils": "^12.12.1", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-xryrmD4jSBQrS2IkMdcTmiS4aSKckbS7kLDCuhUn9110SQKG1w3zlq1RTqCblewg+ZYe+m3sdtzQA6cRwo5g8Q=="], + "framer-motion": ["framer-motion@12.23.12", "", { "dependencies": { "motion-dom": "^12.23.12", "motion-utils": "^12.23.6", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-6e78rdVtnBvlEVgu6eFEAgG9v3wLnYEboM8I5O5EXvfKC8gxGQB8wXJdhkMy10iVcn05jl6CNw7/HTsTCfwcWg=="], "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], @@ -511,7 +513,7 @@ "is-plain-object": ["is-plain-object@5.0.0", "", {}, "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="], - "jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="], + "jiti": ["jiti@2.5.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w=="], "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], @@ -669,9 +671,9 @@ "mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="], - "motion-dom": ["motion-dom@12.16.0", "", { "dependencies": { "motion-utils": "^12.12.1" } }, "sha512-Z2nGwWrrdH4egLEtgYMCEN4V2qQt1qxlKy/uV7w691ztyA41Q5Rbn0KNGbsNVDZr9E8PD2IOQ3hSccRnB6xWzw=="], + "motion-dom": ["motion-dom@12.23.12", "", { "dependencies": { "motion-utils": "^12.23.6" } }, "sha512-RcR4fvMCTESQBD/uKQe49D5RUeDOokkGRmz4ceaJKDBgHYtZtntC/s2vLvY38gqGaytinij/yi3hMcWVcEF5Kw=="], - "motion-utils": ["motion-utils@12.12.1", "", {}, "sha512-f9qiqUHm7hWSLlNW8gS9pisnsN7CRFRD58vNjptKdsqFLpkVnX00TNeD6Q0d27V9KzT7ySFyK1TZ/DShfVOv6w=="], + "motion-utils": ["motion-utils@12.23.6", "", {}, "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ=="], "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], @@ -695,25 +697,25 @@ "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="], + "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], "postcss-selector-parser": ["postcss-selector-parser@6.0.10", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w=="], - "property-information": ["property-information@7.0.0", "", {}, "sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg=="], + "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], "qss": ["qss@3.0.0", "", {}, "sha512-ZHoCB3M/3Voev64zhLLUOKDtaEdJ/lymsJJ7R3KBusVZ2ovNiIB7XOq3Xh6V1a8O+Vho+g2B5YElq9zW7D8aQw=="], "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], - "react": ["react@19.1.0", "", {}, "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg=="], + "react": ["react@19.1.1", "", {}, "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ=="], - "react-dom": ["react-dom@19.1.0", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.0" } }, "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g=="], + "react-dom": ["react-dom@19.1.1", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.1" } }, "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw=="], "react-highlight-words": ["react-highlight-words@0.21.0", "", { "dependencies": { "highlight-words-core": "^1.2.0", "memoize-one": "^4.0.0" }, "peerDependencies": { "react": "^0.14.0 || ^15.0.0 || ^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" } }, "sha512-SdWEeU9fIINArEPO1rO5OxPyuhdEKZQhHzZZP1ie6UeXQf+CjycT1kWaB+9bwGcVbR0NowuHK3RqgqNg6bgBDQ=="], "recma-build-jsx": ["recma-build-jsx@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-util-build-jsx": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew=="], - "recma-jsx": ["recma-jsx@1.0.0", "", { "dependencies": { "acorn-jsx": "^5.0.0", "estree-util-to-js": "^2.0.0", "recma-parse": "^1.0.0", "recma-stringify": "^1.0.0", "unified": "^11.0.0" } }, "sha512-5vwkv65qWwYxg+Atz95acp8DMu1JDSqdGkA2Of1j6rCreyFUE/gp15fC8MnGEuG1W68UKjM6x6+YTWIh7hZM/Q=="], + "recma-jsx": ["recma-jsx@1.0.1", "", { "dependencies": { "acorn-jsx": "^5.0.0", "estree-util-to-js": "^2.0.0", "recma-parse": "^1.0.0", "recma-stringify": "^1.0.0", "unified": "^11.0.0" }, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w=="], "recma-parse": ["recma-parse@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "esast-util-from-js": "^2.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ=="], @@ -749,9 +751,9 @@ "semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], - "sharp": ["sharp@0.34.2", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.4", "semver": "^7.7.2" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.2", "@img/sharp-darwin-x64": "0.34.2", "@img/sharp-libvips-darwin-arm64": "1.1.0", "@img/sharp-libvips-darwin-x64": "1.1.0", "@img/sharp-libvips-linux-arm": "1.1.0", "@img/sharp-libvips-linux-arm64": "1.1.0", "@img/sharp-libvips-linux-ppc64": "1.1.0", "@img/sharp-libvips-linux-s390x": "1.1.0", "@img/sharp-libvips-linux-x64": "1.1.0", "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", "@img/sharp-libvips-linuxmusl-x64": "1.1.0", "@img/sharp-linux-arm": "0.34.2", "@img/sharp-linux-arm64": "0.34.2", "@img/sharp-linux-s390x": "0.34.2", "@img/sharp-linux-x64": "0.34.2", "@img/sharp-linuxmusl-arm64": "0.34.2", "@img/sharp-linuxmusl-x64": "0.34.2", "@img/sharp-wasm32": "0.34.2", "@img/sharp-win32-arm64": "0.34.2", "@img/sharp-win32-ia32": "0.34.2", "@img/sharp-win32-x64": "0.34.2" } }, "sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg=="], + "sharp": ["sharp@0.34.3", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.4", "semver": "^7.7.2" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.3", "@img/sharp-darwin-x64": "0.34.3", "@img/sharp-libvips-darwin-arm64": "1.2.0", "@img/sharp-libvips-darwin-x64": "1.2.0", "@img/sharp-libvips-linux-arm": "1.2.0", "@img/sharp-libvips-linux-arm64": "1.2.0", "@img/sharp-libvips-linux-ppc64": "1.2.0", "@img/sharp-libvips-linux-s390x": "1.2.0", "@img/sharp-libvips-linux-x64": "1.2.0", "@img/sharp-libvips-linuxmusl-arm64": "1.2.0", "@img/sharp-libvips-linuxmusl-x64": "1.2.0", "@img/sharp-linux-arm": "0.34.3", "@img/sharp-linux-arm64": "0.34.3", "@img/sharp-linux-ppc64": "0.34.3", "@img/sharp-linux-s390x": "0.34.3", "@img/sharp-linux-x64": "0.34.3", "@img/sharp-linuxmusl-arm64": "0.34.3", "@img/sharp-linuxmusl-x64": "0.34.3", "@img/sharp-wasm32": "0.34.3", "@img/sharp-win32-arm64": "0.34.3", "@img/sharp-win32-ia32": "0.34.3", "@img/sharp-win32-x64": "0.34.3" } }, "sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg=="], - "shiki": ["shiki@3.6.0", "", { "dependencies": { "@shikijs/core": "3.6.0", "@shikijs/engine-javascript": "3.6.0", "@shikijs/engine-oniguruma": "3.6.0", "@shikijs/langs": "3.6.0", "@shikijs/themes": "3.6.0", "@shikijs/types": "3.6.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-tKn/Y0MGBTffQoklaATXmTqDU02zx8NYBGQ+F6gy87/YjKbizcLd+Cybh/0ZtOBX9r1NEnAy/GTRDKtOsc1L9w=="], + "shiki": ["shiki@3.9.2", "", { "dependencies": { "@shikijs/core": "3.9.2", "@shikijs/engine-javascript": "3.9.2", "@shikijs/engine-oniguruma": "3.9.2", "@shikijs/langs": "3.9.2", "@shikijs/themes": "3.9.2", "@shikijs/types": "3.9.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-t6NKl5e/zGTvw/IyftLcumolgOczhuroqwXngDeMqJ3h3EQiTY/7wmfgPlsmloD8oYfqkEDqxiaH37Pjm1zUhQ=="], "simple-functional-loader": ["simple-functional-loader@1.2.1", "", { "dependencies": { "loader-utils": "^2.0.0" } }, "sha512-GPDrxrQkE7ijm35QlfPFVp5hBHR6ZcaUq42TEDgf1U5iTL3IDLFvKAbHE/ODqpdfJJ7Xn4cr/slBn12jjNPkaQ=="], @@ -759,7 +761,7 @@ "sirv": ["sirv@2.0.4", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ=="], - "source-map": ["source-map@0.7.4", "", {}, "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA=="], + "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], @@ -769,17 +771,17 @@ "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], - "style-to-js": ["style-to-js@1.1.16", "", { "dependencies": { "style-to-object": "1.0.8" } }, "sha512-/Q6ld50hKYPH3d/r6nr117TZkHR0w0kGGIVfpG9N6D8NymRPM9RqCUv4pRpJ62E5DqOYx2AFpbZMyCPnjQCnOw=="], + "style-to-js": ["style-to-js@1.1.17", "", { "dependencies": { "style-to-object": "1.0.9" } }, "sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA=="], - "style-to-object": ["style-to-object@1.0.8", "", { "dependencies": { "inline-style-parser": "0.2.4" } }, "sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g=="], + "style-to-object": ["style-to-object@1.0.9", "", { "dependencies": { "inline-style-parser": "0.2.4" } }, "sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw=="], "styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="], "tabbable": ["tabbable@6.2.0", "", {}, "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="], - "tailwindcss": ["tailwindcss@4.1.8", "", {}, "sha512-kjeW8gjdxasbmFKpVGrGd5T4i40mV5J2Rasw48QARfYeQ8YS9x02ON9SFWax3Qf616rt4Cp3nVNIj6Hd1mP3og=="], + "tailwindcss": ["tailwindcss@4.1.12", "", {}, "sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA=="], - "tapable": ["tapable@2.2.1", "", {}, "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="], + "tapable": ["tapable@2.2.2", "", {}, "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg=="], "tar": ["tar@7.4.3", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" } }, "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw=="], @@ -793,9 +795,9 @@ "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], + "typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="], - "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + "undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="], "unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="], @@ -821,7 +823,7 @@ "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], - "vfile-message": ["vfile-message@4.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw=="], + "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="], "webpack-bundle-analyzer": ["webpack-bundle-analyzer@4.10.1", "", { "dependencies": { "@discoveryjs/json-ext": "0.5.7", "acorn": "^8.0.4", "acorn-walk": "^8.0.0", "commander": "^7.2.0", "debounce": "^1.2.1", "escape-string-regexp": "^4.0.0", "gzip-size": "^6.0.0", "html-escaper": "^2.0.2", "is-plain-object": "^5.0.0", "opener": "^1.5.2", "picocolors": "^1.0.0", "sirv": "^2.0.3", "ws": "^7.3.1" }, "bin": { "webpack-bundle-analyzer": "lib/bin/analyzer.js" } }, "sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ=="], @@ -829,23 +831,33 @@ "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], - "zustand": ["zustand@5.0.5", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-mILtRfKW9xM47hqxGIxCv12gXusoY/xTSHBYApXozR0HmQv299whhBeeAcRy+KrPPybzosvJBCOmVjq6x12fCg=="], + "zustand": ["zustand@5.0.7", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-Ot6uqHDW/O2VdYsKLLU8GQu8sCOM1LcoE8RwvLv9uuRT9s6SOHCKs0ZEOhxg+I1Ld+A1Q5lwx+UlKXXUoCZITg=="], "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], - "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.4.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g=="], + "@react-aria/focus/@swc/helpers": ["@swc/helpers@0.5.17", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A=="], - "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="], + "@react-aria/interactions/@swc/helpers": ["@swc/helpers@0.5.17", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A=="], - "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA=="], + "@react-aria/ssr/@swc/helpers": ["@swc/helpers@0.5.17", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A=="], - "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.10", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.9.0" }, "bundled": true }, "sha512-bCsCyeZEwVErsGmyPNSzwfwFn4OdxBj0mmv6hOFucB/k81Ojdu68RbZdxYsRQUPc9l6SU5F/cG+bXgWs3oUgsQ=="], + "@react-aria/utils/@swc/helpers": ["@swc/helpers@0.5.17", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A=="], - "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.9.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw=="], + "@react-stately/flags/@swc/helpers": ["@swc/helpers@0.5.17", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A=="], - "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "@react-stately/utils/@swc/helpers": ["@swc/helpers@0.5.17", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A=="], - "@types/react-highlight-words/@types/react": ["@types/react@19.1.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.4.5", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.4", "tslib": "^2.4.0" }, "bundled": true }, "sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.4.5", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.4", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g=="], + + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" }, "bundled": true }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="], + + "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ=="], + + "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "esast-util-from-estree/estree-util-visit": ["estree-util-visit@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/unist": "^3.0.0" } }, "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww=="], diff --git a/components/Code.tsx b/components/Code.tsx index 42fd46c..ce19ff6 100644 --- a/components/Code.tsx +++ b/components/Code.tsx @@ -5,9 +5,9 @@ import clsx from "clsx"; import { Children, type ComponentPropsWithoutRef, - type ReactNode, createContext, isValidElement, + type ReactNode, useContext, useEffect, useRef, @@ -144,7 +144,6 @@ function CodePanel({ label?: string; code?: string; }) { - // biome-ignore lint/suspicious/noExplicitAny: const child = Children.only(children) as ReactNode & { props: any }; if (isValidElement(child)) { @@ -207,8 +206,7 @@ function CodeGroupHeader({ > {getPanelTitle( isValidElement(child) - ? // biome-ignore lint/suspicious/noExplicitAny: - (child.props as any) + ? (child.props as any) : {}, )} @@ -326,7 +324,6 @@ export function CodeGroup({ }: ComponentPropsWithoutRef & { title: string }) { const languages = Children.map(children, (child) => - // biome-ignore lint/suspicious/noExplicitAny: getPanelTitle(isValidElement(child) ? (child.props as any) : {}), ) ?? []; const tabGroupProps = useTabGroupProps(languages); @@ -375,8 +372,8 @@ export function Code({ children, ...props }: ComponentPropsWithoutRef<"code">) { ); } return ( - // biome-ignore lint/security/noDangerouslySetInnerHtml: - // biome-ignore lint/style/useNamingConvention: + // biome-ignore lint/security/noDangerouslySetInnerHtml: HTML is trusted + // biome-ignore lint/style/useNamingConvention: Biome incorrectly tags this as bad naming ); } diff --git a/components/Feedback.tsx b/components/Feedback.tsx index 163dec2..b461175 100644 --- a/components/Feedback.tsx +++ b/components/Feedback.tsx @@ -59,7 +59,6 @@ const FeedbackForm = forwardRef< }); const FeedbackThanks = forwardRef>( - // biome-ignore lint/style/useNamingConvention: function FeedbackThanks(_props, ref) { return (
{squares && ( - // biome-ignore lint/a11y/noSvgWithoutTitle: + // biome-ignore lint/a11y/noSvgWithoutTitle: it's decoration

diff --git a/components/Header.tsx b/components/Header.tsx index 7e52026..9f98f89 100644 --- a/components/Header.tsx +++ b/components/Header.tsx @@ -2,10 +2,10 @@ import clsx from "clsx"; import { motion, useScroll, useTransform } from "framer-motion"; import Link from "next/link"; import { - type CSSProperties, type ComponentRef, - type ReactNode, + type CSSProperties, forwardRef, + type ReactNode, } from "react"; import { Button } from "./Button"; @@ -13,8 +13,8 @@ import { Logo } from "./Logo"; import { MobileNavigation, useIsInsideMobileNavigation, + useMobileNavigationStore, } from "./MobileNavigation"; -import { useMobileNavigationStore } from "./MobileNavigation"; import { MobileSearch, Search } from "./Search"; import { ThemeToggle } from "./ThemeToggle"; diff --git a/components/MobileNavigation.tsx b/components/MobileNavigation.tsx index 56d9d4d..a2f994c 100644 --- a/components/MobileNavigation.tsx +++ b/components/MobileNavigation.tsx @@ -11,9 +11,9 @@ import { motion } from "framer-motion"; import { usePathname, useSearchParams } from "next/navigation"; import { type ComponentPropsWithoutRef, + createContext, type MouseEvent, Suspense, - createContext, useContext, useEffect, useRef, diff --git a/components/Navigation.tsx b/components/Navigation.tsx index 0c1e953..4a164bc 100644 --- a/components/Navigation.tsx +++ b/components/Navigation.tsx @@ -208,8 +208,8 @@ function NavigationGroup({ {link.href === pathname && sections.length > 0 && ( + // biome-ignore lint/a11y/useSemanticElements: already a
    role="list" initial={{ opacity: 0 }} animate={{ diff --git a/components/Property.tsx b/components/Property.tsx index e45f14d..6524de3 100644 --- a/components/Property.tsx +++ b/components/Property.tsx @@ -1,7 +1,7 @@ "use client"; import Link from "next/link"; -import { type ReactNode, createContext, useContext } from "react"; +import { createContext, type ReactNode, useContext } from "react"; import { AnchorIcon } from "./Heading"; export const PropertyContext = createContext<{ @@ -13,7 +13,10 @@ export const PropertyContext = createContext<{ export function Properties({ children, name, -}: { children: ReactNode; name: string }) { +}: { + children: ReactNode; + name: string; +}) { return (
      diff --git a/components/Resources.tsx b/components/Resources.tsx index 0e3a64d..5810e98 100644 --- a/components/Resources.tsx +++ b/components/Resources.tsx @@ -1,5 +1,6 @@ "use client"; +import { Icon } from "@iconify-icon/react"; import { type MotionValue, motion, @@ -7,8 +8,6 @@ import { useMotionValue, } from "framer-motion"; import Link from "next/link"; - -import { Icon } from "@iconify-icon/react"; import type { ComponentPropsWithoutRef, MouseEvent } from "react"; import { GridPattern } from "./GridPattern"; import { Heading } from "./Heading"; diff --git a/components/Search.tsx b/components/Search.tsx index 34699f5..5f8acec 100644 --- a/components/Search.tsx +++ b/components/Search.tsx @@ -19,11 +19,11 @@ import { type ComponentPropsWithoutRef, type ComponentRef, Fragment, + forwardRef, type MouseEvent, type KeyboardEvent as ReactKeyboardEvent, Suspense, type SyntheticEvent, - forwardRef, useCallback, useEffect, useId, @@ -164,7 +164,6 @@ function LoadingIcon(props: ComponentPropsWithoutRef<"svg">) { function HighlightQuery({ text, query }: { text: string; query: string }) { return ( - // @ts-ignore export { Button } from "./Button"; -export { CodeGroup, Code as code, Pre as pre } from "./Code"; -export { Property, Properties } from "./Property"; +export { Code as code, CodeGroup, Pre as pre } from "./Code"; +export { Properties, Property } from "./Property"; export function wrapper({ children }: { children: ReactNode }) { return ( diff --git a/mdx/rehype.mjs b/mdx/rehype.mjs index 7cf89f1..0d281a2 100644 --- a/mdx/rehype.mjs +++ b/mdx/rehype.mjs @@ -12,7 +12,6 @@ import { visit } from "unist-util-visit"; function rehypeParseCodeBlocks() { return (tree) => { - // biome-ignore lint/style/useNamingConvention: visit(tree, "element", (node, _nodeIndex, parentNode) => { if (node.tagName === "code" && node.properties.className) { parentNode.properties.language = diff --git a/next.config.mjs b/next.config.mjs index 64b6f60..97832f6 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,6 +1,5 @@ -import nextMDX from "@next/mdx"; - import bundleAnalyzer from "@next/bundle-analyzer"; +import nextMDX from "@next/mdx"; import { recmaPlugins } from "./mdx/recma.mjs"; import { rehypePlugins } from "./mdx/rehype.mjs"; import { remarkPlugins } from "./mdx/remark.mjs"; diff --git a/package.json b/package.json index f72817d..d8e08a8 100644 --- a/package.json +++ b/package.json @@ -12,51 +12,55 @@ }, "dependencies": { "@algolia/autocomplete-core": "^1.19.2", - "@headlessui/react": "^2.2.4", + "@headlessui/react": "^2.2.7", "@headlessui/tailwindcss": "^0.2.2", "@mdx-js/loader": "^3.1.0", "@mdx-js/react": "^3.1.0", "@next/mdx": "^15.3.3", - "@radix-ui/react-hover-card": "^1.1.14", + "@radix-ui/react-hover-card": "^1.1.15", "@sindresorhus/slugify": "^2.2.1", - "@tailwindcss/postcss": "^4.1.8", + "@tailwindcss/postcss": "^4.1.12", "@tailwindcss/typography": "^0.5.16", "@types/mdx": "^2.0.13", - "@types/node": "^22.15.30", - "@types/react": "^19.1.6", - "@types/react-dom": "^19.1.6", + "@types/node": "^24.2.1", + "@types/react": "^19.1.10", + "@types/react-dom": "^19.1.7", "@types/react-highlight-words": "^0.20.0", - "acorn": "^8.14.1", + "acorn": "^8.15.0", "clsx": "^2.1.1", "fast-glob": "^3.3.3", "flexsearch": "^0.8.205", - "framer-motion": "^12.16.0", + "framer-motion": "^12.23.12", "mdast-util-to-string": "^4.0.0", "mdx-annotations": "^0.1.4", - "next": "^15.3.3", + "next": "15.3.3", "next-themes": "^0.4.6", "qss": "^3.0.0", - "react": "^19.1.0", - "react-dom": "^19.1.0", + "react": "^19.1.1", + "react-dom": "^19.1.1", "react-highlight-words": "^0.21.0", "remark": "^15.0.1", "remark-gfm": "^4.0.1", "remark-mdx": "^3.1.0", - "shiki": "^3.6.0", + "shiki": "^3.9.2", "simple-functional-loader": "^1.2.1", - "tailwindcss": "^4.1.8", - "typescript": "^5.8.3", + "tailwindcss": "^4.1.12", + "typescript": "^5.9.2", "unist-util-filter": "^5.0.1", "unist-util-visit": "^5.0.0", "uwuifier": "^4.2.2", - "zustand": "^5.0.5" + "zustand": "^5.0.7" }, "devDependencies": { - "@biomejs/biome": "^1.9.4", + "@biomejs/biome": "^2.2.0", "@iconify-icon/react": "^3.0.0", - "@next/bundle-analyzer": "^15.3.3", - "@shikijs/transformers": "^3.6.0", - "sharp": "^0.34.2" + "@next/bundle-analyzer": "^15.4.6", + "@shikijs/transformers": "^3.9.2", + "sharp": "^0.34.3" }, - "trustedDependencies": ["@biomejs/biome", "@tailwindcss/oxide", "sharp"] + "trustedDependencies": [ + "@biomejs/biome", + "@tailwindcss/oxide", + "sharp" + ] } diff --git a/public/pl.js b/public/pl.js index 193bbf9..4d2e22e 100644 --- a/public/pl.js +++ b/public/pl.js @@ -1 +1,124 @@ -!function(){"use strict";var l=window.location,i=window.document,t=i.currentScript,r=t.getAttribute("data-api")||new URL(t.src).origin+"/api/event",o=t.getAttribute("data-domain");function s(t,e){t&&console.warn("Ignoring Event: "+t),e&&e.callback&&e.callback()}function e(t,e){if(/^localhost$|^127(\.[0-9]+){0,2}\.[0-9]+$|^\[::1?\]$/.test(l.hostname)||"file:"===l.protocol)return s("localhost",e);if((window._phantom||window.__nightmare||window.navigator.webdriver||window.Cypress)&&!window.__plausible)return s(null,e);try{if("true"===window.localStorage.plausible_ignore)return s("localStorage flag",e)}catch(t){}var a={},n=(a.n=t,a.u=l.href,a.d=o,a.r=i.referrer||null,e&&e.meta&&(a.m=JSON.stringify(e.meta)),e&&e.props&&(a.p=e.props),new XMLHttpRequest);n.open("POST",r,!0),n.setRequestHeader("Content-Type","text/plain"),n.send(JSON.stringify(a)),n.onreadystatechange=function(){4===n.readyState&&e&&e.callback&&e.callback({status:n.status})}}var a=window.plausible&&window.plausible.q||[];window.plausible=e;for(var n,p=0;p { + 4 === n.readyState && + e && + e.callback && + e.callback({ status: n.status }); + }); + } + var a = (window.plausible && window.plausible.q) || []; + window.plausible = e; + for (var n, p = 0; p < a.length; p++) e.apply(this, a[p]); + function c() { + n !== l.pathname && ((n = l.pathname), e("pageview")); + } + function u() { + c(); + } + var d, + t = window.history; + t.pushState && + ((d = t.pushState), + (t.pushState = function () { + d.apply(this, arguments), u(); + }), + window.addEventListener("popstate", u)), + "prerender" === i.visibilityState + ? i.addEventListener("visibilitychange", () => { + n || "visible" !== i.visibilityState || c(); + }) + : c(); + var f = 1; + function w(t) { + var e, a, n, i, r; + function o() { + n || ((n = !0), (window.location = a.href)); + } + ("auxclick" === t.type && t.button !== f) || + ((e = ((t) => { + for ( + ; + t && + (void 0 === t.tagName || + !(e = t) || + !e.tagName || + "a" !== e.tagName.toLowerCase() || + !t.href); + ) + t = t.parentNode; + var e; + return t; + })(t.target)) && + e.href && + e.href.split("?")[0], + (r = e) && + r.href && + r.host && + r.host !== l.host && + ((r = t), + (t = { + name: "Outbound Link: Click", + props: { url: (a = e).href }, + }), + (n = !1), + !((t, e) => { + if (!t.defaultPrevented) + return ( + (e = + !e.target || + e.target.match(/^_(self|parent|top)$/i)), + (t = + !(t.ctrlKey || t.metaKey || t.shiftKey) && + "click" === t.type), + e && t + ); + })(r, a) + ? ((i = { props: t.props }), plausible(t.name, i)) + : ((i = { props: t.props, callback: o }), + plausible(t.name, i), + setTimeout(o, 5e3), + r.preventDefault()))); + } + i.addEventListener("click", w), i.addEventListener("auxclick", w); +})(); diff --git a/styles/tailwind.css b/styles/tailwind.css index 0b0817e..f7ffae3 100644 --- a/styles/tailwind.css +++ b/styles/tailwind.css @@ -143,12 +143,16 @@ .prose [class*="language-"] .has-focused .line:not(.focused) { filter: blur(0.095rem); opacity: 0.4; - transition: filter 0.35s, opacity 0.35s; + transition: + filter 0.35s, + opacity 0.35s; } .prose [class*="language-"] .has-focused .line:not(.focused) { opacity: 0.7; - transition: filter 0.35s, opacity 0.35s; + transition: + filter 0.35s, + opacity 0.35s; } .prose [class*="language-"]:hover .has-focused .line:not(.focused) { From 064a4aa8289a831127c05dacfce49c94f9dcc056 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Sun, 21 Sep 2025 17:07:59 +0200 Subject: [PATCH 20/25] fix: :lipstick: Remove navbar and footer on print --- components/Footer.tsx | 2 +- components/Layout.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/Footer.tsx b/components/Footer.tsx index 43bb81f..9c83278 100644 --- a/components/Footer.tsx +++ b/components/Footer.tsx @@ -129,7 +129,7 @@ function SmallPrint() { export function Footer() { return ( -