feat(teams): project rosters by audience rung, and add to the Team page
The module's half of TEAMS.md phase 3. `projectRoster` is the optional fourth provider method and the only one core calls on a request path. Core holds the roster and owns its public shape; the question that is this module's is who is allowed to look, because the audience rungs and their configuration live here. The answer is all-or-nothing, which is the honest translation rather than a shortcut: a rung is a property of the FEATURE, and there is no configuration in which some members of a guild are public and others are not. The refusal semantics INVERT here, and the tests say so. For the other three methods a refusal means "change nothing" and an empty array would be destructive. Core fails CLOSED on this one, so the dangerous answer is the opposite — returning every key because the config could not be read would publish a roster an operator gated to staff. Every path that cannot reach a confident answer refuses, including the catch. The anonymous case is answered directly rather than by handing `viewerLevel` a synthetic request. Given one with no `req.user` it falls through to `auth.getUserFromRequest`, which expects real cookies and throws on a fake — and that throw would have become a refusal, so every anonymous visitor would have been served an empty roster on a shard whose guilds are public. Caught by the tests, not by reading. `team.overview` gets a live population reading beside core's stored one. Core's number comes from the last roster sync and is coarse by construction; this is the `presence.online` feed this module already holds. It is explicitly not a per-Team presence figure — the shard publishes a global aggregate and no per-guild breakdown exists on the wire, so claiming one would be inventing a number — and it renders nothing at all when it has nothing true to say. `team.member.row` is left unfilled. The useful thing to put there is a link to the character behind a row, and the props core can supply do not identify one: the member key and the site account id are withheld from every public roster. An empty cell beats a guess. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -52,6 +52,7 @@ import PlayerCharacter from './routes/player/PlayerCharacter.jsx'
|
||||
import ShardStatusLink from './components/ShardStatusLink.jsx'
|
||||
import UserShardSections from './routes/admin/UserShardSections.jsx'
|
||||
import InviteGameAccountStep from './components/InviteGameAccountStep.jsx'
|
||||
import TeamOverviewStrip from './components/TeamOverviewStrip.jsx'
|
||||
|
||||
const ID = 'uo'
|
||||
|
||||
@@ -180,6 +181,18 @@ registry.registerFeatureProvider(ID, ID, useShardFlags)
|
||||
registry.registerExtension(ID, 'site.footer.status', ShardStatusLink)
|
||||
registry.registerExtension(ID, 'admin.users.detail', UserShardSections)
|
||||
registry.registerExtension(ID, 'player.invite.accepted', InviteGameAccountStep)
|
||||
// The fourth, and the first that was never core's: `team.overview` is new in
|
||||
// 1.6.0 and core renders the whole Team page without it (TEAMS.md §3.4). This
|
||||
// adds a live reading beside core's stored one, and renders nothing when it has
|
||||
// nothing true to say.
|
||||
//
|
||||
// `team.member.row` is declared by core and deliberately LEFT UNFILLED. Its
|
||||
// useful contents would be a link to the character behind a roster row, and the
|
||||
// props core can supply do not identify one: the member key and the site account
|
||||
// id are withheld from every public roster (§3.2), so this module would be
|
||||
// guessing from a display name. Filling it with a guess is worse than an empty
|
||||
// cell.
|
||||
registry.registerExtension(ID, 'team.overview', TeamOverviewStrip)
|
||||
|
||||
// `module.json`'s `coreApi` range is checked by the loader before this file is
|
||||
// ever served, so there is nothing to re-check here. It is logged because a
|
||||
|
||||
Reference in New Issue
Block a user