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

entitlement

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: 12 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrUnavailable = errors.New("access: entitlements unavailable")

ErrUnavailable wraps a failed billing read. The result it comes with is the fail-closed one: only free rules and claimed tiers open, nothing is offered.

Functions

func AudiencesSQL

func AudiencesSQL(alias string, tiers []string) (string, map[string]any, error)

AudiencesSQL is a text[] expression over the content_facets row aliased alias naming who opens it without buying it: Anyone and every one of tiers for a public row or matured public release, the current base and released tier audiences for a restricted row, nobody otherwise. Totals count rows per audience with it. Args are pgx named args prefixed audience_.

func Effective

func Effective(content access.Rule, override *access.Rule) access.Rule

Effective is a version's rule: its override, else its content's.

func PublicSQL

func PublicSQL(alias string) string

PublicSQL reports anonymous access from the current rule and mature releases. alias is a trusted SQL identifier, validated by Filter.SQL/AudiencesSQL.

func ReleasedTiersSQL

func ReleasedTiersSQL(alias string) string

ReleasedTiersSQL lists the tier audiences that have reached their timestamp.

func WithMemo

func WithMemo(ctx context.Context) context.Context

WithMemo returns ctx with a request memo: within it a viewer's Filter is read once and Decide answers from it (or from keys already read), so Filter then Decide is one billing read. The engine installs it on every request. A ctx that already has one is returned unchanged.

Types

type Decision

type Decision struct {
	Allowed bool
	// Unknown: the billing read failed, so the item is denied and nothing is
	// offered (the viewer may already hold it).
	Unknown bool
	// Sell are the keys whose purchase opens it, the rule's own first (its
	// tiers or entity), then the version's;
	// The host resolves these keys through its billing provider.
	Sell []access.Key
	// Requires is the key a buyer must hold first (ChannelPPV), nil when held.
	Requires *access.Key
	// Preview is the part a viewer may read while it is locked.
	Preview *access.Preview
	// Releases describe upcoming additional audiences.
	Releases []access.Release
}

Decision is one item's verdict.

type Filter

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

Filter is one viewer's access as one billing read left it: the configured tiers they hold and their keys in the tenant's content and group keyspaces. It does no I/O: listings push it into SQL (Filter.SQL), loops call Allows. A Filter is immutable and safe for concurrent use.

func (*Filter) Allows

func (f *Filter) Allows(it access.Item) (allowed, known bool)

Allows decides it from the filter alone. known is false when the answer needs a key the filter did not read in full (a truncated keyspace, a failed read); Gate.Settle and Gate.Decide resolve those. Allows and SQL(Hide) agree: the SQL admits exactly the rows Allows allows or does not know, and on an Unknown filter only the allowed ones.

func (*Filter) Anonymous

func (f *Filter) Anonymous() bool

Anonymous reports a filter of an anonymous viewer: it holds nothing.

func (*Filter) Channels

func (f *Filter) Channels() []string

Channels returns the channel ids whose membership key the viewer holds, sorted.

func (*Filter) Complete

func (f *Filter) Complete() bool

Complete reports whether Contents, Versions and Channels are the viewer's whole holdings. An anonymous filter is complete; an unknown one is not.

func (*Filter) Contents

func (f *Filter) Contents() []string

Contents returns legacy parent grants for audit and explicit migration. They do not grant version access and must not be used as audience ownership.

func (*Filter) SQL

func (f *Filter) SQL(alias string, mode access.Mode) (string, map[string]any, error)

SQL returns a boolean predicate over the content_facets row aliased alias, with its pgx named args (all prefixed access_). Hide admits the rows the viewer opens: free, a held tier the rule names, a held key of the rule's channel, or an exact held version key; plus, while a keyspace is truncated, its candidates, which Gate.Settle decides. An Unknown filter admits no candidates. Lock admits every row. The text depends only on alias and mode, so one prepared statement serves every viewer. Lock mode retains inaccessible items for a locked preview; Hide mode excludes them.

func (*Filter) Tier

func (f *Filter) Tier(name string) bool

Tier reports whether the viewer holds the configured tier name.

func (*Filter) Unknown

func (f *Filter) Unknown() bool

Unknown reports a failed billing read: only free rules and claimed tiers open, and nothing is for sale.

func (*Filter) Versions

func (f *Filter) Versions() map[string]string

Versions returns the held version keys: version id -> content id.

type Gate

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

Gate decides access to versions from one billing read per viewer and request (see WithMemo).

func NewGate

func NewGate(c GateConfig) (*Gate, error)

NewGate validates c.

func (*Gate) Decide

func (g *Gate) Decide(ctx context.Context, actor access.Actor, items []access.Item) ([]Decision, error)

Decide decides items for actor in order. It answers from the request's memoized Filter and keys where they suffice and reads every other key in one billing read. A failed read denies what it would have decided (Unknown) and returns an error wrapping ErrUnavailable. An item with an invalid id or rule is denied with nothing offered and logged.

func (*Gate) Filter

func (g *Gate) Filter(ctx context.Context, actor access.Actor) (*Filter, error)

Filter reads the viewer's access in one billing read: the configured tiers a token claim does not answer and the tenant's content and entity keyspaces. Within WithMemo it is read once per request. An anonymous viewer costs no read. On a failed read Filter returns the fail-closed filter (Unknown) and an error wrapping ErrUnavailable: serve that filter or answer 503.

func (*Gate) Holds

func (g *Gate) Holds(ctx context.Context, actor access.Actor, keys []access.Key) ([]bool, error)

Holds reports, per key in order, whether actor holds it: from the request's memoized Filter and keys where they suffice, the rest in one billing read. An anonymous actor holds nothing and costs no read. A failed read answers false for what it would have decided and returns an error wrapping ErrUnavailable. Non-tier keys outside this gate's tenant are refused without a billing read.

func (*Gate) Settle

func (g *Gate) Settle(ctx context.Context, actor access.Actor, f *Filter, items []access.Item) (keep []bool, short bool, err error)

Settle completes f's verdicts for a hide-mode page: items f decides keep its answer, the rest (candidates of a truncated keyspace) are decided in one exact read. keep[i] reports items[i] open; short reports a dropped item, so the page may hold fewer rows than asked. It costs no read when f decides every item. A failed read drops the undecided items and returns an error wrapping ErrUnavailable.

func (*Gate) Tenant

func (g *Gate) Tenant() string

Tenant is the gate's tenant.

func (*Gate) Tiers

func (g *Gate) Tiers() []string

Tiers returns the configured tiers, sorted.

type GateConfig

type GateConfig struct {
	// Tenant is the tenant of every key: [a-z0-9_-]{1,64}.
	Tenant string
	// Kinds supplies the configured tiers, the only bare keys ContentKit
	// interprets, and the token claims answering them without a billing read.
	Kinds kinds.Config
	// Billing answers held keys; nil holds none for anyone, so only free
	// rules and claimed tiers open.
	Billing access.Billing
	Logger  *slog.Logger
	// Now is the application clock used for audience-release decisions.
	// Nil uses time.Now, matching ordinary production behavior.
	Now func() time.Time
}

GateConfig configures a Gate from the engine's config.

Jump to

Keyboard shortcuts

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