chore: rename everything to versia

This commit is contained in:
DevMiner 2024-08-28 00:25:25 +02:00
parent 0223ea0535
commit 3876ad2738
112 changed files with 587 additions and 576 deletions

View file

@ -2,7 +2,7 @@ package versia
import (
"encoding/json"
versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
versiautils "github.com/versia-pub/versia-go/pkg/versia/utils"
)
// Delete signals the deletion of an entity. For more information, see the [Spec].

View file

@ -2,7 +2,7 @@ package versia
import (
"encoding/json"
versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
versiautils "github.com/versia-pub/versia-go/pkg/versia/utils"
)
// Follow defines a follow relationship between two users. For more information, see the [Spec].

View file

@ -2,7 +2,7 @@ package versia
import (
"encoding/json"
versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
versiautils "github.com/versia-pub/versia-go/pkg/versia/utils"
)
// Group is a way to organize users and notes into communities. For more information, see the [Spec].

View file

@ -2,54 +2,44 @@ package versia
import (
"encoding/json"
versiacrypto "github.com/lysand-org/versia-go/pkg/versia/crypto"
versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
versiacrypto "github.com/versia-pub/versia-go/pkg/versia/crypto"
versiautils "github.com/versia-pub/versia-go/pkg/versia/utils"
)
// User represents a user object in the Lysand protocol. For more information, see the [Spec].
// User represents a user object in the Versia protocol. For more information, see the [Spec].
//
// [Spec]: https://lysand.org/objects/user
// [Spec]: https://versia.pub/entities/user
type User struct {
Entity
// PublicKey is the public key of the user.
// https://lysand.org/objects/user#public-key
PublicKey UserPublicKey `json:"public_key"`
// DisplayName is the display name of the user.
// https://lysand.org/objects/user#display-name
DisplayName *string `json:"display_name,omitempty"`
// Username is the username of the user. Must be unique on the instance and match the following regex: ^[a-z0-9_-]+$
// https://lysand.org/objects/user#username
Username string `json:"username"`
// Indexable is a boolean that indicates whether the user is indexable by search engines.
// https://lysand.org/objects/user#indexable
Indexable bool `json:"indexable"`
// ManuallyApprovesFollowers is a boolean that indicates whether the user manually approves followers.
// https://lysand.org/objects/user#manually-approves-followers
ManuallyApprovesFollowers bool `json:"manually_approves_followers"`
// Avatar is the avatar of the user in different image content types.
// https://lysand.org/objects/user#avatar
Avatar versiautils.ImageContentTypeMap `json:"avatar,omitempty"`
// Header is the header image of the user in different image content types.
// https://lysand.org/objects/user#header
Header versiautils.ImageContentTypeMap `json:"header,omitempty"`
Avatar versiautils.ImageContentMap `json:"avatar,omitempty"`
// Bio is the biography of the user in different text content types.
// https://lysand.org/objects/user#bio
Bio versiautils.TextContentTypeMap `json:"bio"`
Bio versiautils.TextContentTypeMap `json:"bio,omitempty"`
// DisplayName is the display name of the user.
DisplayName *string `json:"display_name,omitempty"`
// Fields is a list of fields that the user has filled out.
// https://lysand.org/objects/user#fields
Fields []UserField `json:"fields,omitempty"`
Fields []UserField `json:"fields"`
// Username is the username of the user. Must be unique on the instance and match the following regex: ^[a-z0-9_-]+$
Username string `json:"username"`
// Header is the header image of the user in different image content types.
Header versiautils.ImageContentMap `json:"header,omitempty"`
// PublicKey is the public key of the user.
PublicKey UserPublicKey `json:"public_key"`
// ManuallyApprovesFollowers is a boolean that indicates whether the user manually approves followers.
ManuallyApprovesFollowers *bool `json:"manually_approves_followers,omitempty"`
// Indexable is a boolean that indicates whether the user is indexable by search engines.
Indexable *bool `json:"indexable,omitempty"`
// Inbox is the inbox of the user.
// https://lysand.org/objects/user#posts
Inbox *versiautils.URL `json:"inbox"`
// Collections is a map of all collections for a user
@ -86,7 +76,7 @@ type UserCollections map[UserCollectionType]*versiautils.URL
// UserPublicKey represents a public key for a user. For more information, see the [Spec].
//
// [Spec]: https://lysand.org/security/keys#public-key-cryptography
// [Spec]: https://versia.pub/signatures
type UserPublicKey struct {
Actor *versiautils.URL `json:"actor"`

View file

@ -1,25 +0,0 @@
package versia
// Attachment is a file or other piece of content that is attached to a post. For more information, see the [Spec].
//
// [Spec]: https://lysand.org/structures/content-format
type Attachment struct {
// URL to the attachment
Content string `json:"content"`
Description string `json:"description"`
Hash DataHash `json:"hash"`
Size int `json:"size"`
// BlurHash is available when the content type is an image
BlurHash *string `json:"blurhash,omitempty"`
// BlurHash is available when the content type is an image
Height *int `json:"height,omitempty"`
// BlurHash is available when the content type is an image
Width *int `json:"width,omitempty"`
FPS *int `json:"fps,omitempty"`
}
type DataHash struct {
SHA256 string `json:"sha256"`
}

View file

@ -1,6 +1,6 @@
package versia
import versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
import versiautils "github.com/versia-pub/versia-go/pkg/versia/utils"
// Collection is a paginated group of entities. For more information, see the [Spec].
//

View file

@ -7,7 +7,7 @@ import (
"net/url"
)
// FederationHeaders represents the signature header of the Lysand protocol. For more information, see the [Spec].
// FederationHeaders represents the signature header of the Versia protocol. For more information, see the [Spec].
//
// [Spec]: https://versia.pub/signatures#signature-definition
type FederationHeaders struct {

View file

@ -2,43 +2,30 @@ package versia
import (
"github.com/google/uuid"
versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
versiautils "github.com/versia-pub/versia-go/pkg/versia/utils"
)
// Entity is the base type for all Lysand entities. For more information, see the [Spec].
// Entity is the base type for all Versia entities. For more information, see the [Spec].
//
// [Spec]: https://lysand.org/objects#types
// [Spec]: https://versia.pub/entities
type Entity struct {
// Type is the type of the entity
Type string `json:"type"`
// ID is a UUID for the entity
ID uuid.UUID `json:"id"`
// URI is the URL to the entity
URI *versiautils.URL `json:"uri"`
// Type is the type of the entity
Type string `json:"type"`
// CreatedAt is the time the entity was created
CreatedAt versiautils.Time `json:"created_at"`
// Extensions is a map of active extensions
// https://lysand.org/objects/server-metadata#extensions
// URI is the URL to the entity
URI *versiautils.URL `json:"uri"`
// Extensions is a map of active extensions for the entity
Extensions Extensions `json:"extensions,omitempty"`
}
// Extensions represents the active extensions on an entity. For more information, see the [Spec].
//
// [Spec]: https://versia.pub/extensions#extension-definition
type Extensions map[string]any
// {
// "org.lysand:custom_emojis": {
// "emojis": [
// {
// "name": "neocat_3c",
// "url": {
// "image/webp": {
// "content": "https://cdn.lysand.org/a97727158bf062ad31cbfb02e212ce0c7eca599a2f863276511b8512270b25e8/neocat_3c_256.webp"
// }
// }
// }
// ]
// }
// }

View file

@ -2,11 +2,11 @@ package versia
import (
"encoding/json"
versiacrypto "github.com/lysand-org/versia-go/pkg/versia/crypto"
versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
versiacrypto "github.com/versia-pub/versia-go/pkg/versia/crypto"
versiautils "github.com/versia-pub/versia-go/pkg/versia/utils"
)
// InstanceMetadata represents the metadata of a Lysand instance. For more information, see the [Spec].
// InstanceMetadata represents the metadata of a Versia instance. For more information, see the [Spec].
//
// ! Unlike other entities, instance metadata is not meant to be federated.
//
@ -43,15 +43,15 @@ type InstanceMetadata struct {
Admins *versiautils.URL `json:"admins,omitempty"`
// Logo is the URL to the instance's logo
Logo *versiautils.ImageContentTypeMap `json:"logo,omitempty"`
Logo *versiautils.ImageContentMap `json:"logo,omitempty"`
// Banner is the URL to the instance's banner
Banner *versiautils.ImageContentTypeMap `json:"banner,omitempty"`
Banner *versiautils.ImageContentMap `json:"banner,omitempty"`
// Software is information about the instance software
Software InstanceSoftware `json:"software"`
// Compatibility is information about the instance's compatibility with different Lysand versions
// Compatibility is information about the instance's compatibility with different Versia versions
Compatibility InstanceCompatibility `json:"compatibility"`
}
@ -62,7 +62,7 @@ func (s InstanceMetadata) MarshalJSON() ([]byte, error) {
return json.Marshal(s2)
}
// InstanceSoftware represents the software of a Lysand instance.
// InstanceSoftware represents the software of a Versia instance.
type InstanceSoftware struct {
// Name is the name of the instance software
Name string `json:"name"`
@ -70,9 +70,9 @@ type InstanceSoftware struct {
Version string `json:"version"`
}
// InstanceCompatibility represents the compatibility of a Lysand instance.
// InstanceCompatibility represents the compatibility of a Versia instance.
type InstanceCompatibility struct {
// Versions is a list of versions of Lysand the instance is compatible with
// Versions is a list of versions of Versia the instance is compatible with
Versions []string `json:"versions"`
// Extensions is a list of extensions supported by the instance

View file

@ -2,23 +2,7 @@ package versia
import (
"encoding/json"
versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
)
// NoteVisibility is the visibility of a note. For more information, see the [Spec].
//
// [Spec]: https://lysand.org/objects/publications#visibility
type NoteVisibility string
const (
// NoteVisiblePublic means that the Note is visible to everyone.
NoteVisiblePublic NoteVisibility = "public"
// NoteVisibleUnlisted means that the Note is visible everyone, but should not appear in public timelines and search results.
NoteVisibleUnlisted NoteVisibility = "unlisted"
// NoteVisibleFollowers means that the Note is visible to followers only.
NoteVisibleFollowers NoteVisibility = "followers"
// NoteVisibleDirect means that the Note is a direct message, and is visible only to the mentioned users.
NoteVisibleDirect NoteVisibility = "direct"
versiautils "github.com/versia-pub/versia-go/pkg/versia/utils"
)
// Note is a published message, similar to a tweet (from Twitter) or a toot (from Mastodon).
@ -28,57 +12,42 @@ const (
type Note struct {
Entity
// Attachments is a list of attachment objects, keyed by their MIME type
Attachments []versiautils.NoteAttachmentContentMap `json:"attachments,omitempty"`
// Author is the URL to the user
// https://lysand.org/objects/publications#author
Author *versiautils.URL `json:"author"`
// Content is the content of the publication
// https://lysand.org/objects/publications#content
Content versiautils.TextContentTypeMap `json:"content,omitempty"`
// Category is the category of the publication
// https://lysand.org/objects/publications#category
// Category is the category of the note
Category *CategoryType `json:"category,omitempty"`
// Device that created the publication
// https://lysand.org/objects/publications#device
// Content is the content of the note
Content versiautils.TextContentTypeMap `json:"content,omitempty"`
// Device that created the note
Device *Device `json:"device,omitempty"`
// Previews is a list of URLs to preview images
// https://lysand.org/objects/publications#previews
Previews []LinkPreview `json:"previews,omitempty"`
// Group is the URL to a group
// https://lysand.org/objects/publications#group
// TODO: Properly parse these, can be "public" | "followers" as well
Group *versiautils.URL `json:"group,omitempty"`
// Attachments is a list of attachment objects, keyed by their MIME type
// https://lysand.org/objects/publications#attachments
Attachments []versiautils.ContentTypeMap[Attachment] `json:"attachments,omitempty"`
// RepliesTo is the URL to the publication being replied to
// https://lysand.org/objects/publications#replies-to
RepliesTo *versiautils.URL `json:"replies_to,omitempty"`
// Quoting is the URL to the publication being quoted
// https://lysand.org/objects/publications#quotes
Quoting *versiautils.URL `json:"quoting,omitempty"`
// Mentions is a list of URLs to users
// https://lysand.org/objects/publications#mentionshttps://lysand.org/objects/publications#mentions
Mentions []versiautils.URL `json:"mentions,omitempty"`
// Subject is the subject of the publication
// https://lysand.org/objects/publications#subject
Subject *string `json:"subject,omitempty"`
// IsSensitive is a boolean indicating whether the publication contains sensitive content
// https://lysand.org/objects/publications#is-sensitive
// IsSensitive is a boolean indicating whether the note contains sensitive content
IsSensitive *bool `json:"is_sensitive,omitempty"`
// Visibility is the visibility of the publication
// https://lysand.org/objects/publications#visibility
Visibility NoteVisibility `json:"visibility"`
// Mentions is a list of URLs to users
Mentions []versiautils.URL `json:"mentions,omitempty"`
// Previews is a list of URLs to preview images
Previews []LinkPreview `json:"previews,omitempty"`
// Quotes is the URL to the note being quoted
Quotes *versiautils.URL `json:"quotes,omitempty"`
// RepliesTo is the URL to the note being replied to
RepliesTo *versiautils.URL `json:"replies_to,omitempty"`
// Subject is the subject of the note
Subject *string `json:"subject,omitempty"`
}
func (p Note) MarshalJSON() ([]byte, error) {
@ -90,27 +59,27 @@ func (p Note) MarshalJSON() ([]byte, error) {
// LinkPreview is a preview of a link. For more information, see the [Spec].
//
// [Spec]: https://lysand.org/objects/publications#types
// [Spec]: https://versia.pub/entities/note#entity-definition
type LinkPreview struct {
Link *versiautils.URL `json:"link"`
Title string `json:"title"`
Description *string `json:"description"`
Image *versiautils.URL `json:"image"`
Icon *versiautils.URL `json:"icon"`
Description *string `json:"description,omitempty"`
Image *versiautils.URL `json:"image,omitempty"`
Icon *versiautils.URL `json:"icon,omitempty"`
}
// Device is the device that creates publications. For more information, see the [Spec].
// Device is the device that creates note. For more information, see the [Spec].
//
// [Spec]: https://lysand.org/objects/publications#types
// [Spec]: https://versia.pub/entities/note#entity-definition
type Device struct {
Name string `json:"name"`
Version string `json:"version,omitempty"`
URL *versiautils.URL `json:"url,omitempty"`
}
// CategoryType is the type of publication. For more information, see the [Spec].
// CategoryType is the type of note. For more information, see the [Spec].
//
// [Spec]: https://lysand.org/objects/publications#types
// [Spec]: https://versia.pub/entities/note#entity-definition
type CategoryType string
const (

View file

@ -0,0 +1,150 @@
package versiautils
import (
"encoding/json"
"errors"
"fmt"
"slices"
)
var (
validTextContentTypes = []string{"text/html", "text/plain"}
validImageContentTypes = []string{"image/png", "image/jpeg", "image/gif", "image/svg+xml"}
)
// ContentMap is a map of content types to their respective content.
type ContentMap[T any] map[string]T
type UnexpectedContentTypeError struct {
MIMEType string
}
func (e UnexpectedContentTypeError) Error() string {
return fmt.Sprintf("unexpected content type: %s", e.MIMEType)
}
func (m ContentMap[T]) unmarshalJSON(raw []byte, valid []string) error {
var cm map[string]json.RawMessage
if err := json.Unmarshal(raw, &cm); err != nil {
return err
}
m = make(ContentMap[T])
errs := make([]error, 0)
for k, v := range cm {
if valid != nil {
if !slices.Contains(valid, k) {
errs = append(errs, UnexpectedContentTypeError{k})
continue
}
}
var c T
if err := json.Unmarshal(v, &c); err != nil {
errs = append(errs, err)
continue
}
m[k] = c
}
if len(errs) > 0 {
return MultipleError{errs}
}
return nil
}
func (m ContentMap[T]) getPreferred(preferred []string) *T {
for _, v := range preferred {
if c, ok := m[v]; ok {
return &c
}
}
return nil
}
// TextContent is embedded string. For more information, see the [Spec].
//
// [Spec]: https://versia.pub/structures/content-format
type TextContent struct {
Content string `json:"content"`
// Remote is always false
Remote bool `json:"remote"`
}
type TextContentTypeMap ContentMap[TextContent]
func (t TextContentTypeMap) UnmarshalJSON(data []byte) error {
return (ContentMap[TextContent])(t).unmarshalJSON(data, validTextContentTypes)
}
func (t TextContentTypeMap) String() string {
if c := (ContentMap[TextContent])(t).getPreferred(validTextContentTypes); c != nil {
return c.Content
}
return ""
}
// File is a file or other piece of content. For more information, see the [Spec].
//
// [Spec]: https://versia.pub/structures/content-format
type File struct {
// Remote is always true
Remote bool `json:"remote"`
// URL to the attachment
Content *URL `json:"content"`
Description string `json:"description"`
Hash DataHash `json:"hash"`
Size int `json:"size"`
// BlurHash is available when the content type is an image
BlurHash *string `json:"blurhash,omitempty"`
// BlurHash is available when the content type is an image
Height *int `json:"height,omitempty"`
// BlurHash is available when the content type is an image
Width *int `json:"width,omitempty"`
FPS *int `json:"fps,omitempty"`
}
type DataHash struct {
SHA256 string `json:"sha256"`
}
type ImageContentMap ContentMap[File]
func (i ImageContentMap) UnmarshalJSON(data []byte) error {
return (ContentMap[File])(i).unmarshalJSON(data, validImageContentTypes)
}
func (i ImageContentMap) String() string {
if c := (ContentMap[File])(i).getPreferred(validImageContentTypes); c != nil {
return c.Content.String()
}
return ""
}
type NoteAttachmentContentMap ContentMap[File]
var ErrContentMapEntryNotRemote = errors.New("content map entry not remote")
func (i NoteAttachmentContentMap) UnmarshalJSON(data []byte) error {
if err := (ContentMap[File])(i).unmarshalJSON(data, nil); err != nil {
return err
}
errs := make([]error, 0)
for _, a := range i {
if !a.Remote {
errs = append(errs, ErrContentMapEntryNotRemote)
}
}
if len(errs) > 0 {
return MultipleError{errs}
}
return nil
}

View file

@ -1,85 +0,0 @@
package versiautils
import (
"encoding/json"
"slices"
"github.com/rs/zerolog/log"
)
var (
validTextContentTypes = []string{"text/html", "text/plain"}
validImageContentTypes = []string{"image/png", "image/jpeg", "image/gif", "image/svg+xml"}
)
// ContentTypeMap is a map of content types to their respective content.
type ContentTypeMap[T any] map[string]T
func (m *ContentTypeMap[T]) unmarshalJSON(raw []byte, valid []string) error {
var cm map[string]json.RawMessage
if err := json.Unmarshal(raw, &cm); err != nil {
return err
}
*m = make(ContentTypeMap[T])
for k, v := range cm {
if !slices.Contains(valid, k) {
// TODO: replace with logr
log.Debug().Caller().Str("mimetype", k).Msg("unexpected content type, skipping")
continue
}
var c T
if err := json.Unmarshal(v, &c); err != nil {
return err
}
(*m)[k] = c
}
return nil
}
func (m ContentTypeMap[T]) getPreferred(preferred []string) *T {
for _, v := range preferred {
if c, ok := m[v]; ok {
return &c
}
}
return nil
}
type TextContent struct {
Content string `json:"content"`
}
type TextContentTypeMap ContentTypeMap[TextContent]
func (t *TextContentTypeMap) UnmarshalJSON(data []byte) error {
return (*ContentTypeMap[TextContent])(t).unmarshalJSON(data, validTextContentTypes)
}
func (t TextContentTypeMap) String() string {
if c := (ContentTypeMap[TextContent])(t).getPreferred(validTextContentTypes); c != nil {
return c.Content
}
return ""
}
type ImageContent struct {
Content *URL `json:"content"`
}
type ImageContentTypeMap ContentTypeMap[ImageContent]
func (i *ImageContentTypeMap) UnmarshalJSON(data []byte) error {
return (*ContentTypeMap[ImageContent])(i).unmarshalJSON(data, validImageContentTypes)
}
func (i ImageContentTypeMap) String() string {
if c := (ContentTypeMap[ImageContent])(i).getPreferred(validImageContentTypes); c != nil {
return c.Content.String()
}
return ""
}

View file

@ -0,0 +1,22 @@
package versiautils
import (
"strings"
)
type MultipleError struct {
Errors []error
}
func (e MultipleError) Error() string {
s := strings.Builder{}
for i, err := range e.Errors {
s.WriteString(err.Error())
if i != len(e.Errors) {
s.WriteRune('\n')
}
}
return s.String()
}