Help us shape the future of Go! Take the 2026 Go Developer Survey

entities

package
v0.135.0 Latest Latest
Warning

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

Go to latest
Published: Oct 28, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package entities is how content is grouped: tags, artists, series, characters, channels, playlists and featured rails. Entity kinds come from kinds.Config.EntityKinds. A entity has localized names and aliases, per-language text, declared attributes, a cover, a parent, an optional scope and edges to other entities; content joins it through memberships, at content level or for one version where the kind allows. A version's effective entities (EffectiveEntities) feed content_facets.entity_ids; counts derive from those facets.

Index

Constants

View Source
const AvatarPreset = "avatar"

AvatarPreset is the media preset avatars render in (media.AvatarPreset).

View Source
const DefaultDeletedRetention = 30 * 24 * time.Hour

DefaultDeletedRetention is how long a deleted user-owned entity keeps its media folder, so a restore brings it back.

View Source
const (
	EventCreated = "entity.created"
)
View Source
const (
	EventDeleted = "entity.deleted"
)
View Source
const (
	// EventMerged names the final survivor in MergedInto. Earlier merges into
	// the merged entity are re-recorded with the same survivor.
	EventMerged = "entity.merged"
)
View Source
const (
	EventRestored = "entity.restored"
)
View Source
const (
	EventUpdated = "entity.updated"
)
View Source
const MaxListIDs = 100

MaxListIDs bounds ListOptions.IDs.

View Source
const MaxMatchNames = 100

MaxMatchNames bounds MatchQuery.Names.

View Source
const NameSeparators = `[[:space:]_‐‑‒–—―-]+`

NameSeparators are ignored when names match. Removing all punctuation would conflate distinct names such as C/C++ or AC/DC and ACDC.

Variables

View Source
var (
	ErrInvalid = errors.New("entities: invalid input")
)

Functions

This section is empty.

Types

type AppBinding

type AppBinding interface {
	ContentKitScope() (tenantID, appID string)
}

AppBinding identifies the tenant/app an authorization scope provider serves. A scoped engine requires a matching binding before enabling auth_scope kinds.

type Avatar

type Avatar struct {
	Image string `json:"image,omitempty"`
	// Renditions are its public images, filled on reads (Options.Covers).
	Renditions []Rendition `json:"renditions,omitempty"`
}

Avatar is an entity's square picture (kinds.EntityKind.HasAvatar): an image uploaded to the entity's media folder ("avatar/i-{uuid}"), selected by name. Without a selection a read shows the folder's first avatar, else the kind's default.

type Change added in v0.135.0

type Change struct {
	Type       string
	Kind       string
	ID         EntityID
	MergedInto EntityID
}

Change is one committed entity mutation.

type ContentEntities

type ContentEntities struct {
	// ContentID names the content; routes take it from the path.
	ContentID string `json:"-"`
	// VersionScope limits replacement to one ownership scope. Nil preserves
	// the legacy all-version replacement; empty means shared content links;
	// otherwise it names the one version whose links may change.
	VersionScope *string `json:"-"`
	// Kinds limits the write to these entity kinds; empty means every entity
	// kind the content's kind declares.
	Kinds       []string     `json:"kinds,omitempty"`
	Memberships []Membership `json:"memberships"`
	// Create links these names too, creating entities of creatable kinds that
	// no active entity names yet, in the same transaction.
	Create []NewEntity `json:"create,omitempty"`
}

ContentEntities is one content's memberships in the entity kinds Kinds names.

type ContentMemberships

type ContentMemberships struct {
	ContentID   string       `json:"content_id"`
	Memberships []Membership `json:"memberships"`
	Entities    []EntityCard `json:"entities"`
}

ContentMemberships is a content's memberships with the entities they name.

type Count

type Count struct {
	ContentKind string `json:"content_kind"`
	Language    string `json:"language"`
	Count       int    `json:"count"`
}

Count is the number of distinct live, listed contents of one kind in a entity (its descendants included) or owned by it, serving one language; Language "" counts every language once.

type Cover

type Cover struct {
	Image     string `json:"image,omitempty"`
	ContentID string `json:"content_id,omitempty"`
	Auto      bool   `json:"auto,omitempty"`
	// Renditions are its public images, filled on reads (Options.Covers).
	Renditions []Rendition `json:"renditions,omitempty"`
}

