feat(session): resolved permission map snapshot (USER_PERMISSIONS_UPDATED)

Adds the wire pipeline for `Outgoing.UserPermissionsMapComposer = 10070`
shipped by Arcturus-Morningstar-Extended ≥ 4.2.10. The composer sends
the resolved `permission_definitions` map for the current user
(filtered to ALLOWED / ROOM_OWNER entries) at login and after every
`HabboManager.setRank` — so a runtime promote/demote re-derives every
React-side permission gate.

- NitroEventType.USER_PERMISSIONS_UPDATED — new invalidation event.
- IncomingHeader.USER_PERMISSIONS_MAP = 10070.
- UserPermissionsMapParser reads `int count + (string key, int value)*`.
- UserPermissionsMapEvent + NitroMessages registration.
- SessionDataManager._permissions Map + getPermissionsSnapshot()
  referentially-stable per the snapshot convention. New handler
  onUserPermissionsMapEvent copies the parser map into the manager
  (so the parser's mutable reference doesn't leak) and invalidates.
- ISessionDataManager.getPermissionsSnapshot() — public contract.

React-side consumers ship in the companion commit on
feat/react19-modernization. The wire is backward-compatible: older
emulators never send the packet, the snapshot stays empty Map, and
all useHasPermission(key) gates return false (mod-only UI hidden by
default = safe).

Verification: tsgo clean, vitest 138/138.
This commit is contained in:
simoleo89
2026-05-19 18:59:35 +02:00
parent 87e67d58df
commit 159c5eb6e8
9 changed files with 130 additions and 2 deletions
@@ -55,4 +55,11 @@ export interface ISessionDataManager
uiFlags: number;
tags: string[];
getUserDataSnapshot(): Readonly<IUserDataSnapshot>;
/**
* Referentially-stable view of the resolved permission map for
* the current user. Invalidated by `USER_PERMISSIONS_UPDATED`.
* Empty when the connected emulator doesn't ship the extended
* `UserPermissionsMapComposer` (Arcturus ≥ 4.2.10).
*/
getPermissionsSnapshot(): ReadonlyMap<string, number>;
}