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

catalog

package
v0.117.0 Latest Latest
Warning

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

Go to latest
Published: Oct 23, 2026 License: MIT Imports: 49 Imported by: 0

Documentation

Overview

Package catalog is ContentKit's own content: content items (a gallery, a movie, a creator or blog post), their per-language text, creators, versions with their text and segments, the state machine (draft, published, scheduled, deleted), the listing projection (content_facets), the one visibility rule every read applies, the retained event log and the catalog totals. Kinds are configuration (package kinds); nothing here names a host's nouns.

Index

Constants

View Source
const (
	EventContentCreated     = "content.created"
	EventContentUpdated     = "content.updated"
	EventContentScheduled   = "content.scheduled"
	EventContentPublished   = "content.published"
	EventContentUnpublished = "content.unpublished"
	EventContentDeleted     = "content.deleted"
	EventContentRestored    = "content.restored"
	EventContentPurged      = "content.purged"
	EventVersionCreated     = "version.created"
	EventVersionUpdated     = "version.updated"
	EventVersionPublished   = "version.published"
	EventVersionDeleted     = "version.deleted"
	EventVersionPurged      = "version.purged"
	EventAudienceReleased   = "version.audience_released"
)

Event types recorded with the domain mutation.

View Source
const (
	StateDraft     = "draft"
	StatePublished = "published"
	StateDeleted   = "deleted"
)

Content states.

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

DefaultDeletedRetention is how long deleted content keeps its media and can be restored before PurgeDeleted erases it.

View Source
const DefaultEventRetention = 90 * 24 * time.Hour

DefaultEventRetention is independent of readers' progress.

View Source
const HeldKind = "content"

HeldKind is the review queue's kind for held content (content.Runtime's /moderation/held?kind=content).

View Source
const ImageScheme = "contentkit:"

ImageScheme is the URL scheme of an inline image reference in a body.

View Source
const MaxManageIDs = 100

MaxManageIDs bounds ManageQuery.IDs.

View Source
const Queue = "contentkit_catalog"

Queue is the River queue of content jobs. Keep its persisted routing name stable so jobs queued before the terminology change continue to run.

Variables

View Source
var (
	ErrEventCursorInvalid = errors.New("catalog: invalid event cursor")
	ErrEventCursorExpired = errors.New("catalog: event cursor expired; resync current state")
)
View Source
var (
	ErrInvalid   = errors.New("catalog: invalid request")
	ErrNotFound  = errors.New("catalog: not found")
	ErrForbidden = errors.New("catalog: forbidden")
	ErrConflict  = errors.New("catalog: conflict")
)

Errors; match with errors.Is.

Functions

func BackfillVersionTitles added in v0.112.0

func BackfillVersionTitles(ctx context.Context, pool *pgxpool.Pool, schema, tenant, kind string) (int64, error)

BackfillVersionTitles is an explicit, repeatable adoption step for a kind switching to original_and_version titles. It only copies titles from the exact same content language into a version serving that language. Existing edition titles/descriptions and all content text remain unchanged. It never invents an original title or infers the source language.

func ImageRef

func ImageRef(name string) string

ImageRef is the body reference to an inline image name ("i-{uuid}").

func RefreshPaths added in v0.104.0

func RefreshPaths(ctx context.Context, pool *pgxpool.Pool, schema, tenant string, model kinds.Config) (int, error)

RefreshPaths is the operator form of Store.RefreshPaths for one tenant, or every tenant in the schema when tenant is ""; it opens no server, auth or billing runtime.

func RetireOpenCounters added in v0.104.0

func RetireOpenCounters(ctx context.Context, pool *pgxpool.Pool, schema string, legacyWritersStopped bool) error

RetireOpenCounters is the operator form; it opens no server/auth/billing runtime.

Types

type AuthError

type AuthError struct{ Err error }

AuthError is a permission check the auth could not answer: 401 when the credential ended, else 503. It never grants.

func (*AuthError) Error

func (e *AuthError) Error() string

func (*AuthError) Unwrap

func (e *AuthError) Unwrap() error

type BodyImageInput added in v0.87.0

type BodyImageInput struct {
	Image   *string `json:"image"`
	Version string  `json:"version"`
}

BodyImageInput names a body image uploaded to one version (Upload.Body).

type Content

type Content struct {
	ID   string `json:"id"`
	Kind string `json:"kind"`
	// Code and Path are its page: /{lang}/{route}/{code}/{slug}.
	Code string `json:"code"`
	Path string `json:"path"`
	// Language is the localized text language. Title may instead come from the
	// selected edition or OriginalTitle under the kind's title policy.
	Language string `json:"language"`
	Title    string `json:"title"`
	// OriginalTitle is the shared source-language title, independent of editions.
	// OriginalLanguage is optional: unknown source languages are never guessed.
	OriginalTitle    string `json:"original_title,omitempty"`
	OriginalLanguage string `json:"original_language,omitempty"`
	// Slug is Path's decorative tail in the page's language (entity and
	// title, "/"-joined); Slugs is it per language. Links built from them
	// equal Path.
	Slug        string            `json:"slug,omitempty"`
	Slugs       map[string]string `json:"slugs,omitempty"`
	Description string            `json:"description,omitempty"`
	// Body shows each inline image with a current public file as its URL;
	// only editors and viewers Decision allows get it. Description is the
	// teaser everyone reads.
	Body string `json:"body,omitempty"`
	// Decision is the viewer's access to the item: allowed when they open any
	// of its versions, else its first version's paywall.
	Decision Decision `json:"decision"`
	// Images maps each resolved image name of Body to its URL: the body
	// images of the edition the viewer opens (DefaultVersion among them).
	Images map[string]string `json:"images,omitempty"`
	// Cover is the cover of the edition the request's language opens by
	// default (DefaultVersion): what cards and meta tags show.
	Cover *Cover `json:"cover,omitempty"`
	State string `json:"state"`
	// Comments is open, closed or hidden.
	Comments      string         `json:"comments"`
	PublishAt     *time.Time     `json:"publish_at,omitempty"`
	PublishedAt   *time.Time     `json:"published_at,omitempty"`
	Live          bool           `json:"live"`
	Access        access.Rule    `json:"access"`
	Restrictions  []string       `json:"restrictions"`
	Attributes    map[string]any `json:"attributes"`
	OwnerEntityID string         `json:"owner_group_id,omitempty"`
	// Owner is the owner entity's card (a channel's name, path, avatar and
	// cover) while it is active.
	Owner    *entities.EntityCard `json:"owner,omitempty"`
	Creators []Creator            `json:"creators"`
	// Entities are shared/null-version memberships. Version-specific entities
	// are carried by each Version.Entities, never merged across editions here.
	Entities []EntitySummary `json:"entities"`
	Versions []Version       `json:"versions"`
	// SelectedVersionID is the edition selected for this response: the direct
	// version lookup's edition, or the default among the visible versions.
	SelectedVersionID string `json:"selected_version_id,omitempty"`
	// Viewer is the signed-in reader's standing with the item, to resume
	// it; each version carries its own.
	Viewer *ViewerState `json:"viewer,omitempty"`
	// Editor: the viewer may edit it; the fields below are theirs.
	Editor           bool            `json:"editor"`
	Text             map[string]Text `json:"text,omitempty"`
	Moderation       string          `json:"moderation,omitempty"`
	ModerationReason string          `json:"moderation_reason,omitempty"`
	EverSold         bool            `json:"ever_sold,omitempty"`
	// Offer is the item's current offer, for its offer editors.
	Offer     *offers.Offer `json:"offer,omitempty"`
	Revision  int64         `json:"revision"`
	CreatedAt time.Time     `json:"created_at"`
	UpdatedAt time.Time     `json:"updated_at"`
	DeletedAt *time.Time    `json:"deleted_at,omitempty"`
}

