Improve error logging

zio/stable
Paul Frazee 2023-01-02 21:39:15 -06:00
parent 6885fb2b41
commit 4eabc2d65a
49 changed files with 212 additions and 188 deletions

View File

@ -14,6 +14,8 @@
}, },
"dependencies": { "dependencies": {
"@atproto/api": "^0.0.5", "@atproto/api": "^0.0.5",
"@atproto/lexicon": "^0.0.2",
"@atproto/xrpc": "^0.0.2",
"@bam.tech/react-native-image-resizer": "^3.0.4", "@bam.tech/react-native-image-resizer": "^3.0.4",
"@fortawesome/fontawesome-svg-core": "^6.1.1", "@fortawesome/fontawesome-svg-core": "^6.1.1",
"@fortawesome/free-regular-svg-icons": "^6.1.1", "@fortawesome/free-regular-svg-icons": "^6.1.1",
@ -92,7 +94,9 @@
"./jest/jestSetup.js", "./jest/jestSetup.js",
"./node_modules/react-native-gesture-handler/jestSetup.js" "./node_modules/react-native-gesture-handler/jestSetup.js"
], ],
"setupFilesAfterEnv": ["@testing-library/jest-native/extend-expect"], "setupFilesAfterEnv": [
"@testing-library/jest-native/extend-expect"
],
"moduleFileExtensions": [ "moduleFileExtensions": [
"ts", "ts",
"tsx", "tsx",

View File

@ -25,7 +25,7 @@ export async function setupState() {
data = (await storage.load(ROOT_STATE_STORAGE_KEY)) || {} data = (await storage.load(ROOT_STATE_STORAGE_KEY)) || {}
rootStore.hydrate(data) rootStore.hydrate(data)
} catch (e: any) { } catch (e: any) {
rootStore.log.error('Failed to load state from storage', e.toString()) rootStore.log.error('Failed to load state from storage', e)
} }
rootStore.log.debug('Initial hydrate') rootStore.log.debug('Initial hydrate')
@ -36,7 +36,7 @@ export async function setupState() {
return rootStore.fetchStateUpdate() return rootStore.fetchStateUpdate()
}) })
.catch((e: any) => { .catch((e: any) => {
rootStore.log.warn('Failed initial connect', e.toString()) rootStore.log.warn('Failed initial connect', e)
}) })
// @ts-ignore .on() is correct -prf // @ts-ignore .on() is correct -prf
api.sessionManager.on('session', () => { api.sessionManager.on('session', () => {

View File

@ -126,10 +126,7 @@ export async function post(
}, },
} as AppBskyEmbedExternal.Main } as AppBskyEmbedExternal.Main
} catch (e: any) { } catch (e: any) {
store.log.warn( store.log.warn(`Failed to fetch link meta for ${link.value}`, e)
`Failed to fetch link meta for ${link.value}`,
e.toString(),
)
} }
} }
} }

View File

@ -320,11 +320,14 @@ export class FeedModel {
this.error = '' this.error = ''
} }
private _xIdle(err: string = '') { private _xIdle(err?: any) {
this.isLoading = false this.isLoading = false
this.isRefreshing = false this.isRefreshing = false
this.hasLoaded = true this.hasLoaded = true
this.error = cleanError(err) this.error = err ? cleanError(err.toString()) : ''
if (err) {
this.rootStore.log.error('Posts feed request failed', err)
}
} }
// loader functions // loader functions
@ -352,7 +355,7 @@ export class FeedModel {
await this._replaceAll(res) await this._replaceAll(res)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
this._xIdle(e.toString()) this._xIdle(e)
} }
} }
@ -363,7 +366,7 @@ export class FeedModel {
await this._prependAll(res) await this._prependAll(res)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
this._xIdle(e.toString()) this._xIdle(e)
} }
} }
@ -380,7 +383,7 @@ export class FeedModel {
await this._appendAll(res) await this._appendAll(res)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
this._xIdle(`Failed to load feed: ${e.toString()}`) this._xIdle(e)
} }
} }
@ -408,7 +411,7 @@ export class FeedModel {
} while (numToFetch > 0) } while (numToFetch > 0)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
this._xIdle(`Failed to update feed: ${e.toString()}`) this._xIdle(e)
} }
} }

View File

@ -80,11 +80,14 @@ export class GetAssertionsView {
this.error = '' this.error = ''
} }
private _xIdle(err: string = '') { private _xIdle(err?: any) {
this.isLoading = false this.isLoading = false
this.isRefreshing = false this.isRefreshing = false
this.hasLoaded = true this.hasLoaded = true
this.error = err this.error = err ? err.toString() : ''
if (err) {
this.rootStore.log.error('Failed to fetch assertions', err)
}
} }
// loader functions // loader functions
@ -99,7 +102,7 @@ export class GetAssertionsView {
this._replaceAll(res) this._replaceAll(res)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
this._xIdle(e.toString()) this._xIdle(e)
} }
} }

View File

