improve scopemissingerror messages
6 unmodified lines7891011111213141546 unmodified lines62636465666667686970336 unmodified linesExpand all6 unmodified linesimport { Avatar, buttonStyles, inputStyles } from './components/common';import { clearApiCaches, resolveActor } from './lib/api/identity';import { useAuth } from './lib/auth';import { useLiveEvents, type LiveEvent } from './lib/live-events';import { formatRelativeTime } from './lib/repo-utils';import { formatRelativeTime, getErrorMessage } from './lib/repo-utils';import { useAppSettings } from './lib/settings';
const TOPBAR_MENU_SELECTOR = 'details[data-topbar-menu]';
46 unmodified lines setSaved(true); reloadAppviewBackedQueries(); } catch (cause) { setSaved(false); setError(cause instanceof Error ? cause.message : 'Invalid appview URL'); setError(getErrorMessage(cause)); } };
const onReset = () => {336 unmodified linesExpand all10 unmodified lines11121314151617181948 unmodified lines6869707171727374757623 unmodified lines10010110210310310410510610710814 unmodified lines12312412512612612712712812913013155 unmodified lines10 unmodified linesimport type { Component, JSX } from 'solid-js';import { createContext, createSignal, onMount, useContext } from 'solid-js';
import { TANGLED_OAUTH_SCOPE, identityResolver } from './api';import { getErrorMessage } from './repo-utils';
const CURRENT_DID_KEY = 'untangled.currentDid';
configureOAuth({48 unmodified lines deleteStoredSession(preferred); localStorage.removeItem(CURRENT_DID_KEY); setAgent(null); setCurrentDid(null); setError(cause instanceof Error ? cause.message : 'Failed to restore session'); setError(getErrorMessage(cause)); } finally { setIsLoading(false); } };23 unmodified lines });
window.location.assign(url.toString()); } catch (cause) { setError(cause instanceof Error ? cause.message : 'Failed to start OAuth sign-in'); setError(getErrorMessage(cause)); throw cause; } };
14 unmodified lines return typeof (state as { returnTo?: unknown } | null)?.returnTo === 'string' ? (state as { returnTo: string }).returnTo : '/'; } catch (cause) { const message = cause instanceof Error ? cause.message : 'OAuth sign-in failed'; setError(message); setError(getErrorMessage(cause)); throw cause; } finally { setIsLoading(false); }55 unmodified lines84 unmodified lines8586878889908990919293949596979899100101102223 unmodified linesExpand all84 unmodified lines if (absSeconds < 31_536_000) return rtf.format(Math.round(seconds / 2_592_000), 'month'); return rtf.format(Math.round(seconds / 31_536_000), 'year');};
export const getErrorMessage = (cause: unknown): string => cause instanceof Error ? cause.message : 'Unknown error';export const getErrorMessage = (cause: unknown): string => { if (cause instanceof Error) { const message = cause.message; if (cause.name === 'ScopeMissingError' || message.includes('ScopeMissingError')) { return `please relogin (${message})`; } return message; } return 'Unknown error';};
export const formatBytes = (value: number): string => { if (value < 1024) { return `${value} B`;223 unmodified linesExpand all22 unmodified lines23242526272728293031447 unmodified linesExpand all479480481482483483484485486487107 unmodified linesExpand all595596597598599599600601602603198 unmodified linesExpand all22 unmodified linesimport { resolveActor } from '../lib/api/identity';import { listRepoRecords, type RepoRecord } from '../lib/api/repos';import { useAuth } from '../lib/auth';import { useLiveEvents, type LiveEvent } from '../lib/live-events';import { formatRelativeTime, loadRecentRepos, loadRecentIssuesPulls } from '../lib/repo-utils';import { formatRelativeTime, getErrorMessage, loadRecentRepos, loadRecentIssuesPulls } from '../lib/repo-utils';
const SAMPLE_REPOS: Array<{ owner: string; slug: string;447 unmodified linesExpand all fallback={<HomeFeedLoading />} > <Show when={!ownReposQuery.error} fallback={<ErrorState message={ownReposQuery.error instanceof Error ? ownReposQuery.error.message : 'Failed to load activity'} />} fallback={<ErrorState message={getErrorMessage(ownReposQuery.error)} />} > <Show when={activityItems().length > 0} fallback={<HomeFeedEmpty title="No repo activity yet" body="New repo, issue, and pull request activity will land here." />}107 unmodified linesExpand all fallback={<LoadingState label="Loading followed repos..." />} > <Show when={!followingQuery.error} fallback={<ErrorState message={followingQuery.error instanceof Error ? followingQuery.error.message : 'Failed to load timeline'} />} fallback={<ErrorState message={getErrorMessage(followingQuery.error)} />} > <Show when={(followingQuery.data?.activity.length ?? 0) > 0} fallback={<HomeEmpty label="No followed repo activity yet." />}198 unmodified linesExpand all39 unmodified lines40414243444445464748821 unmodified linesExpand all87087187287387487587687787887988088188288388488520 unmodified lines906907908909910911912913914106 unmodified linesExpand all1021102210231024102510261027102810293 unmodified lines1033103410351036103710381039104010411 unmodified line1043104410451046104710481049105010516 unmodified lines1058105910601061106210631064106510669 unmodified lines1076107710781079108010811082108310841 unmodified line1086108710881089109010911092109310945 unmodified lines110011011102110311041105110611071108110911101111111211131114116 unmodified linesExpand all12311232123312341235123612371238123912401241124212431244207 unmodified linesExpand all39 unmodified linesimport { resolveActor, getActorProfile, resolveAvatarUrl, putActorProfile } from '../lib/api/identity';import { listRepoRecords, getRepoByDid, type RepoContext } from '../lib/api/repos';import { useAuth } from '../lib/auth';import { listAllAppviewRecords } from '../lib/api/appview';import { formatRelativeTime } from '../lib/repo-utils';import { formatRelativeTime, getErrorMessage } from '../lib/repo-utils';import { ShTangledFeedStar, ShTangledActorProfile } from '@atcute/tangled';
const ProfileTabs: Component<{ activeTab: string;821 unmodified linesExpand all const [repoSearch, setRepoSearch] = createSignal(''); const [actionLoading, setActionLoading] = createSignal(false); const [isRedirecting, setIsRedirecting] = createSignal(false); const [error, setError] = createSignal<string | null>(null);
const actorParam = () => params.actor as string;
createEffect(() => { actorParam(); setIsRedirecting(false); setError(null); });
const isDid = () => actorParam().startsWith('did:');
20 unmodified lines createEffect(() => { const err = repoDidQuery.error; if (err) { console.error('Failed to resolve DID as repo:', err); setError(getErrorMessage(err)); } });
const activeTab = () => {106 unmodified linesExpand all const profileDid = actorQuery.data?.did; if (!agent || !profileDid) return;
setActionLoading(true); setError(null); try { const rkey = followRecordRkey(); if (rkey) { await deleteFollow(agent, rkey);3 unmodified lines queryClient.invalidateQueries({ queryKey: ['viewer-follows', auth.currentDid()] }); queryClient.invalidateQueries({ queryKey: ['profile-followers', profileDid] }); } catch (e) { console.error('Failed to toggle follow status', e); setError(getErrorMessage(e)); } finally { setActionLoading(false); } };1 unmodified line const handleItemFollowToggle = async (did: Did) => { const agent = auth.agent(); if (!agent) return;
setError(null); try { const viewerFollows = viewerFollowsQuery.data ?? []; const existing = viewerFollows.find((f) => f.value.subject === did); if (existing) {6 unmodified lines queryClient.invalidateQueries({ queryKey: ['profile-followers', did] }); } } catch (e) { console.error('Failed to toggle follow status for list item', e); setError(getErrorMessage(e)); } };
const vouchQuery = createQuery(() => ({9 unmodified lines const profileDid = actorQuery.data?.did; if (!agent || !profileDid) return;
setVouchActionLoading(true); setError(null); try { if (kind === 'none') { await deleteVouchRecord(agent, profileDid); } else {1 unmodified line } queryClient.invalidateQueries({ queryKey: ['vouch-record', auth.currentDid(), profileDid] }); } catch (e) { console.error('Failed to submit vouch status', e); setError(getErrorMessage(e)); } finally { setVouchActionLoading(false); } };5 unmodified lines const profileDid = actorQuery.data?.did; if (!agent || !profileDid) return;
setProfileUpdateLoading(true); setError(null); try { await putActorProfile(agent, profile); queryClient.invalidateQueries({ queryKey: ['profile-record', profileDid] }); } catch (e) { console.error('Failed to update profile record', e); setError(getErrorMessage(e)); } finally { setProfileUpdateLoading(false); } };116 unmodified linesExpand all openPRCount={openPRCount()} openIssueCount={openIssueCount()} closedIssueCount={closedIssueCount()} />
<Show when={error()}> <div class="mt-4 p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded text-sm text-red-600 dark:text-red-400"> {error()} </div> </Show> </div>
<Switch> {/* Overview Tab (split into two columns) */}207 unmodified linesExpand all230 unmodified linesExpand all231232233234235235236237238239144 unmodified linesExpand all38438538638738838838939039139213 unmodified lines40640740840941041041141241341420 unmodified lines435436437438439439440441442443258 unmodified linesExpand all230 unmodified linesExpand all const created = await createIssue(agent, repo, { title: title(), body: body() }); await client.invalidateQueries({ queryKey: issuesQueryKey(repo.repoDid) }); navigate(issueHref(repo, created.uri)); } catch (cause) { setError(cause instanceof Error ? cause.message : 'Failed to create issue'); setError(getErrorMessage(cause)); } finally { setSubmitting(false); } };144 unmodified linesExpand all await client.invalidateQueries({ queryKey: issuesQueryKey(repo.repoDid), refetchType: 'none' }); await client.invalidateQueries({ queryKey: issueQueryKey(repo.repoDid, issueRef()), refetchType: 'none' }); await client.invalidateQueries({ queryKey: issueQueryKey(repo.repoDid, parseAtUri(detail.issue.uri).rkey), refetchType: 'none' }); } catch (cause) { setError(cause instanceof Error ? cause.message : 'Failed to update issue state'); setError(getErrorMessage(cause)); } finally { setWorkingAction(null); } };13 unmodified lines await createIssueComment(agent, detail.issue.uri, detail.issue.cid ?? '', comment()); setComment(''); await withIssueInvalidation(repo, issueRef(), detail.issue.uri); } catch (cause) { setError(cause instanceof Error ? cause.message : 'Failed to create comment'); setError(getErrorMessage(cause)); } finally { setWorkingAction(null); } };20 unmodified lines setReplyBody(''); setReplyingTo(null); await withIssueInvalidation(repo, issueRef(), detail.issue.uri); } catch (cause) { setError(cause instanceof Error ? cause.message : 'Failed to create reply'); setError(getErrorMessage(cause)); } finally { setWorkingAction(null); } };258 unmodified linesExpand all477 unmodified linesExpand all478479480481482482483484485486669 unmodified linesExpand all115611571158115911601160116111621163116434 unmodified lines119912001201120212031203120412051206120720 unmodified lines1228122912301231123212321233123412351236405 unmodified linesExpand all477 unmodified linesExpand all }); await client.invalidateQueries({ queryKey: pullsQueryKey(repo.repoDid) }); navigate(pullHref(repo, created.uri)); } catch (cause) { setError(cause instanceof Error ? cause.message : 'Failed to create pull request'); setError(getErrorMessage(cause)); } finally { setSubmitting(false); } };669 unmodified linesExpand all await setPullStatus(agent, detail.pull.uri, nextState); updatePullStatusCaches(repo, pullRef(), detail.pull.uri, nextState); await markPullQueriesStale(repo, pullRef(), detail.pull.uri); } catch (cause) { setError(cause instanceof Error ? cause.message : 'Failed to update pull state'); setError(getErrorMessage(cause)); } finally { setWorkingAction(null); } };34 unmodified lines await client.invalidateQueries({ queryKey: ['repo-log', repo.repoDid] }); await client.invalidateQueries({ queryKey: ['repo-branches', repo.repoDid] }); await client.invalidateQueries({ queryKey: ['repo-languages', repo.repoDid] }); } catch (cause) { setError(cause instanceof Error ? cause.message : 'Failed to merge pull request'); setError(getErrorMessage(cause)); } finally { setWorkingAction(null); } };20 unmodified lines setComment(''); setComposerOpen(false); await invalidate(repo, pullRef(), detail.pull.uri); } catch (cause) { setError(cause instanceof Error ? cause.message : 'Failed to create comment'); setError(getErrorMessage(cause)); } finally { setWorkingAction(null); } };405 unmodified linesExpand all