Content is a content item as a viewer sees it: its text in the viewer's language (falling back), its live versions (every version for editors), entities and attributes. A viewer who opens none of its versions gets what its kind's locked view shows (kinds.Locked), and of each locked version what that view shows.

type ContentInput

type ContentInput struct {
	Kind string `json:"kind"`
	// Text is the text per language.
	Text             map[string]Text `json:"text,omitempty"`
	OriginalTitle    string          `json:"original_title,omitempty"`
	OriginalLanguage string          `json:"original_language,omitempty"`
	// Comments is open (the default when permitted), closed (existing ones
	// show, new ones are refused) or hidden. A kind excluding open defaults to
	// its first configured comment mode.
	Comments string `json:"comments,omitempty"`
	// Access defaults to public when permitted, otherwise the kind's first
	// allowed level (and the first configured tier for tier access).
	Access       *access.Rule   `json:"access,omitempty"`
	Restrictions []string       `json:"restrictions,omitempty"`
	Attributes   map[string]any `json:"attributes,omitempty"`
	// OwnerEntityID is the home entity (a channel); its editors edit the item.
	// It never changes.
	OwnerEntityID string `json:"owner_group_id,omitempty"`
	// Creators nil credits the creating person as its author.
	Creators *[]Creator `json:"creators,omitempty"`
	// Versions: none gives the item one serving its text's languages (a
	// kind with hidden versions takes none).
	Versions []VersionInput `json:"versions,omitempty"`
}

ContentInput creates a content item, a draft until published.

type ContentPatch

type ContentPatch struct {
	OriginalTitle    *string        `json:"original_title,omitempty"`
	OriginalLanguage *string        `json:"original_language,omitempty"`
	Comments         *string        `json:"comments,omitempty"`
	Access           *access.Rule   `json:"access,omitempty"`
	Restrictions     *[]string      `json:"restrictions,omitempty"`
	Attributes       map[string]any `json:"attributes,omitempty"` // replaces all
	Creators         *[]Creator     `json:"creators,omitempty"`
	// Revision, when set, refuses the edit (409) unless it is current.
	Revision *int64 `json:"revision,omitempty"`
}

ContentPatch edits a content item; nil fields stay.

type Cover

type Cover struct {
	Image      string                  `json:"image,omitempty"`
	URL        *string                 `json:"url,omitempty"`
	Renditions []media.PublicRendition `json:"renditions,omitempty"`
}

Cover is a version's cover: Image is the cover upload its editors selected ("i-{uuid}"; empty shows its first, else its kind's default); URL is its widest public rendition.

type CreateAuthorization added in v0.93.0

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

CreateAuthorization is one fully validated, in-process creation plan. PrepareCreate performs permission queries and body processing before a transaction reserves a pool connection. The plan is not serializable and must be used immediately with exactly the inputs that were prepared.

func (*CreateAuthorization) CreateTx added in v0.93.0

func (a *CreateAuthorization) CreateTx(ctx context.Context, tx pgx.Tx, in []ContentInput) ([]string, error)

CreateTx writes this prepared creation in the caller-owned transaction. It never invokes a body processor or the authorization provider.

type Creator

type Creator struct {
	UserID   string `json:"user_id"`
	Role     string `json:"role,omitempty"`
	Position int    `json:"position"`
}

Creator is a person credited on a content item; creators edit it.

type CreatorsInput

type CreatorsInput struct {
	Creators []Creator `json:"creators"`
}

CreatorsInput replaces the creators.

type Decision

type Decision struct {
	Allowed bool `json:"allowed"`
	// Unknown: entitlements could not be read; denied, nothing offered.
	Unknown bool `json:"unknown,omitempty"`
	// Sell is the keys a paywall offers; Requires the key a buyer holds first.
	Sell     []string `json:"sell,omitempty"`
	Requires string   `json:"requires,omitempty"`
	// Preview is what a locked viewer still reads; Releases describe additional audiences.
	Preview  *access.Preview  `json:"preview,omitempty"`
	Releases []access.Release `json:"releases,omitempty"`
	// Offers are the purchasable offers of Sell's keys; tiers are the host's
	// to label.
	Offers []offers.Sale `json:"offers,omitempty"`
}

Decision is a viewer's access verdict on a version.

type Entities added in v0.117.0

type Entities interface {
	EffectiveEntities(ctx context.Context, q entities.Querier, versionIDs []string) (map[string][]string, error)
	Cards(ctx context.Context, ids []entities.EntityID, o entities.CardOptions) ([]entities.EntityCard, error)
}

Entities answers each version's effective entity ids (its content's memberships, its own and what they imply), read in q's transaction, and owner entities' cards: *entities.Store.

type EntitySummary added in v0.117.0

type EntitySummary struct {
	ID   string `json:"id"`
	Kind string `json:"kind"`
	Slug string `json:"slug"`
	Name string `json:"name"`
	Code string `json:"code,omitempty"`
	Path string `json:"path,omitempty"`
}

EntitySummary names one entity a content item belongs to; Code and Path are its page, as content's are, when its kind has one.

type Event

type Event struct {
	Type       string
	Kind       string
	ContentID  string
	VersionID  string
	OccurredAt time.Time
	Release    *access.Release
}

Event is the catalog fact appended by a mutation. Readers receive EventRecord.

type EventPage added in v0.116.0

type EventPage struct {
	Events           []EventRecord `json:"events"`
	NextCursor       string        `json:"next_cursor"`
	HasMore          bool          `json:"has_more"`
	RetentionSeconds int64         `json:"retention_seconds"`
}

