site

package module
v0.2.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 27, 2026 License: MPL-2.0 Imports: 15 Imported by: 0

README

GoAT Site

GoAT Site implements Standard.site in Go.

Use anhgelus.world/xrpc, a lightweight XRPC client.

Main repository is hosted on Tangled, an ATProto forge.

My website is using this library to publish its content on ATProto.

Usage

[!NOTE] Check anhgelus.world/xrpc's documentation first!

Get the module with:

go get -u anhgelus.world/goat-site

Each Standard.site lexicon is implemented:

  • Publication is for site.standard.publication;
  • Document is for site.standard.document;
  • Subscription is for site.standard.graph.subscription.

These types implement xrpc.Record, an interface describing records.

You can get, list, create, update or delete them with functions:

  • xrpc.GetRecord[*site.Publication] to get a publication;
  • xrpc.ListRecords[*site.Document] to list documents;
  • xrpc.CreateRecord to create a new document;
  • xrpc.PutRecord to update a subscription;
  • xrpc.DeleteRecord[*site.Publication] to delete a publication.

You can verify a publication with Publication.Verify and a document with Document.Verify:

var pub *site.Publication
var did *atproto.DID
var client xrpc.Client
var rkey atproto.RecordKey
valid, err := pub.Verify(context.TODO(), client, did, rkey)
if err != nil {
    panic(err)
}
if !valid {
    println("invalid publication :(")
}

var doc *site.Document
pubUrl, err := doc.PublicationURL(context.TODO(), client)
if err != nil {
    panic(err)
}
valid, err = doc.Verify(context.TODO(), client, pubUrl, did, rkey)
if err != nil {
    panic(err)
}
if !valid {
    panic("invalid document :(")
}

Creating custom records

Document.Content is an open union: you can create your own lexicon to use it.

If the NSID of your lexicon is tld.example.content and its definition in Go is:

type Content struct {
    // Pars represents the paragraphs in [Content].
    Pars []string `json:"pars"`
}

To use it, you have to implement site.Record:

var CollectionContent = atproto.NewNSIDBuilder(`tld.example`).Name("content").Build()

func (c *Content) Collection() *atproto.NSID {
    return CollectionContent
}

But if you use xrpc.GetRecord[*site.Document] to retrieve one, it will return a simple site.Document without your custom content! The Document.Content field is a xrpc.Union, a type representing an open union. You can get the collection of the content with Union.Collection() and the raw bytes with Union.Raw. You can also directly parse your Content with Union.As:

var doc *site.Document
c := new(Content)
// returns an error if it cannot parse or if the type is invalid
if !doc.Content.As(c) {
    panic("not a Content :(")
}
Marshal/Unmarshal

See anhgelus.world/xrpc documentation.

Extending lexicons

Lexicons defined by Standard.site can be extended.

To extend a lexicon, you can create a new type and embed the base lexicon:

type CustomPublication struct {
    site.Publication
    // your custom fields
}

You can call any functions with this new lexicon: the embedded base lexicon already implements the xrpc.Record interface!

Documentation

Overview

Package site implements Standard.site lexicons in Go.

Publication is the implementation of site.standard.publication.

Document is the implementation of site.standard.document.

Subscription is the implementation of site.standard.graph.subscription.

See the xrpc package to learn how to use them.

Extending lexicons

Standard lexicons are designed to be extended. You can extend them by declaring a new type embedding them:

type CustomPublication struct {
  site.Publication
  // your custom fields
}

You should not reimplement xrpc.Record, because the embedded struct already implements it.

Index

Constants

This section is empty.

Variables

View Source
var (
	CollectionDocument    = collectionDocument.Build()
	CollectionContributor = collectionDocument.Fragment("contributor").Build()
)
View Source
var (
	CollectionSubscription = collectionGraph.Name("subscription").Build()
	CollectionRecommend    = collectionGraph.Name("recommend").Build()
)
View Source
var (
	// CollectionBase is the base NSID for Standard.site.
	CollectionBase = atproto.NewNSIDBuilder("site.standard")
	CollectionBlob = "blob"
)
View Source
var (
	CollectionTheme          = CollectionBase.SubAuthority("theme")
	CollectionThemeBasic     = CollectionTheme.Name("basic").Build()
	CollectionThemeColor     = CollectionTheme.Name("color")
	CollectionThemeColorRGB  = CollectionThemeColor.Fragment("rgb").Build()
	CollectionThemeColorRGBA = CollectionThemeColor.Fragment("rgba").Build()
)
View Source
var CollectionPublication = CollectionBase.Name("publication").Build()
View Source
var ErrCannotVerifyWithNoPath = errors.New("cannot verify a document with no path")
View Source
var (
	ErrIncompleteURL = errors.New("incomplete url")
)

Functions

func GetDocumentVerificationTag

func GetDocumentVerificationTag(repo *atproto.DID, rkey atproto.RecordKey) template.HTML

