Bluesky app fork with some witchin' additions 馃挮
witchsky.app
bluesky
fork
client
1import AtpAgent from '@atproto/api'
2import {jwtDecode} from 'jwt-decode'
3
4import {isJwtExpired} from '#/lib/jwt'
5import {hasProp} from '#/lib/type-guards'
6import * as persisted from '#/state/persisted'
7import {sessionAccountToSession} from './agent'
8import {type SessionAccount} from './types'
9
10export function readLastActiveAccount() {
11 const {currentAccount, accounts} = persisted.get('session')
12 return accounts.find(a => a.did === currentAccount?.did)
13}
14
15export function isSignupQueued(accessJwt: string | undefined) {
16 if (accessJwt) {
17 const sessData = jwtDecode(accessJwt)
18 return (
19 hasProp(sessData, 'scope') &&
20 sessData.scope === 'com.atproto.signupQueued'
21 )
22 }
23 return false
24}
25
26export function isSessionExpired(account: SessionAccount) {
27 if (account.accessJwt) {
28 return isJwtExpired(account.accessJwt)
29 } else {
30 return true
31 }
32}
33
34/**
35 * Creates and attempted to resumeSession for every stored session.
36 * Intended to be used to send push token revokations just before logout.
37 */
38export async function createTemporaryAgentsAndResume(
39 accounts: SessionAccount[],
40) {
41 const agents = await Promise.allSettled(
42 accounts.map(async account => {
43 const agent: AtpAgent = new AtpAgent({service: account.service})
44 if (account.pdsUrl) {
45 agent.sessionManager.pdsUrl = new URL(account.pdsUrl)
46 }
47
48 const session = sessionAccountToSession(account)
49 const res = await agent.resumeSession(session)
50 if (!res.success) throw new Error('Failed to resume session')
51
52 agent.assertAuthenticated() // confirm auth success
53
54 return agent
55 }),
56 )
57
58 return agents
59 .filter(x => x.status === 'fulfilled')
60 .map(promise => promise.value)
61}