EventPage always provides a continuation, including an empty stream.

type EventQuery added in v0.116.0

type EventQuery struct {
	After string
	Limit int
	Types []string
}

EventQuery reads one app's retained log. Callers own their continuation.

type EventRecord added in v0.116.0

type EventRecord struct {
	ID         string          `json:"id"`
	Version    int             `json:"version"`
	Type       string          `json:"type"`
	Kind       string          `json:"kind"`
	ContentID  string          `json:"content_id"`
	VersionID  string          `json:"version_id,omitempty"`
	OccurredAt time.Time       `json:"occurred_at"`
	RecordedAt time.Time       `json:"recorded_at"`
	Source     string          `json:"source"`
	Scope      string          `json:"scope"`
	Data       json.RawMessage `json:"data,omitempty"`
}

EventRecord is an immutable committed catalog fact. IDs are decimal strings so JSON clients do not lose bigint precision.

type ImportContent

type ImportContent struct {
	ID               string
	Kind             string
	State            string
	PublishAt        *time.Time
	PublishedAt      *time.Time
	DeletedAt        *time.Time
	OriginalTitle    *string
	OriginalLanguage *string
	// Comments is open (when empty), closed or hidden.
	Comments      string
	Access        *access.Rule
	Restrictions  []string
	Attributes    map[string]any
	OwnerEntityID string
	Creators      []Creator
	Text          map[string]Text
	Versions      []ImportVersion
	Code          string
	CreatedAt     *time.Time
	UpdatedAt     *time.Time
}

ImportContent is a content item as the bulk import writes it: its id, state and times kept, trusted (not screened). Nil Creators, Text and a version's Text and Segments keep what is stored; given ones replace it.

type ImportVersion

type ImportVersion struct {
	ID string
	// Code is the version code to keep; empty keeps the stored one or
	// assigns one. A version never changes its code.
	Code        string
	Languages   []string
	Traits      []string
	Label       string
	State       string
	PublishAt   *time.Time
	PublishedAt *time.Time
	DeletedAt   *time.Time
	Access      *access.Rule
	Attributes  map[string]any
	Ordinal     *int
	// Cover selects one of the version's cover uploads (i-{uuid}).
	Cover     string
	Text      map[string]VersionText
	Segments  []Segment
	CreatedAt *time.Time
	UpdatedAt *time.Time
}

ImportVersion is one version of an ImportContent, positioned as listed.

type InlineImage

type InlineImage struct {
	Ref string  `json:"ref"`
	URL *string `json:"url"`
}

InlineImage is an inline image of a body: Ref goes where its URL would ("contentkit:i-{uuid}"); URL shows it to the editor now (null until it has a file to show).

type LanguageTotal

type LanguageTotal struct {
	Public int64            `json:"public"`
	Tiers  map[string]int64 `json:"tiers"`
}

LanguageTotal sizes one kind in one language, as Total does.

type ManageCount added in v0.104.0

type ManageCount struct {
	Total int `json:"total"`
	// Truncated makes Total a lower bound.
	Truncated bool `json:"truncated,omitempty"`
}

ManageCount is how many items a manage listing selects.

type ManageQuery

type ManageQuery struct {
	Kind string
	// State is draft, scheduled, published (live) or deleted; "" is every
	// state but deleted.
	State       string
	OwnerEntity string
	// Text matches title, description or body, ignoring case.
	Text string
	// Code selects the item with this content code; with State "" it matches
	// deleted items too, so editor links keep resolving.
	Code string
	// IDs selects these items (at most MaxManageIDs); with State "" it
	// matches deleted items too, so member lists resolve every member.
	IDs []string
	// Access keeps items whose own rule has this level; Tier those whose rule
	// names this configured tier (implying the tier level).
	Access, Tier  string
	Limit, Offset int
}

ManageQuery selects content items to manage.

type ManagementName added in v0.104.0

type ManagementName struct{ ID, Kind, Title, Language string }

ManagementName is the current name of an item its caller may edit. No body, media, public-listing policy or audience billing check is needed to navigate.

type ManagementNames added in v0.104.0

type ManagementNames struct {
	Contents []ManagementName
	Entities []entities.EntityCard
}

type ManagementSearchQuery added in v0.104.0

type ManagementSearchQuery struct {
	Query, Language                  string
	ContentKinds, EntityKinds        []string
	IncludeContents, IncludeEntities bool
	Limit                            int
}

type Media

type Media struct {
	// Registry constructs media references in each kind's effective namespace.
	// Nil retains the legacy standalone binding to the catalog key.
	Registry *media.Registry
	// Reader signs opened versions' body images and gives editors previews.
	Reader   Reader
	Versions VersionMedia // *versions.Service
}

Media connects content items to ContentKit media, built over the catalog's Resolver and RefreshTx (media/versions): bind it with BindMedia before serving. A content's media lives in its versions: each version's item (kind, content, version) holds its cover and, in private/, its copy of the body's images, which only the version's openers read.

type Moderation

type Moderation interface {
	Screen(ctx context.Context, in content.ModerationInput) (content.Screening, error)
}

Moderation screens text before it publishes: content.Runtime.

type NotReadyError added in v0.104.0

type NotReadyError struct{ Pending []versions.MediaPending }

NotReadyError refuses making versions live while their media is still processing or being published; it is versions.ErrNotReady.

func (*NotReadyError) Error added in v0.104.0

func (e *NotReadyError) Error() string

func (*NotReadyError) Unwrap added in v0.104.0

func (e *NotReadyError) Unwrap() error

type Offers

type Offers interface {
	Resync(ctx context.Context, tx pgx.Tx, targets []offers.Target) error
	Sales(ctx context.Context, keys []string) (map[string]offers.Sale, error)
	Current(ctx context.Context, a auth.Authenticator, actor access.Actor, targets []offers.Target) ([]*offers.Offer, error)
}

Offers is *offers.Service: Resync re-syncs the targets' products in the writing transaction; Sales and Current fill reads' paywalls and editors' offers.

type Options