GetDocumentVerificationTag returns the HTML link tag checked during the verification of the Document.

func GetPublicationVerificationURI

func GetPublicationVerificationURI(path string) string

GetPublicationVerificationURI returns the URI called during the verification of the Publication.

path must be empty if the Publication is located at the domain root. path must start with a slash.

See HandlePublicationVerification.

func HandlePublicationVerification

func HandlePublicationVerification(repo *atproto.DID, rkey atproto.RecordKey) http.Handler

HandlePublicationVerification returns an http.Handler used during the verification of the Publication.

See GetPublicationVerificationURI.

Types

type Contributor

type Contributor struct {
	// DID of the [Contributor].
	DID *atproto.DID `json:"did"`
	// Role of the [Contributor] in the [Document].
	// Max length: 1000.
	// Max graphemes: 100.
	Role string `json:"role,omitempty"`
	// DisplayName overrides the name of the [Contributor].
	// Max length: 1000.
	// Max graphemes: 100.
	DisplayName string `json:"displayName,omitempty"`
}

Contributor of a Document.

func (*Contributor) Collection

func (c *Contributor) Collection() *atproto.NSID

type Document

type Document struct {
	// Site points to a [Publication] record `at://` or a [Publication.URL] `https://` for loose documents.
	// Avoid trailing slashes.
	Site *URL `json:"site"`
	// Title of the [Document].
	// Max length: 5000.
	// Max graphemes: 500.
	Title string `json:"title"`
	// PublishedAt is the [time.Time] of the [Document]'s publish time.
	PublishedAt time.Time `json:"publishedAt"`
	// Path is combined with [Document.Site] or [Publication.URL] to construct a canonical URL to the document.
	// A slash should be included at the beginning of this value.
	Path *string `json:"path,omitempty"`
	// A brief Description or excerpt from the [Document].
	// Max length: 30000.
	// Max graphemes: 3000.
	Description *string `json:"description,omitempty"`
	// CoverImage to used for thumbnail or cover.
	// Less than 1MB in size.
	CoverImage *xrpc.Blob `json:"coverImage,omitempty"`
	// Content is an [xrpc.Union] used to define the [Document]'s content.
	Content *xrpc.Union `json:"content,omitempty"`
	// TextContent is a plaintext representation of the [Document.Content].
	// Should not contain markdown or other formatting.
	TextContent string `json:"textContent,omitempty"`
	// BlueskyPostRef is a strong reference to a Bluesky post.
	// Useful to keep track of comments off-platform.
	BlueskyPostRef *xrpc.StrongRef `json:"bskyPostRef,omitempty"`
	// Tags is an array of strings used to tag or categorize the [Document].
	// Avoid prepending tags with hashtags.
	// Max length: 1280.
	// Max graphemes: 128.
	Tags []string `json:"tags,omitempty"`
	// Contributors who helped for the [Document].
	Contributors []*Contributor `json:"contributors,omitempty"`
	// Links describes relationships between this document and external resources.
	Links *xrpc.Union `json:"links,omitempty"`
	// UpdatedAt is the [time.Time] of the [Document]'s last edit.
	UpdatedAt *time.Time `json:"updatedAt,omitempty"`
}

Document may be standalone or associated with a Publication. This xrpc.Record can be used to store a document's content and its associated metadata.

func (*Document) Collection

func (d *Document) Collection() *atproto.NSID

func (*Document) MarshalMap

func (d *Document) MarshalMap() (any, error)

func (*Document) PublicationURL

func (d *Document) PublicationURL(ctx context.Context, client xrpc.Client) (*url.URL, error)

PublicationURL returns the url.URL of the linked Publication.

Prefer using [GetRecord] if you plan to retrieve the record. Under the hood, this method retrieves the Publication record if Document.Site is an [ATURL].

func (*Document) UnmarshalJSON

func (d *Document) UnmarshalJSON(b []byte) error

func (*Document) Verify

func (d *Document) Verify(ctx context.Context, client *http.Client, pubURL *url.URL, did *atproto.DID, rkey atproto.RecordKey) (bool, error)

Verify the Document.

type ErrInvalidCollection

type ErrInvalidCollection struct {
	// contains filtered or unexported fields
}

func (ErrInvalidCollection) Error

func (err ErrInvalidCollection) Error() string

type Preferences

type Preferences struct {
	// ShowInDiscover decides whether the [Publication] should appear in discovery feeds.
	ShowInDiscover bool `json:"showInDiscover"`
}

Preferences of the Publication.

type Publication

