From 748212e000f963976bca5d63e0961d75a7e8b296 Mon Sep 17 00:00:00 2001
From: dan <dan.abramov@gmail.com>
Date: Wed, 6 Dec 2023 18:32:14 +0000
Subject: Remove getSession waterfall (#2112)

---
 src/state/session/index.tsx | 78 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 55 insertions(+), 23 deletions(-)

(limited to 'src/state/session/index.tsx')

diff --git a/src/state/session/index.tsx b/src/state/session/index.tsx
index 0d52d2521..49c1326d9 100644
--- a/src/state/session/index.tsx
+++ b/src/state/session/index.tsx
@@ -1,6 +1,7 @@
 import React from 'react'
 import {BskyAgent, AtpPersistSessionHandler} from '@atproto/api'
 import {useQueryClient} from '@tanstack/react-query'
+import {jwtDecode} from 'jwt-decode'
 
 import {networkRetry} from '#/lib/async/retry'
 import {logger} from '#/logger'
@@ -327,34 +328,65 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
         ),
       })
 
-      await networkRetry(3, () =>
-        agent.resumeSession({
-          accessJwt: account.accessJwt || '',
-          refreshJwt: account.refreshJwt || '',
-          did: account.did,
-          handle: account.handle,
-        }),
-      )
+      let canReusePrevSession = false
+      try {
+        if (account.accessJwt) {
+          const decoded = jwtDecode(account.accessJwt)
+          if (decoded.exp) {
+            const didExpire = Date.now() >= decoded.exp * 1000
+            if (!didExpire) {
+              canReusePrevSession = true
+            }
+          }
+        }
+      } catch (e) {
+        console.error('Could not decode jwt.')
+      }
 
-      if (!agent.session) {
-        throw new Error(`session: initSession failed to establish a session`)
+      const prevSession = {
+        accessJwt: account.accessJwt || '',
+        refreshJwt: account.refreshJwt || '',
+        did: account.did,
+        handle: account.handle,
       }
 
-      // ensure changes in handle/email etc are captured on reload
-      const freshAccount: SessionAccount = {
-        service: agent.service.toString(),
-        did: agent.session.did,
-        handle: agent.session.handle,
-        email: agent.session.email,
-        emailConfirmed: agent.session.emailConfirmed || false,
-        refreshJwt: agent.session.refreshJwt,
-        accessJwt: agent.session.accessJwt,
+      if (canReusePrevSession) {
+        agent.session = prevSession
+        __globalAgent = agent
+        queryClient.clear()
+        upsertAccount(account)
+        emitSessionLoaded(account, agent)
+        // Intentionally not awaited to unblock the UI:
+        resumeSessionWithFreshAccount().then(async freshAccount => {
+          if (JSON.stringify(account) !== JSON.stringify(freshAccount)) {
+            upsertAccount(freshAccount)
+            emitSessionLoaded(freshAccount, agent)
+          }
+        })
+      } else {
+        const freshAccount = await resumeSessionWithFreshAccount()
+        __globalAgent = agent
+        queryClient.clear()
+        upsertAccount(freshAccount)
+        emitSessionLoaded(freshAccount, agent)
       }
 
-      __globalAgent = agent
-      queryClient.clear()
-      upsertAccount(freshAccount)
-      emitSessionLoaded(freshAccount, agent)
+      async function resumeSessionWithFreshAccount(): Promise<SessionAccount> {
+        await networkRetry(3, () => agent.resumeSession(prevSession))
+        if (!agent.session) {
+          throw new Error(`session: initSession failed to establish a session`)
+        }
+        // ensure changes in handle/email etc are captured on reload
+        return {
+          service: agent.service.toString(),
+          did: agent.session.did,
+          handle: agent.session.handle,
+          email: agent.session.email,
+          emailConfirmed: agent.session.emailConfirmed || false,
+          refreshJwt: agent.session.refreshJwt,
+          accessJwt: agent.session.accessJwt,
+        }
+      }
     },
     [upsertAccount, queryClient],
   )
-- 
cgit 1.4.1

