Show raw api
{
"functions": [
{
"name": "SetReplicatedFeatureFactNames",
"desc": "Applies what the server says each feature reads. The entry point the client's replication arrives\nthrough, and the seam a test drives directly.\n\nFacts named here need no resolver in this realm -- an unregistered fact reads as unresolved locally and\ntakes its answer from the per-player replication, which is the whole point of being told about it.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "payload",
"desc": "",
"lua_type": "{ [string]: { string } }"
}
],
"returns": [],
"function_type": "static",
"source": {
"line": 325,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "HasFeature",
"desc": "",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "featureName",
"desc": "",
"lua_type": "string"
}
],
"returns": [
{
"desc": "",
"lua_type": "boolean"
}
],
"function_type": "static",
"source": {
"line": 432,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "IsFeatureAllowedByName",
"desc": "Whether the player may use this feature, addressed by name, as a plain boolean. Unresolved reads as\nfalse: a caller working from a string wants an answer, and failing closed is the safe half.\n\nPrefer the [AccessFeature] object where you have one -- a typo in a require is an error, a typo in a\nstring is a feature that quietly denies.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "player",
"desc": "",
"lua_type": "Player"
},
{
"name": "featureName",
"desc": "",
"lua_type": "string"
},
{
"name": "subject",
"desc": "",
"lua_type": "any?"
}
],
"returns": [
{
"desc": "",
"lua_type": "boolean"
}
],
"function_type": "static",
"source": {
"line": 450,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "ObserveIsFeatureAllowedByName",
"desc": "",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "player",
"desc": "",
"lua_type": "Player"
},
{
"name": "featureName",
"desc": "",
"lua_type": "string"
},
{
"name": "subject",
"desc": "",
"lua_type": "any?"
}
],
"returns": [
{
"desc": "",
"lua_type": "Observable<boolean>"
}
],
"function_type": "static",
"source": {
"line": 473,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "PromiseIsFeatureAllowedByName",
"desc": "",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "player",
"desc": "",
"lua_type": "Player"
},
{
"name": "featureName",
"desc": "",
"lua_type": "string"
},
{
"name": "subject",
"desc": "",
"lua_type": "any?"
}
],
"returns": [
{
"desc": "",
"lua_type": "Promise<boolean>"
}
],
"function_type": "static",
"source": {
"line": 491,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "ObserveFeatureAllowedStateByName",
"desc": "The full verdict for a feature addressed by name, so a caller can tell a refusal from a non-answer.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "player",
"desc": "",
"lua_type": "Player"
},
{
"name": "featureName",
"desc": "",
"lua_type": "string"
},
{
"name": "subject",
"desc": "",
"lua_type": "any?"
}
],
"returns": [
{
"desc": "",
"lua_type": "Observable<AccessState>"
}
],
"function_type": "static",
"source": {
"line": 513,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "TeardownPlayer",
"desc": "Releases everything held for a player: their overrides, every fact layer's cached resolution, and any\npromise still waiting on a verdict for them.\n\nDriven by [AccessService] off `Players.PlayerRemoving` in a real game, and callable directly by a test\nor by anything holding a mock rather than a real Player -- so a session ends deterministically instead\nof waiting on the collector.\n\nDeliberately not wired to a player-observing utility in here: this service is shared, and every such\nutility depends on `playermock`, which this package already depends on for its own tests. Two paths to\none module duplicates it in a built place and the loader can no longer resolve the name.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "player",
"desc": "",
"lua_type": "Player"
}
],
"returns": [],
"function_type": "static",
"source": {
"line": 541,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "ObserveIsPlayerPresent",
"desc": "Whether the player is still here. False forever once they have left.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "player",
"desc": "",
"lua_type": "Player"
}
],
"returns": [
{
"desc": "",
"lua_type": "Observable<boolean>"
}
],
"function_type": "static",
"source": {
"line": 570,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "RegisterFact",
"desc": "Registers a layer of a fact.\n\nTwo layers of the same fact must differ in both priority and source. Equal priorities would make the\nwinner depend on registration order, and equal sources would leave a readout unable to say which layer\ndecided -- both are refused at registration rather than discovered while someone is complaining.\n\nRegistering does not take ownership. A fact has a lifetime of its own, so give it to a maid at the\npoint you make it and the disposer to a maid too.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "fact",
"desc": "",
"lua_type": "AccessFact"
}
],
"returns": [
{
"desc": "Removes the layer",
"lua_type": "() -> ()"
}
],
"function_type": "static",
"source": {
"line": 617,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "AddAccessFact",
"desc": "Registers a fact from a value instead of a resolver -- one answer for every player.\n\nPrefer [AccessDataService.RegisterFact] with a resolver declared in shared code. Whoever calls this\nowns which realm has the fact, and a server-only call leaves the client with a fact that never\nresolves, which stalls every feature declaring it.\n\nUnlike [AccessDataService.RegisterFact], the returned disposer also destroys the fact: it is made here\nand never handed out, so there is no call site that could own it.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "factName",
"desc": "",
"lua_type": "string"
},
{
"name": "value",
"desc": "",
"lua_type": "ValueObject.Mountable<boolean?>"
},
{
"name": "options",
"desc": "",
"lua_type": "AccessFactOptions?"
}
],
"returns": [
{
"desc": "Removes the layer and destroys the fact",
"lua_type": "() -> ()"
}
],
"function_type": "static",
"source": {
"line": 742,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "RegisterFeature",
"desc": "",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "feature",
"desc": "",
"lua_type": "AccessFeature"
}
],
"returns": [
{
"desc": "Removes the registration",
"lua_type": "() -> ()"
}
],
"function_type": "static",
"source": {
"line": 764,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "GetFactLayers",
"desc": "The layers registered for a fact, highest priority first.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "factName",
"desc": "",
"lua_type": "string"
}
],
"returns": [
{
"desc": "",
"lua_type": "{ AccessFact }"
}
],
"function_type": "static",
"source": {
"line": 803,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "HasFact",
"desc": "",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "factName",
"desc": "",
"lua_type": "string"
}
],
"returns": [
{
"desc": "",
"lua_type": "boolean"
}
],
"function_type": "static",
"source": {
"line": 815,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "GetFeature",
"desc": "The feature registered under this name, for console commands and anything else working from a string.\nCode should hold the [AccessFeature] itself -- a typo in a require is an error, a typo in a string is a\nfeature that quietly denies.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "featureName",
"desc": "",
"lua_type": "string"
}
],
"returns": [
{
"desc": "",
"lua_type": "AccessFeature?"
}
],
"function_type": "static",
"source": {
"line": 829,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "GetFactNames",
"desc": "",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
}
],
"returns": [
{
"desc": "",
"lua_type": "{ string }"
}
],
"function_type": "static",
"source": {
"line": 838,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "GetFeatureNames",
"desc": "",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
}
],
"returns": [
{
"desc": "",
"lua_type": "{ string }"
}
],
"function_type": "static",
"source": {
"line": 851,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "ObserveFeatureNames",
"desc": "Every registered feature name, live. Changes as a game registers more.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
}
],
"returns": [
{
"desc": "",
"lua_type": "Observable<{ string }>"
}
],
"function_type": "static",
"source": {
"line": 863,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "ObserveFeature",
"desc": "Whether the player may use this feature, live.\n\nOpens on unresolved rather than on nothing, so a consumer always has a state to render. Repeats of the\nsame verdict are suppressed.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "player",
"desc": "",
"lua_type": "Player"
},
{
"name": "feature",
"desc": "",
"lua_type": "AccessFeature"
},
{
"name": "subject",
"desc": "Passed to the feature's compute, for per-thing features",
"lua_type": "any?"
}
],
"returns": [
{
"desc": "",
"lua_type": "Observable<AccessState>"
}
],
"function_type": "static",
"source": {
"line": 878,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "ObserveIsAllowed",
"desc": "Whether the player may use this feature, as a plain boolean.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "player",
"desc": "",
"lua_type": "Player"
},
{
"name": "feature",
"desc": "",
"lua_type": "AccessFeature"
},
{
"name": "subject",
"desc": "",
"lua_type": "any?"
}
],
"returns": [
{
"desc": "",
"lua_type": "Observable<boolean>"
}
],
"function_type": "static",
"source": {
"line": 948,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "PromiseFeature",
"desc": "The verdict once it actually settles, skipping unresolved.\n\nGOTCHA: stays pending for as long as the answer stays unknown. That is deliberate -- a gate that\nresolved on a non-answer would be deciding by coin toss -- but it means a caller that must act within a\nbounded time has to impose its own timeout and decide what a timeout means for it.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "player",
"desc": "",
"lua_type": "Player"
},
{
"name": "feature",
"desc": "",
"lua_type": "AccessFeature"
},
{
"name": "subject",
"desc": "",
"lua_type": "any?"
}
],
"returns": [
{
"desc": "",
"lua_type": "Promise<AccessState>"
}
],
"function_type": "static",
"source": {
"line": 972,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "SetFactOverride",
"desc": "Forces a fact for this player, whatever its layers say. Pass nil to force unresolved, which is the\nstate hardest to reproduce by hand and the one that strands players.\n\nSits above every other layer, so an override never has to be reconciled against whatever a game added\nlater. It shows up in a report as its own layer, with the layers it outranked still listed underneath\n-- so nobody mistakes an override left on for a genuine entitlement.\n\nServer-authoritative: a client that could set this could grant itself anything. Overrides are for\ntests and for console commands run by someone who already has permission.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "player",
"desc": "",
"lua_type": "Player"
},
{
"name": "factName",
"desc": "",
"lua_type": "string"
},
{
"name": "value",
"desc": "",
"lua_type": "boolean?"
}
],
"returns": [
{
"desc": "Clears this override",
"lua_type": "() -> ()"
}
],
"function_type": "static",
"source": {
"line": 1015,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "ClearFactOverride",
"desc": "",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "player",
"desc": "",
"lua_type": "Player"
},
{
"name": "factName",
"desc": "",
"lua_type": "string"
}
],
"returns": [],
"function_type": "static",
"source": {
"line": 1056,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "ClearFactOverrides",
"desc": "",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "player",
"desc": "",
"lua_type": "Player"
}
],
"returns": [],
"function_type": "static",
"source": {
"line": 1078,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "ObserveFactReport",
"desc": "One fact, fully explained. The readout a console command renders, and the answer to \"denied, but on\naccount of what\".",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "player",
"desc": "",
"lua_type": "Player"
},
{
"name": "factName",
"desc": "",
"lua_type": "string"
}
],
"returns": [
{
"desc": "",
"lua_type": "Observable<AccessFactReport>"
}
],
"function_type": "static",
"source": {
"line": 1095,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "ObserveFactReports",
"desc": "Every registered fact for this player, fully explained.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "player",
"desc": "",
"lua_type": "Player"
}
],
"returns": [
{
"desc": "",
"lua_type": "Observable<{ [string]: AccessFactReport }>"
}
],
"function_type": "static",
"source": {
"line": 1207,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "ObserveFactNames",
"desc": "The registered fact names, live. Emits again whenever a layer is registered or removed.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
}
],
"returns": [
{
"desc": "",
"lua_type": "Observable<{ string }>"
}
],
"function_type": "static",
"source": {
"line": 1233,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "ObserveFeatureReport",
"desc": "A feature's verdict together with every fact it was reached from -- the whole answer to a complaint,\nin one subscription.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "player",
"desc": "",
"lua_type": "Player"
},
{
"name": "feature",
"desc": "",
"lua_type": "AccessFeature"
},
{
"name": "subject",
"desc": "",
"lua_type": "any?"
}
],
"returns": [
{
"desc": "",
"lua_type": "Observable<AccessFeatureReport>"
}
],
"function_type": "static",
"source": {
"line": 1246,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "GetDebugState",
"desc": "Everything registered, as plain tables. Player-independent -- for \"what does this game gate, and what\nanswers it\", which is the question you have before you have a player to ask about.\n\nLive per-player state is [AccessDataService.ObserveFactReports], and the console renders both.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService\n"
}
],
"returns": [
{
"desc": "",
"lua_type": "{ facts: { [string]: { { factName: string, priority: number, source: string } } }, features: { [string]: { featureName: string, facts: { string } } } }"
}
],
"function_type": "static",
"source": {
"line": 1288,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "_mergeContributions",
"desc": "The merge, as a pure function: layers highest priority first, the first that contributes decides.",
"params": [
{
"name": "factName",
"desc": "",
"lua_type": "string"
},
{
"name": "contributions",
"desc": "",
"lua_type": "{ { source: string, priority: number, contribution: AccessFactContribution } }"
}
],
"returns": [
{
"desc": "",
"lua_type": "AccessFactReport"
}
],
"function_type": "static",
"private": true,
"source": {
"line": 1354,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "SetServerFactValue",
"desc": "Records what the server says a fact reads as for this player. Called by the client's replication\nreceiver; the server itself never calls it.\n\nReplication is unconditional -- every fact's server answer is sent -- and what a client *does* with\nit is the fact's [AccessFactServerOverrideBehavior]. Splitting it that way means a fact can never\naccidentally not replicate, only decline to be overridden by what arrived.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "player",
"desc": "",
"lua_type": "Player"
},
{
"name": "factName",
"desc": "",
"lua_type": "string"
},
{
"name": "value",
"desc": "",
"lua_type": "boolean?"
},
{
"name": "abstained",
"desc": "",
"lua_type": "boolean?"
},
{
"name": "metadata",
"desc": "",
"lua_type": "any?\n"
}
],
"returns": [],
"function_type": "static",
"source": {
"line": 1507,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "ObserveFactOverrides",
"desc": "The overrides in force for this player in *this* realm, live.\n\nWhat [AccessPlayer] replicates. A box is present for every overridden fact, and its `value` is absent\nwhen the override forces unresolved -- which is a thing somebody deliberately does, and so has to\nsurvive the trip rather than looking like no override at all.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "player",
"desc": "",
"lua_type": "Player"
}
],
"returns": [
{
"desc": "",
"lua_type": "Observable<{ [string]: { value: boolean? } }>"
}
],
"function_type": "static",
"source": {
"line": 1580,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "SetReplicatedFactOverrides",
"desc": "Applies the overrides the server has in force. The entry point the client's replication arrives\nthrough, and the seam a test drives directly.\n\nOverrides are debugging instructions, not entitlements, and an instruction that only took effect in one\nrealm would be the worst of both: a console session that opens the server's gate while the client still\nrenders it shut, with nothing in either readout saying why.\n\nAn override set locally shadows one that arrives here, so a person investigating in this realm is not\nfighting somebody else's console.",
"params": [
{
"name": "self",
"desc": "",
"lua_type": "AccessDataService"
},
{
"name": "player",
"desc": "",
"lua_type": "Player"
},
{
"name": "entries",
"desc": "",
"lua_type": "{ [string]: { value: boolean? } }"
}
],
"returns": [],
"function_type": "static",
"source": {
"line": 1603,
"path": "src/access/src/Shared/AccessDataService.lua"
}
}
],
"properties": [],
"types": [
{
"name": "AccessFactLayerReport",
"desc": "What one layer said, and whether it was the one that decided.\n\n`contributes` is the distinction the whole merge turns on: a layer that abstained said nothing and was\nskipped, whereas a layer that contributed `nil` said \"nobody knows yet\" and stopped the fall-through.",
"fields": [
{
"name": "source",
"lua_type": "string",
"desc": ""
},
{
"name": "priority",
"lua_type": "number",
"desc": ""
},
{
"name": "contributes",
"lua_type": "boolean",
"desc": ""
},
{
"name": "value",
"lua_type": "boolean?",
"desc": "meaningful only when contributes"
},
{
"name": "decided",
"lua_type": "boolean",
"desc": "true for the single layer that won"
}
],
"source": {
"line": 83,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "AccessFactReport",
"desc": "One fact, fully explained: what features read, who decided it, and what every layer said. `layers` is\nordered highest priority first, so it reads top-down the way the merge ran.",
"fields": [
{
"name": "factName",
"lua_type": "string",
"desc": ""
},
{
"name": "value",
"lua_type": "boolean?",
"desc": "what features read"
},
{
"name": "decidedBy",
"lua_type": "string?",
"desc": "nil when every layer abstained"
},
{
"name": "layers",
"lua_type": "{ AccessFactLayerReport }",
"desc": ""
}
],
"source": {
"line": 104,
"path": "src/access/src/Shared/AccessDataService.lua"
}
},
{
"name": "AccessFeatureReport",
"desc": "A verdict together with every fact it was reached from -- the whole answer to \"why can this player not\nget in\", in one place.",
"fields": [
{
"name": "featureName",
"lua_type": "string",
"desc": ""
},
{
"name": "state",
"lua_type": "AccessState",
"desc": ""
},
{
"name": "facts",
"lua_type": "{ [string]: AccessFactReport }",
"desc": ""
}
],
"source": {
"line": 130,
"path": "src/access/src/Shared/AccessDataService.lua"
}
}
],
"name": "AccessDataService",
"desc": "Aggregates every [AccessFact] a game registers and answers every [AccessFeature] it gates against them.\nOne place resolves the facts, one place applies the policy, and both realms read the same registry --\nso the menu, the storefront and the server's arrival gate reach one verdict instead of three that drift.\n\nRegistration belongs in shared code, during `Init`:\n\n```lua\nfunction MyGameAccess:Init(serviceBag)\n\tlocal accessDataService = serviceBag:GetService(AccessDataService)\n\n\tself._maid:GiveTask(accessDataService:RegisterFact(MyGameFacts.OwnsGame))\n\tself._maid:GiveTask(accessDataService:RegisterFeature(MyGameFeatures.Chapters))\nend\n```\n\n## How a fact is decided\n\nSeveral layers may answer one fact. They are ordered by [AccessFactPriority], highest first, and **the\nfirst layer that contributes decides**. What it contributes may be `true`, `false`, or unresolved; a\nlayer that abstains ([AccessFact.ABSTAIN]) is skipped entirely. If nothing contributes, the fact is\nunresolved.\n\nThe merge does not return a value, it returns an [AccessFactReport] -- every layer, what each said, and\nwhich one won -- and the value features read is a field on it. The gate and the debug readout are\ntherefore the same computation, so a readout can never explain a decision that was not the one made.\n\n## What is deliberately not here\n\nFacts are addressable by name so they can be inspected and overridden, but there is no `ObserveFact`.\nYou can set a fact and you can look at one; you cannot subscribe to one and write your own rule at a\ncall site. That asymmetry is what keeps every consumer reading the same verdict, which is the entire\nreason this is a package rather than four call sites that each decide for themselves.",
"source": {
"line": 38,
"path": "src/access/src/Shared/AccessDataService.lua"
}
}