AccessStateUtils
The verdict an AccessFeature produces, and the fold most features want.
Three outcomes, not two. disallowed(UNRESOLVED) means no answer came back yet -- a lookup still in
flight, a service that failed, a realm that cannot resolve a fact at all -- and it is deliberately not
the same as being denied. Each consumer decides what an unanswered question means for it: a storefront
may offer on it, an enforcement gate must never open on it.
Types
AccessState
type AccessState = AccessAllowedState | AccessDisallowedStateAccessFactState
type AccessFactState = {[string]: string}Every declared fact and what it said, as an AccessFactContributionState.
Always present, never nil: a Lua table cannot hold a nil, so the old boolean? map silently lost
exactly the facts that had not answered -- the ones a gate most needs to know about.
Properties
Reasons
AccessStateUtils.Reasons: {UNRESOLVED: string,NOT_GRANTED: string}The reasons this module produces on its own. A feature is free to return any other string; these are the two that fall out of the fact fold rather than out of game policy.
Functions
allowed
AccessStateUtils.allowed(grantedBy: {string}?) → AccessAllowedState
Allowed, listing every fact that granted rather than the first one found. Callers surface grantedBy
in debug output, so a state that was granted three ways says so.
disallowed
AccessStateUtils.disallowed(reason: string) → AccessDisallowedStateunresolved
AccessStateUtils.unresolved() → AccessDisallowedStateisAllowed
isUnresolved
Whether a state is specifically unresolved, for the callers that must not act on a non-answer.
key
Two states are the same verdict when they deny for the same reason, or grant on the same facts.
fromFacts
The fold most features want: any true fact allows, an unanswered fact leaves it unresolved, and only a complete set of false answers denies.
Order matters. A true fact wins even while another is still unresolved, because an answer that already grants cannot be changed by one that hasn't arrived -- waiting for it would keep an entitled player out for no reason.
fromAllFacts
Granted only when every named fact allows, unresolved while any is unanswered, refused as soon as one denies.
The and-of that every flag-gated grant actually is -- isEarlyAccessTester and
testerEarlyAccessEnabled -- so a feature can declare its shape rather than hand-write the fold.
fromNoFacts
Granted when every named fact is definitely false, unresolved while any is unanswered.
The gate "does not own the game" needs this rather than a not: inverting the value turns unresolved
into true, which is the difference between "we could not confirm" and "definitely does not own it" --
and on a purchase gate that difference is offering to sell something somebody already has.
anyAllowed
The first allowed verdict among these, else unresolved if any is, else the first refusal.
An or-fold over whole verdicts rather than over facts, which is what lets a composed feature keep both halves' reasoning instead of collapsing to a boolean on the way.
fromAnyFact
The same fold over every fact present, for a feature whose fact list is not fixed when it is written. Safe now that states are always present -- it was not, when an unanswered fact vanished from the map.