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

catalogstore

package
v0.136.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: 57 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

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

Functions

func DefaultVersion

func DefaultVersion(vs []catalog.Version, language string) *catalog.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.

func ImageRef

func ImageRef(name string) string

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

func InitializeFixedOwners

func InitializeFixedOwners(ctx context.Context, pool *pgxpool.Pool, schema, tenant string, model kinds.Config, scopes entities.ScopeProvisioner) error

InitializeFixedOwners realizes the fixed owner_entity declarations during an explicit migration. It preserves existing entities, grants and access rules. Host writers must be stopped while changing ownership policy; concurrent migrators are serialized around their database writes.

Entity IDs commit before external scope provisioning so an interrupted call can retry with the same identity. No database transaction or pooled connection is held during the provider call. Content is attached only after provisioning succeeds and the stored identities and policies have been checked again.

func QueueFor

func QueueFor(cat string) string

QueueFor isolates workers bound to different catalog/application scopes.

Types

type CreateAuthorization

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

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

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

type Entities

type Entities interface {
	EffectiveEntities(ctx context.Context, q entitystore.Querier, versionIDs []string) (map[string][]string, error)
	Cards(ctx context.Context, ids []entities.EntityID, o entitystore.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 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 *mediastore.Registry
	// Reader signs opened versions' body images and gives editors previews.
	Reader   catalog.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 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 *entitlement.Gate
	// 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
	Channels *channelstore.Store
	// Body sanitizes text bodies; nil strips tags.
	Body catalog.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
	// AfterPurge completes durable cross-store cleanup after local deletion.
	// It runs even when some local deletions failed, and retries via this sweep.
	AfterPurge func(context.Context) error

	// DocumentsChanged queues search refresh with the catalog write.
	DocumentsChanged func(ctx context.Context, q Querier) error
	Now              func() time.Time
	Logger           *slog.Logger
}

Options configures a Store.

type PublicationScheduler

type PublicationScheduler interface {
	SchedulePublicationTx(context.Context, pgx.Tx, []versions.Target) error
}

PublicationScheduler admits every content kind through the same durable request.

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 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) BindPublication

func (s *Store) BindPublication(p PublicationScheduler) error

BindPublication installs the engine's publication service independently of media. Bind it before accepting content writes.

func (*Store) BindStanding

func (s *Store) BindStanding(st catalog.Standing)

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

func (*Store) BodyImage

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

BodyImage takes a body image an editor uploaded to a version (Upload.Body): it returns its reference and an editor preview. No other version is changed.

func (*Store) BuildDocuments

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

BuildDocuments returns exactly the requested editions. A missing, unpublished or nonmatching-language edition deletes its own document, not another version.

func (*Store) Close

func (s *Store) Close()

Close releases the totals cache.

func (*Store) CompletePublicationTx

func (s *Store) CompletePublicationTx(ctx context.Context, tx pgx.Tx, target versions.Target, at time.Time) error

CompletePublicationTx records actual availability after the publisher has committed its completed release in this transaction. Chapter/request idempotency belongs to that set; this method records first-publication facts only on the corresponding row transition and refreshes discovery atomically.

func (*Store) ContentChanged

func (s *Store) ContentChanged(ctx context.Context, q entitystore.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) ([]*catalog.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. Editors also get every language's text and every version.

func (*Store) CountManaged

func (s *Store) CountManaged(ctx context.Context, actor access.Actor, q catalog.ManageQuery) (catalog.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 []catalog.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) 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). The same transaction schedules withdrawal; retained originals remain restorable until permanent purge.

func (*Store) DeleteRepost

func (s *Store) DeleteRepost(ctx context.Context, actor access.Actor, destination, contentID string) error

func (*Store) DeleteVersions

func (s *Store) DeleteVersions(ctx context.Context, actor access.Actor, keys []catalog.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

func (*Store) EntitiesChanged

func (s *Store) EntitiesChanged(ctx context.Context, q entitystore.Querier, changes []entities.Change) error

EntitiesChanged is entities.Options.EntitiesChanged: it appends the entities' events to the log in the writing transaction.

func (*Store) EntitiesRenamed

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

EntitiesRenamed is entities.Options.NamesChanged: in q's transaction it queues the reindexing of every edition showing a renamed entity as one row per entity, which the search sync expands in batches (ExpandDocuments). A rename resets the row's cursor and takes a new revision, so a rename during expansion restarts it rather than being lost.

func (*Store) EventReader

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) ExpandDocuments

func (s *Store) ExpandDocuments(ctx context.Context, limit int) (bool, error)