Cover is an entity's picture: an image uploaded to the entity's media folder ("i-{uuid}") or a member content's cover, the cover of the edition a reader's language opens by default. Auto covers are the most-favorited live member, selected at read time when none is explicitly chosen.

type CoverOf

type CoverOf struct {
	Kind     string
	ID       EntityID
	Cover    Cover
	Language string
	Preset   string
}

CoverOf is one entity's picture to resolve: its cover, or with Preset "avatar" its avatar (Cover.Image the selected one, if any). A content's cover is its default edition's in Language.

type CoverResolver

type CoverResolver interface {
	Covers(ctx context.Context, covers []CoverOf) ([][]Rendition, error)
}

CoverResolver turns covers and avatars into their public renditions, per picture in order, one call per page: media/versions.Service.EntityCovers.

type Edge

type Edge struct {
	From     EntityID `json:"from"`
	Relation string   `json:"relation"`
	To       EntityID `json:"to"`
}

Edge is a typed relation between two entities beside parent and scope: "from is <relation> of to", such as a character member_of a second series.

type EdgeInput

type EdgeInput struct {
	Relation string   `json:"relation"`
	To       EntityID `json:"to"`
}

EdgeInput is an edge from the entity a route names.

type Entity

type Entity struct {
	ID   EntityID `json:"id"`
	Kind string   `json:"kind"`
	Slug string   `json:"slug"`
	// Internal marks a classification used by policy rather than public metadata.
	Internal bool `json:"internal"`
	// ScopeID is the entity the slug is unique within (a character's series).
	ScopeID     EntityID       `json:"scope_id,omitempty"`
	ParentID    EntityID       `json:"parent_id,omitempty"`
	State       State          `json:"state"`
	MergedInto  EntityID       `json:"merged_into,omitempty"`
	Attributes  map[string]any `json:"attributes"`
	Cover       *Cover         `json:"cover,omitempty"`
	Avatar      *Avatar        `json:"avatar,omitempty"`
	OwnerUserID string         `json:"-"`
	// AuthScope is the AuthKit group whose holders of
	// access.EntitySettingsManage edit it; ContentKit provisions it for a
	// kind with auth_scope (Options.Scopes).
	AuthScope string    `json:"-"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
	Revision  int64     `json:"revision"`
}

Entity is one entity record.

type EntityAccess added in v0.125.0

type EntityAccess struct {
	Key     access.Key `json:"key"`
	Member  bool       `json:"member"`
	Editor  bool       `json:"editor,omitempty"`
	Unknown bool       `json:"unknown,omitempty"`
}

EntityAccess is an entity entitlement and the current viewer's standing. Product and price information belongs to the billing provider.

type EntityCard

type EntityCard struct {
	ID       EntityID `json:"id"`
	Kind     string   `json:"kind"`
	Slug     string   `json:"slug"`
	Internal bool     `json:"internal"`
	ScopeID  EntityID `json:"scope_id,omitempty"`
	ParentID EntityID `json:"parent_id,omitempty"`
	State    State    `json:"state"`
	// MergedInto is a merged entity's final survivor.
	MergedInto   EntityID `json:"merged_into,omitempty"`
	Name         string   `json:"name"`
	NameLanguage string   `json:"name_language,omitempty"`
	Code         string   `json:"code,omitempty"`
	Path         string   `json:"path,omitempty"`
	Cover        *Cover   `json:"cover,omitempty"`
	// Avatar is a user-owned entity's avatar.
	Avatar     *Avatar        `json:"avatar,omitempty"`
	Count      int            `json:"count"`
	Attributes map[string]any `json:"attributes"`
	// Access is an entitlement-backed entity's key and the
	// viewer's standing.
	Access    *EntityAccess `json:"access,omitempty"`
	CreatedAt time.Time     `json:"created_at"`
}

EntityCard is a listed entity: what a directory page or a chip needs.

type EntityDetail

type EntityDetail struct {
	Entity
	Name         string       `json:"name"`
	NameLanguage string       `json:"name_language,omitempty"`
	Code         string       `json:"code,omitempty"`
	Path         string       `json:"path,omitempty"`
	Names        []Name       `json:"names"`
	Text         []Text       `json:"text"`
	Parent       *EntityCard  `json:"parent,omitempty"`
	Scope        *EntityCard  `json:"scope,omitempty"`
	Children     []EntityCard `json:"children"`
	Edges        []Edge       `json:"edges"`
	Counts       []Count      `json:"counts"`
	// Access is an entitlement-backed entity's key and the
	// viewer's standing.
	Access *EntityAccess `json:"access,omitempty"`
}

EntityDetail is one entity with everything its page shows.

func (EntityDetail) MatchesIdentity added in v0.131.0

func (d EntityDetail) MatchesIdentity(names []Name, text []Text) bool

MatchesIdentity compares caller-supplied names and localized text using the same normalization as writes. It is useful when replaying an acknowledged creation: omitted alias kinds, language casing and surrounding name/sort-key whitespace must not turn an identical request into a conflicting identity.

type EntityID

type EntityID = contentref.EntityID

EntityID identifies one entity within a tenant: a UUIDv7, kept across import.

type EntityInput

type EntityInput struct {
	// ID is optional; omitted ids are generated.
	ID   EntityID `json:"id,omitempty"`
	Kind string   `json:"kind"`
	Slug string   `json:"slug"`
	// Internal classifications are visible only through management reads.
	Internal bool `json:"internal,omitempty"`
	// ScopeID is required for a kind scoped by another (a character's series).
	ScopeID    EntityID       `json:"scope_id,omitempty"`
	ParentID   EntityID       `json:"parent_id,omitempty"`
	Attributes map[string]any `json:"attributes,omitempty"`
	Cover      *Cover         `json:"cover,omitempty"`
	Avatar     *Avatar        `json:"avatar,omitempty"`
	// OwnerUserID owns a user-owned entity; a person creating one owns it.
	OwnerUserID string `json:"-"`
	// AuthScope is staff's (an import's); ContentKit provisions it otherwise.
	AuthScope string `json:"-"`
	Names     []Name `json:"names,omitempty"`
	Text      []Text `json:"text,omitempty"`
}

EntityInput creates one entity.

type EntityNames

type EntityNames struct {
	ID    EntityID `json:"id"`
	Names []Name   `json:"names"`
}

EntityNames is one entity's names in a names write.

type EntityPage

type EntityPage struct {
	Entities []EntityCard `json:"entities"`
	// NextCursor pages on; empty on the last page.
	NextCursor string `json:"next_cursor,omitempty"`
	// Total is every matching entity, on numbered pages only.
	Total *int `json:"total,omitempty"`
}

EntityPage is one page of a listing.

type EntityUpdate

type EntityUpdate struct {
	// ID names the entity; routes take it from the path.
	ID       EntityID  `json:"-"`
	Slug     *string   `json:"slug,omitempty"`
	Internal *bool     `json:"internal,omitempty"`
	ScopeID  *EntityID `json:"scope_id,omitempty"`
	// ParentID "" detaches the entity from its parent.
	ParentID *EntityID `json:"parent_id,omitempty"`
	// State restores (active) or deletes an entity.
	State *State `json:"state,omitempty"`
	// Attributes replaces every attribute.
	Attributes map[string]any `json:"attributes,omitempty"`
	// Cover selects a cover; an empty one returns to the automatic cover.
	Cover *Cover `json:"cover,omitempty"`
	// Avatar selects the entity's avatar (kinds with avatars); an empty one returns to
	// the first.
	Avatar      *Avatar `json:"avatar,omitempty"`
	OwnerUserID *string `json:"-"`
	AuthScope   *string `json:"-"`
	// Names replaces every name and alias.
	Names []Name `json:"names,omitempty"`
	// Text replaces the text of every language.
	Text []Text `json:"text,omitempty"`
}

EntityUpdate changes one entity's given fields; nil fields are unchanged.

type ImportEntity

type ImportEntity struct {
	ID   EntityID
	Kind string
	Slug string
	// Internal preserves the stored classification when omitted.
	Internal    *bool
	ScopeID     EntityID
	ParentID    EntityID
	State       State
	Attributes  map[string]any
	Cover       *Cover
	Avatar      *Avatar
	OwnerUserID string
	// AuthScope names the entity's AuthKit scope; empty keeps the stored one.
	AuthScope string
	Names     []Name
	Text      []Text
	// Edges are the entity's edges to others (From is the entity).
	Edges     []Edge
	Code      string
	CreatedAt *time.Time
	UpdatedAt *time.Time
}

ImportEntity is an entity as the bulk import writes it: its id kept. Nil Names, Text and Edges keep what is stored; given ones replace it.

type LocalScopes

type LocalScopes interface {
	HoldingScopes(ctx context.Context, user string, kinds, scopeIDs []string) (map[string][]string, error)
}

LocalScopes optionally narrows authorization lookups to scope IDs verified by this app's store. It lets a shared identity directory resolve grants without enumerating or trusting entities belonging to other apps.

type MatchQuery added in v0.135.0

type MatchQuery struct {
	Kind string
	// Scope is the entity the names are unique within; empty matches unscoped
	// entities only.
	Scope EntityID
	// Language matches names in it only; empty matches every language.
	Language string
	// Normalized compares ContentKit's normalized forms, folding case, accents
	// and whitespace; otherwise names must be equal byte for byte.
	Normalized bool
	// Names are matched whole: a comma never separates two names.
	Names []string
}

MatchQuery selects the entities MatchNames compares names against: active, public entities of Kind within Scope.

type MemberOptions

type MemberOptions struct {
	// Cursor is the previous page's NextCursor.
	Cursor string
	// Limit defaults to 50 and is capped at 500.
	Limit int
}

MemberOptions pages Members.

type MemberPage

type MemberPage struct {
	Members []Membership `json:"members"`
	// NextCursor pages on; empty on the last page.
	NextCursor string `json:"next_cursor,omitempty"`
}

MemberPage is one page of an entity's memberships.

type MemberRef

type MemberRef struct {
	ContentID string `json:"content_id"`
	VersionID string `json:"version_id,omitempty"`
}

MemberRef names a member of an entity: content, or one version of it.

type Membership

type Membership struct {
	EntityID  EntityID        `json:"group_id,omitempty"`
	ContentID string          `json:"content_id,omitempty"`
	VersionID string          `json:"version_id,omitempty"`
	Role      string          `json:"role,omitempty"`
	Position  *int            `json:"position,omitempty"`
	State     MembershipState `json:"state,omitempty"`
}

Membership places content, or one version of it, in an entity. Position orders an ordered entity (appended when omitted).

type MembershipState

type MembershipState string

MembershipState: a proposed membership (a suggestion awaiting review) is stored but effective nowhere until it is accepted.

const (
	MembershipActive MembershipState = "active"
)
const (
	MembershipProposed MembershipState = "proposed"
)

type Merge

type Merge struct {
	From EntityID `json:"from"`
	Into EntityID `json:"into"`
}

Merge folds entity From into entity Into of the same kind.

type MergeInput

type MergeInput struct {
	Into EntityID `json:"into"`
}

MergeInput names the entity a merge folds into.

type MergeReport

type MergeReport struct {
	From             EntityID `json:"from"`
	Into             EntityID `json:"into"`
	MembershipsMoved int64    `json:"memberships_moved"`
	NamesMoved       int64    `json:"names_moved"`
	EdgesMoved       int64    `json:"edges_moved"`
	EntitiesMoved    int64    `json:"groups_moved"`
}

MergeReport summarizes one merge.

type MyEntity

type MyEntity struct {
	EntityCard
	// Owner: the viewer is its recorded owner and retains ownership authority.
	Owner bool `json:"owner"`
	// Editor: the viewer holds its kind's access.EntitySettingsManage in its
	// AuthKit scope.
	Editor bool `json:"editor"`
	// CanPost permits new personal posts in this channel.
	CanPost bool `json:"can_post"`
	// CanEditOwn permits editing the viewer's own posts, not other authors.
	CanEditOwn bool `json:"can_edit_own"`
	// Writer: the viewer holds its kind's access.EntityContentWrite there.
	Writer bool `json:"writer"`
	// Moderator: the viewer holds its kind's access.EntityCommentsModerate
	// there, or owns it.
	Moderator bool `json:"moderator"`
	// Member: the viewer holds its key.
	Member bool `json:"member"`
}

MyEntity is an entity of the viewer's, with how it is theirs.

type MyEntityPage

type MyEntityPage struct {
	Entities   []MyEntity `json:"entities"`
	NextCursor string     `json:"next_cursor,omitempty"`
}

MyEntityPage is one page of the viewer's entities.

type Name

type Name struct {
	Language string   `json:"language"`
	Kind     NameKind `json:"kind"`
	Name     string   `json:"name"`
}

Name is one localized canonical name or alias.

type NameKind

type NameKind string

NameKind distinguishes the one canonical name per language from aliases.

const (
	NameAlias NameKind = "alias"
)
const (
	NameCanonical NameKind = "name"
)

type NameMatch added in v0.135.0

type NameMatch struct {
	Name string     `json:"name"`
	IDs  []EntityID `json:"ids"`
}

NameMatch is the entities whose canonical name or alias matches Name, in id order: none is unresolved, two (at most) is ambiguous.

type NewEntity

type NewEntity struct {
	Kind string `json:"kind"`
	Name string `json:"name"`
	// Language of a created entity's canonical name; the catalog's first by default.
	Language string `json:"language,omitempty"`
}

NewEntity is a name a content write links, creating the entity when no active entity of its kind carries that name or alias in any language.

type Order

type Order struct {
	// EntityID names the entity; routes take it from the path.
	EntityID EntityID    `json:"-"`
	Members  []MemberRef `json:"members"`
}

Order sets the member order of one ordered entity.

type OwnedContent

type OwnedContent interface {
	// DeleteOwned deletes the live content of the deleted ones among entities,
	// recording each entity as its content's cause; bought content stays
	// readable to its buyers.
	DeleteOwned(ctx context.Context, ents []string) error
	// RestoreOwned restores the content the active ones among entities
	// deleted when they were, unless it was purged since; content deleted
	// for another reason stays deleted.
	RestoreOwned(ctx context.Context, ents []string) error
}

OwnedContent follows user-owned entities' deletion and restore with the content they own (owner_entity): the catalog. A nil entities is every entity.

type Ref

type Ref struct {
	Kind string
	ID   EntityID
}

Ref names one entity with its kind.

type Rendition

type Rendition struct {
	URL string `json:"url"`
	W   int    `json:"w"`
	H   int    `json:"h"`
}

Rendition is one public image of a cover, as media.PublicRendition.

type Scope

type Scope struct {
	// Restore permits deliberately restoring a previously retired group. Normal
	// provisioning (including configured fixed owners) preserves live groups
	// and refuses deleted groups rather than silently removing their grants.
	Restore bool
	ID      string
	Kind    string
	Owner   string
}

Scope is one entity's AuthKit scope: ContentKit keys it by the entity's id.

type ScopeProvisioner added in v0.129.0

type ScopeProvisioner interface {
	Provision(ctx context.Context, scopes []Scope) error
}

ScopeProvisioner ensures the declared authorization groups exist. It is the only provider capability needed by explicit fixed-owner migrations.

type Scopes

type Scopes interface {
	ScopeProvisioner
	// Retire stops each scope resolving and granting.
	Retire(ctx context.Context, ids []string) error
	// Holding answers, per live scope of the kinds' personas user belongs
	// to, the kind's access.ChannelPermissions user holds there.
	Holding(ctx context.Context, user string, kinds []string) (map[string][]string, error)
}

Scopes keeps the AuthKit groups of auth_scope entity kinds. Provision and Retire are idempotent; runtime adds read/revocation behavior to provisioning.

type Sort

type Sort string

Sort orders an entity listing; every order is made total by id.

const (
	// SortCount orders by content count, largest first.
	SortCount Sort = "count"
)
const (
	// SortName orders by sort key, else display name. The default.
	SortName Sort = "name"
)
const (
	// SortNewest orders by creation, newest first.
	SortNewest Sort = "newest"
)

type State

type State string

State of an entity. A merged entity points at its survivor (MergedInto); deleted entities keep their memberships but are effective nowhere.

const (
	StateActive State = "active"
)
const (
	StateDeleted State = "deleted"
)
const (
	StateMerged State = "merged"
)

type Text

type Text struct {
	Language    string `json:"language"`
	Description string `json:"description,omitempty"`
	SortKey     string `json:"sort_key,omitempty"`
}

Text is an entity's description and sort key in one language.

type Written

type Written struct {
	Count int `json:"count"`
}

Written counts the items a write named.

Jump to

Keyboard shortcuts

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