about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/statsig/statsig.tsx26
-rw-r--r--src/state/session/index.tsx15
2 files changed, 40 insertions, 1 deletions
diff --git a/src/lib/statsig/statsig.tsx b/src/lib/statsig/statsig.tsx
index 151b365d3..c43d2bf8a 100644
--- a/src/lib/statsig/statsig.tsx
+++ b/src/lib/statsig/statsig.tsx
@@ -8,6 +8,7 @@ import {logger} from '#/logger'
 import {isWeb} from '#/platform/detection'
 import {IS_TESTFLIGHT} from 'lib/app-info'
 import {useSession} from '../../state/session'
+import {timeout} from '../async/timeout'
 import {useNonReactiveCallback} from '../hooks/useNonReactiveCallback'
 import {LogEvents} from './events'
 import {Gate} from './gates'
@@ -164,6 +165,31 @@ AppState.addEventListener('change', (state: AppStateStatus) => {
   }
 })
 
+export async function tryFetchGates(
+  did: string,
+  strategy: 'prefer-low-latency' | 'prefer-fresh-gates',
+) {
+  try {
+    let timeoutMs = 250 // Don't block the UI if we can't do this fast.
+    if (strategy === 'prefer-fresh-gates') {
+      // Use this for less common operations where the user would be OK with a delay.
+      timeoutMs = 1500
+    }
+    // Note: This condition is currently false the very first render because
+    // Statsig has not initialized yet. In the future, we can fix this by
+    // doing the initialization ourselves instead of relying on the provider.
+    if (Statsig.initializeCalled()) {
+      await Promise.race([
+        timeout(timeoutMs),
+        Statsig.prefetchUsers([toStatsigUser(did)]),
+      ])
+    }
+  } catch (e) {
+    // Don't leak errors to the calling code, this is meant to be always safe.
+    console.error(e)
+  }
+}
+
 export function Provider({children}: {children: React.ReactNode}) {
   const {currentAccount, accounts} = useSession()
   const did = currentAccount?.did
diff --git a/src/state/session/index.tsx b/src/state/session/index.tsx
index b88181ebd..1d60eaf8f 100644
--- a/src/state/session/index.tsx
+++ b/src/state/session/index.tsx
@@ -9,7 +9,7 @@ import {jwtDecode} from 'jwt-decode'
 import {track} from '#/lib/analytics/analytics'
 import {networkRetry} from '#/lib/async/retry'
 import {IS_TEST_USER} from '#/lib/constants'
-import {logEvent, LogEvents} from '#/lib/statsig/statsig'
+import {logEvent, LogEvents, tryFetchGates} from '#/lib/statsig/statsig'
 import {hasProp} from '#/lib/type-guards'
 import {logger} from '#/logger'
 import {isWeb} from '#/platform/detection'
@@ -243,6 +243,10 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
       if (!agent.session) {
         throw new Error(`session: createAccount failed to establish a session`)
       }
+      const fetchingGates = tryFetchGates(
+        agent.session.did,
+        'prefer-fresh-gates',
+      )
 
       const deactivated = isSessionDeactivated(agent.session.accessJwt)
       if (!deactivated) {
@@ -283,6 +287,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
       )
 
       __globalAgent = agent
+      await fetchingGates
       upsertAccount(account)
 
       logger.debug(`session: created account`, {}, logger.DebugContext.session)
@@ -303,6 +308,10 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
       if (!agent.session) {
         throw new Error(`session: login failed to establish a session`)
       }
+      const fetchingGates = tryFetchGates(
+        agent.session.did,
+        'prefer-fresh-gates',
+      )
 
       const account: SessionAccount = {
         service: agent.service.toString(),
@@ -330,6 +339,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
       __globalAgent = agent
       // @ts-ignore
       if (IS_DEV && isWeb) window.agent = agent
+      await fetchingGates
       upsertAccount(account)
 
       logger.debug(`session: logged in`, {}, logger.DebugContext.session)
@@ -362,6 +372,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
   const initSession = React.useCallback<ApiContext['initSession']>(
     async account => {
       logger.debug(`session: initSession`, {}, logger.DebugContext.session)
+      const fetchingGates = tryFetchGates(account.did, 'prefer-low-latency')
 
       const agent = new BskyAgent({
         service: account.service,
@@ -406,6 +417,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
 
         agent.session = prevSession
         __globalAgent = agent
+        await fetchingGates
         upsertAccount(account)
 
         if (prevSession.deactivated) {
@@ -442,6 +454,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
         try {
           const freshAccount = await resumeSessionWithFreshAccount()
           __globalAgent = agent
+          await fetchingGates
           upsertAccount(freshAccount)
         } catch (e) {
           /*