type Options struct {
	Pool   *pgxpool.Pool
	Schema string
	Tenant string
	// Kinds is the site's content model. Required.
	Kinds kinds.Config
	// Auth gates the routes and answers staff and owner-entity permissions.
	Auth auth.Authenticator
	// Gate answers viewers' entitlements; nil builds one without billing
	// (only free rules and claimed tiers open).
	Gate *access.Gate
	// Offers renames the products of content whose title changes and answers
	// paywalls' offers; nil when nothing is sold.
	Offers Offers
	// Entities answers effective entity ids for content_facets; nil: none. Wire
	// its Options.ContentChanged to Store.ContentChanged and its
	// Options.NamesChanged to Store.EntitiesRenamed.
	Entities Entities
	// Moderation screens text of content that is or goes live; nil approves
	// unless contentkit.NewRuntime binds its content runtime (BindModeration).
	Moderation Moderation
	// Body sanitizes text bodies; nil strips tags.
	Body Sanitizer
	// DeletedRetention: see DefaultDeletedRetention.
	DeletedRetention time.Duration
	// EventRetention keeps committed facts independently of reader progress. Zero is ninety days.
	EventRetention time.Duration
	// OnPurge records required application cleanup in the same transaction.
	OnPurge func(context.Context, pgx.Tx, []contentref.ContentRef) error
	// PlayableKinds are the kinds whose versions list only once their media
	// plays (an HLS rendition is out): a new version starts not playable until
	// media records otherwise. Only kinds media streams belong here.
	PlayableKinds []string
	// DocumentsChanged runs in the writing transaction after a write queued
	// search documents, so the engine can sync them at once. Optional.
	DocumentsChanged func(ctx context.Context, q Querier) error
	// References clears host-owned edition links during permanent purge.
	References VersionReferenceOwner
	Now        func() time.Time
	Logger     *slog.Logger
}

Options configures a Store.

type OrderInput

type OrderInput struct {
	IDs []string `json:"ids"`
}

OrderInput orders versions.

type Publish

type Publish struct {
	ContentID string
	At        *time.Time
}

Publish publishes a content item now, or at At when it is in the future (scheduled).

type PublishInput

type PublishInput struct {
	PublishAt *time.Time `json:"publish_at,omitempty"`
}

PublishInput publishes now, or at PublishAt when it is in the future.

type Querier

type Querier interface {
	Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error)
	QueryRow(ctx context.Context, sql string, args ...any) pgx.Row
	Exec(ctx context.Context, sql string, args ...any) (pgconn.CommandTag, error)
}

Querier is a pool or a transaction.

type Reader

type Reader interface {
	Read(ctx context.Context, ref contentref.ContentRef, actor access.Actor, o media.ReadOptions) (*media.ReadResult, error)
	// NamedURLs signs an opened item's named images that have no public files.
	NamedURLs(ctx context.Context, ref contentref.ContentRef, actor access.Actor, names []string) (map[string]string, error)
}

Reader reads an item as the media read API does.

type Sanitizer

type Sanitizer = content.ContentProcessor

Sanitizer cleans rich text on write: content.ContentProcessor.

type Segment

type Segment struct {
	Position  int        `json:"position"`
	Title     string     `json:"title,omitempty"`
	StartPage string     `json:"start_page,omitempty"`
	Start     int        `json:"start"`
	End       int        `json:"end"`
	ReleaseAt *time.Time `json:"release_at,omitempty"`
	// Released is computed on reads.
	Released bool `json:"released"`
}

Segment is an ordered, individually released range of a version (a chapter): items [Start, End). A segment is released once it and every earlier one are past ReleaseAt.

type SegmentInput added in v0.106.0

type SegmentInput struct {
	Position  int        `json:"position,omitempty"`
	Title     string     `json:"title,omitempty"`
	StartPage string     `json:"start_page,omitempty"`
	Start     int        `json:"start,omitempty"`
	End       int        `json:"end,omitempty"`
	ReleaseAt *time.Time `json:"release_at,omitempty"`
	Released  bool       `json:"released,omitempty"` // ignored, retained for older clients
}

SegmentInput authors a chapter by its stable source page identity. Start and End remain accepted together for older range-based clients. Anchored writes omit both indices; the next start or the final page determines the end.

type SegmentsInput

type SegmentsInput struct {
	Segments []SegmentInput `json:"segments"`
}

SegmentsInput replaces a version's segments.

type Standing added in v0.85.0

type Standing interface {
	Standing(ctx context.Context, actor access.Actor, refs []contentref.ContentRef) ([]ViewerState, error)
}

Standing reads a signed-in person's standing with content items and versions, per ref in order: *discovery.Service.

type Store

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

Store is one tenant's catalog.

func New

func New(ctx context.Context, opts Options) (*Store, error)

New validates opts and checks the schema has the catalog tables.

func (*Store) BindMedia

func (s *Store) BindMedia(m Media) error

BindMedia attaches media; call it once, before serving.

func (*Store) BindModeration

func (s *Store) BindModeration(m Moderation)

BindModeration screens through m when Options.Moderation is nil, so one moderator serves comments and catalog text; call it before serving.

func (*Store) BindStanding added in v0.85.0

func (s *Store) BindStanding(st Standing)

BindStanding fills detail reads' viewer state from st; call it once, before serving.

func (*Store) BodyImage added in v0.87.0

func (s *Store) BodyImage(ctx context.Context, actor access.Actor, contentID string, in BodyImageInput) (InlineImage, error)

BodyImage takes a body image an editor uploaded to a version (Upload.Body): it queues the image's copy into every other version and returns its reference and a URL that shows it to the editor now.

func (*Store) BuildDocuments

func (s *Store) BuildDocuments(ctx context.Context, kind, language string, refs []contentref.ContentRef) ([]search.KeywordDocument, error)

BuildDocuments returns the current document of each published item of refs with text in language; the others get none, which deletes theirs.

func (*Store) Close

func (s *Store) Close()

Close releases the totals cache.

func (*Store) ContentChanged

func (s *Store) ContentChanged(ctx context.Context, q entities.Querier, contentIDs []string) error

ContentChanged is entities.Options.ContentChanged: after the entities module re-derived the items' entity_ids in q's transaction, it re-derives their decorative paths (a path entity may have changed), queues their search documents (entity names are keywords) and records the change.

func (*Store) Contents

func (s *Store) Contents(ctx context.Context, v *Viewer, ids []string) ([]*Content, error)

Contents reads content items as v sees them (spec §4): an item the viewer may not see, or that does not exist, is nil. Text is in the viewer's language, else the site's first language, else the first it has; an item whose edit awaits review shows its last approved text to everyone but its editors. Editors also get every language's text, every version and the moderation state.

func (*Store) CountManaged added in v0.104.0

func (s *Store) CountManaged(ctx context.Context, actor access.Actor, q ManageQuery) (ManageCount, error)

CountManaged counts what Manage selects for q, exactly up to manageCountBound. It counts a bounded selection without sorting or transferring its ids.

func (*Store) Create

func (s *Store) Create(ctx context.Context, actor access.Actor, in []ContentInput) ([]string, error)