@ -1,4 +1,5 @@
import {makeAutoObservable} from 'mobx' import {makeAutoObservable} from 'mobx'
import {XRPCError, XRPCInvalidResponseError} from '@atproto/xrpc'
import {isObj, hasProp} from '../lib/type-guards' import {isObj, hasProp} from '../lib/type-guards'
interface LogEntry { interface LogEntry {
@ -51,9 +52,7 @@ export class LogModel {
} }
debug(summary: string, details?: any) { debug(summary: string, details?: any) {
if (details && typeof details !== 'string') { details = detailsToStr(details)
details = JSON.stringify(details, null, 2)
}
console.debug(summary, details || '') console.debug(summary, details || '')
this.add({ this.add({
id: genId(), id: genId(),
@ -65,10 +64,8 @@ export class LogModel {
} }
warn(summary: string, details?: any) { warn(summary: string, details?: any) {
if (details && typeof details !== 'string') { details = detailsToStr(details)
details = JSON.stringify(details, null, 2) console.debug(summary, details || '')
}
console.warn(summary, details || '')
this.add({ this.add({
id: genId(), id: genId(),
type: 'warn', type: 'warn',
@ -79,10 +76,8 @@ export class LogModel {
} }
error(summary: string, details?: any) { error(summary: string, details?: any) {
if (details && typeof details !== 'string') { details = detailsToStr(details)
details = JSON.stringify(details, null, 2) console.debug(summary, details || '')
}
console.error(summary, details || '')
this.add({ this.add({
id: genId(), id: genId(),
type: 'error', type: 'error',
@ -92,3 +87,25 @@ export class LogModel {
}) })
} }
} }
function detailsToStr(details?: any) {
if (details && typeof details !== 'string') {
if (
details instanceof XRPCInvalidResponseError ||
details.constructor.name === 'XRPCInvalidResponseError'
) {
return `The server gave an ill-formatted response.\nMethod: ${
details.lexiconNsid
}.\nError: ${details.validationError.toString()}`
} else if (
details instanceof XRPCError ||
details.constructor.name === 'XRPCError'
) {
return `An XRPC error occurred.\nStatus: ${details.status}\nError: ${details.error}\nMessage: ${details.message}`
} else if (details instanceof Error) {
return details.toString()
}
return JSON.stringify(details, null, 2)
}
return details
}

View File

@ -104,22 +104,13 @@ export class MeModel {
}) })
await Promise.all([ await Promise.all([
this.memberships?.setup().catch(e => { this.memberships?.setup().catch(e => {
this.rootStore.log.error( this.rootStore.log.error('Failed to setup memberships model', e)
'Failed to setup memberships model',
e.toString(),
)
}), }),
this.mainFeed.setup().catch(e => { this.mainFeed.setup().catch(e => {
this.rootStore.log.error( this.rootStore.log.error('Failed to setup main feed model', e)
'Failed to setup main feed model',
e.toString(),
)
}), }),
this.notifications.setup().catch(e => { this.notifications.setup().catch(e => {
this.rootStore.log.error( this.rootStore.log.error('Failed to setup notifications model', e)
'Failed to setup notifications model',
e.toString(),
)
}), }),
]) ])
} else { } else {

View File

@ -104,11 +104,14 @@ export class MembersViewModel {
this.error = '' this.error = ''
} }
private _xIdle(err: string = '') { private _xIdle(err?: any) {
this.isLoading = false this.isLoading = false
this.isRefreshing = false this.isRefreshing = false
this.hasLoaded = true this.hasLoaded = true
this.error = err this.error = err ? err.toString() : ''
if (err) {
this.rootStore.log.error('Failed to fetch members', err)
}
} }
// loader functions // loader functions
@ -123,7 +126,7 @@ export class MembersViewModel {
this._replaceAll(res) this._replaceAll(res)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
this._xIdle(`Failed to load feed: ${e.toString()}`) this._xIdle(e)
} }
} }

View File

@ -82,11 +82,14 @@ export class MembershipsViewModel {
this.error = '' this.error = ''
} }
private _xIdle(err: string = '') { private _xIdle(err?: any) {
this.isLoading = false this.isLoading = false
this.isRefreshing = false this.isRefreshing = false
this.hasLoaded = true this.hasLoaded = true
this.error = err this.error = err ? err.toString() : ''
if (err) {
this.rootStore.log.error('Failed to fetch memberships', err)
}
} }
// loader functions // loader functions
@ -101,7 +104,7 @@ export class MembershipsViewModel {
this._replaceAll(res) this._replaceAll(res)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
this._xIdle(`Failed to load feed: ${e.toString()}`) this._xIdle(e)
} }
} }

View File

