The kind of event, for filtering and for picking a render branch.
Deliberately WIDER than GuildFishingEventKind: the server serves the live list as kinds, and
it can grow before this package does. Typing it as the three known literals made a switch look
exhaustive and a default look like dead code - which is exactly how an unrecognised kind ends
up falling into whichever branch happens to be last.
(string & {}) keeps autocomplete on the known values while still accepting any string, so the
default case is required rather than remembered.
SWITCH ON THIS, then narrow detail inside a known branch. detail is a closed union so that
its fields narrow properly, which means a switch on detail.kind alone IS treated as exhaustive
and puts the dead-default problem straight back.
The line exactly as it was posted. Already rendered - do not rebuild it.
Who the entry is ABOUT. For a moderation entry that is the target; the actor is in detail.
Optionalusername?: string | nullDisplay name for userId, resolved server-side.
null when the bot has no name on record - render the id rather than a placeholder, and never
drop the row, since the page's total counts it either way. Absent on APIs predating this.
The structured event behind the line.
nullonly on a row whose payload could not be read back. It is alsonullto TypeScript in spirit for a kind this package does not know: the value is there on the wire, but it matches no member of the union, so treat an unmatchedkindas "rendermessageand nothing else".messageis the honest fallback in every one of those cases, because it is what was actually posted to Discord rather than something reconstructed.