Create creates content items as drafts and returns their ids in order. actor needs root:content:write, or to edit each item's owner entity.

func (*Store) Delete

func (s *Store) Delete(ctx context.Context, actor access.Actor, ids []string) error

Delete deletes a hidden-version kind or an already empty content item. Visible-version kinds are deleted by deleting their versions instead.

func (*Store) DeleteForModeration added in v0.112.0

func (s *Store) DeleteForModeration(ctx context.Context, actor access.Actor, ids []string) error

DeleteForModeration hides content without changing its editions. This embedded operation has no public delete route. Existing purchaser access and retention protections still apply.

func (*Store) DeleteOwned

func (s *Store) DeleteOwned(ctx context.Context, entities []string) error

DeleteOwned deletes the live content of the deleted user-owned entities among entities (every one with nil), recording each entity as its content's cause (entities.OwnedContent): holders of a deleted item's key still read it until the content is erased after the deletion retention.

func (*Store) DeleteVersions

func (s *Store) DeleteVersions(ctx context.Context, actor access.Actor, keys []VersionKey) error

DeleteVersions soft-deletes editions. Removing the final undeleted edition also soft-deletes its parent in the same transaction.

func (*Store) DocumentKinds

func (s *Store) DocumentKinds() []string

DocumentKinds are the content kinds the catalog documents.

func (*Store) EntitiesRenamed added in v0.117.0

func (s *Store) EntitiesRenamed(ctx context.Context, q entities.Querier, entityIDs []string) error

EntitiesRenamed is entities.Options.NamesChanged: it queues, in one statement, the search documents of every item whose facets name one of the entities (ancestors included), since their keywords are those entities' names. It locks no content and leaves facets and revisions alone.

func (*Store) EventReader added in v0.117.0

func (s *Store) EventReader() eventlog.Reader

EventReader is bound to this store's app. Public callers use Client.EventReader, which retains the client's authorization and transport behavior.

func (*Store) Existing added in v0.104.0

func (s *Store) Existing(ctx context.Context, ids []string) (map[string]bool, error)

Existing reports which of ids are this tenant's content items or versions, for the media orphan sweep; deleted rows not yet purged still exist.

func (*Store) Handler

func (s *Store) Handler() http.Handler

Handler serves the catalog routes behind their gates over Options.Auth, each request in an access.WithMemo context (one billing read). Its paths are under the module's prefix (httpapi.Contents, /v1): mount it with that prefix stripped.

func (*Store) Held

func (s *Store) Held(ctx context.Context, after time.Time, afterID string, limit int) ([]content.HeldItem, error)

Held pages held content items oldest first, for content's review queue (content.HeldSource under HeldKind): the text shown is the site's first language's, else any.

func (*Store) Import

func (s *Store) Import(ctx context.Context, tx pgx.Tx, in []ImportContent) error

Import writes content items in tx: new ones are inserted, stored ones updated where the import changes them. Then what depends on them follows, as after every write: codes, facets, search documents, events, media exposure and publications, and offers' product names. A version of another content item or a kind change is ErrInvalid.

func (*Store) ImportDeletes added in v0.85.0

func (s *Store) ImportDeletes(ctx context.Context, tx pgx.Tx, contents, versions []string) error

ImportDeletes preserves the source's independent content tombstones and follows version deletion with automatic empty-parent deletion. Purchased content is still retained for its holders. Hidden versions go with their item.

func (*Store) Kinds

func (s *Store) Kinds() kinds.Config

Kinds is the store's content model.

func (*Store) ListDocuments

func (s *Store) ListDocuments(ctx context.Context, kind, language, cursor string, limit int) ([]contentref.ContentRef, string, bool, error)

ListDocuments pages the published items of kind with text in language, in id order, for backfill.

func (*Store) ListEvents added in v0.116.0

func (s *Store) ListEvents(ctx context.Context, query EventQuery) (EventPage, error)

ListEvents preserves the catalog wire format over the shared paging engine.

func (*Store) LookupVersion added in v0.114.0

func (s *Store) LookupVersion(ctx context.Context, viewer *Viewer, versionID string) (*Content, error)

LookupVersion returns its parent detail with only the requested edition. The parent relationship is database-owned; no media path participates in resolving it. Normal visibility and access rules still apply.

func (*Store) Manage

func (s *Store) Manage(ctx context.Context, actor access.Actor, q ManageQuery) ([]string, error)

Manage lists the ids of items actor manages, newest first: every item for root:content:write holders; else what they created, or with OwnerEntity the entity's items when they edit it.

func (*Store) ManagementSearch added in v0.104.0

func (s *Store) ManagementSearch(ctx context.Context, actor access.Actor, q ManagementSearchQuery) (ManagementNames, error)

ManagementSearch uses current operator text, not public approved snapshots. Write/creator/owner-entity eligibility runs inside every indexed SQL query before its limit; entity names require the same authority as /manage/entities.

func (*Store) OrderVersions

func (s *Store) OrderVersions(ctx context.Context, actor access.Actor, contentID string, ids []string) error

OrderVersions sets the order of a content item's versions: ids lists every version not deleted, first first; deleted ones follow.

func (*Store) PrepareCreate added in v0.93.0

func (s *Store) PrepareCreate(ctx context.Context, actor access.Actor, in []ContentInput) (*CreateAuthorization, error)

func (*Store) PruneEvents added in v0.116.0

func (s *Store) PruneEvents(ctx context.Context) (int, error)

PruneEvents bounds maintenance while reads independently enforce retention.

func (*Store) Publish

func (s *Store) Publish(ctx context.Context, actor access.Actor, in []Publish) error

Publish publishes content items now, or schedules those with a future At. A published item is screened (all its text); a hold leaves it unpublished until a reviewer approves it. Rescheduling a scheduled item moves its time; a live item is left as it is.

func (*Store) PublishChecked added in v0.93.0

func (s *Store) PublishChecked(ctx context.Context, actor access.Actor, in []Publish, check func(context.Context, pgx.Tx) error) error

PublishChecked is Publish with a transaction-local precondition. The check runs after ordinary authorization and content locks, before any publication mutation. It must use tx for database reads and must not open transactions.

func (*Store) PublishDue

func (s *Store) PublishDue(ctx context.Context) (int, error)

PublishDue records due publication and audience-release facts and refreshes their projections. Reads use publication and audience timestamps directly; this recorder never determines when a viewer gains access. The return value counts the publication stamps and separately caught-up audience releases.

func (*Store) PurgeDeleted

func (s *Store) PurgeDeleted(ctx context.Context) (int, error)

PurgeDeleted erases content and versions deleted longer than the retention ago, including purchased content. Billing products and purchase history stay; holders lose access to the erased media. It returns the number erased.

