feat: mesh status indicator state helpers for chat header

Add resolveMeshStatusState, richer P2P badge labels (connecting/syncing/relay),
and tooltip copy so the UI can show live mesh health for guild and DM.
This commit is contained in:
Raven Scott
2026-07-13 02:43:52 -04:00
parent 8935250c31
commit f9cbc5bf5f
+151 -9
View File
@@ -24,16 +24,28 @@ const { shouldShowMeshBoundedBadge, buildMeshBoundedBadgeContent } = boundedBadg
const meshStabilityUiReconnectChromeFieldKeys = [
'statsPeers',
'hasStats',
'p2pBadgeText'
'p2pBadgeText',
'meshStatusState'
]
const meshStabilityUiReconnectChromeActionKeys = [
'syncChatHeader',
'syncPendingBanner',
'syncServerRail',
'updateP2pBadge'
'updateP2pBadge',
'updateMeshStatus'
]
/** Visual / semantic states for the chat-header mesh status indicator. */
const MESH_STATUS_STATES = Object.freeze([
'idle',
'local',
'connecting',
'live',
'syncing',
'relay'
])
function listMeshStabilityUiReconnectChromeFieldKeys () {
return meshStabilityUiReconnectChromeFieldKeys.slice()
}
@@ -42,19 +54,146 @@ function listMeshStabilityUiReconnectChromeActionKeys () {
return meshStabilityUiReconnectChromeActionKeys.slice()
}
function formatMeshStabilityP2pBadgeText (stats) {
const peers = stats != null ? Math.max(0, Number(stats.peers) || 0) : null
return peers != null
/**
* Resolve mesh status indicator state from peer count + context.
* @param {object} [ctx]
* @param {number|null} [ctx.peers] display peer count (null = no stats yet)
* @param {string} [ctx.mode] view mode: guild | dm | home | …
* @param {boolean} [ctx.meshBounded]
* @param {boolean} [ctx.pending] guild sync pending
* @param {number} [ctx.openGossip]
* @param {number} [ctx.dmTopicPeers]
* @param {number} [ctx.contactsReachable]
* @param {boolean} [ctx.hasStats]
*/
function resolveMeshStatusState (ctx = {}) {
const hasStats = ctx.hasStats != null ? !!ctx.hasStats : ctx.peers != null
if (!hasStats && (ctx.peers == null || Number.isNaN(Number(ctx.peers)))) {
return 'idle'
}
const peers = Math.max(0, Number(ctx.peers) || 0)
const mode = String(ctx.mode || '')
const pending = !!ctx.pending
const meshBounded = !!ctx.meshBounded
const dmTopicPeers = Math.max(0, Number(ctx.dmTopicPeers) || 0)
const contactsReachable = Math.max(0, Number(ctx.contactsReachable) || 0)
if (peers > 0) {
if (pending) return 'syncing'
// DM: topic empty but contacts mesh is carrying traffic
if (mode === 'dm' && dmTopicPeers === 0 && contactsReachable > 0) return 'relay'
return 'live'
}
if (mode === 'guild' && meshBounded) return 'connecting'
if (mode === 'dm' && (meshBounded || Number(ctx.openGossip) > 0)) return 'connecting'
if (mode === 'guild' || mode === 'dm') return 'local'
return 'local'
}
/**
* Short label for the mesh status pill (kept P2P-prefixed for legacy readers).
* @param {object|null} stats
* @param {object} [ctx] extra context for state (mode, meshBounded, …)
*/
function formatMeshStabilityP2pBadgeText (stats, ctx = {}) {
if (stats == null && !ctx.forceState) return 'P2P · local'
const peers =
stats != null ? Math.max(0, Number(stats.peers) || 0) : Math.max(0, Number(ctx.peers) || 0)
const state =
ctx.state ||
resolveMeshStatusState({
peers: stats != null ? peers : null,
hasStats: stats != null,
mode: ctx.mode,
meshBounded: ctx.meshBounded,
pending: ctx.pending,
openGossip: stats?.openGossip ?? ctx.openGossip,
dmTopicPeers: stats?.dmTopicPeers ?? ctx.dmTopicPeers,
contactsReachable: stats?.contactsReachable ?? ctx.contactsReachable
})
if (state === 'connecting') return 'P2P · connecting…'
if (state === 'syncing') {
return `P2P · syncing · ${peers} peer${peers === 1 ? '' : 's'}`
}
if (state === 'relay') {
return `P2P · relay · ${peers} peer${peers === 1 ? '' : 's'}`
}
if (state === 'live') {
return `P2P · ${peers} peer${peers === 1 ? '' : 's'}`
}
if (state === 'idle') return 'P2P · local'
return peers > 0
? `P2P · ${peers} peer${peers === 1 ? '' : 's'}`
: `P2P · local`
: 'P2P · local'
}
/**
* Richer tooltip for the mesh status indicator.
*/
function formatMeshStatusTitle (stats, ctx = {}) {
const peers = stats != null ? Math.max(0, Number(stats.peers) || 0) : 0
const state =
ctx.state ||
resolveMeshStatusState({
peers: stats != null ? peers : null,
hasStats: stats != null,
mode: ctx.mode,
meshBounded: ctx.meshBounded,
pending: ctx.pending,
openGossip: stats?.openGossip ?? ctx.openGossip,
dmTopicPeers: stats?.dmTopicPeers ?? ctx.dmTopicPeers,
contactsReachable: stats?.contactsReachable ?? ctx.contactsReachable
})
const mode = String(ctx.mode || '')
const parts = []
if (state === 'idle' || state === 'local') {
parts.push(mode === 'dm' ? 'Direct message mesh idle' : mode === 'guild' ? 'Guild mesh local only' : 'Peer-to-peer mesh')
} else if (state === 'connecting') {
parts.push(mode === 'dm' ? 'Connecting to DM mesh…' : 'Connecting to guild mesh…')
} else if (state === 'syncing') {
parts.push(`Syncing with ${peers} peer${peers === 1 ? '' : 's'}`)
} else if (state === 'relay') {
parts.push(`DM relay via contacts · ${peers} reachable`)
} else {
parts.push(`Mesh live · ${peers} peer${peers === 1 ? '' : 's'}`)
}
const dmTopic = Math.max(0, Number(stats?.dmTopicPeers ?? ctx.dmTopicPeers) || 0)
const contacts = Math.max(0, Number(stats?.contactsReachable ?? ctx.contactsReachable) || 0)
if (mode === 'dm' && (dmTopic > 0 || contacts > 0)) {
parts.push(`topic ${dmTopic} · contacts ${contacts}`)
}
const openGossip = Math.max(0, Number(stats?.openGossip ?? ctx.openGossip) || 0)
if (openGossip > 0 && mode === 'guild') {
parts.push(`${openGossip} channel gossip open`)
}
if (ctx.pending) parts.push('sync pending')
if (ctx.meshBounded && peers === 0) parts.push('waiting for peers')
return parts.join(' · ')
}
function pickMeshStabilityReconnectChromeFields (view) {
const stats = view?.stats
return {
statsPeers: Number(stats?.peers) || 0,
const peers = Number(stats?.peers) || 0
const mode = view?.mode || null
const rail = view?.guild?.id ? view?.guildSyncHealthRail?.[view.guild.id] : null
const ctx = {
mode,
meshBounded: !!(rail?.meshBounded || view?.guildMeshBounded),
pending: !!view?.guildSyncHealth?.pending,
openGossip: stats?.openGossip,
dmTopicPeers: stats?.dmTopicPeers,
contactsReachable: stats?.contactsReachable
}
const state = resolveMeshStatusState({
peers: stats != null ? peers : null,
hasStats: stats != null,
p2pBadgeText: formatMeshStabilityP2pBadgeText(stats)
...ctx
})
return {
statsPeers: peers,
hasStats: stats != null,
p2pBadgeText: formatMeshStabilityP2pBadgeText(stats, { ...ctx, state }),
meshStatusState: state
}
}
@@ -68,11 +207,14 @@ function buildMeshStabilityReconnectChromeSnapshot (view) {
module.exports = {
meshStabilityUiReconnectChromeFieldKeys,
meshStabilityUiReconnectChromeActionKeys,
MESH_STATUS_STATES,
MESH_PEER_DISPLAY_ZERO_DROP_HOLD_MS,
MESH_PEER_CONTACT_GRACE_MS,
listMeshStabilityUiReconnectChromeFieldKeys,
listMeshStabilityUiReconnectChromeActionKeys,
resolveMeshStatusState,
formatMeshStabilityP2pBadgeText,
formatMeshStatusTitle,
createMeshPeerDisplayStabilizer,
stepMeshPeerDisplayStabilizer,
resolveMeshPeerContactAt,