ExpandDocuments is worker.Expander. It marks the documents of the next limit items showing the renamed entity expanded least recently, then advances that entity's cursor, or deletes its row once none remain, at the revision and cursor it read: a rename meanwhile keeps the row to restart, and an overlapping run only repeats marks. It locks the row only after marking, the order an entity edit takes them in, so the two never deadlock. It reports whether any renamed entity remains.

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) Import

func (s *Store) Import(ctx context.Context, tx pgx.Tx, in []catalog.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. A version of another content item or a kind change is ErrInvalid.

func (*Store) ImportDeletes

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, including hidden versions, with automatic empty-parent deletion. All soft-deleted content follows the deletion retention.

func (*Store) ListDocuments

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

ListDocuments pages edition references for the existing search backfill.

func (*Store) ListEvents

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

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

func (*Store) LookupVersion

func (s *Store) LookupVersion(ctx context.Context, viewer *Viewer, versionID string) (*catalog.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 catalog.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 Channel the entity's items when they edit it.

func (*Store) ManagementSearch

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

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

func (*Store) PruneEvents

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

PruneEvents bounds maintenance while reads independently enforce retention.

func (*Store) PublicationCompletedTx

func (s *Store) PublicationCompletedTx(ctx context.Context, tx pgx.Tx, target versions.Target, requestID string, chapters []string, released bool, at time.Time) error

PublicationCompletedTx records a meaningful publication after its final copy/retirement work. The caller owns the locked retiring->completed transition and calls this once in that transaction, never for a no-op or an already completed retry. Request history supplies deduplication provenance; no consumer receipt or second operation table is created.

func (*Store) Publish

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

Publish accepts durable publication now, or schedules it for a future At. Already released files stay available while any new publication is pending.

func (*Store) PurgeDeleted

func (s *Store) PurgeDeleted(ctx context.Context) (total int, resultErr 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) PutRepost

func (s *Store) PutRepost(ctx context.Context, actor access.Actor, destination, contentID, host string) (channels.Repost, error)

PutRepost adds one destination reference to a published original. It never changes original ownership, access, versions, media or interaction counters.

func (*Store) PutVersions

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

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

func (*Store) ReconcileFacets

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's release completed, kept through deletion so holders of a deleted item still read what was live; deleted marks either deletion. Availability comes only from a completed publication. 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

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) 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 and not deleted, or edited by the viewer), accessible when the viewer opens it (a content reference: any of its visible versions), with staff, authenticated authors and owner-entity editors as Editor and the author 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) RiverJobs

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

RiverJobs contributes retention and permanent deletion work. Publication belongs to the version release service and has no recurring catalog sweep.

func (*Store) Totals

func (s *Store) Totals(ctx context.Context, q catalog.TotalsQuery) (catalog.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 []catalog.Update) error

Update edits content items.

func (*Store) VersionStatuses

func (s *Store) VersionStatuses(ctx context.Context, ids []string) ([]catalog.VersionStatus, error)

VersionStatuses returns the existing editions among ids in ids' order.

func (*Store) Viewer

func (s *Store) Viewer(ctx context.Context, o catalog.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, authenticated authors), and is Hidden otherwise. Other kinds are Visible.

func (*Store) WithdrawPublicationTx

func (s *Store) WithdrawPublicationTx(ctx context.Context, tx pgx.Tx, target versions.Target, hasReleased bool) error

WithdrawPublicationTx updates current availability after the publisher has withdrawn files and committed the remaining active release set. A chapter withdrawal leaves other released chapters visible. Historical dates remain.

type VersionMedia

type VersionMedia interface {
	// Covers resolves versions' covers.
	Covers(ctx context.Context, covers []versions.CoverOf) ([][]media.PublicRendition, error)
	// DeleteTx claims irreversible erasure under the eligibility row locks.
	DeleteTx(ctx context.Context, tx pgx.Tx, targets []versions.Target) error
	// Delete verifies physical deletion after that claim has committed.
	Delete(ctx context.Context, targets []versions.Target) error
	// ResumeDeletes completes late-write cleanup owned by content purge.
	ResumeDeletes(ctx context.Context, limit int) (int, error)
	// CheckRestorableTx refuses restoration once irreversible erasure started.
	CheckRestorableTx(ctx context.Context, tx pgx.Tx, targets []versions.Target) error
	// SyncFences makes committed deletions and restores of targets'
	// versions stop or resume serving their media.
	SyncFences(ctx context.Context, targets []versions.Target) 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 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, authenticated authors 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) CanPostToChannel

func (v *Viewer) CanPostToChannel(ctx context.Context, id string) (bool, error)

CanPostToChannel checks current destination posting authority. It grants no authority over an original referenced by a repost.

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

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

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) Shown

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

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.

Jump to

Keyboard shortcuts

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