func (*Store) PutText

func (s *Store) PutText(ctx context.Context, actor access.Actor, in []TextPut) error

PutText sets or removes text per language. Text of a published item is screened first: a rejection writes nothing (content.RejectedError), a hold keeps the item's last approved text public until a reviewer decides.

func (*Store) PutVersions

func (s *Store) PutVersions(ctx context.Context, actor access.Actor, in []VersionPut) ([]string, error)

PutVersions creates (VersionID "") or edits versions and returns their ids in order.

func (*Store) ReconcileFacets added in v0.104.0

func (s *Store) ReconcileFacets(ctx context.Context) (int, error)

ReconcileFacets explicitly refreshes every item's facets and search-document marks from current catalog state, recording the current access snapshot. Use it to repair stale projections after upgrading a writer; ordinary publication does not revisit already-published versions. Each transaction locks at most 200 parents in ID order before refreshing them. It returns the number of items processed.

func (*Store) Ref

func (s *Store) Ref(kind, id string) contentref.ContentRef

Ref is a content item's reference.

func (*Store) RefreshFacets

func (s *Store) RefreshFacets(ctx context.Context, q Querier, contentIDs []string) error

RefreshFacets rewrites the content_facets rows of every version of the content items, and queues their search documents, in q's transaction. live_from is when a version went (or goes) live, kept through deletion so holders of a deleted item still read what was live; deleted marks either deletion; unplayable marks a gated player version whose media does not play yet (playable false; unknown lists). Every write to a content item, its versions, memberships, access, listing, restrictions, traits or attributes calls it before committing; the entities module calls it after membership changes.

func (*Store) RefreshPaths added in v0.104.0

func (s *Store) RefreshPaths(ctx context.Context) (int, error)

RefreshPaths re-derives the decorative paths of every item whose kind has a path entity, in batches; run it after enabling or changing a kind's path_entity. Idempotent; it returns the items visited.

func (*Store) RefreshTx

func (s *Store) RefreshTx(ctx context.Context, tx pgx.Tx, versionIDs []string) error

RefreshTx is versions.Facets: it refreshes the facets of the versions' content items after their media facts changed.

func (*Store) ResolveHeld

func (s *Store) ResolveHeld(ctx context.Context, id string, d content.ReviewDecision) error

ResolveHeld applies a reviewer's decision to a held content item at the revision the queue listed: approval publishes it (or its edit), rejection keeps it from going live (an edit of a live item leaves its last approved text public).

func (*Store) Resolver

func (s *Store) Resolver() resolve.Resolver

Resolver is the resolve.Resolver of content items for media (media/versions) and interactions: a content reference (kind, content) or one of its versions is visible by the rule for direct reads (live, deleted and held by its own keys, or edited by the viewer), accessible when the viewer opens it (a content reference: any of its visible versions), with staff, creators and owner-entity editors as Editor and the first creator as Owner. A reference it omits is unseen.

func (*Store) Restore

func (s *Store) Restore(ctx context.Context, actor access.Actor, ids []string) error

Restore brings deleted content items back as they were: published (or scheduled) when they had been, else drafts.

func (*Store) RestoreOwned

func (s *Store) RestoreOwned(ctx context.Context, entities []string) error

RestoreOwned restores the content the active entities among entities (every one with nil) deleted when they were deleted (entities.OwnedContent), as Restore does; content deleted for another reason stays deleted, and content purged since is gone.

func (*Store) RetireOpenCounters added in v0.104.0

func (s *Store) RetireOpenCounters(ctx context.Context, legacyWritersStopped bool) error

RetireOpenCounters removes the unused imported view-count columns and the retired facet popularity cache (open-derived reach scores and window ratings). Call only after every app/importer sharing this catalog has upgraded; never on startup. Source images, content, reactions, favorites and reading resume/progress are unaffected.

func (*Store) RiverJobs

func (s *Store) RiverJobs() riverhelpers.Contribution

RiverJobs contributes content's periodic jobs to the engine's River client: publication and audience-release facts (every 5m), event log retention and purging deleted content (1h).

func (*Store) Tenant

func (s *Store) Tenant() string

Tenant is the store's tenant.

func (*Store) Totals

func (s *Store) Totals(ctx context.Context, q TotalsQuery) (Totals, error)

Totals counts the listed content of each kind by who opens it, cached per site and kind: a count reloads in the background after ten minutes, and the last good one serves while reloads fail, for up to a day.

func (*Store) Unpublish

func (s *Store) Unpublish(ctx context.Context, actor access.Actor, ids []string) error

Unpublish returns published or scheduled content items to drafts.

func (*Store) Update

func (s *Store) Update(ctx context.Context, actor access.Actor, in []Update) error

Update edits content items.

func (*Store) Viewer

func (s *Store) Viewer(ctx context.Context, o ViewerOptions) (*Viewer, error)

Viewer resolves o once per request: the site, staff rights, entitlements (one billing read, fail-closed when unavailable), the site's required entities and the viewer's content filters (config defaults merged with their own).

func (*Store) Visibility

func (s *Store) Visibility(r *http.Request, links []contenturl.Link) ([]contenturl.Visibility, error)

Visibility is contenturl.RouterOptions.Visibility for content kinds: a page shows while its item is live for an anonymous visitor of the request's site, is Gone once a live item was deleted (or erased), is a Preview for a signed-in editor of an item not live yet (staff, creators), and is Hidden otherwise. Other kinds are Visible.

type Text

type Text struct {
	Title       string   `json:"title"`
	Slug        string   `json:"slug,omitempty"`
	Description string   `json:"description,omitempty"`
	Body        string   `json:"body,omitempty"`
	SortKey     string   `json:"sort_key,omitempty"`
	Aliases     []string `json:"aliases,omitempty"`
}

Text is a content item's text in one language. Body is rich text whose inline images are "contentkit:i-{uuid}" references (ImageRef).

type TextPut

type TextPut struct {
	ContentID string
	Language  string
	Text      *Text
}

TextPut sets (Text non-nil) or removes one language's text.

type Total

type Total struct {
	Public    int64                    `json:"public"`
	Tiers     map[string]int64         `json:"tiers"`
	Languages map[string]LanguageTotal `json:"languages"`
}

Total sizes one kind. Public counts what an anonymous visitor's listing shows and opens; Tiers[t] every eligible item a holder of t opens, members-listed ones included. An item counts once in the kind's total and once per language any of its eligible versions serves, never per version. The site's scope and the default content filters apply.

type Totals

type Totals struct {
	Kinds map[string]Total `json:"kinds"`
}

Totals is the catalog's size by content kind.

