An ATproto social media client -- with an independent Appview.

fix: agent that uses pbllc proxy header for preference calls

Changed files
+96
src
state
+96
src/state/session/appview-agent.ts
··· 1 + import { 2 + type AtpSessionData, 3 + type AtpSessionEvent, 4 + BskyAgent, 5 + } from '@atproto/api' 6 + 7 + import {BSKY_SERVICE, PBLLC_BLUESKY_PROXY_HEADER} from '#/lib/constants' 8 + import {logger} from '#/logger' 9 + import {emitNetworkConfirmed, emitNetworkLost} from '../events' 10 + import {sessionAccountToSession} from './agent' 11 + import {addSessionErrorLog} from './logging' 12 + import {type SessionAccount} from './types' 13 + 14 + /** 15 + * Specialized agent for appview operations that always uses the PBLLC proxy 16 + */ 17 + export class AppviewBskyAgent extends BskyAgent { 18 + persistSessionHandler: ((event: AtpSessionEvent) => void) | undefined = 19 + undefined 20 + 21 + constructor() { 22 + super({ 23 + service: BSKY_SERVICE, 24 + async fetch(...args) { 25 + let success = false 26 + try { 27 + const result = await globalThis.fetch(...args) 28 + success = true 29 + return result 30 + } catch (e) { 31 + success = false 32 + throw e 33 + } finally { 34 + if (success) { 35 + emitNetworkConfirmed() 36 + } else { 37 + emitNetworkLost() 38 + } 39 + } 40 + }, 41 + persistSession: (event: AtpSessionEvent) => { 42 + if (this.persistSessionHandler) { 43 + this.persistSessionHandler(event) 44 + } 45 + }, 46 + }) 47 + 48 + // Always configure with PBLLC proxy 49 + this.configureProxy(PBLLC_BLUESKY_PROXY_HEADER.get()) 50 + } 51 + 52 + /** 53 + * Set up the appview agent with the current user's session 54 + */ 55 + initializeWithAccount(account: SessionAccount) { 56 + try { 57 + const session: AtpSessionData = sessionAccountToSession(account) 58 + this.sessionManager.session = session 59 + 60 + if (account.pdsUrl) { 61 + this.sessionManager.pdsUrl = new URL(account.pdsUrl) 62 + } 63 + 64 + this.persistSessionHandler = event => { 65 + if (event !== 'create' && event !== 'update') { 66 + addSessionErrorLog(account.did, event) 67 + } 68 + } 69 + 70 + return true 71 + } catch (error) { 72 + logger.error('Failed to initialize appview agent', {error}) 73 + return false 74 + } 75 + } 76 + 77 + /** 78 + * Clear the current session data 79 + */ 80 + clearSession() { 81 + this.sessionManager.session = undefined 82 + this.persistSessionHandler = undefined 83 + } 84 + } 85 + 86 + // Singleton instance for appview operations 87 + const _appviewAgent = new AppviewBskyAgent() 88 + 89 + /** 90 + * Returns the appview agent instance 91 + */ 92 + export function getBskyAppviewAgent(): AppviewBskyAgent { 93 + return _appviewAgent 94 + } 95 + 96 + // No replacement needed, content already handled in previous edit