@ -151,7 +151,7 @@ export class NotificationsViewItemModel implements GroupedNotification {
await this.additionalPost.setup().catch(e => { await this.additionalPost.setup().catch(e => {
this.rootStore.log.error( this.rootStore.log.error(
'Failed to load post needed by notification', 'Failed to load post needed by notification',
e.toString(), e,
) )
}) })
} }
@ -266,10 +266,7 @@ export class NotificationsViewModel {
}) })
this.rootStore.me.clearNotificationCount() this.rootStore.me.clearNotificationCount()
} catch (e: any) { } catch (e: any) {
this.rootStore.log.warn( this.rootStore.log.warn('Failed to update notifications read state', e)
'Failed to update notifications read state',
e.toString(),
)
} }
} }
@ -282,11 +279,15 @@ export class NotificationsViewModel {
this.error = '' this.error = ''
} }
private _xIdle(err: string = '') { private _xIdle(err?: any) {
this.isLoading = false this.isLoading = false
this.isRefreshing = false this.isRefreshing = false
this.hasLoaded = true this.hasLoaded = true
this.error = cleanError(err) this.error = cleanError(err)
this.error = err ? cleanError(err) : ''
if (err) {
this.rootStore.log.error('Failed to fetch notifications', err)
}
} }
// loader functions // loader functions
@ -314,7 +315,7 @@ export class NotificationsViewModel {
await this._replaceAll(res) await this._replaceAll(res)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
this._xIdle(`Failed to load notifications: ${e.toString()}`) this._xIdle(e)
} }
} }
@ -332,7 +333,7 @@ export class NotificationsViewModel {
await this._appendAll(res) await this._appendAll(res)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
this._xIdle(`Failed to load notifications: ${e.toString()}`) this._xIdle(e)
} }
} }
@ -359,7 +360,7 @@ export class NotificationsViewModel {
} while (numToFetch > 0) } while (numToFetch > 0)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
this._xIdle(`Failed to update notifications: ${e.toString()}`) this._xIdle(e)
} }
} }
@ -386,7 +387,7 @@ export class NotificationsViewModel {
await Promise.all(promises).catch(e => { await Promise.all(promises).catch(e => {
this.rootStore.log.error( this.rootStore.log.error(
'Uncaught failure during notifications-view _appendAll()', 'Uncaught failure during notifications-view _appendAll()',
e.toString(), e,
) )
}) })
runInAction(() => { runInAction(() => {

View File

@ -236,11 +236,14 @@ export class PostThreadViewModel {
this.notFound = false this.notFound = false
} }
private _xIdle(err: any = undefined) { private _xIdle(err?: any) {
this.isLoading = false this.isLoading = false
this.isRefreshing = false this.isRefreshing = false
this.hasLoaded = true this.hasLoaded = true
this.error = err ? err.toString() : '' this.error = err ? err.toString() : ''
if (err) {
this.rootStore.log.error('Failed to fetch assertions', err)
}
this.notFound = err instanceof GetPostThread.NotFoundError this.notFound = err instanceof GetPostThread.NotFoundError
} }

View File

@ -63,10 +63,14 @@ export class PostModel implements RemoveIndex<Post.Record> {
this.error = '' this.error = ''
} }
private _xIdle(err: string = '') { private _xIdle(err?: any) {
this.isLoading = false this.isLoading = false
this.hasLoaded = true this.hasLoaded = true
this.error = cleanError(err) this.error = cleanError(err)
this.error = err ? cleanError(err) : ''
if (err) {
this.rootStore.log.error('Failed to fetch post', err)
}
} }
// loader functions // loader functions
@ -87,7 +91,7 @@ export class PostModel implements RemoveIndex<Post.Record> {
this._replaceAll(res.value) this._replaceAll(res.value)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
this._xIdle(e.toString()) this._xIdle(e)
} }
} }

View File

@ -114,28 +114,20 @@ export class ProfileUiModel {
await Promise.all([ await Promise.all([
this.profile this.profile
.setup() .setup()
.catch(err => .catch(err => this.rootStore.log.error('Failed to fetch profile', err)),
this.rootStore.log.error('Failed to fetch profile', err.toString()),
),
this.feed this.feed
.setup() .setup()
.catch(err => .catch(err => this.rootStore.log.error('Failed to fetch feed', err)),
this.rootStore.log.error('Failed to fetch feed', err.toString()),
),
]) ])
if (this.isUser) { if (this.isUser) {
await this.memberships await this.memberships
.setup() .setup()
.catch(err => .catch(err => this.rootStore.log.error('Failed to fetch members', err))
this.rootStore.log.error('Failed to fetch members', err.toString()),
)
} }
if (this.isScene) { if (this.isScene) {
await this.members await this.members
.setup() .setup()
.catch(err => .catch(err => this.rootStore.log.error('Failed to fetch members', err))
this.rootStore.log.error('Failed to fetch members', err.toString()),
)
} }
} }

View File

@ -178,11 +178,14 @@ export class ProfileViewModel {
this.error = '' this.error = ''
} }
private _xIdle(err: string = '') { private _xIdle(err?: any) {
this.isLoading = false this.isLoading = false
this.isRefreshing = false this.isRefreshing = false
this.hasLoaded = true this.hasLoaded = true
this.error = err this.error = err ? err.toString() : ''
if (err) {
this.rootStore.log.error('Failed to fetch profile', err)
}
} }
// loader functions // loader functions
@ -198,7 +201,7 @@ export class ProfileViewModel {
this._replaceAll(res) this._replaceAll(res)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
this._xIdle(e.toString()) this._xIdle(e)
} }
} }

View File

@ -94,11 +94,14 @@ export class RepostedByViewModel {
this.error = '' this.error = ''
} }
private _xIdle(err: string = '') { private _xIdle(err?: any) {
this.isLoading = false this.isLoading = false
this.isRefreshing = false this.isRefreshing = false
this.hasLoaded = true this.hasLoaded = true
this.error = err this.error = err ? err.toString() : ''
if (err) {
this.rootStore.log.error('Failed to fetch reposted by view', err)
}
} }
// loader functions // loader functions
@ -127,7 +130,7 @@ export class RepostedByViewModel {
this._replaceAll(res) this._replaceAll(res)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
this._xIdle(`Failed to load feed: ${e.toString()}`) this._xIdle(e)
} }
} }

View File

@ -59,7 +59,7 @@ export class RootStoreModel {
if (isNetworkError(e)) { if (isNetworkError(e)) {
this.session.setOnline(false) // connection lost this.session.setOnline(false) // connection lost
} }
this.log.error('Failed to fetch latest state', e.toString()) this.log.error('Failed to fetch latest state', e)
} }
} }

View File