type TotalsClient

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

TotalsClient reads another deployment's catalog totals (GET /v1/catalog/totals), such as a sibling site's, server to server, cached per kind like Store.Totals.

func NewTotalsClient

func NewTotalsClient(baseURL string, hc *http.Client) (*TotalsClient, error)

NewTotalsClient reads the deployment whose ContentKit is mounted at baseURL, e.g. "https://hentai0.com/api/v1/contentkit". A nil hc has a ten-second timeout.

func (*TotalsClient) Close

func (c *TotalsClient) Close()

Close releases the cache's goroutines.

func (*TotalsClient) Totals

func (c *TotalsClient) Totals(ctx context.Context, q TotalsQuery) (Totals, error)

Totals reads the remote's totals as Store.Totals answers them, in the site the remote derives from its host: q.Kinds is required and q.Domain empty.

type TotalsQuery

type TotalsQuery struct {
	// Kinds are content kinds; empty means all of them.
	Kinds []string
	// Languages are the languages Total.Languages reports; empty means every
	// language with a counted item. Kind totals ignore it.
	Languages []string
	// Domain is the stable domain name whose scope applies; empty selects
	// main. The HTTP route takes it from the request's host.
	Domain string
}

TotalsQuery selects the kinds and languages to total.

type Update

type Update struct {
	ID string
	ContentPatch
}

Update is one ContentPatch.

type Version

type Version struct {
	ID string `json:"id"`
	// Code selects it on its content's page (?v=): unique within the content,
	// fixed for the version's life.
	Code      string   `json:"code"`
	Position  int      `json:"position"`
	Languages []string `json:"languages"`
	Traits    []string `json:"traits"`
	Label     string   `json:"label,omitempty"`
	// Title and Description are the override in the detail's language.
	Title       string `json:"title,omitempty"`
	Description string `json:"description,omitempty"`
	// State is the editors' to see.
	State       string     `json:"state,omitempty"`
	PublishAt   *time.Time `json:"publish_at,omitempty"`
	PublishedAt *time.Time `json:"published_at,omitempty"`
	// Live: published, past PublishAt, its content live.
	Live bool `json:"live"`
	// Access is the version's own rule; nil inherits the content's.
	Access     *access.Rule   `json:"access,omitempty"`
	Attributes map[string]any `json:"attributes"`
	// Entities are entities attached specifically to this version. Combine them
	// with Content.Entities when presenting the selected version's credits.
	Entities   []EntitySummary `json:"entities"`
	Pages      *int            `json:"pages,omitempty"`
	DurationMS *int64          `json:"duration_ms,omitempty"`
	Width      *int            `json:"width,omitempty"`
	Height     *int            `json:"height,omitempty"`
	HasAudio   bool            `json:"has_audio"`
	Ordinal    *int            `json:"ordinal,omitempty"`
	// Cover is absent when its kind's locked view hides it from the viewer.
	Cover    *Cover    `json:"cover,omitempty"`
	Segments []Segment `json:"segments"`
	Decision Decision  `json:"decision"`
	// Text is every language's override, for editors.
	Text map[string]VersionText `json:"text,omitempty"`
	// Offer is the version's current offer, for its offer editors.
	Offer *offers.Offer `json:"offer,omitempty"`
	// Viewer is the signed-in reader's standing with the version.
	Viewer *ViewerState `json:"viewer,omitempty"`
}

Version is what a viewer opens.

func DefaultVersion added in v0.87.0

func DefaultVersion(vs []Version, language string) *Version

DefaultVersion is the version a reader of language opens by default, the one rule cards and contentkit-ui's defaultVersion follow (internal/edition): the first live version serving language, else the first live one, else the first; vs in position order. Nil when vs is empty.

type VersionFork

type VersionFork struct {
	From     string `json:"from"`
	Playback bool   `json:"playback,omitempty"`
	Segments bool   `json:"segments,omitempty"`
}

VersionFork copies a sibling version's media into a new version: its uploads and reader metadata, with Playback its audio, with Segments its segments.

type VersionInput

type VersionInput struct {
	Languages []string  `json:"languages,omitempty"`
	Traits    *[]string `json:"traits,omitempty"`
	Label     *string   `json:"label,omitempty"`
	// State is draft or published: a published version is live once its
	// content is and PublishAt passed. A version created with its item
	// defaults to published, one added later to draft.
	State     string     `json:"state,omitempty"`
	PublishAt *time.Time `json:"publish_at,omitempty"`
	// Access overrides the content's rule; ClearAccess inherits it again.
	Access      *access.Rule           `json:"access,omitempty"`
	ClearAccess bool                   `json:"clear_access,omitempty"`
	Attributes  map[string]any         `json:"attributes,omitempty"` // replaces all
	Text        map[string]VersionText `json:"text,omitempty"`       // replaces all
	Segments    *[]SegmentInput        `json:"segments,omitempty"`   // replaces all
	Ordinal     *int                   `json:"ordinal,omitempty"`
	// Cover selects one of the version's cover uploads by name (i-{uuid});
	// "" returns to its first.
	Cover *string `json:"cover,omitempty"`
	// Fork fills a new version's media from a sibling (creation only).
	Fork *VersionFork `json:"fork,omitempty"`
}

VersionInput creates or edits a version; nil fields stay (or default).

type VersionKey

type VersionKey struct{ ContentID, VersionID string }

VersionKey names one version.

type VersionMedia

type VersionMedia interface {
	// Covers resolves versions' covers.
	Covers(ctx context.Context, covers []versions.CoverOf) ([][]media.PublicRendition, error)
	// CopyBodiesTx copies body images between a content's versions.
	CopyBodiesTx(ctx context.Context, tx pgx.Tx, copies []versions.BodyCopy) error
	// ExposeTx follows a visibility change.
	ExposeTx(ctx context.Context, tx pgx.Tx, targets []versions.Target) error
	// RepublishTx follows a change of a version's effective rule or segments.
	RepublishTx(ctx context.Context, tx pgx.Tx, versions []versions.Target) error
	// DeleteTx deletes media before the rows go.
	DeleteTx(ctx context.Context, tx pgx.Tx, targets []versions.Target) error
	// ForkTx fills new versions' media from siblings.
	ForkTx(ctx context.Context, tx pgx.Tx, forks []versions.Fork) error
	// PendingTx reports versions whose media is not ready to go live.
	PendingTx(ctx context.Context, tx pgx.Tx, targets []versions.Target) ([]versions.MediaPending, error)
}

