Bluesky app fork with some witchin' additions 💫 witchsky.app
bluesky fork client
117
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: stay on original page with oauth login

xan.lol ab8e3dc8 e0187145

+103 -53
+58 -50
src/App.web.tsx
··· 41 41 useSessionApi, 42 42 } from '#/state/session' 43 43 import {getWebOAuthClient} from '#/state/session/oauth-web-client' 44 + import {consumeOAuthReturnUrl} from '#/state/session/oauth-web-return-url' 44 45 import {readLastActiveAccount} from '#/state/session/util' 45 46 import {Provider as ShellStateProvider} from '#/state/shell' 46 47 import {Provider as ComposerProvider} from '#/state/shell/composer' ··· 72 73 features, 73 74 setupDeviceId, 74 75 } from '#/analytics' 75 - import {SettingsSyncGate} from '#/features/settingsSync' 76 76 import { 77 77 prefetchLiveEvents, 78 78 Provider as LiveEventsProvider, 79 79 } from '#/features/liveEvents/context' 80 + import {SettingsSyncGate} from '#/features/settingsSync' 80 81 import * as Geo from '#/geolocation' 81 82 import {Splash} from '#/Splash' 82 83 import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider' ··· 144 145 }, 145 146 'LoginForm', 146 147 ) 148 + 149 + const returnUrl = consumeOAuthReturnUrl() 150 + if (returnUrl) { 151 + window.location.replace(returnUrl) 152 + return 153 + } 154 + 147 155 // Clear hash fragment after processing 148 156 window.history.replaceState(null, '', window.location.pathname) 149 157 return ··· 187 195 <AnalyticsFeaturesContext> 188 196 <QueryProvider currentDid={currentAccount?.did}> 189 197 <SettingsSyncGate> 190 - <PolicyUpdateOverlayProvider> 191 - <LiveEventsProvider> 192 - <AgeAssuranceV2Provider> 193 - <ComposerProvider> 194 - <MessagesProvider> 195 - {/* LabelDefsProvider MUST come before ModerationOptsProvider */} 196 - <LabelDefsProvider> 197 - <ModerationOptsProvider> 198 - <LoggedOutViewProvider> 199 - <SelectedFeedProvider> 200 - <HiddenRepliesProvider> 201 - <HomeBadgeProvider> 202 - <UnreadNotifsProvider> 203 - <BackgroundNotificationPreferencesProvider> 204 - <MutedThreadsProvider> 205 - <SafeAreaProvider> 206 - <SafeAreaOverride> 207 - <ProgressGuideProvider> 208 - <ServiceConfigProvider> 209 - <EmailVerificationProvider> 210 - <HideBottomBarBorderProvider> 211 - <IntentDialogProvider> 212 - <TranslateOnDeviceProvider> 213 - <HotkeysProvider> 214 - <Shell /> 215 - <ToastOutlet /> 216 - </HotkeysProvider> 217 - </TranslateOnDeviceProvider> 218 - </IntentDialogProvider> 219 - </HideBottomBarBorderProvider> 220 - </EmailVerificationProvider> 221 - </ServiceConfigProvider> 222 - </ProgressGuideProvider> 223 - </SafeAreaOverride> 224 - </SafeAreaProvider> 225 - </MutedThreadsProvider> 226 - </BackgroundNotificationPreferencesProvider> 227 - </UnreadNotifsProvider> 228 - </HomeBadgeProvider> 229 - </HiddenRepliesProvider> 230 - </SelectedFeedProvider> 231 - </LoggedOutViewProvider> 232 - </ModerationOptsProvider> 233 - </LabelDefsProvider> 234 - </MessagesProvider> 235 - </ComposerProvider> 236 - </AgeAssuranceV2Provider> 237 - </LiveEventsProvider> 238 - </PolicyUpdateOverlayProvider> 198 + <PolicyUpdateOverlayProvider> 199 + <LiveEventsProvider> 200 + <AgeAssuranceV2Provider> 201 + <ComposerProvider> 202 + <MessagesProvider> 203 + {/* LabelDefsProvider MUST come before ModerationOptsProvider */} 204 + <LabelDefsProvider> 205 + <ModerationOptsProvider> 206 + <LoggedOutViewProvider> 207 + <SelectedFeedProvider> 208 + <HiddenRepliesProvider> 209 + <HomeBadgeProvider> 210 + <UnreadNotifsProvider> 211 + <BackgroundNotificationPreferencesProvider> 212 + <MutedThreadsProvider> 213 + <SafeAreaProvider> 214 + <SafeAreaOverride> 215 + <ProgressGuideProvider> 216 + <ServiceConfigProvider> 217 + <EmailVerificationProvider> 218 + <HideBottomBarBorderProvider> 219 + <IntentDialogProvider> 220 + <TranslateOnDeviceProvider> 221 + <HotkeysProvider> 222 + <Shell /> 223 + <ToastOutlet /> 224 + </HotkeysProvider> 225 + </TranslateOnDeviceProvider> 226 + </IntentDialogProvider> 227 + </HideBottomBarBorderProvider> 228 + </EmailVerificationProvider> 229 + </ServiceConfigProvider> 230 + </ProgressGuideProvider> 231 + </SafeAreaOverride> 232 + </SafeAreaProvider> 233 + </MutedThreadsProvider> 234 + </BackgroundNotificationPreferencesProvider> 235 + </UnreadNotifsProvider> 236 + </HomeBadgeProvider> 237 + </HiddenRepliesProvider> 238 + </SelectedFeedProvider> 239 + </LoggedOutViewProvider> 240 + </ModerationOptsProvider> 241 + </LabelDefsProvider> 242 + </MessagesProvider> 243 + </ComposerProvider> 244 + </AgeAssuranceV2Provider> 245 + </LiveEventsProvider> 246 + </PolicyUpdateOverlayProvider> 239 247 </SettingsSyncGate> 240 248 </QueryProvider> 241 249 </AnalyticsFeaturesContext>
+4
src/lib/routes/web.ts
··· 1 + export function replaceWebLocation(href: string) { 2 + if (typeof window === 'undefined') return 3 + window.location.replace(href) 4 + }
+14 -3
src/screens/Login/AuthCallback.tsx
··· 2 2 import {useNavigation} from '@react-navigation/native' 3 3 4 4 import {type NavigationProp} from '#/lib/routes/types' 5 + import {replaceWebLocation} from '#/lib/routes/web' 5 6 import {logger} from '#/logger' 6 7 import {useSessionApi} from '#/state/session' 7 8 import {getWebOAuthClient} from '#/state/session/oauth-web-client' 9 + import {consumeOAuthReturnUrl} from '#/state/session/oauth-web-return-url' 8 10 9 11 export function AuthCallback() { 10 12 const {login} = useSessionApi() 11 13 const navigation = useNavigation<NavigationProp>() 12 14 13 15 useEffect(() => { 14 - ;(async () => { 16 + void (async () => { 15 17 try { 16 18 const client = getWebOAuthClient() 17 19 const result = await client.init() ··· 26 28 'LoginForm', 27 29 ) 28 30 } 31 + 32 + const returnUrl = consumeOAuthReturnUrl() 33 + if (returnUrl) { 34 + replaceWebLocation(returnUrl) 35 + return 36 + } 37 + 29 38 navigation.replace('Home') 30 - } catch (e: any) { 31 - logger.error('OAuth callback failed', {error: e.message}) 39 + } catch (e: unknown) { 40 + logger.error('OAuth callback failed', { 41 + error: e instanceof Error ? e.message : String(e), 42 + }) 32 43 navigation.replace('Home') 33 44 } 34 45 })()
+2
src/screens/Login/LoginForm.web.tsx
··· 21 21 import {useSetHasCheckedForStarterPack} from '#/state/preferences/used-starter-packs' 22 22 import {useSessionApi} from '#/state/session' 23 23 import {getWebOAuthClient} from '#/state/session/oauth-web-client' 24 + import {saveOAuthReturnUrl} from '#/state/session/oauth-web-return-url' 24 25 import {useLoggedOutViewControls} from '#/state/shell/logged-out' 25 26 import {atoms as a, useTheme} from '#/alf' 26 27 import {Button, ButtonIcon, ButtonText} from '#/components/Button' ··· 204 205 setIsProcessing(true) 205 206 206 207 try { 208 + saveOAuthReturnUrl() 207 209 const client = getWebOAuthClient() 208 210 await client.signIn(identifier) 209 211 // Browser will redirect to authorization server
+25
src/state/session/oauth-web-return-url.ts
··· 1 + const OAUTH_RETURN_URL_KEY = 'oauth_return_url' 2 + 3 + export function saveOAuthReturnUrl(url = window.location.href) { 4 + if (typeof window === 'undefined') return 5 + 6 + window.sessionStorage.setItem(OAUTH_RETURN_URL_KEY, url) 7 + } 8 + 9 + export function consumeOAuthReturnUrl() { 10 + if (typeof window === 'undefined') return undefined 11 + 12 + const savedUrl = window.sessionStorage.getItem(OAUTH_RETURN_URL_KEY) 13 + window.sessionStorage.removeItem(OAUTH_RETURN_URL_KEY) 14 + 15 + if (!savedUrl) return undefined 16 + 17 + try { 18 + const url = new URL(savedUrl, window.location.origin) 19 + if (url.origin !== window.location.origin) return undefined 20 + if (url.pathname === '/auth/web/callback') return undefined 21 + return `${url.pathname}${url.search}${url.hash}` 22 + } catch { 23 + return undefined 24 + } 25 + }