Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

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

Improve error logging

+212 -188
+5 -1
package.json
··· 14 14 }, 15 15 "dependencies": { 16 16 "@atproto/api": "^0.0.5", 17 + "@atproto/lexicon": "^0.0.2", 18 + "@atproto/xrpc": "^0.0.2", 17 19 "@bam.tech/react-native-image-resizer": "^3.0.4", 18 20 "@fortawesome/fontawesome-svg-core": "^6.1.1", 19 21 "@fortawesome/free-regular-svg-icons": "^6.1.1", ··· 92 94 "./jest/jestSetup.js", 93 95 "./node_modules/react-native-gesture-handler/jestSetup.js" 94 96 ], 95 - "setupFilesAfterEnv": ["@testing-library/jest-native/extend-expect"], 97 + "setupFilesAfterEnv": [ 98 + "@testing-library/jest-native/extend-expect" 99 + ], 96 100 "moduleFileExtensions": [ 97 101 "ts", 98 102 "tsx",
+2 -2
src/state/index.ts
··· 25 25 data = (await storage.load(ROOT_STATE_STORAGE_KEY)) || {} 26 26 rootStore.hydrate(data) 27 27 } catch (e: any) { 28 - rootStore.log.error('Failed to load state from storage', e.toString()) 28 + rootStore.log.error('Failed to load state from storage', e) 29 29 } 30 30 31 31 rootStore.log.debug('Initial hydrate') ··· 36 36 return rootStore.fetchStateUpdate() 37 37 }) 38 38 .catch((e: any) => { 39 - rootStore.log.warn('Failed initial connect', e.toString()) 39 + rootStore.log.warn('Failed initial connect', e) 40 40 }) 41 41 // @ts-ignore .on() is correct -prf 42 42 api.sessionManager.on('session', () => {
+1 -4
src/state/lib/api.ts
··· 126 126 }, 127 127 } as AppBskyEmbedExternal.Main 128 128 } catch (e: any) { 129 - store.log.warn( 130 - `Failed to fetch link meta for ${link.value}`, 131 - e.toString(), 132 - ) 129 + store.log.warn(`Failed to fetch link meta for ${link.value}`, e) 133 130 } 134 131 } 135 132 }
+9 -6
src/state/models/feed-view.ts
··· 320 320 this.error = '' 321 321 } 322 322 323 - private _xIdle(err: string = '') { 323 + private _xIdle(err?: any) { 324 324 this.isLoading = false 325 325 this.isRefreshing = false 326 326 this.hasLoaded = true 327 - this.error = cleanError(err) 327 + this.error = err ? cleanError(err.toString()) : '' 328 + if (err) { 329 + this.rootStore.log.error('Posts feed request failed', err) 330 + } 328 331 } 329 332 330 333 // loader functions ··· 352 355 await this._replaceAll(res) 353 356 this._xIdle() 354 357 } catch (e: any) { 355 - this._xIdle(e.toString()) 358 + this._xIdle(e) 356 359 } 357 360 } 358 361 ··· 363 366 await this._prependAll(res) 364 367 this._xIdle() 365 368 } catch (e: any) { 366 - this._xIdle(e.toString()) 369 + this._xIdle(e) 367 370 } 368 371 } 369 372 ··· 380 383 await this._appendAll(res) 381 384 this._xIdle() 382 385 } catch (e: any) { 383 - this._xIdle(`Failed to load feed: ${e.toString()}`) 386 + this._xIdle(e) 384 387 } 385 388 } 386 389 ··· 408 411 } while (numToFetch > 0) 409 412 this._xIdle() 410 413 } catch (e: any) { 411 - this._xIdle(`Failed to update feed: ${e.toString()}`) 414 + this._xIdle(e) 412 415 } 413 416 } 414 417
+6 -3
src/state/models/get-assertions-view.ts
··· 80 80 this.error = '' 81 81 } 82 82 83 - private _xIdle(err: string = '') { 83 + private _xIdle(err?: any) { 84 84 this.isLoading = false 85 85 this.isRefreshing = false 86 86 this.hasLoaded = true 87 - this.error = err 87 + this.error = err ? err.toString() : '' 88 + if (err) { 89 + this.rootStore.log.error('Failed to fetch assertions', err) 90 + } 88 91 } 89 92 90 93 // loader functions ··· 99 102 this._replaceAll(res) 100 103 this._xIdle() 101 104 } catch (e: any) { 102 - this._xIdle(e.toString()) 105 + this._xIdle(e) 103 106 } 104 107 } 105 108
+28 -11
src/state/models/log.ts
··· 1 1 import {makeAutoObservable} from 'mobx' 2 + import {XRPCError, XRPCInvalidResponseError} from '@atproto/xrpc' 2 3 import {isObj, hasProp} from '../lib/type-guards' 3 4 4 5 interface LogEntry { ··· 51 52 } 52 53 53 54 debug(summary: string, details?: any) { 54 - if (details && typeof details !== 'string') { 55 - details = JSON.stringify(details, null, 2) 56 - } 55 + details = detailsToStr(details) 57 56 console.debug(summary, details || '') 58 57 this.add({ 59 58 id: genId(), ··· 65 64 } 66 65 67 66 warn(summary: string, details?: any) { 68 - if (details && typeof details !== 'string') { 69 - details = JSON.stringify(details, null, 2) 70 - } 71 - console.warn(summary, details || '') 67 + details = detailsToStr(details) 68 + console.debug(summary, details || '') 72 69 this.add({ 73 70 id: genId(), 74 71 type: 'warn', ··· 79 76 } 80 77 81 78 error(summary: string, details?: any) { 82 - if (details && typeof details !== 'string') { 83 - details = JSON.stringify(details, null, 2) 84 - } 85 - console.error(summary, details || '') 79 + details = detailsToStr(details) 80 + console.debug(summary, details || '') 86 81 this.add({ 87 82 id: genId(), 88 83 type: 'error', ··· 92 87 }) 93 88 } 94 89 } 90 + 91 + function detailsToStr(details?: any) { 92 + if (details && typeof details !== 'string') { 93 + if ( 94 + details instanceof XRPCInvalidResponseError || 95 + details.constructor.name === 'XRPCInvalidResponseError' 96 + ) { 97 + return `The server gave an ill-formatted response.\nMethod: ${ 98 + details.lexiconNsid 99 + }.\nError: ${details.validationError.toString()}` 100 + } else if ( 101 + details instanceof XRPCError || 102 + details.constructor.name === 'XRPCError' 103 + ) { 104 + return `An XRPC error occurred.\nStatus: ${details.status}\nError: ${details.error}\nMessage: ${details.message}` 105 + } else if (details instanceof Error) { 106 + return details.toString() 107 + } 108 + return JSON.stringify(details, null, 2) 109 + } 110 + return details 111 + }
+3 -12
src/state/models/me.ts
··· 104 104 }) 105 105 await Promise.all([ 106 106 this.memberships?.setup().catch(e => { 107 - this.rootStore.log.error( 108 - 'Failed to setup memberships model', 109 - e.toString(), 110 - ) 107 + this.rootStore.log.error('Failed to setup memberships model', e) 111 108 }), 112 109 this.mainFeed.setup().catch(e => { 113 - this.rootStore.log.error( 114 - 'Failed to setup main feed model', 115 - e.toString(), 116 - ) 110 + this.rootStore.log.error('Failed to setup main feed model', e) 117 111 }), 118 112 this.notifications.setup().catch(e => { 119 - this.rootStore.log.error( 120 - 'Failed to setup notifications model', 121 - e.toString(), 122 - ) 113 + this.rootStore.log.error('Failed to setup notifications model', e) 123 114 }), 124 115 ]) 125 116 } else {
+6 -3
src/state/models/members-view.ts
··· 104 104 this.error = '' 105 105 } 106 106 107 - private _xIdle(err: string = '') { 107 + private _xIdle(err?: any) { 108 108 this.isLoading = false 109 109 this.isRefreshing = false 110 110 this.hasLoaded = true 111 - this.error = err 111 + this.error = err ? err.toString() : '' 112 + if (err) { 113 + this.rootStore.log.error('Failed to fetch members', err) 114 + } 112 115 } 113 116 114 117 // loader functions ··· 123 126 this._replaceAll(res) 124 127 this._xIdle() 125 128 } catch (e: any) { 126 - this._xIdle(`Failed to load feed: ${e.toString()}`) 129 + this._xIdle(e) 127 130 } 128 131 } 129 132
+6 -3
src/state/models/memberships-view.ts
··· 82 82 this.error = '' 83 83 } 84 84 85 - private _xIdle(err: string = '') { 85 + private _xIdle(err?: any) { 86 86 this.isLoading = false 87 87 this.isRefreshing = false 88 88 this.hasLoaded = true 89 - this.error = err 89 + this.error = err ? err.toString() : '' 90 + if (err) { 91 + this.rootStore.log.error('Failed to fetch memberships', err) 92 + } 90 93 } 91 94 92 95 // loader functions ··· 101 104 this._replaceAll(res) 102 105 this._xIdle() 103 106 } catch (e: any) { 104 - this._xIdle(`Failed to load feed: ${e.toString()}`) 107 + this._xIdle(e) 105 108 } 106 109 } 107 110
+11 -10
src/state/models/notifications-view.ts
··· 151 151 await this.additionalPost.setup().catch(e => { 152 152 this.rootStore.log.error( 153 153 'Failed to load post needed by notification', 154 - e.toString(), 154 + e, 155 155 ) 156 156 }) 157 157 } ··· 266 266 }) 267 267 this.rootStore.me.clearNotificationCount() 268 268 } catch (e: any) { 269 - this.rootStore.log.warn( 270 - 'Failed to update notifications read state', 271 - e.toString(), 272 - ) 269 + this.rootStore.log.warn('Failed to update notifications read state', e) 273 270 } 274 271 } 275 272 ··· 282 279 this.error = '' 283 280 } 284 281 285 - private _xIdle(err: string = '') { 282 + private _xIdle(err?: any) { 286 283 this.isLoading = false 287 284 this.isRefreshing = false 288 285 this.hasLoaded = true 289 286 this.error = cleanError(err) 287 + this.error = err ? cleanError(err) : '' 288 + if (err) { 289 + this.rootStore.log.error('Failed to fetch notifications', err) 290 + } 290 291 } 291 292 292 293 // loader functions ··· 314 315 await this._replaceAll(res) 315 316 this._xIdle() 316 317 } catch (e: any) { 317 - this._xIdle(`Failed to load notifications: ${e.toString()}`) 318 + this._xIdle(e) 318 319 } 319 320 } 320 321 ··· 332 333 await this._appendAll(res) 333 334 this._xIdle() 334 335 } catch (e: any) { 335 - this._xIdle(`Failed to load notifications: ${e.toString()}`) 336 + this._xIdle(e) 336 337 } 337 338 } 338 339 ··· 359 360 } while (numToFetch > 0) 360 361 this._xIdle() 361 362 } catch (e: any) { 362 - this._xIdle(`Failed to update notifications: ${e.toString()}`) 363 + this._xIdle(e) 363 364 } 364 365 } 365 366 ··· 386 387 await Promise.all(promises).catch(e => { 387 388 this.rootStore.log.error( 388 389 'Uncaught failure during notifications-view _appendAll()', 389 - e.toString(), 390 + e, 390 391 ) 391 392 }) 392 393 runInAction(() => {
+4 -1
src/state/models/post-thread-view.ts
··· 236 236 this.notFound = false 237 237 } 238 238 239 - private _xIdle(err: any = undefined) { 239 + private _xIdle(err?: any) { 240 240 this.isLoading = false 241 241 this.isRefreshing = false 242 242 this.hasLoaded = true 243 243 this.error = err ? err.toString() : '' 244 + if (err) { 245 + this.rootStore.log.error('Failed to fetch assertions', err) 246 + } 244 247 this.notFound = err instanceof GetPostThread.NotFoundError 245 248 } 246 249
+6 -2
src/state/models/post.ts
··· 63 63 this.error = '' 64 64 } 65 65 66 - private _xIdle(err: string = '') { 66 + private _xIdle(err?: any) { 67 67 this.isLoading = false 68 68 this.hasLoaded = true 69 69 this.error = cleanError(err) 70 + this.error = err ? cleanError(err) : '' 71 + if (err) { 72 + this.rootStore.log.error('Failed to fetch post', err) 73 + } 70 74 } 71 75 72 76 // loader functions ··· 87 91 this._replaceAll(res.value) 88 92 this._xIdle() 89 93 } catch (e: any) { 90 - this._xIdle(e.toString()) 94 + this._xIdle(e) 91 95 } 92 96 } 93 97
+4 -12
src/state/models/profile-ui.ts
··· 114 114 await Promise.all([ 115 115 this.profile 116 116 .setup() 117 - .catch(err => 118 - this.rootStore.log.error('Failed to fetch profile', err.toString()), 119 - ), 117 + .catch(err => this.rootStore.log.error('Failed to fetch profile', err)), 120 118 this.feed 121 119 .setup() 122 - .catch(err => 123 - this.rootStore.log.error('Failed to fetch feed', err.toString()), 124 - ), 120 + .catch(err => this.rootStore.log.error('Failed to fetch feed', err)), 125 121 ]) 126 122 if (this.isUser) { 127 123 await this.memberships 128 124 .setup() 129 - .catch(err => 130 - this.rootStore.log.error('Failed to fetch members', err.toString()), 131 - ) 125 + .catch(err => this.rootStore.log.error('Failed to fetch members', err)) 132 126 } 133 127 if (this.isScene) { 134 128 await this.members 135 129 .setup() 136 - .catch(err => 137 - this.rootStore.log.error('Failed to fetch members', err.toString()), 138 - ) 130 + .catch(err => this.rootStore.log.error('Failed to fetch members', err)) 139 131 } 140 132 } 141 133
+6 -3
src/state/models/profile-view.ts
··· 178 178 this.error = '' 179 179 } 180 180 181 - private _xIdle(err: string = '') { 181 + private _xIdle(err?: any) { 182 182 this.isLoading = false 183 183 this.isRefreshing = false 184 184 this.hasLoaded = true 185 - this.error = err 185 + this.error = err ? err.toString() : '' 186 + if (err) { 187 + this.rootStore.log.error('Failed to fetch profile', err) 188 + } 186 189 } 187 190 188 191 // loader functions ··· 198 201 this._replaceAll(res) 199 202 this._xIdle() 200 203 } catch (e: any) { 201 - this._xIdle(e.toString()) 204 + this._xIdle(e) 202 205 } 203 206 } 204 207
+6 -3
src/state/models/reposted-by-view.ts
··· 94 94 this.error = '' 95 95 } 96 96 97 - private _xIdle(err: string = '') { 97 + private _xIdle(err?: any) { 98 98 this.isLoading = false 99 99 this.isRefreshing = false 100 100 this.hasLoaded = true 101 - this.error = err 101 + this.error = err ? err.toString() : '' 102 + if (err) { 103 + this.rootStore.log.error('Failed to fetch reposted by view', err) 104 + } 102 105 } 103 106 104 107 // loader functions ··· 127 130 this._replaceAll(res) 128 131 this._xIdle() 129 132 } catch (e: any) { 130 - this._xIdle(`Failed to load feed: ${e.toString()}`) 133 + this._xIdle(e) 131 134 } 132 135 } 133 136
+1 -1
src/state/models/root-store.ts
··· 59 59 if (isNetworkError(e)) { 60 60 this.session.setOnline(false) // connection lost 61 61 } 62 - this.log.error('Failed to fetch latest state', e.toString()) 62 + this.log.error('Failed to fetch latest state', e) 63 63 } 64 64 } 65 65
+4 -13
src/state/models/session.ts
··· 124 124 } catch (e: any) { 125 125 this.rootStore.log.error( 126 126 `Invalid service URL: ${this.data.service}. Resetting session.`, 127 - e.toString(), 127 + e, 128 128 ) 129 129 this.clear() 130 130 return false ··· 160 160 this.rootStore.me.clear() 161 161 } 162 162 this.rootStore.me.load().catch(e => { 163 - this.rootStore.log.error( 164 - 'Failed to fetch local user information', 165 - e.toString(), 166 - ) 163 + this.rootStore.log.error('Failed to fetch local user information', e) 167 164 }) 168 165 return // success 169 166 } ··· 207 204 this.configureApi() 208 205 this.setOnline(true, false) 209 206 this.rootStore.me.load().catch(e => { 210 - this.rootStore.log.error( 211 - 'Failed to fetch local user information', 212 - e.toString(), 213 - ) 207 + this.rootStore.log.error('Failed to fetch local user information', e) 214 208 }) 215 209 } 216 210 } ··· 246 240 this.rootStore.onboard.start() 247 241 this.configureApi() 248 242 this.rootStore.me.load().catch(e => { 249 - this.rootStore.log.error( 250 - 'Failed to fetch local user information', 251 - e.toString(), 252 - ) 243 + this.rootStore.log.error('Failed to fetch local user information', e) 253 244 }) 254 245 } 255 246 }
+6 -3
src/state/models/suggested-actors-view.ts
··· 58 58 this.error = '' 59 59 } 60 60 61 - private _xIdle(err: string = '') { 61 + private _xIdle(err?: any) { 62 62 this.isLoading = false 63 63 this.isRefreshing = false 64 64 this.hasLoaded = true 65 - this.error = err 65 + this.error = err ? err.toString() : '' 66 + if (err) { 67 + this.rootStore.log.error('Failed to fetch suggested actors', err) 68 + } 66 69 } 67 70 68 71 // loader functions ··· 88 91 ) 89 92 this._xIdle() 90 93 } catch (e: any) { 91 - this._xIdle(e.toString()) 94 + this._xIdle(e) 92 95 } 93 96 } 94 97
+7 -4
src/state/models/suggested-invites-view.ts
··· 83 83 this.error = '' 84 84 } 85 85 86 - private _xIdle(err: string = '') { 86 + private _xIdle(err?: any) { 87 87 this.isLoading = false 88 88 this.isRefreshing = false 89 89 this.hasLoaded = true 90 - this.error = err 90 + this.error = err ? err.toString() : '' 91 + if (err) { 92 + this.rootStore.log.error('Failed to fetch suggested invites', err) 93 + } 91 94 } 92 95 93 96 // loader functions ··· 101 104 } catch (e: any) { 102 105 this.rootStore.log.error( 103 106 'Failed to fetch current scene members in suggested invites', 104 - e.toString(), 107 + e, 105 108 ) 106 109 this._xIdle( 107 110 'Failed to fetch the current scene members. Check your internet connection and try again.', ··· 113 116 } catch (e: any) { 114 117 this.rootStore.log.error( 115 118 'Failed to fetch current followers in suggested invites', 116 - e.toString(), 119 + e, 117 120 ) 118 121 this._xIdle( 119 122 'Failed to fetch the your current followers. Check your internet connection and try again.',
+5 -2
src/state/models/user-followers-view.ts
··· 76 76 this.error = '' 77 77 } 78 78 79 - private _xIdle(err: string = '') { 79 + private _xIdle(err?: any) { 80 80 this.isLoading = false 81 81 this.isRefreshing = false 82 82 this.hasLoaded = true 83 - this.error = err 83 + this.error = err ? err.toString() : '' 84 + if (err) { 85 + this.rootStore.log.error('Failed to fetch user followers', err) 86 + } 84 87 } 85 88 86 89 // loader functions
+5 -2
src/state/models/user-follows-view.ts
··· 76 76 this.error = '' 77 77 } 78 78 79 - private _xIdle(err: string = '') { 79 + private _xIdle(err?: any) { 80 80 this.isLoading = false 81 81 this.isRefreshing = false 82 82 this.hasLoaded = true 83 - this.error = err 83 + this.error = err ? err.toString() : '' 84 + if (err) { 85 + this.rootStore.log.error('Failed to fetch user follows', err) 86 + } 84 87 } 85 88 86 89 // loader functions
+6 -3
src/state/models/votes-view.ts
··· 91 91 this.error = '' 92 92 } 93 93 94 - private _xIdle(err: string = '') { 94 + private _xIdle(err?: any) { 95 95 this.isLoading = false 96 96 this.isRefreshing = false 97 97 this.hasLoaded = true 98 - this.error = err 98 + this.error = err ? err.toString() : '' 99 + if (err) { 100 + this.rootStore.log.error('Failed to fetch votes', err) 101 + } 99 102 } 100 103 101 104 // loader functions ··· 124 127 this._replaceAll(res) 125 128 this._xIdle() 126 129 } catch (e: any) { 127 - this._xIdle(`Failed to load feed: ${e.toString()}`) 130 + this._xIdle(e) 128 131 } 129 132 } 130 133
+2 -2
src/view/com/composer/PhotoCarouselPicker.tsx
··· 40 40 onSelectPhotos([uri, ...selectedPhotos]) 41 41 } catch (err: any) { 42 42 // ignore 43 - store.log.warn('Error using camera', err.toString()) 43 + store.log.warn('Error using camera', err) 44 44 } 45 45 }, [store.log, selectedPhotos, onSelectPhotos]) 46 46 ··· 56 56 onSelectPhotos([finalUri, ...selectedPhotos]) 57 57 } catch (err: any) { 58 58 // ignore 59 - store.log.warn('Error selecting photo', err.toString()) 59 + store.log.warn('Error selecting photo', err) 60 60 } 61 61 }, 62 62 [store.log, selectedPhotos, onSelectPhotos],
+4 -4
src/view/com/discover/SuggestedFollows.tsx
··· 45 45 view 46 46 .setup() 47 47 .catch((err: any) => 48 - store.log.error('Failed to fetch suggestions', err.toString()), 48 + store.log.error('Failed to fetch suggestions', err), 49 49 ) 50 50 }, [view, store.log]) 51 51 ··· 59 59 view 60 60 .setup() 61 61 .catch((err: any) => 62 - store.log.error('Failed to fetch suggestions', err.toString()), 62 + store.log.error('Failed to fetch suggestions', err), 63 63 ) 64 64 65 65 const onPressFollow = async (item: SuggestedActor) => { ··· 67 67 const res = await apilib.follow(store, item.did, item.declaration.cid) 68 68 setFollows({[item.did]: res.uri, ...follows}) 69 69 } catch (e: any) { 70 - store.log.error('Failed fo create follow', {error: e.toString(), item}) 70 + store.log.error('Failed fo create follow', e) 71 71 Toast.show('An issue occurred, please try again.') 72 72 } 73 73 } ··· 76 76 await apilib.unfollow(store, follows[item.did]) 77 77 setFollows(_omit(follows, [item.did])) 78 78 } catch (e: any) { 79 - store.log.error('Failed fo delete follow', {error: e.toString(), item}) 79 + store.log.error('Failed fo delete follow', e) 80 80 Toast.show('An issue occurred, please try again.') 81 81 } 82 82 }
+2 -2
src/view/com/login/CreateAccount.tsx
··· 54 54 if (aborted) return 55 55 store.log.warn( 56 56 `Failed to fetch service description for ${serviceUrl}`, 57 - err.toString(), 57 + err, 58 58 ) 59 59 setError( 60 60 'Unable to contact your service. Please check your Internet connection.', ··· 100 100 errMsg = 101 101 'Invite code not accepted. Check that you input it correctly and try again.' 102 102 } 103 - store.log.warn('Failed to create account', e.toString()) 103 + store.log.error('Failed to create account', e) 104 104 setIsProcessing(false) 105 105 setError(errMsg.replace(/^Error:/, '')) 106 106 }
+4 -4
src/view/com/login/Signin.tsx
··· 53 53 if (aborted) return 54 54 store.log.warn( 55 55 `Failed to fetch service description for ${serviceUrl}`, 56 - err.toString(), 56 + err, 57 57 ) 58 58 setError( 59 59 'Unable to contact your service. Please check your Internet connection.', ··· 171 171 }) 172 172 } catch (e: any) { 173 173 const errMsg = e.toString() 174 - store.log.warn('Failed to login', e.toString()) 174 + store.log.warn('Failed to login', e) 175 175 setIsProcessing(false) 176 176 if (errMsg.includes('Authentication Required')) { 177 177 setError('Invalid username or password') ··· 307 307 onEmailSent() 308 308 } catch (e: any) { 309 309 const errMsg = e.toString() 310 - store.log.warn('Failed to request password reset', e.toString()) 310 + store.log.warn('Failed to request password reset', e) 311 311 setIsProcessing(false) 312 312 if (isNetworkError(e)) { 313 313 setError( ··· 419 419 onPasswordSet() 420 420 } catch (e: any) { 421 421 const errMsg = e.toString() 422 - store.log.warn('Failed to set new password', e.toString()) 422 + store.log.warn('Failed to set new password', e) 423 423 setIsProcessing(false) 424 424 if (isNetworkError(e)) { 425 425 setError(
+3 -9
src/view/com/modals/CreateScene.tsx
··· 57 57 }) 58 58 .catch(e => 59 59 // an error here is not critical 60 - store.log.error( 61 - 'Failed to update scene profile during creation', 62 - e.toString(), 63 - ), 60 + store.log.error('Failed to update scene profile during creation', e), 64 61 ) 65 62 // follow the scene 66 63 await store.api.app.bsky.graph.follow ··· 78 75 ) 79 76 .catch(e => 80 77 // an error here is not critical 81 - store.log.error( 82 - 'Failed to follow scene after creation', 83 - e.toString(), 84 - ), 78 + store.log.error('Failed to follow scene after creation', e), 85 79 ) 86 80 Toast.show('Scene created') 87 81 store.shell.closeModal() ··· 94 88 } else if (e instanceof AppBskyActorCreateScene.HandleNotAvailableError) { 95 89 setError(`The handle "${handle}" is not available.`) 96 90 } else { 97 - store.log.error('Failed to create scene', e.toString()) 91 + store.log.error('Failed to create scene', e) 98 92 setError( 99 93 'Failed to create the scene. Check your internet connection and try again.', 100 94 )
+3 -3
src/view/com/modals/InviteToScene.tsx
··· 86 86 Toast.show('Invite sent') 87 87 } catch (e: any) { 88 88 setError('There was an issue with the invite. Please try again.') 89 - store.log.error('Failed to invite user to scene', e.toString()) 89 + store.log.error('Failed to invite user to scene', e) 90 90 } 91 91 } 92 92 const onPressUndo = async (subjectDid: string, assertionUri: string) => { ··· 100 100 setCreatedInvites(_omit(createdInvites, [subjectDid])) 101 101 } catch (e: any) { 102 102 setError('There was an issue with the invite. Please try again.') 103 - store.log.error('Failed to delete a scene invite', e.toString()) 103 + store.log.error('Failed to delete a scene invite', e) 104 104 } 105 105 } 106 106 ··· 119 119 Toast.show('Invite removed') 120 120 } catch (e: any) { 121 121 setError('There was an issue with the invite. Please try again.') 122 - store.log.error('Failed to delete an invite', e.toString()) 122 + store.log.error('Failed to delete an invite', e) 123 123 } 124 124 } 125 125
+2 -8
src/view/com/notifications/Feed.tsx
··· 39 39 view 40 40 .refresh() 41 41 .catch(err => 42 - view.rootStore.log.error( 43 - 'Failed to refresh notifications feed', 44 - err.toString(), 45 - ), 42 + view.rootStore.log.error('Failed to refresh notifications feed', err), 46 43 ) 47 44 } 48 45 const onEndReached = () => { 49 46 view 50 47 .loadMore() 51 48 .catch(err => 52 - view.rootStore.log.error( 53 - 'Failed to load more notifications', 54 - err.toString(), 55 - ), 49 + view.rootStore.log.error('Failed to load more notifications', err), 56 50 ) 57 51 } 58 52 let data
+1 -3
src/view/com/post-thread/PostRepostedBy.tsx
··· 28 28 setView(newView) 29 29 newView 30 30 .setup() 31 - .catch(err => 32 - store.log.error('Failed to fetch reposted by', err.toString()), 33 - ) 31 + .catch(err => store.log.error('Failed to fetch reposted by', err)) 34 32 }, [uri, view?.params.uri, store]) 35 33 36 34 const onRefresh = () => {
+1 -4
src/view/com/post-thread/PostThread.tsx
··· 21 21 view 22 22 ?.refresh() 23 23 .catch(err => 24 - view.rootStore.log.error( 25 - 'Failed to refresh posts thread', 26 - err.toString(), 27 - ), 24 + view.rootStore.log.error('Failed to refresh posts thread', err), 28 25 ) 29 26 } 30 27 const onLayout = () => {
+3 -3
src/view/com/post-thread/PostThreadItem.tsx
··· 72 72 const onPressToggleRepost = () => { 73 73 item 74 74 .toggleRepost() 75 - .catch(e => store.log.error('Failed to toggle repost', e.toString())) 75 + .catch(e => store.log.error('Failed to toggle repost', e)) 76 76 } 77 77 const onPressToggleUpvote = () => { 78 78 item 79 79 .toggleUpvote() 80 - .catch(e => store.log.error('Failed to toggle upvote', e.toString())) 80 + .catch(e => store.log.error('Failed to toggle upvote', e)) 81 81 } 82 82 const onCopyPostText = () => { 83 83 Clipboard.setString(record.text) ··· 90 90 Toast.show('Post deleted') 91 91 }, 92 92 e => { 93 - store.log.error('Failed to delete post', e.toString()) 93 + store.log.error('Failed to delete post', e) 94 94 Toast.show('Failed to delete post, please try again') 95 95 }, 96 96 )
+1 -1
src/view/com/post-thread/PostVotedBy.tsx
··· 30 30 setView(newView) 31 31 newView 32 32 .setup() 33 - .catch(err => store.log.error('Failed to fetch voted by', err.toString())) 33 + .catch(err => store.log.error('Failed to fetch voted by', err)) 34 34 }, [uri, view?.params.uri, store]) 35 35 36 36 const onRefresh = () => {
+4 -6
src/view/com/post/Post.tsx
··· 47 47 } 48 48 const newView = new PostThreadViewModel(store, {uri, depth: 0}) 49 49 setView(newView) 50 - newView 51 - .setup() 52 - .catch(err => store.log.error('Failed to fetch post', err.toString())) 50 + newView.setup().catch(err => store.log.error('Failed to fetch post', err)) 53 51 }, [initView, uri, view?.params.uri, store]) 54 52 55 53 // deleted ··· 112 110 const onPressToggleRepost = () => { 113 111 item 114 112 .toggleRepost() 115 - .catch(e => store.log.error('Failed to toggle repost', e.toString())) 113 + .catch(e => store.log.error('Failed to toggle repost', e)) 116 114 } 117 115 const onPressToggleUpvote = () => { 118 116 item 119 117 .toggleUpvote() 120 - .catch(e => store.log.error('Failed to toggle upvote', e.toString())) 118 + .catch(e => store.log.error('Failed to toggle upvote', e)) 121 119 } 122 120 const onCopyPostText = () => { 123 121 Clipboard.setString(record.text) ··· 130 128 Toast.show('Post deleted') 131 129 }, 132 130 e => { 133 - store.log.error('Failed to delete post', e.toString()) 131 + store.log.error('Failed to delete post', e) 134 132 Toast.show('Failed to delete post, please try again') 135 133 }, 136 134 )
+1 -3
src/view/com/post/PostText.tsx
··· 23 23 } 24 24 const newModel = new PostModel(store, uri) 25 25 setModel(newModel) 26 - newModel 27 - .setup() 28 - .catch(err => store.log.error('Failed to fetch post', err.toString())) 26 + newModel.setup().catch(err => store.log.error('Failed to fetch post', err)) 29 27 }, [uri, model?.uri, store]) 30 28 31 29 // loading
+2 -7
src/view/com/posts/Feed.tsx
··· 56 56 feed 57 57 .refresh() 58 58 .catch(err => 59 - feed.rootStore.log.error( 60 - 'Failed to refresh posts feed', 61 - err.toString(), 62 - ), 59 + feed.rootStore.log.error('Failed to refresh posts feed', err), 63 60 ) 64 61 } 65 62 const onEndReached = () => { 66 63 feed 67 64 .loadMore() 68 - .catch(err => 69 - feed.rootStore.log.error('Failed to load more posts', err.toString()), 70 - ) 65 + .catch(err => feed.rootStore.log.error('Failed to load more posts', err)) 71 66 } 72 67 let data 73 68 if (feed.hasLoaded) {
+3 -3
src/view/com/posts/FeedItem.tsx
··· 69 69 const onPressToggleRepost = () => { 70 70 item 71 71 .toggleRepost() 72 - .catch(e => store.log.error('Failed to toggle repost', e.toString())) 72 + .catch(e => store.log.error('Failed to toggle repost', e)) 73 73 } 74 74 const onPressToggleUpvote = () => { 75 75 item 76 76 .toggleUpvote() 77 - .catch(e => store.log.error('Failed to toggle upvote', e.toString())) 77 + .catch(e => store.log.error('Failed to toggle upvote', e)) 78 78 } 79 79 const onCopyPostText = () => { 80 80 Clipboard.setString(record.text) ··· 87 87 Toast.show('Post deleted') 88 88 }, 89 89 e => { 90 - store.log.error('Failed to delete post', e.toString()) 90 + store.log.error('Failed to delete post', e) 91 91 Toast.show('Failed to delete post, please try again') 92 92 }, 93 93 )
+1 -3
src/view/com/profile/ProfileFollowers.tsx
··· 29 29 setView(newView) 30 30 newView 31 31 .setup() 32 - .catch(err => 33 - store.log.error('Failed to fetch user followers', err.toString()), 34 - ) 32 + .catch(err => store.log.error('Failed to fetch user followers', err)) 35 33 }, [name, view?.params.user, store]) 36 34 37 35 const onRefresh = () => {
+1 -3
src/view/com/profile/ProfileFollows.tsx
··· 29 29 setView(newView) 30 30 newView 31 31 .setup() 32 - .catch(err => 33 - store.log.error('Failed to fetch user follows', err.toString()), 34 - ) 32 + .catch(err => store.log.error('Failed to fetch user follows', err)) 35 33 }, [name, view?.params.user, store]) 36 34 37 35 const onRefresh = () => {
+3 -3
src/view/com/profile/ProfileHeader.tsx
··· 52 52 }`, 53 53 ) 54 54 }, 55 - err => store.log.error('Failed to toggle follow', err.toString()), 55 + err => store.log.error('Failed to toggle follow', err), 56 56 ) 57 57 } 58 58 const onPressEditProfile = () => { ··· 94 94 await view.muteAccount() 95 95 Toast.show('Account muted') 96 96 } catch (e: any) { 97 - store.log.error('Failed to mute account', e.toString()) 97 + store.log.error('Failed to mute account', e) 98 98 Toast.show(`There was an issue! ${e.toString()}`) 99 99 } 100 100 } ··· 103 103 await view.unmuteAccount() 104 104 Toast.show('Account unmuted') 105 105 } catch (e: any) { 106 - store.log.error('Failed to unmute account', e.toString()) 106 + store.log.error('Failed to unmute account', e) 107 107 Toast.show(`There was an issue! ${e.toString()}`) 108 108 } 109 109 }
+1 -1
src/view/com/profile/ProfileMembers.tsx
··· 22 22 setView(newView) 23 23 newView 24 24 .setup() 25 - .catch(err => store.log.error('Failed to fetch members', err.toString())) 25 + .catch(err => store.log.error('Failed to fetch members', err)) 26 26 }, [name, view?.params.actor, store]) 27 27 28 28 const onRefresh = () => {
+1
src/view/lib/ThemeContext.tsx
··· 41 41 | 'caption' 42 42 | 'overline1' 43 43 | 'overline2' 44 + | 'mono1' 44 45 export type Typography = Record<TypographyVariant, TextStyle> 45 46 46 47 export interface Theme {
+5
src/view/lib/themes.ts
··· 1 + import {Platform} from 'react-native' 1 2 import type {Theme} from './ThemeContext' 2 3 import {colors} from './styles' 3 4 ··· 135 136 overline2: { 136 137 fontSize: 14, 137 138 fontWeight: '600', 139 + }, 140 + mono1: { 141 + fontSize: 14, 142 + fontFamily: Platform.OS === 'android' ? 'monospace' : 'Courier New', 138 143 }, 139 144 }, 140 145 }
+1 -1
src/view/screens/Home.tsx
··· 37 37 } 38 38 store.log.debug('Polling home feed') 39 39 store.me.mainFeed.checkForLatest().catch(e => { 40 - store.log.error('Failed to poll feed', e.toString()) 40 + store.log.error('Failed to poll feed', e) 41 41 }) 42 42 } 43 43
+6 -4
src/view/screens/Log.tsx
··· 65 65 </Text> 66 66 </TouchableOpacity> 67 67 {expanded.includes(entry.id) ? ( 68 - <View style={[pal.btn, styles.details]}> 69 - <Text type="body1" style={pal.text}> 70 - {entry.details} 71 - </Text> 68 + <View style={[pal.view, s.pl10, s.pr10, s.pb10]}> 69 + <View style={[pal.btn, styles.details]}> 70 + <Text type="mono1" style={pal.text}> 71 + {entry.details} 72 + </Text> 73 + </View> 72 74 </View> 73 75 ) : undefined} 74 76 </View>
+1 -1
src/view/screens/Notifications.tsx
··· 19 19 store.me.notifications 20 20 .update() 21 21 .catch(e => { 22 - store.log.error('Error while updating notifications feed', e.toString()) 22 + store.log.error('Error while updating notifications feed', e) 23 23 }) 24 24 .then(() => { 25 25 store.me.notifications.updateReadState()
+1 -1
src/view/screens/PostThread.tsx
··· 38 38 } 39 39 }, 40 40 err => { 41 - store.log.error('Failed to fetch thread', err.toString()) 41 + store.log.error('Failed to fetch thread', err) 42 42 }, 43 43 ) 44 44 }
+2 -5
src/view/screens/Profile.tsx
··· 63 63 uiState 64 64 .refresh() 65 65 .catch((err: any) => 66 - store.log.error('Failed to refresh user profile', err.toString()), 66 + store.log.error('Failed to refresh user profile', err), 67 67 ) 68 68 } 69 69 const onEndReached = () => { 70 70 uiState 71 71 .loadMore() 72 72 .catch((err: any) => 73 - store.log.error( 74 - 'Failed to load more entries in user profile', 75 - err.toString(), 76 - ), 73 + store.log.error('Failed to load more entries in user profile', err), 77 74 ) 78 75 } 79 76 const onPressTryAgain = () => {
+16
yarn.lock
··· 35 35 "@atproto/nsid" "*" 36 36 zod "^3.14.2" 37 37 38 + "@atproto/lexicon@^0.0.2": 39 + version "0.0.2" 40 + resolved "https://registry.yarnpkg.com/@atproto/lexicon/-/lexicon-0.0.2.tgz#9fc2fd573d8507a6186494d939824a422a8e18b6" 41 + integrity sha512-lWxXGW/EPU2dXqlM+UoNdJfVpQ3bQ57TCmurqb/wFj1IjrWKdZbMqnQfwf3bzQ+UzVt+ZTKGxsJkw1vvk7/gmA== 42 + dependencies: 43 + "@atproto/nsid" "*" 44 + zod "^3.14.2" 45 + 38 46 "@atproto/nsid@*": 39 47 version "0.0.1" 40 48 resolved "https://registry.yarnpkg.com/@atproto/nsid/-/nsid-0.0.1.tgz#0cdc00cefe8f0b1385f352b9f57b3ad37fff09a4" ··· 44 52 version "0.0.1" 45 53 resolved "https://registry.yarnpkg.com/@atproto/xrpc/-/xrpc-0.0.1.tgz#451918148dfea534577e8da620aea739173fd187" 46 54 integrity sha512-l4FrsQ0TGdOU8CbwwA/OY2n0Hvi54fJEfi3zkmr86mwYn2/M2dB1DpQaZhONOIdVVouPZSgW6pCH7ApEXW4dKw== 55 + dependencies: 56 + "@atproto/lexicon" "*" 57 + zod "^3.14.2" 58 + 59 + "@atproto/xrpc@^0.0.2": 60 + version "0.0.2" 61 + resolved "https://registry.yarnpkg.com/@atproto/xrpc/-/xrpc-0.0.2.tgz#d76defd91fd4e2b806bee5e2dfaa42c849275e49" 62 + integrity sha512-/v4/WlxczDJOh+/M4UzWVgYjJ9DzbIZxGTTWxzvKHz4dvJKnO1ZTXtXIqXjAI9kPEh5BDm9cpQ6ik6M1k9YLZg== 47 63 dependencies: 48 64 "@atproto/lexicon" "*" 49 65 zod "^3.14.2"