@ -124,7 +124,7 @@ export class SessionModel {
} catch (e: any) { } catch (e: any) {
this.rootStore.log.error( this.rootStore.log.error(
`Invalid service URL: ${this.data.service}. Resetting session.`, `Invalid service URL: ${this.data.service}. Resetting session.`,
e.toString(), e,
) )
this.clear() this.clear()
return false return false
@ -160,10 +160,7 @@ export class SessionModel {
this.rootStore.me.clear() this.rootStore.me.clear()
} }
this.rootStore.me.load().catch(e => { this.rootStore.me.load().catch(e => {
this.rootStore.log.error( this.rootStore.log.error('Failed to fetch local user information', e)
'Failed to fetch local user information',
e.toString(),
)
}) })
return // success return // success
} }
@ -207,10 +204,7 @@ export class SessionModel {
this.configureApi() this.configureApi()
this.setOnline(true, false) this.setOnline(true, false)
this.rootStore.me.load().catch(e => { this.rootStore.me.load().catch(e => {
this.rootStore.log.error( this.rootStore.log.error('Failed to fetch local user information', e)
'Failed to fetch local user information',
e.toString(),
)
}) })
} }
} }
@ -246,10 +240,7 @@ export class SessionModel {
this.rootStore.onboard.start() this.rootStore.onboard.start()
this.configureApi() this.configureApi()
this.rootStore.me.load().catch(e => { this.rootStore.me.load().catch(e => {
this.rootStore.log.error( this.rootStore.log.error('Failed to fetch local user information', e)
'Failed to fetch local user information',
e.toString(),
)
}) })
} }
} }

View File

@ -58,11 +58,14 @@ export class SuggestedActorsViewModel {
this.error = '' this.error = ''
} }
private _xIdle(err: string = '') { private _xIdle(err?: any) {
this.isLoading = false this.isLoading = false
this.isRefreshing = false this.isRefreshing = false
this.hasLoaded = true this.hasLoaded = true
this.error = err this.error = err ? err.toString() : ''
if (err) {
this.rootStore.log.error('Failed to fetch suggested actors', err)
}
} }
// loader functions // loader functions
@ -88,7 +91,7 @@ export class SuggestedActorsViewModel {
) )
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
this._xIdle(e.toString()) this._xIdle(e)
} }
} }

View File

@ -83,11 +83,14 @@ export class SuggestedInvitesView {
this.error = '' this.error = ''
} }
private _xIdle(err: string = '') { private _xIdle(err?: any) {
this.isLoading = false this.isLoading = false
this.isRefreshing = false this.isRefreshing = false
this.hasLoaded = true this.hasLoaded = true
this.error = err this.error = err ? err.toString() : ''
if (err) {
this.rootStore.log.error('Failed to fetch suggested invites', err)
}
} }
// loader functions // loader functions
@ -101,7 +104,7 @@ export class SuggestedInvitesView {
} catch (e: any) { } catch (e: any) {
this.rootStore.log.error( this.rootStore.log.error(
'Failed to fetch current scene members in suggested invites', 'Failed to fetch current scene members in suggested invites',
e.toString(), e,
) )
this._xIdle( this._xIdle(
'Failed to fetch the current scene members. Check your internet connection and try again.', 'Failed to fetch the current scene members. Check your internet connection and try again.',
@ -113,7 +116,7 @@ export class SuggestedInvitesView {
} catch (e: any) { } catch (e: any) {
this.rootStore.log.error( this.rootStore.log.error(
'Failed to fetch current followers in suggested invites', 'Failed to fetch current followers in suggested invites',
e.toString(), e,
) )
this._xIdle( this._xIdle(
'Failed to fetch the your current followers. Check your internet connection and try again.', 'Failed to fetch the your current followers. Check your internet connection and try again.',

View File

@ -76,11 +76,14 @@ export class UserFollowersViewModel {
this.error = '' this.error = ''
} }
private _xIdle(err: string = '') { private _xIdle(err?: any) {
this.isLoading = false this.isLoading = false
this.isRefreshing = false this.isRefreshing = false
this.hasLoaded = true this.hasLoaded = true
this.error = err this.error = err ? err.toString() : ''
if (err) {
this.rootStore.log.error('Failed to fetch user followers', err)
}
} }
// loader functions // loader functions

View File

@ -76,11 +76,14 @@ export class UserFollowsViewModel {
this.error = '' this.error = ''
} }
private _xIdle(err: string = '') { private _xIdle(err?: any) {
this.isLoading = false this.isLoading = false
this.isRefreshing = false this.isRefreshing = false
this.hasLoaded = true this.hasLoaded = true
this.error = err this.error = err ? err.toString() : ''
if (err) {
this.rootStore.log.error('Failed to fetch user follows', err)
}
} }
// loader functions // loader functions

View File

@ -91,11 +91,14 @@ export class VotesViewModel {
this.error = '' this.error = ''
} }
private _xIdle(err: string = '') { private _xIdle(err?: any) {
this.isLoading = false this.isLoading = false
this.isRefreshing = false this.isRefreshing = false
this.hasLoaded = true this.hasLoaded = true
this.error = err this.error = err ? err.toString() : ''
if (err) {
this.rootStore.log.error('Failed to fetch votes', err)
}
} }
// loader functions // loader functions
@ -124,7 +127,7 @@ export class VotesViewModel {
this._replaceAll(res) this._replaceAll(res)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
this._xIdle(`Failed to load feed: ${e.toString()}`) this._xIdle(e)
} }
} }

View File

@ -40,7 +40,7 @@ export const PhotoCarouselPicker = ({
onSelectPhotos([uri, ...selectedPhotos]) onSelectPhotos([uri, ...selectedPhotos])
} catch (err: any) { } catch (err: any) {
// ignore // ignore
store.log.warn('Error using camera', err.toString()) store.log.warn('Error using camera', err)
} }
}, [store.log, selectedPhotos, onSelectPhotos]) }, [store.log, selectedPhotos, onSelectPhotos])
@ -56,7 +56,7 @@ export const PhotoCarouselPicker = ({
onSelectPhotos([finalUri, ...selectedPhotos]) onSelectPhotos([finalUri, ...selectedPhotos])
} catch (err: any) { } catch (err: any) {
// ignore // ignore
store.log.warn('Error selecting photo', err.toString()) store.log.warn('Error selecting photo', err)
} }
}, },
[store.log, selectedPhotos, onSelectPhotos], [store.log, selectedPhotos, onSelectPhotos],

