Something went wrong. Try again.
FlockOff is a mass-block tool for the Atmosphere flockoff.app
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172import { APPVIEW_URL } from './appview'
/** * Beta access control — allowlist via an AT Protocol list. * * Set BETA_LIST_URI to an AT URI (at://did/app.bsky.graph.list/rkey) to * restrict login to members of that list. Remove the env var to open the * app to everyone (production launch mode). * * The list is fetched from the public Bluesky API and cached in memory for * CACHE_TTL_MS. Members added to the list on Bluesky will gain access within * that window without any server restart or code change. */
declare global { // eslint-disable-next-line no-var var __betaListCache: { dids: Set<string>; fetchedAt: number } | undefined}
const CACHE_TTL_MS = 5 * 60 * 1000 // 5 minutes
async function fetchAllowedDids(): Promise<Set<string>> { const listUri = process.env.BETA_LIST_URI if (!listUri) return new Set()
const now = Date.now() if ( globalThis.__betaListCache && now - globalThis.__betaListCache.fetchedAt < CACHE_TTL_MS ) { return globalThis.__betaListCache.dids }
const dids = new Set<string>() let cursor: string | undefined
try { do { const params = new URLSearchParams({ list: listUri, limit: '100' }) if (cursor) params.set('cursor', cursor) const res = await fetch( `${APPVIEW_URL}/xrpc/app.bsky.graph.getList?${params}` ) if (!res.ok) break const data = await res.json() for (const item of (data.items ?? []) as Array<{ subject?: { did?: string } }>) { if (item.subject?.did) dids.add(item.subject.did) } cursor = data.cursor } while (cursor) } catch (err) { console.error('[beta] failed to fetch allowlist:', err) // On fetch failure, fall back to stale cache rather than blocking everyone if (globalThis.__betaListCache) return globalThis.__betaListCache.dids }
globalThis.__betaListCache = { dids, fetchedAt: now } return dids}
/** Returns true if the user is allowed to access the app. */export async function isAllowedUser(did: string): Promise<boolean> { if (!process.env.BETA_LIST_URI) return true const dids = await fetchAllowedDids() return dids.has(did)}
/** Returns true when beta restriction is active (BETA_LIST_URI is set). */export function isBetaRestricted(): boolean { return !!process.env.BETA_LIST_URI}