type Publication struct {
	// Base URL of the [Publication].
	// This value will be combined with the [Document.Path] to construct a full URL for the document.
	// Avoid trailing slashes.
	URL *url.URL `json:"-"`
	// Name of the [Publication].
	// Max length: 5000.
	// Max graphemes: 500.
	Name string `json:"name"`
	// Icon to identify the [Publication].
	// Must be a square image and should be at least 256x256.
	Icon *xrpc.Blob `json:"icon,omitempty"`
	// Description of the [Publication].
	// Max length: 30000.
	// Max graphemes: 3000.
	Description *string `json:"description,omitempty"`
	// Simplified theme for tools and apps to utilize when displaying content.
	BasicTheme *Theme `json:"basicTheme,omitempty"`
	// Platform-specific [Preferences] for the [Publication], including discovery and visibility settings.
	Preferences *Preferences `json:"preferences,omitempty"`
}

Publication represents a collection of [Document]s published to the web. It includes important information about a publication including its location on the web, theming information, user Preferences, and more.

The Publication [Record] is not a requirement, but is recommended when publishing collections of related [Document]s.

func (*Publication) Collection

func (p *Publication) Collection() *atproto.NSID

func (*Publication) MarshalMap

func (p *Publication) MarshalMap() (any, error)

func (*Publication) UnmarshalJSON

func (p *Publication) UnmarshalJSON(b []byte) error

func (*Publication) Verify

func (p *Publication) Verify(ctx context.Context, client *http.Client, repo *atproto.DID, rkey atproto.RecordKey) (bool, error)

Verify the Publication.

type RGB

type RGB struct {
	Red   uint8 `json:"r"`
	Green uint8 `json:"g"`
	Blue  uint8 `json:"b"`
}

RGB represents a RGB color.

See also RGBA.

func NewRGB

func NewRGB(r, g, b uint8) *RGB

func (*RGB) Collection

func (r *RGB) Collection() *atproto.NSID

func (*RGB) RGBA

func (r *RGB) RGBA() *RGBA

func (*RGB) String

func (r *RGB) String() string

type RGBA

type RGBA struct {
	RGB
	// Alpha is the alpha channel where 0 is transparent and 100 is opaque.
	Alpha uint8 `json:"a"`
}

RGBA represents a color.RGBA.

See also RGB.

func NewRGBA

func NewRGBA(r *color.RGBA) *RGBA

func NewRawRGBA

func NewRawRGBA(r, g, b, a uint8) *RGBA

func (*RGBA) Collection

func (r *RGBA) Collection() *atproto.NSID

func (*RGBA) String

func (r *RGBA) String() string

type Recommend

type Recommend struct {
	// Document is an AT-URI reference to the recommended document.
	Document  atproto.RawURI `json:"document"`
	CreatedAt time.Time      `json:"createdAt"`
}

func (*Recommend) Collection

func (r *Recommend) Collection() *atproto.NSID

type Subscription

type Subscription struct {
	// Publication is an AT-URI reference to the publication record being subscribed to.
	// E.g., `at://did:plc:abc123/site.standard.publication/xyz789`.
	Publication atproto.RawURI `json:"publication"`
	CreatedAt   *time.Time     `json:"createdAt,omitempty"`
}

Subscription enable users to follow publications and receive updates about new content. They represent the social connection between readers and the publications they're interested in.

func (*Subscription) Collection

func (s *Subscription) Collection() *atproto.NSID

type Theme

type Theme struct {
	// Background is the color used for content background.
	Background *RGB `json:"background"`
	// Foreground is the color used for content text.
	Foreground *RGB `json:"foreground"`
	// Accent is the color used for links and button backgrounds.
	Accent *RGB `json:"accent"`
	// AccentForeground is the color used for button text.
	AccentForeground *RGB `json:"accentForeground"`
}

Theme ensures [Publication]s maintain their visual identity across different reading applications and platforms by defining core colors for content display.

func (*Theme) Collection

func (t *Theme) Collection() *atproto.NSID

type URL

type URL struct {
	// contains filtered or unexported fields
}

URL represents an url.URL that may be an atproto.RawURI.

See ParseURL, FromURL and FromRawAT.

func FromRawAT added in v0.2.1

func FromRawAT(raw atproto.RawURI) *URL

func FromURL added in v0.2.1

func FromURL(u *url.URL) *URL

func ParseURL

func ParseURL(raw string) (*URL, error)

ParseURL returns an URL from a raw string.

func (*URL) AT

func (u *URL) AT() *atproto.RawURI

AT returns the [ATURL]. Panics if it isn't an [ATURL].

See URL.IsAT.

func (*URL) IsAT

func (u *URL) IsAT() bool

IsAT returns true if the URL is an [ATURL].

See URL.AT and URL.URL.

func (*URL) MarshalMap

func (u *URL) MarshalMap() (any, error)

func (*URL) URL

func (u *URL) URL() *url.URL

URL returns the url.URL. Panics if it is an [ATURL].

See URL.IsAT.

func (*URL) UnmarshalJSON

func (u *URL) UnmarshalJSON(b []byte) error

Source Files

  • doc.go
  • document.go
  • graph.go
  • lexicons.go
  • publication.go
  • theme.go
  • url.go

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL