// Buddy "presence" taxonomy. Presence is BEHAVIORAL, not just time-decay: // online — authored something (post / reply / repost) within the window // idle — only passive activity (likes, follows, …) within the window // offline — no activity at all within the window // i.e. "are they at the keyboard creating, just lurking, or gone?" // Collections that count as actively-present authoring. Replies share the // `app.bsky.feed.post` collection with posts, so they're covered too. const ACTIVE = new Set([ 'app.bsky.feed.post', 'app.bsky.feed.repost', 'app.bsky.feed.threadgate', 'app.bsky.feed.postgate', ]); export const isActiveAction = (collection) => ACTIVE.has(collection); // `lastActive` = last authoring action; `lastSeen` = last action of any kind. export function stateFor({ lastActive, lastSeen }, windowMs) { const now = Date.now(); if (lastActive && now - lastActive <= windowMs) return 'online'; if (lastSeen && now - lastSeen <= windowMs) return 'idle'; return 'offline'; } const ACTION_VERB = { 'app.bsky.feed.post': 'posted', 'app.bsky.feed.like': 'liked a post', 'app.bsky.feed.repost': 'reposted', 'app.bsky.graph.follow': 'followed someone', 'app.bsky.graph.block': 'blocked someone', 'app.bsky.graph.listitem': 'edited a list', 'app.bsky.actor.profile': 'updated their profile', 'app.bsky.feed.threadgate': 'posted', 'app.bsky.feed.postgate': 'posted', }; export const verbFor = (collection) => ACTION_VERB[collection] || 'active';