View File

@ -45,7 +45,7 @@ export const SuggestedFollows = observer(
view view
.setup() .setup()
.catch((err: any) => .catch((err: any) =>
store.log.error('Failed to fetch suggestions', err.toString()), store.log.error('Failed to fetch suggestions', err),
) )
}, [view, store.log]) }, [view, store.log])
@ -59,7 +59,7 @@ export const SuggestedFollows = observer(
view view
.setup() .setup()
.catch((err: any) => .catch((err: any) =>
store.log.error('Failed to fetch suggestions', err.toString()), store.log.error('Failed to fetch suggestions', err),
) )
const onPressFollow = async (item: SuggestedActor) => { const onPressFollow = async (item: SuggestedActor) => {
@ -67,7 +67,7 @@ export const SuggestedFollows = observer(
const res = await apilib.follow(store, item.did, item.declaration.cid) const res = await apilib.follow(store, item.did, item.declaration.cid)
setFollows({[item.did]: res.uri, ...follows}) setFollows({[item.did]: res.uri, ...follows})
} catch (e: any) { } catch (e: any) {
store.log.error('Failed fo create follow', {error: e.toString(), item}) store.log.error('Failed fo create follow', e)
Toast.show('An issue occurred, please try again.') Toast.show('An issue occurred, please try again.')
} }
} }
@ -76,7 +76,7 @@ export const SuggestedFollows = observer(
await apilib.unfollow(store, follows[item.did]) await apilib.unfollow(store, follows[item.did])
setFollows(_omit(follows, [item.did])) setFollows(_omit(follows, [item.did]))
} catch (e: any) { } catch (e: any) {
store.log.error('Failed fo delete follow', {error: e.toString(), item}) store.log.error('Failed fo delete follow', e)
Toast.show('An issue occurred, please try again.') Toast.show('An issue occurred, please try again.')
} }
} }

View File

@ -54,7 +54,7 @@ export const CreateAccount = ({onPressBack}: {onPressBack: () => void}) => {
if (aborted) return if (aborted) return
store.log.warn( store.log.warn(
`Failed to fetch service description for ${serviceUrl}`, `Failed to fetch service description for ${serviceUrl}`,
err.toString(), err,
) )
setError( setError(
'Unable to contact your service. Please check your Internet connection.', 'Unable to contact your service. Please check your Internet connection.',
@ -100,7 +100,7 @@ export const CreateAccount = ({onPressBack}: {onPressBack: () => void}) => {
errMsg = errMsg =
'Invite code not accepted. Check that you input it correctly and try again.' 'Invite code not accepted. Check that you input it correctly and try again.'
} }
store.log.warn('Failed to create account', e.toString()) store.log.error('Failed to create account', e)
setIsProcessing(false) setIsProcessing(false)
setError(errMsg.replace(/^Error:/, '')) setError(errMsg.replace(/^Error:/, ''))
} }

View File