VersionMedia is the media calls catalog writes make in their transaction (a target is a content item, every version's media, or one version) and reads make for covers.

type VersionPut

type VersionPut struct {
	ContentID string
	VersionID string
	VersionInput
}

VersionPut creates (VersionID "") or edits a version.

type VersionReferenceOwner added in v0.112.0

type VersionReferenceOwner interface {
	PurgeVersions(ctx context.Context, q Querier, catalog string, versionIDs []string) error
}

VersionReferenceOwner clears host links before versions are permanently erased. Calls use the catalog mutation's transaction with parent contents locked. An error rolls back the purge. Unpublish and soft deletion do not call this hook: hosts can retain their selection while publication is suspended.

type VersionReferences added in v0.112.0

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

VersionReferences supplies storage-only joins and validation for host-owned links to exact catalog editions. It does not authorize host operations or grant reader access. The host must authorize its own edit before using it.

func NewVersionReferences added in v0.112.0

func NewVersionReferences(schema, tenant string) (*VersionReferences, error)

func (*VersionReferences) LockPublishedSQLTx added in v0.112.0

func (r *VersionReferences) LockPublishedSQLTx(ctx context.Context, tx *sql.Tx, versionID, kind, language string) (string, error)

LockPublishedSQLTx validates and reserves a currently published edition of kind in language. It returns its owning content ID. Locks are parent first, edition second, and must precede any host row locks. This serializes selection with publication changes and permanent purge. It does not follow aliases. Use READ COMMITTED and roll back on error; tx is never committed here.

func (*VersionReferences) PublicationSQL added in v0.112.0

func (r *VersionReferences) PublicationSQL() string

PublicationSQL is a SELECT suitable for a host query's derived table. Join on BOTH catalog_key and version_id; version identity is catalog-scoped. The returned columns are catalog_key, version_id, content_id, kind, languages, published_at and published. Publication includes the parent, scheduling, moderation and soft deletion, but not a viewer's entitlement or preferences. It is evaluated at the database statement's time, before host pagination. Hosts must not write this relation or depend on its underlying table names.

type VersionText

type VersionText struct {
	Title       string `json:"title,omitempty"`
	Description string `json:"description,omitempty"`
}

VersionText overrides a version's title and description in one language.

type Viewer

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

Viewer is the one visibility rule (ContentKit #117 spec §4) for one request: live content and versions, the site scope, the viewer's content filters and entitlements, and the staff, creators and owner-entity editors who see everything. Listed renders it as SQL over content_facets for lists and searches; Store.Contents and Resolver decide items with it.

func (*Viewer) Actor

func (v *Viewer) Actor() access.Actor

Actor is the viewer's actor.

func (*Viewer) Domain added in v0.97.0

func (v *Viewer) Domain() kinds.Domain

Domain is the request entrypoint and its visibility policy.

func (*Viewer) Editors

func (v *Viewer) Editors(ctx context.Context, entities []string) map[string]bool

Editors reports, per owner entity, whether the viewer edits its content and so opens it: staff edit every entity's; anyone else is asked once per entity per request, and a failed check reads as not an editor.

func (*Viewer) HiddenContentFilters added in v0.99.0

func (v *Viewer) HiddenContentFilters() map[string][]string

HiddenContentFilters copies the optional, public entity filters currently hidden by this viewer, by content kind. Required, fixed and internal rules are domain policy, never optional filters.

func (*Viewer) Indexable added in v0.85.0

func (v *Viewer) Indexable(alias string) (string, pgx.NamedArgs)

Indexable is a boolean SQL predicate over the content_facets row aliased alias: the versions a site lists to anyone, as its sitemaps name them: live, not deleted, playable and in the viewer's site scope. Access, the language and a reader's content filters do not apply. Args are pgx named args prefixed ci_.

func (*Viewer) Listed

func (v *Viewer) Listed(alias string) (string, pgx.NamedArgs)

Listed is a boolean SQL predicate over the content_facets row aliased alias: the versions the viewer's listing shows. A list shows one card per content item among its rows. In Hide mode, rows a truncated keyspace may unlock are admitted as candidates: decide them with Contents (or access.Gate.Settle) before showing. Args are pgx named args prefixed cv_ and access_.

func (*Viewer) Playable added in v0.112.0

func (v *Viewer) Playable(alias string) string

Playable is a boolean SQL predicate over the content_facets row aliased alias, to AND with Listed (it uses Listed's args): versions that play, or that the viewer may see before they do as staff, channel editor or creator. Browsing applies it; a reader's own history and saved items do not.

func (*Viewer) Shown added in v0.87.0

func (v *Viewer) Shown(alias string) (string, pgx.NamedArgs)

Shown is Listed in every language: the versions a content's page offers the viewer, among which its language's default edition opens. Its args are Listed's.

func (*Viewer) Staff

func (v *Viewer) Staff() bool

Staff reports a viewer holding root:content:view-restricted or root:content:write: they see everything inside the domain boundary.

func (*Viewer) WithoutContentFilters added in v0.99.0

func (v *Viewer) WithoutContentFilters() *Viewer

WithoutContentFilters returns a request-local viewer with only optional entity preferences relaxed. The domain, entitlements, language, access mode and captured clock remain the original request's. It never relaxes required, fixed or internal domain policy.

type ViewerOptions

type ViewerOptions struct {
	Actor access.Actor
	// Host is the request's host; it picks the site (kinds.Config.DomainFor).
	Host string
	// Language, when set, lists only content with a live version serving it.
	Language string
	// Mode defaults to access.Lock.
	Mode access.Mode
	// EditorEntities are owner entities (channels) whose editors see their whole
	// content in lists; the viewer's editorship of each is checked.
	EditorEntities []string
	// Requested are entities a list requires (an entity's page): the viewer's
	// content filters do not hide them, so the page shows what the entity's
	// count counts.
	Requested []string
}

ViewerOptions describes one request's reader.

type ViewerState added in v0.85.0

type ViewerState struct {
	Favorited bool `json:"favorited"`
	// Reaction is their like (1) or dislike (-1) of the item; absent for neither.
	Reaction int `json:"reaction,omitempty"`
	// Seen, Completed, Progress, ProgressMax and Resume (the client's own
	// pointer, such as a page) come from the signal plane. Progress counts
	// whole pages for a reader and seconds for a player.
	Seen        bool       `json:"seen"`
	Completed   bool       `json:"completed"`
	Progress    uint32     `json:"progress"`
	ProgressMax uint32     `json:"progress_max"`
	Resume      string     `json:"resume,omitempty"`
	LastReadAt  *time.Time `json:"last_read_at,omitempty"`
}

ViewerState is a signed-in reader's own standing with a content item or version: their favorite and, with a signal plane, where they are in it.

Jump to

Keyboard shortcuts

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