replies timeline only, appview-less bluesky client

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

ptr.pet 38c2b4d7 dbb96e6f

verified
Changed files
+33 -8
src
+2 -1
src/app.css
···
}
@utility error-disclaimer {
-
@apply rounded-sm border-2 border-red-500 bg-red-500/8 p-2;
+
@apply rounded-sm border-2 border-red-500 p-2;
+
background-color: color-mix(in srgb, var(--color-red-500) 15%, var(--nucleus-bg));
p {
@apply text-base text-wrap wrap-break-word text-red-500;
}
+4
src/lib/at/client.ts
···
public didDoc: MiniDoc | null = null;
async login(identifier: ActorIdentifier, agent: OAuthUserAgent): Promise<Result<null, string>> {
+
if ((agent.session.token.expires_at ?? 0) < Date.now()) {
+
return err('token expired, relogin');
+
}
+
const didDoc = await this.resolveDidDoc(identifier);
if (!didDoc.ok) return err(didDoc.error);
this.didDoc = didDoc.value;
+27 -7
src/routes/+page.svelte
···
const { data: loadData }: PageProps = $props();
+
let errors = $state(loadData.client.ok ? [] : [loadData.client.error]);
+
let errorsOpen = $state(false);
+
let selectedDid = $state((localStorage.getItem('selectedDid') ?? null) as AtprotoDid | null);
$effect(() => {
if (selectedDid) {
···
if (clients.has(account.did)) return;
const client = new AtpClient();
const result = await client.login(account.did, await sessions.get(account.did));
-
if (result.ok) clients.set(account.did, client);
+
if (!result.ok) {
+
errors.push(`failed to login into @${account.handle ?? account.did}: ${result.error}`);
+
return;
+
}
+
clients.set(account.did, client);
};
const handleAccountSelected = async (did: AtprotoDid) => {
···
{/if}
</div>
-
{#if !loadData.client.ok}
-
<div class="error-disclaimer">
-
<p>
-
<Icon class="inline h-12 w-12" icon="heroicons:exclamation-triangle-16-solid" />
-
{loadData.client.error}
-
</p>
+
{#if errors.length > 0}
+
<div class="relative error-disclaimer">
+
<div class="flex items-center gap-2 text-red-500">
+
<Icon class="inline h-10 w-10" icon="heroicons:exclamation-triangle-16-solid" />
+
there are ({errors.length}) errors
+
<div class="grow"></div>
+
<button onclick={() => (errorsOpen = !errorsOpen)} class="action-button p-1 px-1.5"
+
>{errorsOpen ? 'hide details' : 'see details'}</button
+
>
+
</div>
+
{#if errorsOpen}
+
<div
+
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"
+
>
+
{#each errors as error, idx (idx)}
+
<p>• {error}</p>
+
{/each}
+
</div>
+
{/if}
</div>
{/if}