Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

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

Address lint warnings (#10188)

authored by

DS Boyce and committed by
GitHub
d0d00ba9 e4b4e48a

+170 -173
+2 -2
src/App.native.tsx
··· 215 215 } 216 216 217 217 function App() { 218 - const [isReady, setReady] = useState(false) 218 + const [isReady, setIsReady] = useState(false) 219 219 220 220 useEffect(() => { 221 221 void Promise.all([initPersistedState(), Geo.resolve(), setupDeviceId]).then( 222 - () => setReady(true), 222 + () => setIsReady(true), 223 223 ) 224 224 }, []) 225 225
+2 -2
src/App.web.tsx
··· 194 194 } 195 195 196 196 function App() { 197 - const [isReady, setReady] = useState(false) 197 + const [isReady, setIsReady] = useState(false) 198 198 199 199 useEffect(() => { 200 200 void Promise.all([initPersistedState(), Geo.resolve(), setupDeviceId]).then( 201 - () => setReady(true), 201 + () => setIsReady(true), 202 202 ) 203 203 }, []) 204 204
+12 -12
src/ageAssurance/data.tsx
··· 105 105 ) 106 106 } 107 107 let configPrefetchPromise: Promise<void> | undefined 108 - export async function prefetchConfig() { 108 + export function prefetchConfig() { 109 109 if (configPrefetchPromise) { 110 110 logger.debug(`prefetchAgeAssuranceConfig: already in progress`) 111 111 return 112 112 } 113 113 114 - configPrefetchPromise = new Promise(async resolve => { 114 + configPrefetchPromise = (async () => { 115 115 await cacheHydrationPromise 116 116 const cached = getConfigFromCache() 117 117 118 118 if (cached) { 119 119 logger.debug(`prefetchAgeAssuranceConfig: using cache`) 120 - resolve() 121 120 } else { 122 121 try { 123 122 logger.debug(`prefetchAgeAssuranceConfig: resolving...`) ··· 126 125 configQueryKey, 127 126 res, 128 127 ) 129 - } catch (e: any) { 128 + } catch (err) { 129 + const e = err as Error 130 130 logger.warn(`prefetchAgeAssuranceConfig: failed`, { 131 131 safeMessage: e.message, 132 132 }) 133 - } finally { 134 - resolve() 135 133 } 136 134 } 137 - }) 135 + })() 138 136 } 139 137 export async function refetchConfig() { 140 138 logger.debug(`refetchConfig: fetching...`) ··· 228 226 logger.debug(`prefetchServerState: resolving...`) 229 227 const res = await networkRetry(3, () => getServerState({agent})) 230 228 qc.setQueryData<AppBskyAgeassuranceGetState.OutputSchema>(qk, res) 231 - } catch (e: any) { 229 + } catch (err) { 230 + const e = err as Error 232 231 logger.warn(`prefetchServerState: failed`, { 233 232 safeMessage: e.message, 234 233 }) ··· 248 247 export function usePatchServerState() { 249 248 const {currentAccount} = useSession() 250 249 return useCallback( 251 - async (next: AppBskyAgeassuranceDefs.State) => { 250 + (next: AppBskyAgeassuranceDefs.State) => { 252 251 if (!currentAccount) return 253 252 const did = currentAccount.did 254 253 const prev = getServerStateFromCache({did}) ··· 313 312 // only refetch when needed 314 313 if (isAssured || !isAArequired) return 315 314 316 - refetch() 315 + void refetch() 317 316 }) 318 317 }, [did, refetch, isAssured]) 319 318 ··· 409 408 logger.debug(`prefetchOtherRequiredData: resolving...`) 410 409 const res = await networkRetry(3, () => getOtherRequiredData({agent})) 411 410 qc.setQueryData<OtherRequiredData>(qk, res) 412 - } catch (e: any) { 411 + } catch (err) { 412 + const e = err as Error 413 413 logger.warn(`prefetchOtherRequiredData: failed`, { 414 414 safeMessage: e.message, 415 415 }) ··· 418 418 export function usePatchOtherRequiredData() { 419 419 const {currentAccount} = useSession() 420 420 return useCallback( 421 - async (next: OtherRequiredData) => { 421 + (next: OtherRequiredData) => { 422 422 if (!currentAccount) return 423 423 const did = currentAccount.did 424 424 const prev = getOtherRequiredDataFromCache({did})
+1 -1
src/ageAssurance/index.tsx
··· 85 85 86 86 const handleAccessUpdate = useCallback( 87 87 (s: AgeAssuranceState) => { 88 - getAndRegisterPushToken({ 88 + void getAndRegisterPushToken({ 89 89 isAgeRestricted: s.access !== AgeAssuranceAccess.Full, 90 90 }) 91 91 },
+1
src/ageAssurance/state.ts
··· 99 99 100 100 useEffect(() => { 101 101 if (prevAccess !== state.access) { 102 + // eslint-disable-next-line react-hooks/set-state-in-effect 102 103 setPrevAccess(state.access) 103 104 cb(state) 104 105 logger.debug(`useOnAgeAssuranceAccessUpdate`, {state})
+11 -9
src/screens/Settings/Settings.tsx
··· 161 161 p => p.did === account.did, 162 162 )} 163 163 pendingDid={pendingDid} 164 - onPressSwitchAccount={onPressSwitchAccount} 164 + onPressSwitchAccount={(account, logContext) => 165 + void onPressSwitchAccount(account, logContext) 166 + } 165 167 /> 166 168 ))} 167 169 <AddAccountRow /> ··· 245 247 </SettingsList.ItemText> 246 248 </SettingsList.LinkItem> 247 249 <SettingsList.PressableItem 248 - onPress={() => Linking.openURL(HELP_DESK_URL)} 250 + onPress={() => void Linking.openURL(HELP_DESK_URL)} 249 251 label={_(msg`Help`)} 250 252 accessibilityHint={_(msg`Opens helpdesk in browser`)}> 251 253 <SettingsList.ItemIcon icon={CircleQuestionIcon} /> ··· 392 394 } = useApplyPullRequestOTAUpdate() 393 395 const [actyNotifNudged, setActyNotifNudged] = useActivitySubscriptionsNudged() 394 396 395 - const resetOnboarding = async () => { 397 + const resetOnboarding = () => { 396 398 navigation.navigate('Home') 397 399 onboardingDispatch({type: 'start'}) 398 400 Toast.show(_(msg`Onboarding reset`)) ··· 407 409 const lastEmailConfirm = new Date() 408 410 // wind back 3 days 409 411 lastEmailConfirm.setDate(lastEmailConfirm.getDate() - 3) 410 - persisted.write('reminders', { 412 + void persisted.write('reminders', { 411 413 ...persisted.get('reminders'), 412 414 lastEmailConfirm: lastEmailConfirm.toISOString(), 413 415 }) ··· 431 433 style: 'default', 432 434 text: 'Apply', 433 435 onPress: (channel?: string) => { 434 - tryApplyUpdate(channel ?? '') 436 + void tryApplyUpdate(channel ?? '') 435 437 }, 436 438 }, 437 439 ], ··· 473 475 </SettingsList.ItemText> 474 476 </SettingsList.PressableItem> 475 477 <SettingsList.PressableItem 476 - onPress={() => resetOnboarding()} 478 + onPress={() => void resetOnboarding()} 477 479 label={_(msg`Reset onboarding state`)}> 478 480 <SettingsList.ItemText> 479 481 <Trans>Reset onboarding state</Trans> ··· 496 498 </SettingsList.PressableItem> 497 499 )} 498 500 <SettingsList.PressableItem 499 - onPress={() => clearAllStorage()} 501 + onPress={() => void clearAllStorage()} 500 502 label={_(msg`Clear all storage data`)}> 501 503 <SettingsList.ItemText> 502 504 <Trans>Clear all storage data (restart after this)</Trans> ··· 513 515 ) : null} 514 516 {IS_NATIVE && isCurrentlyRunningPullRequestDeployment ? ( 515 517 <SettingsList.PressableItem 516 - onPress={revertToEmbedded} 518 + onPress={() => void revertToEmbedded()} 517 519 label={_(msg`Unapply Pull Request`)}> 518 520 <SettingsList.ItemText> 519 521 <Trans>Unapply Pull Request {currentChannel}</Trans> ··· 543 545 <Button 544 546 onPress={() => { 545 547 device.set([PolicyUpdate202508], false) 546 - agent.bskyAppRemoveNuxs([PolicyUpdate202508]) 548 + void agent.bskyAppRemoveNuxs([PolicyUpdate202508]) 547 549 Toast.show(`Done`, { 548 550 type: 'info', 549 551 })
+2 -2
src/screens/Signup/StepCaptcha/CaptchaWebView.web.tsx
··· 48 48 return 49 49 } 50 50 onSuccess(code) 51 - } catch (e: unknown) { 51 + } catch (e) { 52 52 // We don't actually want to record an error here, because this will happen quite a bit. We will only be able to 53 - // get hte href of the iframe if it's on our domain, so all the hcaptcha requests will throw here, although it's 53 + // get the href of the iframe if it's on our domain, so all the hcaptcha requests will throw here, although it's 54 54 // harmless. Our other indicators of time-to-complete and back press should be more reliable in catching issues. 55 55 } 56 56 }, [stateParam, onSuccess, onError])
+3 -2
src/screens/Signup/StepCaptcha/index.tsx
··· 34 34 const [ready, setReady] = useState(false) 35 35 36 36 useEffect(() => { 37 - ;(async () => { 37 + void (async () => { 38 38 logger.debug('trying to generate attestation token...') 39 39 try { 40 40 if (IS_IOS) { ··· 48 48 setToken(token) 49 49 setPayload(base64UrlEncode(payload)) 50 50 } 51 - } catch (e: any) { 51 + } catch (err) { 52 + const e = err as Error 52 53 logger.error(e) 53 54 } finally { 54 55 setReady(true)
+18 -24
src/screens/Signup/StepInfo/index.tsx
··· 1 1 import {useEffect, useRef, useState} from 'react' 2 2 import {type TextInput, View} from 'react-native' 3 - import {msg} from '@lingui/core/macro' 4 - import {useLingui} from '@lingui/react' 5 - import {Plural, Trans} from '@lingui/react/macro' 3 + import {Plural, Trans, useLingui} from '@lingui/react/macro' 6 4 import * as EmailValidator from 'email-validator' 7 5 import type tldts from 'tldts' 8 6 ··· 60 58 refetchServer: () => void 61 59 isLoadingStarterPack: boolean 62 60 }) { 63 - const {_} = useLingui() 61 + const {t: l} = useLingui() 64 62 const ax = useAnalytics() 65 63 const {state, dispatch} = useSignupContext() 66 64 const preemptivelyCompleteActivePolicyUpdate = ··· 94 92 const tldtsRef = useRef<typeof tldts>(undefined) 95 93 useEffect(() => { 96 94 // @ts-expect-error - valid path 97 - import('tldts/dist/index.cjs.min.js').then(tldts => { 95 + void import('tldts/dist/index.cjs.min.js').then(tldts => { 98 96 tldtsRef.current = tldts 99 97 }) 100 98 // This will get used in the avatar creator a few steps later, so lets preload it now 101 99 // @ts-expect-error - valid path 102 - import('react-native-view-shot/src/index') 100 + void import('react-native-view-shot/src/index') 103 101 }, []) 104 102 105 103 const onNextPress = () => { ··· 115 113 if (state.serviceDescription?.inviteCodeRequired && !inviteCode) { 116 114 return dispatch({ 117 115 type: 'setError', 118 - value: _(msg`Please enter your invite code.`), 116 + value: l`Please enter your invite code.`, 119 117 field: 'invite-code', 120 118 }) 121 119 } 122 120 if (!email) { 123 121 return dispatch({ 124 122 type: 'setError', 125 - value: _(msg`Please enter your email.`), 123 + value: l`Please enter your email.`, 126 124 field: 'email', 127 125 }) 128 126 } 129 127 if (!EmailValidator.validate(email)) { 130 128 return dispatch({ 131 129 type: 'setError', 132 - value: _(msg`Your email appears to be invalid.`), 130 + value: l`Your email appears to be invalid.`, 133 131 field: 'email', 134 132 }) 135 133 } ··· 139 137 setHasWarnedEmail(true) 140 138 return dispatch({ 141 139 type: 'setError', 142 - value: _( 143 - msg`Please double-check that you have entered your email address correctly.`, 144 - ), 140 + value: l`Please double-check that you have entered your email address correctly.`, 145 141 }) 146 142 } 147 143 } else if (hasWarnedEmail) { ··· 151 147 if (!password) { 152 148 return dispatch({ 153 149 type: 'setError', 154 - value: _(msg`Please choose your password.`), 150 + value: l`Please choose your password.`, 155 151 field: 'password', 156 152 }) 157 153 } 158 154 if (password.length < 8) { 159 155 return dispatch({ 160 156 type: 'setError', 161 - value: _(msg`Your password must be at least 8 characters long.`), 157 + value: l`Your password must be at least 8 characters long.`, 162 158 field: 'password', 163 159 }) 164 160 } ··· 205 201 dispatch({type: 'clearError'}) 206 202 } 207 203 }} 208 - label={_(msg`Required for this provider`)} 204 + label={l`Required for this provider`} 209 205 defaultValue={state.inviteCode} 210 206 autoCapitalize="none" 211 207 autoComplete="email" ··· 241 237 dispatch({type: 'clearError'}) 242 238 } 243 239 }} 244 - label={_(msg`Enter your email address`)} 240 + label={l`Enter your email address`} 245 241 defaultValue={state.email} 246 242 autoCapitalize="none" 247 243 autoComplete="email" ··· 269 265 dispatch({type: 'clearError'}) 270 266 } 271 267 }} 272 - label={_(msg`Choose your password`)} 268 + label={l`Choose your password`} 273 269 defaultValue={state.password} 274 270 secureTextEntry 275 271 autoComplete="new-password" ··· 297 293 value: sanitizeDate(new Date(date)), 298 294 }) 299 295 }} 300 - label={_(msg`Date of birth`)} 301 - accessibilityHint={_(msg`Select your date of birth`)} 296 + label={l`Date of birth`} 297 + accessibilityHint={l`Select your date of birth`} 302 298 maximumDate={new Date()} 303 299 /> 304 300 </View> ··· 331 327 <Trans> 332 328 Have we got your location wrong?{' '} 333 329 <SimpleInlineLinkText 334 - label={_( 335 - msg`Tap here to confirm your location with GPS.`, 336 - )} 330 + label={l`Tap here to confirm your location with GPS.`} 337 331 {...createStaticClick(() => { 338 332 locationControl.open() 339 333 })}> ··· 363 357 props.closeDialog(() => { 364 358 // set this after close! 365 359 setDeviceGeolocation(props.geolocation) 366 - Toast.show(_(msg`Your location has been updated.`), { 360 + Toast.show(l`Your location has been updated.`, { 367 361 type: 'success', 368 362 }) 369 363 }) ··· 380 374 onBackPress={onPressBack} 381 375 onNextPress={onNextPress} 382 376 onRetryPress={refetchServer} 383 - overrideNextText={hasWarnedEmail ? _(msg`It's correct`) : undefined} 377 + overrideNextText={hasWarnedEmail ? l`It's correct` : undefined} 384 378 /> 385 379 </> 386 380 )
+12 -13
src/screens/Signup/index.tsx
··· 3 3 import ReactNativeDeviceAttest from 'react-native-device-attest' 4 4 import Animated, {FadeIn, LayoutAnimationConfig} from 'react-native-reanimated' 5 5 import {AppBskyGraphStarterpack} from '@atproto/api' 6 - import {msg} from '@lingui/core/macro' 7 - import {useLingui} from '@lingui/react' 8 - import {Trans} from '@lingui/react/macro' 6 + import {Trans, useLingui} from '@lingui/react/macro' 9 7 10 8 import {FEEDBACK_FORM_URL} from '#/lib/constants' 11 9 import {logger} from '#/logger' ··· 36 34 37 35 export function Signup({onPressBack}: {onPressBack: () => void}) { 38 36 const ax = useAnalytics() 39 - const {_} = useLingui() 37 + const {t: l} = useLingui() 40 38 const t = useTheme() 41 39 const [state, dispatch] = useReducer(reducer, { 42 40 ...initialState, ··· 61 59 uri: activeStarterPack?.uri, 62 60 }) 63 61 62 + // eslint-disable-next-line react/hook-use-state 64 63 const [isFetchedAtMount] = useState(starterPack != null) 65 64 const showStarterPackCard = 66 65 activeStarterPack?.uri && !isFetchingStarterPack && starterPack ··· 85 84 dispatch({type: 'setServiceDescription', value: undefined}) 86 85 dispatch({ 87 86 type: 'setError', 88 - value: _( 89 - msg`Unable to contact your service. Please check your Internet connection.`, 90 - ), 87 + value: l`Unable to contact your service. Please check your Internet connection.`, 91 88 }) 92 89 } else if (serviceInfo) { 93 90 dispatch({type: 'setServiceDescription', value: serviceInfo}) 94 91 dispatch({type: 'setError', value: ''}) 95 92 } 96 - }, [_, serviceInfo, isError]) 93 + }, [l, serviceInfo, isError]) 97 94 98 95 useEffect(() => { 99 96 if (state.pendingSubmit) { 100 97 if (!state.pendingSubmit.mutableProcessed) { 98 + // OK to mutate assuming it's never read in render. 99 + // eslint-disable-next-line react-hooks/immutability, react-compiler/react-compiler 101 100 state.pendingSubmit.mutableProcessed = true 102 - submit(state, dispatch) 101 + void submit(state, dispatch) 103 102 } 104 103 } 105 104 }, [state, dispatch, submit]) ··· 133 132 <SignupContext.Provider value={{state, dispatch}}> 134 133 <LoggedOutLayout 135 134 leadin="" 136 - title={_(msg`Create Account`)} 137 - description={_(msg`We're so excited to have you join us!`)} 135 + title={l`Create account`} 136 + description={l`We’re so excited to have you join us!`} 138 137 scrollable> 139 138 <View testID="createAccount" style={a.flex_1}> 140 139 {showStarterPackCard && ··· 204 203 isFetchingStarterPack && !isErrorStarterPack 205 204 } 206 205 isServerError={isError} 207 - refetchServer={refetch} 206 + refetchServer={() => void refetch()} 208 207 /> 209 208 ) : state.activeStep === SignupStep.HANDLE ? ( 210 209 <StepHandle /> ··· 231 230 ]}> 232 231 <Trans>Having trouble?</Trans>{' '} 233 232 <InlineLinkText 234 - label={_(msg`Contact support`)} 233 + label={l`Contact support`} 235 234 to={FEEDBACK_FORM_URL({email: state.email})} 236 235 style={[!gtMobile && a.text_md]}> 237 236 <Trans>Contact support</Trans>
+14 -14
src/screens/Signup/state.ts
··· 4 4 ComAtprotoServerCreateAccount, 5 5 type ComAtprotoServerDescribeServer, 6 6 } from '@atproto/api' 7 - import {msg} from '@lingui/core/macro' 8 - import {useLingui} from '@lingui/react' 7 + import {useLingui} from '@lingui/react/macro' 9 8 import * as EmailValidator from 'email-validator' 10 9 11 10 import {DEFAULT_SERVICE} from '#/lib/constants' ··· 18 17 19 18 export type ServiceDescription = ComAtprotoServerDescribeServer.OutputSchema 20 19 21 - const DEFAULT_DATE = new Date(Date.now() - 60e3 * 60 * 24 * 365 * 20) // default to 20 years ago 20 + const date = new Date() 21 + date.setFullYear(date.getFullYear() - 20) // default to 20 years ago 22 + const DEFAULT_DATE = date 22 23 23 24 export enum SignupStep { 24 25 INFO, ··· 256 257 257 258 export function useSubmitSignup() { 258 259 const ax = useAnalytics() 259 - const {_} = useLingui() 260 + const {t: l} = useLingui() 260 261 const {createAccount} = useSessionApi() 261 262 const onboardingDispatch = useOnboardingDispatch() 262 263 ··· 266 267 dispatch({type: 'setStep', value: SignupStep.INFO}) 267 268 return dispatch({ 268 269 type: 'setError', 269 - value: _(msg`Please enter your email.`), 270 + value: l`Please enter your email.`, 270 271 field: 'email', 271 272 }) 272 273 } ··· 274 275 dispatch({type: 'setStep', value: SignupStep.INFO}) 275 276 return dispatch({ 276 277 type: 'setError', 277 - value: _(msg`Your email appears to be invalid.`), 278 + value: l`Your email appears to be invalid.`, 278 279 field: 'email', 279 280 }) 280 281 } ··· 282 283 dispatch({type: 'setStep', value: SignupStep.INFO}) 283 284 return dispatch({ 284 285 type: 'setError', 285 - value: _(msg`Please choose your password.`), 286 + value: l`Please choose your password.`, 286 287 field: 'password', 287 288 }) 288 289 } ··· 290 291 dispatch({type: 'setStep', value: SignupStep.HANDLE}) 291 292 return dispatch({ 292 293 type: 'setError', 293 - value: _(msg`Please choose your handle.`), 294 + value: l`Please choose your handle.`, 294 295 field: 'handle', 295 296 }) 296 297 } ··· 305 306 }) 306 307 return dispatch({ 307 308 type: 'setError', 308 - value: _(msg`Please complete the verification captcha.`), 309 + value: l`Please complete the verification captcha.`, 309 310 }) 310 311 } 311 312 dispatch({type: 'setError', value: ''}) ··· 337 338 * createAccount fails, one tab is not stuck in onboarding — Eric 338 339 */ 339 340 onboardingDispatch({type: 'start'}) 340 - } catch (e: any) { 341 + } catch (err) { 342 + const e = err as Error 341 343 let errMsg = e.toString() 342 344 if (e instanceof ComAtprotoServerCreateAccount.InvalidInviteCodeError) { 343 345 dispatch({ 344 346 type: 'setError', 345 - value: _( 346 - msg`Invite code not accepted. Check that you input it correctly and try again.`, 347 - ), 347 + value: l`Invite code not accepted. Check that you input it correctly and try again.`, 348 348 field: 'invite-code', 349 349 }) 350 350 dispatch({type: 'setStep', value: SignupStep.INFO}) ··· 370 370 dispatch({type: 'setIsLoading', value: false}) 371 371 } 372 372 }, 373 - [_, onboardingDispatch, createAccount], 373 + [l, ax.logger, createAccount, onboardingDispatch], 374 374 ) 375 375 }
+1 -1
src/state/birthdate.ts
··· 14 14 * Stores the timestamp of the birthday update locally. This is used to 15 15 * debounce birthday updates globally. 16 16 * 17 - * Use {@link useIsBirthDateUpdateAllowed} to check if an update is allowed. 17 + * Use {@link useIsBirthdateUpdateAllowed} to check if an update is allowed. 18 18 */ 19 19 export function snoozeBirthdateUpdateAllowedForDid(did: string) { 20 20 account.set([did, 'birthdateLastUpdatedAt'], new Date().toISOString())
+1 -1
src/state/queries/messages/actor-declaration.ts
··· 52 52 onError: error => { 53 53 logger.error(error) 54 54 if (currentAccount) { 55 - queryClient.invalidateQueries({ 55 + void queryClient.invalidateQueries({ 56 56 queryKey: PROFILE_RKEY(currentAccount.did), 57 57 }) 58 58 }
+80 -83
src/state/session/agent.ts
··· 181 181 // Not awaited so that we can still get into onboarding. 182 182 // This is OK because we won't let you toggle adult stuff until you set the date. 183 183 if (IS_PROD_SERVICE(service)) { 184 - Promise.allSettled( 185 - [ 186 - networkRetry(3, () => { 187 - return agent.setPersonalDetails({ 188 - birthDate: birthdate, 189 - }) 190 - }).catch(e => { 191 - logger.info(`createAgentAndCreateAccount: failed to set birthDate`) 192 - throw e 193 - }), 194 - networkRetry(3, () => { 195 - return agent.upsertProfile(prev => { 196 - const next: Un$Typed<AppBskyActorProfile.Record> = prev || {} 197 - next.displayName = handle 198 - next.createdAt = createdAt 199 - return next 200 - }) 201 - }).catch(e => { 202 - logger.info( 203 - `createAgentAndCreateAccount: failed to set initial profile`, 204 - ) 205 - throw e 206 - }), 207 - networkRetry(1, () => { 208 - return agent.overwriteSavedFeeds([ 209 - { 210 - ...DISCOVER_SAVED_FEED, 211 - id: TID.nextStr(), 212 - }, 213 - { 214 - ...TIMELINE_SAVED_FEED, 215 - id: TID.nextStr(), 216 - }, 217 - ]) 218 - }).catch(e => { 219 - logger.info( 220 - `createAgentAndCreateAccount: failed to set initial feeds`, 221 - ) 222 - throw e 223 - }), 224 - getAge(birthDate) < 18 && 225 - networkRetry(3, () => { 226 - return agent.com.atproto.repo.putRecord({ 227 - repo: account.did, 228 - collection: 'chat.bsky.actor.declaration', 229 - rkey: 'self', 230 - record: { 231 - $type: 'chat.bsky.actor.declaration', 232 - allowIncoming: 'none', 233 - }, 234 - }) 235 - }).catch(e => { 236 - logger.info( 237 - `createAgentAndCreateAccount: failed to set chat declaration`, 238 - ) 239 - throw e 240 - }), 241 - ].filter(Boolean), 242 - ).then(promises => { 184 + void Promise.allSettled([ 185 + networkRetry(3, () => { 186 + return agent.setPersonalDetails({ 187 + birthDate: birthdate, 188 + }) 189 + }).catch(e => { 190 + logger.info(`createAgentAndCreateAccount: failed to set birthDate`) 191 + throw e 192 + }), 193 + networkRetry(3, () => { 194 + return agent.upsertProfile(prev => { 195 + const next: Un$Typed<AppBskyActorProfile.Record> = prev || {} 196 + next.displayName = handle 197 + next.createdAt = createdAt 198 + return next 199 + }) 200 + }).catch(e => { 201 + logger.info( 202 + `createAgentAndCreateAccount: failed to set initial profile`, 203 + ) 204 + throw e 205 + }), 206 + networkRetry(1, () => { 207 + return agent.overwriteSavedFeeds([ 208 + { 209 + ...DISCOVER_SAVED_FEED, 210 + id: TID.nextStr(), 211 + }, 212 + { 213 + ...TIMELINE_SAVED_FEED, 214 + id: TID.nextStr(), 215 + }, 216 + ]) 217 + }).catch(e => { 218 + logger.info(`createAgentAndCreateAccount: failed to set initial feeds`) 219 + throw e 220 + }), 221 + ...(getAge(birthDate) < 18 222 + ? [ 223 + networkRetry(3, () => { 224 + return agent.com.atproto.repo.putRecord({ 225 + repo: account.did, 226 + collection: 'chat.bsky.actor.declaration', 227 + rkey: 'self', 228 + record: { 229 + $type: 'chat.bsky.actor.declaration', 230 + allowIncoming: 'none', 231 + }, 232 + }) 233 + }).catch(e => { 234 + logger.info( 235 + `createAgentAndCreateAccount: failed to set chat declaration`, 236 + ) 237 + throw e 238 + }), 239 + ] 240 + : []), 241 + ]).then(promises => { 243 242 const rejected = promises.filter(p => p.status === 'rejected') 244 243 if (rejected.length > 0) { 245 244 logger.error( ··· 248 247 } 249 248 }) 250 249 } else { 251 - Promise.allSettled( 252 - [ 253 - networkRetry(3, () => { 254 - return agent.setPersonalDetails({ 255 - birthDate: birthDate.toISOString(), 256 - }) 257 - }).catch(e => { 258 - logger.info(`createAgentAndCreateAccount: failed to set birthDate`) 259 - throw e 260 - }), 261 - networkRetry(3, () => { 262 - return agent.upsertProfile(prev => { 263 - const next: Un$Typed<AppBskyActorProfile.Record> = prev || {} 264 - next.createdAt = prev?.createdAt || new Date().toISOString() 265 - return next 266 - }) 267 - }).catch(e => { 268 - logger.info( 269 - `createAgentAndCreateAccount: failed to set initial profile`, 270 - ) 271 - throw e 272 - }), 273 - ].filter(Boolean), 274 - ).then(promises => { 250 + void Promise.allSettled([ 251 + networkRetry(3, () => { 252 + return agent.setPersonalDetails({ 253 + birthDate: birthDate.toISOString(), 254 + }) 255 + }).catch(e => { 256 + logger.info(`createAgentAndCreateAccount: failed to set birthDate`) 257 + throw e 258 + }), 259 + networkRetry(3, () => { 260 + return agent.upsertProfile(prev => { 261 + const next: Un$Typed<AppBskyActorProfile.Record> = prev || {} 262 + next.createdAt = prev?.createdAt || new Date().toISOString() 263 + return next 264 + }) 265 + }).catch(e => { 266 + logger.info( 267 + `createAgentAndCreateAccount: failed to set initial profile`, 268 + ) 269 + throw e 270 + }), 271 + ]).then(promises => { 275 272 const rejected = promises.filter(p => p.status === 'rejected') 276 273 if (rejected.length > 0) { 277 274 logger.error(
+10 -7
src/state/session/index.tsx
··· 8 8 useState, 9 9 useSyncExternalStore, 10 10 } from 'react' 11 - import {type AtpSessionEvent, type BskyAgent} from '@atproto/api' 11 + import {type AtpAgent, type AtpSessionEvent} from '@atproto/api' 12 12 13 13 import * as persisted from '#/state/persisted' 14 14 import {useCloseAllActiveElements} from '#/state/util' ··· 47 47 }) 48 48 StateContext.displayName = 'SessionStateContext' 49 49 50 - const AgentContext = createContext<BskyAgent | null>(null) 50 + const AgentContext = createContext<AtpAgent | null>(null) 51 51 AgentContext.displayName = 'SessionAgentContext' 52 52 53 53 const ApiContext = createContext<SessionApiContext>({ ··· 96 96 ), 97 97 } 98 98 addSessionDebugLog({type: 'persisted:broadcast', data: persistedData}) 99 - persisted.write('session', persistedData) 99 + void persisted.write('session', persistedData) 100 100 } 101 101 this.listeners.forEach(listener => listener()) 102 102 } ··· 105 105 export function Provider({children}: React.PropsWithChildren<{}>) { 106 106 const ax = useAnalyticsBase() 107 107 const cancelPendingTask = useOneTaskAtATime() 108 + // eslint-disable-next-line react/hook-use-state 108 109 const [store] = useState(() => new SessionStore()) 109 110 const state = useSyncExternalStore(store.subscribe, store.getState) 110 111 const onboardingDispatch = useOnboardingDispatch() 111 112 112 113 const onAgentSessionChange = useCallback( 113 - (agent: BskyAgent, accountDid: string, sessionEvent: AtpSessionEvent) => { 114 + (agent: AtpAgent, accountDid: string, sessionEvent: AtpSessionEvent) => { 114 115 const refreshedAccount = agentToSessionAccount(agent) // Mutable, so snapshot it right away. 115 116 if (sessionEvent === 'expired' || sessionEvent === 'create-failed') { 116 117 emitSessionDropped() ··· 327 328 * follower tabs. Follower tabs will therefore receive the fresh 328 329 * session. See APP-1960, or ask Eric. 329 330 */ 330 - resumeSession(syncedAccount) 331 + void resumeSession(syncedAccount) 331 332 } else { 332 - const agent = state.currentAgentState.agent as BskyAgent 333 + const agent = state.currentAgentState.agent as AtpAgent 333 334 const prevSession = agent.session 335 + // eslint-disable-next-line react-compiler/react-compiler 334 336 agent.sessionManager.session = sessionAccountToSession(syncedAccount) 335 337 addSessionDebugLog({ 336 338 type: 'agent:patch', ··· 376 378 ) 377 379 378 380 // @ts-expect-error window type is not declared, debug only 381 + // eslint-disable-next-line react-hooks/immutability 379 382 if (__DEV__ && IS_WEB) window.agent = state.currentAgentState.agent 380 383 381 384 const agent = state.currentAgentState.agent as BskyAppAgent ··· 448 451 ) 449 452 } 450 453 451 - export function useAgent(): BskyAgent { 454 + export function useAgent(): AtpAgent { 452 455 const agent = useContext(AgentContext) 453 456 if (!agent) { 454 457 throw Error('useAgent() must be below <SessionProvider>.')