add relogin warning on session expire
15 unmodified lines161718192021202122232424252627282 unmodified lines313233343536353637383939404142435 unmodified lines4950515253545354555657575859606115 unmodified lines15 unmodified lines } }, "nixpkgs": { "locked": { "lastModified": 1769470494, "narHash": "sha256-kX/2faovWWNPV7PLq4yTdxOFh9fcJ+TlXAK/HE54WP4=", "lastModified": 1781568795, "narHash": "sha256-xDR1Sy/hEf6sPio7ywWCmdgWmY2zbxcGAcsnvv/aR/M=", "owner": "nixos", "repo": "nixpkgs", "rev": "de6cba5efd5dfdb6e955f2da9ce2fe89ee6325dc", "rev": "efe01379b2fa1c8f71ba31a9b6710303bfcd9f1c", "type": "github" }, "original": { "owner": "nixos",2 unmodified lines } }, "nixpkgs-lib": { "locked": { "lastModified": 1765674936, "narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=", "lastModified": 1777168982, "narHash": "sha256-GOkGPcboWE9BmGCRMLX3worL4EMnsnG8MyKmXNeYuhQ=", "owner": "nix-community", "repo": "nixpkgs.lib", "rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85", "rev": "f5901329dade4a6ea039af1433fb087bd9c1fe14", "type": "github" }, "original": { "owner": "nix-community",5 unmodified lines "inputs": { "nixpkgs-lib": "nixpkgs-lib" }, "locked": { "lastModified": 1768135262, "narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=", "lastModified": 1778716662, "narHash": "sha256-m1Yf0wZ8j1OHjTc2UwHwyQRSnNeSgLJOd7q5Y45hzi4=", "owner": "hercules-ci", "repo": "flake-parts", "rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac", "rev": "f7c1a2d347e4c52d5fb8d10cb4d94b5884e546fb", "type": "github" }, "original": { "owner": "hercules-ci",15 unmodified lines7 unmodified lines89101112121314151617182 unmodified linesExpand all20020120220320420520620320420520620720720820921021121221321421521632 unmodified lines7 unmodified linesimport { Link } from "~/components/ui/link";
import { parseCanonicalResourceUri } from "@atcute/lexicons/syntax";import { css } from "styled-system/css";import { sendPost, UploadStatus } from "~/lib/at";import { sendPost, UploadStatus, isSessionExpired } from "~/lib/at";import { showSessionExpiredToast } from "~/lib/sessionExpired";import { toaster } from "~/components/Toaster";import { Dialog } from "~/components/ui/dialog";import { Textarea } from "~/components/ui/textarea";import { Account } from "~/lib/accounts";182 unmodified linesExpand all }); setOpen(false); }) .catch((error) => { if (isSessionExpired(error) && props.account?.did) { showSessionExpiredToast(props.account.did); } else { toaster.create({ title: "send post failed", description: error, type: "error", }); toaster.create({ title: "send post failed", description: error, type: "error", }); } }) .finally(() => { setPosting(false); setUploadStatus(null);32 unmodified lines122345678910111213141516171819202122232425146 unmodified linesExpand allimport { XrpcHandleResolver } from "@atcute/identity-resolver";import { OAuthUserAgent } from "@atcute/oauth-browser-client";import { OAuthUserAgent, TokenRefreshError } from "@atcute/oauth-browser-client";import { Client as AtcuteClient, simpleFetchHandler } from "@atcute/client";import { getSessionClient } from "./oauth";import { AppBskyFeedPost } from "@atcute/bluesky";import { AtprotoDid } from "@atcute/lexicons/syntax";
/** Returns true when the error is caused by an expired or revoked session. */export const isSessionExpired = (err: unknown): boolean => { if (err instanceof TokenRefreshError) return true; if (err instanceof Error) { const msg = err.message.toLowerCase(); if (msg.includes("invalid_grant") || msg.includes("invalid_token")) return true; } if (typeof err === "string") { const msg = err.toLowerCase(); if (msg.includes("invalid_grant") || msg.includes("invalid_token")) return true; } return false;};
export const slingshotUrl = "https://slingshot.microcosm.blue";
export const handleResolver = new XrpcHandleResolver({ serviceUrl: slingshotUrl,146 unmodified linesExpand all109 unmodified linesExpand all110111112113114115116117118109 unmodified linesExpand all const session = await sessions.get(did); if (!session) throw `no session found for ${did}`; return await login(session);};
export const relogin = async (did: AtprotoDid): Promise<void> => { loggingIn.set(did); await flow.start(did);};123456789101112131415161718192021222324252627282930import { HStack } from "styled-system/jsx";import { Text } from "~/components/ui/text";import { Link } from "~/components/ui/link";import { toaster } from "~/components/Toaster";import { relogin } from "./oauth";import type { AtprotoDid } from "@atcute/lexicons/syntax";
/** * Shows a toast telling the user their session expired, with a clickable * "re-login" link that re-triggers the OAuth flow for the given account. */export const showSessionExpiredToast = (did: AtprotoDid) => { toaster.create({ title: "session expired", description: ( <HStack gap="1" flexWrap="wrap"> <Text>your login session has expired, </Text> <Link cursor="pointer" textDecoration="underline" onClick={() => relogin(did)} > click here to re-login </Link> </HStack> ), type: "error", duration: 10_000, });};15 unmodified lines1617181920212223242577 unmodified lines10310410510610710810911011111211311410510610710810911511611711811912012112215 unmodified linesimport { FastAverageColor } from "fast-average-color";import { toaster } from "~/components/Toaster";import { parseColor } from "@ark-ui/solid";import { transcribe } from "./transcribe";import { isSessionExpired } from "./at";import { showSessionExpiredToast } from "./sessionExpired";
export type TaskState = { file: File } & ( | { status: "processing" } | { status: "error"; error: string }77 unmodified lines altText, }); } catch (error) { console.error(error); if (isSessionExpired(error) && did) { showSessionExpiredToast(did); tasks.set(id, { file, status: "error", error: "session expired, please re-login in settings.", }); } else { tasks.set(id, { file, status: "error", error: `failed to process audio: ${error}`, }); tasks.set(id, { file, status: "error", error: `failed to process audio: ${error}`, }); } }};