appview-less bluesky client
27
fork

Configure Feed

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

fix: show the errors if clients cant login, handle token being expired

dusk 38c2b4d7 dbb96e6f

+33 -8
+2 -1
src/app.css
··· 31 31 } 32 32 33 33 @utility error-disclaimer { 34 - @apply rounded-sm border-2 border-red-500 bg-red-500/8 p-2; 34 + @apply rounded-sm border-2 border-red-500 p-2; 35 + background-color: color-mix(in srgb, var(--color-red-500) 15%, var(--nucleus-bg)); 35 36 p { 36 37 @apply text-base text-wrap wrap-break-word text-red-500; 37 38 }
+4
src/lib/at/client.ts
··· 75 75 public didDoc: MiniDoc | null = null; 76 76 77 77 async login(identifier: ActorIdentifier, agent: OAuthUserAgent): Promise<Result<null, string>> { 78 + if ((agent.session.token.expires_at ?? 0) < Date.now()) { 79 + return err('token expired, relogin'); 80 + } 81 + 78 82 const didDoc = await this.resolveDidDoc(identifier); 79 83 if (!didDoc.ok) return err(didDoc.error); 80 84 this.didDoc = didDoc.value;
+27 -7
src/routes/+page.svelte
··· 22 22 23 23 const { data: loadData }: PageProps = $props(); 24 24 25 + let errors = $state(loadData.client.ok ? [] : [loadData.client.error]); 26 + let errorsOpen = $state(false); 27 + 25 28 let selectedDid = $state((localStorage.getItem('selectedDid') ?? null) as AtprotoDid | null); 26 29 $effect(() => { 27 30 if (selectedDid) { ··· 38 41 if (clients.has(account.did)) return; 39 42 const client = new AtpClient(); 40 43 const result = await client.login(account.did, await sessions.get(account.did)); 41 - if (result.ok) clients.set(account.did, client); 44 + if (!result.ok) { 45 + errors.push(`failed to login into @${account.handle ?? account.did}: ${result.error}`); 46 + return; 47 + } 48 + clients.set(account.did, client); 42 49 }; 43 50 44 51 const handleAccountSelected = async (did: AtprotoDid) => { ··· 272 279 {/if} 273 280 </div> 274 281 275 - {#if !loadData.client.ok} 276 - <div class="error-disclaimer"> 277 - <p> 278 - <Icon class="inline h-12 w-12" icon="heroicons:exclamation-triangle-16-solid" /> 279 - {loadData.client.error} 280 - </p> 282 + {#if errors.length > 0} 283 + <div class="relative error-disclaimer"> 284 + <div class="flex items-center gap-2 text-red-500"> 285 + <Icon class="inline h-10 w-10" icon="heroicons:exclamation-triangle-16-solid" /> 286 + there are ({errors.length}) errors 287 + <div class="grow"></div> 288 + <button onclick={() => (errorsOpen = !errorsOpen)} class="action-button p-1 px-1.5" 289 + >{errorsOpen ? 'hide details' : 'see details'}</button 290 + > 291 + </div> 292 + {#if errorsOpen} 293 + <div 294 + class="absolute top-full right-0 left-0 z-50 mt-2 flex animate-fade-in-scale-fast flex-col gap-1 error-disclaimer shadow-lg transition-all" 295 + > 296 + {#each errors as error, idx (idx)} 297 + <p>• {error}</p> 298 + {/each} 299 + </div> 300 + {/if} 281 301 </div> 282 302 {/if} 283 303