Bluesky app fork with some witchin' additions 馃挮 witchsky.app
bluesky fork client
at main 89 lines 2.7 kB view raw
1import {MMKV} from '@bsky.app/react-native-mmkv' 2import {setPolyfills} from '@growthbook/growthbook' 3import {GrowthBook} from '@growthbook/growthbook-react' 4 5import {getNavigationMetadata, type Metadata} from '#/analytics/metadata' 6import * as env from '#/env' 7 8export {Features} from '#/analytics/features/types' 9 10const CACHE = new MMKV({id: 'bsky_features_cache'}) 11 12setPolyfills({ 13 localStorage: { 14 getItem: key => { 15 const value = CACHE.getString(key) 16 return value != null ? JSON.parse(value) : null 17 }, 18 setItem: async (key, value) => { 19 CACHE.set(key, value) 20 }, 21 }, 22}) 23 24/** 25 * We vary the amount of time we wait for GrowthBook to fetch feature 26 * gates based on the strategy specified. 27 */ 28export type FeatureFetchStrategy = 'prefer-low-latency' | 'prefer-fresh-gates' 29 30const TIMEOUT_INIT = 500 // TODO should base on p99 or something 31const TIMEOUT_PREFER_LOW_LATENCY = 250 32const TIMEOUT_PREFER_FRESH_GATES = 1500 33 34export const features = new GrowthBook({ 35 apiHost: env.GROWTHBOOK_API_HOST, 36 clientKey: env.GROWTHBOOK_CLIENT_KEY, 37}) 38 39/** 40 * Initializer promise that must be awaited before using the GrowthBook 41 * instance or rendering the `AnalyticsFeaturesContext`. Note: this may not be 42 * fully initialized if it takes longer than `TIMEOUT_INIT` to initialize. In 43 * that case, we may see a flash of uncustomized content until the 44 * initialization completes. 45 */ 46export const init = new Promise<void>(async y => { 47 await features.init({timeout: TIMEOUT_INIT}) 48 y() 49}) 50 51/** 52 * Refresh feature gates from GrowthBook. Updates attributes based on the 53 * provided account, if any. 54 */ 55export async function refresh({strategy}: {strategy: FeatureFetchStrategy}) { 56 await features.refreshFeatures({ 57 timeout: 58 strategy === 'prefer-low-latency' 59 ? TIMEOUT_PREFER_LOW_LATENCY 60 : TIMEOUT_PREFER_FRESH_GATES, 61 }) 62} 63 64/** 65 * Converts our metadata into GrowthBook attributes and sets them. GrowthBook 66 * attributes are manually configured in the GrowthBook dashboard. So these 67 * values need to match exactly. Therefore, let's add them here manually to and 68 * not spread them to avoid mistakes. 69 */ 70export function setAttributes({ 71 base, 72 geolocation, 73 session, 74 preferences, 75}: Metadata) { 76 features.setAttributes({ 77 deviceId: base.deviceId, 78 sessionId: base.sessionId, 79 platform: base.platform, 80 appVersion: base.appVersion, 81 countryCode: geolocation.countryCode, 82 regionCode: geolocation.regionCode, 83 did: session?.did, 84 isBskyPds: session?.isBskyPds, 85 appLanguage: preferences?.appLanguage, 86 contentLanguages: preferences?.contentLanguages, 87 currentScreen: getNavigationMetadata()?.currentScreen, 88 }) 89}