@ -53,7 +53,7 @@ export const Signin = ({onPressBack}: {onPressBack: () => void}) => {
if (aborted) return if (aborted) return
store.log.warn( store.log.warn(
`Failed to fetch service description for ${serviceUrl}`, `Failed to fetch service description for ${serviceUrl}`,
err.toString(), err,
) )
setError( setError(
'Unable to contact your service. Please check your Internet connection.', 'Unable to contact your service. Please check your Internet connection.',
@ -171,7 +171,7 @@ const LoginForm = ({
}) })
} catch (e: any) { } catch (e: any) {
const errMsg = e.toString() const errMsg = e.toString()
store.log.warn('Failed to login', e.toString()) store.log.warn('Failed to login', e)
setIsProcessing(false) setIsProcessing(false)
if (errMsg.includes('Authentication Required')) { if (errMsg.includes('Authentication Required')) {
setError('Invalid username or password') setError('Invalid username or password')
@ -307,7 +307,7 @@ const ForgotPasswordForm = ({
onEmailSent() onEmailSent()
} catch (e: any) { } catch (e: any) {
const errMsg = e.toString() const errMsg = e.toString()
store.log.warn('Failed to request password reset', e.toString()) store.log.warn('Failed to request password reset', e)
setIsProcessing(false) setIsProcessing(false)
if (isNetworkError(e)) { if (isNetworkError(e)) {
setError( setError(
@ -419,7 +419,7 @@ const SetNewPasswordForm = ({
onPasswordSet() onPasswordSet()
} catch (e: any) { } catch (e: any) {
const errMsg = e.toString() const errMsg = e.toString()
store.log.warn('Failed to set new password', e.toString()) store.log.warn('Failed to set new password', e)
setIsProcessing(false) setIsProcessing(false)
if (isNetworkError(e)) { if (isNetworkError(e)) {
setError( setError(

View File

@ -57,10 +57,7 @@ export function Component({}: {}) {
}) })
.catch(e => .catch(e =>
// an error here is not critical // an error here is not critical
store.log.error( store.log.error('Failed to update scene profile during creation', e),
'Failed to update scene profile during creation',
e.toString(),
),
) )
// follow the scene // follow the scene
await store.api.app.bsky.graph.follow await store.api.app.bsky.graph.follow
@ -78,10 +75,7 @@ export function Component({}: {}) {
) )
.catch(e => .catch(e =>
// an error here is not critical // an error here is not critical
store.log.error( store.log.error('Failed to follow scene after creation', e),
'Failed to follow scene after creation',
e.toString(),
),
) )
Toast.show('Scene created') Toast.show('Scene created')
store.shell.closeModal() store.shell.closeModal()
@ -94,7 +88,7 @@ export function Component({}: {}) {
} else if (e instanceof AppBskyActorCreateScene.HandleNotAvailableError) { } else if (e instanceof AppBskyActorCreateScene.HandleNotAvailableError) {
setError(`The handle "${handle}" is not available.`) setError(`The handle "${handle}" is not available.`)
} else { } else {
store.log.error('Failed to create scene', e.toString()) store.log.error('Failed to create scene', e)
setError( setError(
'Failed to create the scene. Check your internet connection and try again.', 'Failed to create the scene. Check your internet connection and try again.',
) )

View File

@ -86,7 +86,7 @@ export const Component = observer(function Component({
Toast.show('Invite sent') Toast.show('Invite sent')
} catch (e: any) { } catch (e: any) {
setError('There was an issue with the invite. Please try again.') setError('There was an issue with the invite. Please try again.')
store.log.error('Failed to invite user to scene', e.toString()) store.log.error('Failed to invite user to scene', e)
} }
} }
const onPressUndo = async (subjectDid: string, assertionUri: string) => { const onPressUndo = async (subjectDid: string, assertionUri: string) => {
@ -100,7 +100,7 @@ export const Component = observer(function Component({
setCreatedInvites(_omit(createdInvites, [subjectDid])) setCreatedInvites(_omit(createdInvites, [subjectDid]))
} catch (e: any) { } catch (e: any) {
setError('There was an issue with the invite. Please try again.') setError('There was an issue with the invite. Please try again.')
store.log.error('Failed to delete a scene invite', e.toString()) store.log.error('Failed to delete a scene invite', e)
} }
} }
@ -119,7 +119,7 @@ export const Component = observer(function Component({
Toast.show('Invite removed') Toast.show('Invite removed')
} catch (e: any) { } catch (e: any) {
setError('There was an issue with the invite. Please try again.') setError('There was an issue with the invite. Please try again.')
store.log.error('Failed to delete an invite', e.toString()) store.log.error('Failed to delete an invite', e)
} }
} }

View File

@ -39,20 +39,14 @@ export const Feed = observer(function Feed({
view view
.refresh() .refresh()
.catch(err => .catch(err =>
view.rootStore.log.error( view.rootStore.log.error('Failed to refresh notifications feed', err),
'Failed to refresh notifications feed',
err.toString(),
),
) )
} }
const onEndReached = () => { const onEndReached = () => {
view view
.loadMore() .loadMore()
.catch(err => .catch(err =>
view.rootStore.log.error( view.rootStore.log.error('Failed to load more notifications', err),
'Failed to load more notifications',
err.toString(),
),
) )
} }
let data let data

View File

@ -28,9 +28,7 @@ export const PostRepostedBy = observer(function PostRepostedBy({
setView(newView) setView(newView)
newView newView
.setup() .setup()
.catch(err => .catch(err => store.log.error('Failed to fetch reposted by', err))
store.log.error('Failed to fetch reposted by', err.toString()),
)
}, [uri, view?.params.uri, store]) }, [uri, view?.params.uri, store])
const onRefresh = () => { const onRefresh = () => {

View File

@ -21,10 +21,7 @@ export const PostThread = observer(function PostThread({
view view
?.refresh() ?.refresh()
.catch(err => .catch(err =>
view.rootStore.log.error( view.rootStore.log.error('Failed to refresh posts thread', err),
'Failed to refresh posts thread',
err.toString(),
),
) )
} }
const onLayout = () => { const onLayout = () => {

View File

@ -72,12 +72,12 @@ export const PostThreadItem = observer(function PostThreadItem({
const onPressToggleRepost = () => { const onPressToggleRepost = () => {
item item
.toggleRepost() .toggleRepost()
.catch(e => store.log.error('Failed to toggle repost', e.toString())) .catch(e => store.log.error('Failed to toggle repost', e))
} }
const onPressToggleUpvote = () => { const onPressToggleUpvote = () => {
item item
.toggleUpvote() .toggleUpvote()
.catch(e => store.log.error('Failed to toggle upvote', e.toString())) .catch(e => store.log.error('Failed to toggle upvote', e))
} }
const onCopyPostText = () => { const onCopyPostText = () => {
Clipboard.setString(record.text) Clipboard.setString(record.text)
@ -90,7 +90,7 @@ export const PostThreadItem = observer(function PostThreadItem({
Toast.show('Post deleted') Toast.show('Post deleted')
}, },
e => { e => {
store.log.error('Failed to delete post', e.toString()) store.log.error('Failed to delete post', e)
Toast.show('Failed to delete post, please try again') Toast.show('Failed to delete post, please try again')
}, },
) )

View File

@ -30,7 +30,7 @@ export const PostVotedBy = observer(function PostVotedBy({
setView(newView) setView(newView)
newView newView
.setup() .setup()
.catch(err => store.log.error('Failed to fetch voted by', err.toString())) .catch(err => store.log.error('Failed to fetch voted by', err))
}, [uri, view?.params.uri, store]) }, [uri, view?.params.uri, store])
const onRefresh = () => { const onRefresh = () => {

View File

@ -47,9 +47,7 @@ export const Post = observer(function Post({
} }
const newView = new PostThreadViewModel(store, {uri, depth: 0}) const newView = new PostThreadViewModel(store, {uri, depth: 0})
setView(newView) setView(newView)
newView newView.setup().catch(err => store.log.error('Failed to fetch post', err))
.setup()
.catch(err => store.log.error('Failed to fetch post', err.toString()))
}, [initView, uri, view?.params.uri, store]) }, [initView, uri, view?.params.uri, store])
// deleted // deleted
@ -112,12 +110,12 @@ export const Post = observer(function Post({
const onPressToggleRepost = () => { const onPressToggleRepost = () => {
item item
.toggleRepost() .toggleRepost()
.catch(e => store.log.error('Failed to toggle repost', e.toString())) .catch(e => store.log.error('Failed to toggle repost', e))
} }
const onPressToggleUpvote = () => { const onPressToggleUpvote = () => {
item item
.toggleUpvote() .toggleUpvote()
.catch(e => store.log.error('Failed to toggle upvote', e.toString())) .catch(e => store.log.error('Failed to toggle upvote', e))
} }
const onCopyPostText = () => { const onCopyPostText = () => {
Clipboard.setString(record.text) Clipboard.setString(record.text)
@ -130,7 +128,7 @@ export const Post = observer(function Post({
Toast.show('Post deleted') Toast.show('Post deleted')
}, },
e => { e => {
store.log.error('Failed to delete post', e.toString()) store.log.error('Failed to delete post', e)
Toast.show('Failed to delete post, please try again') Toast.show('Failed to delete post, please try again')
}, },
) )

View File

@ -23,9 +23,7 @@ export const PostText = observer(function PostText({
} }
const newModel = new PostModel(store, uri) const newModel = new PostModel(store, uri)
setModel(newModel) setModel(newModel)
newModel newModel.setup().catch(err => store.log.error('Failed to fetch post', err))
.setup()
.catch(err => store.log.error('Failed to fetch post', err.toString()))
}, [uri, model?.uri, store]) }, [uri, model?.uri, store])
// loading // loading

View File

@ -56,18 +56,13 @@ export const Feed = observer(function Feed({
feed feed
.refresh() .refresh()
.catch(err => .catch(err =>
feed.rootStore.log.error( feed.rootStore.log.error('Failed to refresh posts feed', err),
'Failed to refresh posts feed',
err.toString(),
),
) )
} }
const onEndReached = () => { const onEndReached = () => {
feed feed
.loadMore() .loadMore()
.catch(err => .catch(err => feed.rootStore.log.error('Failed to load more posts', err))
feed.rootStore.log.error('Failed to load more posts', err.toString()),
)
} }
let data let data
if (feed.hasLoaded) { if (feed.hasLoaded) {

View File

@ -69,12 +69,12 @@ export const FeedItem = observer(function ({
const onPressToggleRepost = () => { const onPressToggleRepost = () => {
item item
.toggleRepost() .toggleRepost()
.catch(e => store.log.error('Failed to toggle repost', e.toString())) .catch(e => store.log.error('Failed to toggle repost', e))
} }
const onPressToggleUpvote = () => { const onPressToggleUpvote = () => {
item item
.toggleUpvote() .toggleUpvote()
.catch(e => store.log.error('Failed to toggle upvote', e.toString())) .catch(e => store.log.error('Failed to toggle upvote', e))
} }
const onCopyPostText = () => { const onCopyPostText = () => {
Clipboard.setString(record.text) Clipboard.setString(record.text)
@ -87,7 +87,7 @@ export const FeedItem = observer(function ({
Toast.show('Post deleted') Toast.show('Post deleted')
}, },
e => { e => {
store.log.error('Failed to delete post', e.toString()) store.log.error('Failed to delete post', e)
Toast.show('Failed to delete post, please try again') Toast.show('Failed to delete post, please try again')
}, },
) )

View File

@ -29,9 +29,7 @@ export const ProfileFollowers = observer(function ProfileFollowers({
setView(newView) setView(newView)
newView newView
.setup() .setup()
.catch(err => .catch(err => store.log.error('Failed to fetch user followers', err))
store.log.error('Failed to fetch user followers', err.toString()),
)
}, [name, view?.params.user, store]) }, [name, view?.params.user, store])
const onRefresh = () => { const onRefresh = () => {

View File

@ -29,9 +29,7 @@ export const ProfileFollows = observer(function ProfileFollows({
setView(newView) setView(newView)
newView newView
.setup() .setup()
.catch(err => .catch(err => store.log.error('Failed to fetch user follows', err))
store.log.error('Failed to fetch user follows', err.toString()),
)
}, [name, view?.params.user, store]) }, [name, view?.params.user, store])
const onRefresh = () => { const onRefresh = () => {

View File

@ -52,7 +52,7 @@ export const ProfileHeader = observer(function ProfileHeader({
}`, }`,
) )
}, },
err => store.log.error('Failed to toggle follow', err.toString()), err => store.log.error('Failed to toggle follow', err),
) )
} }
const onPressEditProfile = () => { const onPressEditProfile = () => {
@ -94,7 +94,7 @@ export const ProfileHeader = observer(function ProfileHeader({
await view.muteAccount() await view.muteAccount()
Toast.show('Account muted') Toast.show('Account muted')
} catch (e: any) { } catch (e: any) {
store.log.error('Failed to mute account', e.toString()) store.log.error('Failed to mute account', e)
Toast.show(`There was an issue! ${e.toString()}`) Toast.show(`There was an issue! ${e.toString()}`)
} }
} }
@ -103,7 +103,7 @@ export const ProfileHeader = observer(function ProfileHeader({
await view.unmuteAccount() await view.unmuteAccount()
Toast.show('Account unmuted') Toast.show('Account unmuted')
} catch (e: any) { } catch (e: any) {
store.log.error('Failed to unmute account', e.toString()) store.log.error('Failed to unmute account', e)
Toast.show(`There was an issue! ${e.toString()}`) Toast.show(`There was an issue! ${e.toString()}`)
} }
} }

View File

@ -22,7 +22,7 @@ export const ProfileMembers = observer(function ProfileMembers({
setView(newView) setView(newView)
newView newView
.setup() .setup()
.catch(err => store.log.error('Failed to fetch members', err.toString())) .catch(err => store.log.error('Failed to fetch members', err))
}, [name, view?.params.actor, store]) }, [name, view?.params.actor, store])
const onRefresh = () => { const onRefresh = () => {

View File

@ -41,6 +41,7 @@ export type TypographyVariant =
| 'caption' | 'caption'
| 'overline1' | 'overline1'
| 'overline2' | 'overline2'
| 'mono1'
export type Typography = Record<TypographyVariant, TextStyle> export type Typography = Record<TypographyVariant, TextStyle>
export interface Theme { export interface Theme {

View File

@ -1,3 +1,4 @@
import {Platform} from 'react-native'
import type {Theme} from './ThemeContext' import type {Theme} from './ThemeContext'
import {colors} from './styles' import {colors} from './styles'
@ -136,6 +137,10 @@ export const defaultTheme: Theme = {
fontSize: 14, fontSize: 14,
fontWeight: '600', fontWeight: '600',
}, },
mono1: {
fontSize: 14,
fontFamily: Platform.OS === 'android' ? 'monospace' : 'Courier New',
},
}, },
} }

View File

@ -37,7 +37,7 @@ export const Home = observer(function Home({
} }
store.log.debug('Polling home feed') store.log.debug('Polling home feed')
store.me.mainFeed.checkForLatest().catch(e => { store.me.mainFeed.checkForLatest().catch(e => {
store.log.error('Failed to poll feed', e.toString()) store.log.error('Failed to poll feed', e)
}) })
} }

View File

@ -65,11 +65,13 @@ export const Log = observer(function Log({navIdx, visible}: ScreenParams) {
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
{expanded.includes(entry.id) ? ( {expanded.includes(entry.id) ? (
<View style={[pal.view, s.pl10, s.pr10, s.pb10]}>
<View style={[pal.btn, styles.details]}> <View style={[pal.btn, styles.details]}>
<Text type="body1" style={pal.text}> <Text type="mono1" style={pal.text}>
{entry.details} {entry.details}
</Text> </Text>
</View> </View>
</View>
) : undefined} ) : undefined}
</View> </View>
) )

View File

@ -19,7 +19,7 @@ export const Notifications = ({navIdx, visible}: ScreenParams) => {
store.me.notifications store.me.notifications
.update() .update()
.catch(e => { .catch(e => {
store.log.error('Error while updating notifications feed', e.toString()) store.log.error('Error while updating notifications feed', e)
}) })
.then(() => { .then(() => {
store.me.notifications.updateReadState() store.me.notifications.updateReadState()

View File

@ -38,7 +38,7 @@ export const PostThread = ({navIdx, visible, params}: ScreenParams) => {
} }
}, },
err => { err => {
store.log.error('Failed to fetch thread', err.toString()) store.log.error('Failed to fetch thread', err)
}, },
) )
} }

View File

@ -63,17 +63,14 @@ export const Profile = observer(({navIdx, visible, params}: ScreenParams) => {
uiState uiState
.refresh() .refresh()
.catch((err: any) => .catch((err: any) =>
store.log.error('Failed to refresh user profile', err.toString()), store.log.error('Failed to refresh user profile', err),
) )
} }
const onEndReached = () => { const onEndReached = () => {
uiState uiState
.loadMore() .loadMore()
.catch((err: any) => .catch((err: any) =>
store.log.error( store.log.error('Failed to load more entries in user profile', err),
'Failed to load more entries in user profile',
err.toString(),
),
) )
} }
const onPressTryAgain = () => { const onPressTryAgain = () => {

View File

@ -35,6 +35,14 @@
"@atproto/nsid" "*" "@atproto/nsid" "*"
zod "^3.14.2" zod "^3.14.2"
"@atproto/lexicon@^0.0.2":
version "0.0.2"
resolved "https://registry.yarnpkg.com/@atproto/lexicon/-/lexicon-0.0.2.tgz#9fc2fd573d8507a6186494d939824a422a8e18b6"
integrity sha512-lWxXGW/EPU2dXqlM+UoNdJfVpQ3bQ57TCmurqb/wFj1IjrWKdZbMqnQfwf3bzQ+UzVt+ZTKGxsJkw1vvk7/gmA==
dependencies:
"@atproto/nsid" "*"
zod "^3.14.2"
"@atproto/nsid@*": "@atproto/nsid@*":
version "0.0.1" version "0.0.1"
resolved "https://registry.yarnpkg.com/@atproto/nsid/-/nsid-0.0.1.tgz#0cdc00cefe8f0b1385f352b9f57b3ad37fff09a4" resolved "https://registry.yarnpkg.com/@atproto/nsid/-/nsid-0.0.1.tgz#0cdc00cefe8f0b1385f352b9f57b3ad37fff09a4"
@ -48,6 +56,14 @@
"@atproto/lexicon" "*" "@atproto/lexicon" "*"
zod "^3.14.2" zod "^3.14.2"
"@atproto/xrpc@^0.0.2":
version "0.0.2"
resolved "https://registry.yarnpkg.com/@atproto/xrpc/-/xrpc-0.0.2.tgz#d76defd91fd4e2b806bee5e2dfaa42c849275e49"
integrity sha512-/v4/WlxczDJOh+/M4UzWVgYjJ9DzbIZxGTTWxzvKHz4dvJKnO1ZTXtXIqXjAI9kPEh5BDm9cpQ6ik6M1k9YLZg==
dependencies:
"@atproto/lexicon" "*"
zod "^3.14.2"
"@babel/code-frame@7.12.11": "@babel/code-frame@7.12.11":
version "7.12.11" version "7.12.11"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f"