From c721338dc0309783ac965acc0f226783eb1e7fae Mon Sep 17 00:00:00 2001 From: Julien Calixte Date: Tue, 10 Mar 2026 14:18:41 +0100 Subject: [PATCH] fix: atproto oauth dev redirect, tab isolation, and concurrent load guard - Use buildLoopbackClientId(window.location) for dev to include port in redirect URI - Bind Vite dev server to 127.0.0.1 explicitly - Remove scope override in signInRedirect (use metadata default) - Clear OAuth callback params from URL after session restore - Replace follows badge with DaisyUI tabs (All / Following) - Use separate PublicNoteList instances per tab to isolate v-infinite-scroll state - Add isLoading guard in onLoadMore to prevent concurrent fetches --- src/hooks/useATProtoLogin.hook.ts | 2 + src/hooks/usePublicNoteList.hook.ts | 1 + src/modules/atproto/service/atprotoOAuth.ts | 13 +-- src/views/PublicNoteListView.vue | 90 ++++++++++++--------- vite.config.mts | 3 + 5 files changed, 66 insertions(+), 43 deletions(-) diff --git a/src/hooks/useATProtoLogin.hook.ts b/src/hooks/useATProtoLogin.hook.ts index 30c9f75..0502988 100644 --- a/src/hooks/useATProtoLogin.hook.ts +++ b/src/hooks/useATProtoLogin.hook.ts @@ -19,6 +19,8 @@ const initializeAuth = async () => { did.value = session.did handle.value = resolvedHandle await saveSession(session.did, resolvedHandle) + + window.history.replaceState(null, '', window.location.pathname) } else { const stored = await loadSession() did.value = stored?.did ?? '' diff --git a/src/hooks/usePublicNoteList.hook.ts b/src/hooks/usePublicNoteList.hook.ts index 8418f50..5ae367a 100644 --- a/src/hooks/usePublicNoteList.hook.ts +++ b/src/hooks/usePublicNoteList.hook.ts @@ -15,6 +15,7 @@ export function usePublicNoteList(options?: UsePublicNoteListOptions) { const canLoadMore = computed(() => cursor.value !== undefined) const onLoadMore = async () => { + if (isLoading.value) return isLoading.value = true const path = options?.did?.value ? `/${options.did.value}/notes` : "/notes" diff --git a/src/modules/atproto/service/atprotoOAuth.ts b/src/modules/atproto/service/atprotoOAuth.ts index ccb500e..3fe5f03 100644 --- a/src/modules/atproto/service/atprotoOAuth.ts +++ b/src/modules/atproto/service/atprotoOAuth.ts @@ -1,15 +1,16 @@ -import { BrowserOAuthClient } from '@atproto/oauth-client-browser' +import { BrowserOAuthClient, buildLoopbackClientId } from '@atproto/oauth-client-browser' -const CLIENT_ID = import.meta.env.DEV - ? 'http://localhost' - : 'https://remanso.space/client-metadata.json' +const getClientId = () => + import.meta.env.DEV + ? buildLoopbackClientId(new URL(window.location.origin)) + : 'https://remanso.space/client-metadata.json' let clientPromise: Promise | null = null export const getOAuthClient = (): Promise => { if (!clientPromise) { clientPromise = BrowserOAuthClient.load({ - clientId: CLIENT_ID, + clientId: getClientId(), handleResolver: 'https://bsky.social', }) } @@ -18,7 +19,7 @@ export const getOAuthClient = (): Promise => { export const signInWithHandle = async (handle: string): Promise => { const client = await getOAuthClient() - await client.signInRedirect(handle, { scope: 'atproto transition:generic' }) + await client.signInRedirect(handle) } export const restoreSession = async () => { diff --git a/src/views/PublicNoteListView.vue b/src/views/PublicNoteListView.vue index 1f064f7..db61a40 100644 --- a/src/views/PublicNoteListView.vue +++ b/src/views/PublicNoteListView.vue @@ -5,11 +5,15 @@ import SignInAtproto from "@/components/SignInAtproto.vue" import { useATProtoLogin } from "@/hooks/useATProtoLogin.hook" import { useFollows } from "@/hooks/useFollows.hook" import { usePublicNoteList } from "@/hooks/usePublicNoteList.hook" +import { ref } from "vue" const { did, isLoggedIn } = useATProtoLogin() const { follows } = useFollows(did) -const { notes, isLoading, canLoadMore, onLoadMore, getAuthor } = - usePublicNoteList({ followsFilter: follows }) + +const tab = ref<'all' | 'following'>('all') + +const all = usePublicNoteList() +const following = usePublicNoteList({ followsFilter: follows }) @@ -83,11 +106,4 @@ const { notes, isLoading, canLoadMore, onLoadMore, getAuthor } = overflow-y: auto; } } - -.follows-badge { - font-size: 0.8rem; - opacity: 0.7; - text-align: center; - margin-bottom: 0.5rem; -} diff --git a/vite.config.mts b/vite.config.mts index f426947..eb9d740 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -77,6 +77,9 @@ export default defineConfig(({ command }) => { config.define = { global: {}, } + config.server = { + host: '127.0.0.1', + } } return config