mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
at samuel/exp-cli 74 lines 2.1 kB view raw
1import {useMemo} from 'react' 2import { 3 type $Typed, 4 type AppBskyActorDefs, 5 AppBskyEmbedExternal, 6} from '@atproto/api' 7import {isAfter, parseISO} from 'date-fns' 8 9import {useMaybeProfileShadow} from '#/state/cache/profile-shadow' 10import {useLiveNowConfig} from '#/state/service-config' 11import {useTickEveryMinute} from '#/state/shell' 12import type * as bsky from '#/types/bsky' 13 14export function useActorStatus(actor?: bsky.profile.AnyProfileView) { 15 const shadowed = useMaybeProfileShadow(actor) 16 const tick = useTickEveryMinute() 17 const config = useLiveNowConfig() 18 19 return useMemo(() => { 20 tick! // revalidate every minute 21 22 if ( 23 shadowed && 24 'status' in shadowed && 25 shadowed.status && 26 validateStatus(shadowed.did, shadowed.status, config) && 27 isStatusStillActive(shadowed.status.expiresAt) 28 ) { 29 return { 30 isActive: true, 31 status: 'app.bsky.actor.status#live', 32 embed: shadowed.status.embed as $Typed<AppBskyEmbedExternal.View>, // temp_isStatusValid asserts this 33 expiresAt: shadowed.status.expiresAt!, // isStatusStillActive asserts this 34 record: shadowed.status.record, 35 } satisfies AppBskyActorDefs.StatusView 36 } else { 37 return { 38 status: '', 39 isActive: false, 40 record: {}, 41 } satisfies AppBskyActorDefs.StatusView 42 } 43 }, [shadowed, config, tick]) 44} 45 46export function isStatusStillActive(timeStr: string | undefined) { 47 if (!timeStr) return false 48 const now = new Date() 49 const expiry = parseISO(timeStr) 50 51 return isAfter(expiry, now) 52} 53 54export function validateStatus( 55 did: string, 56 status: AppBskyActorDefs.StatusView, 57 config: {did: string; domains: string[]}[], 58) { 59 if (status.status !== 'app.bsky.actor.status#live') return false 60 const sources = config.find(cfg => cfg.did === did) 61 if (!sources) { 62 return false 63 } 64 try { 65 if (AppBskyEmbedExternal.isView(status.embed)) { 66 const url = new URL(status.embed.external.uri) 67 return sources.domains.includes(url.hostname) 68 } else { 69 return false 70 } 71 } catch { 72 return false 73 } 74}