feat: add instance store and Connected Instances settings UI

Introduce instanceStore (Zustand) with full federation lifecycle:
probe remote instances, register with username collision fallback,
login to existing accounts, sync instance list across all connected
instances, auto-reconnect from cached tokens on login/page load, and
cleanup on logout. Add ConnectedInstances component to User Settings
with home instance card, remote instance management, and inline
add-instance flow (URL probe → register/login → connected).
This commit is contained in:
Jannis Braun
2026-03-02 23:31:28 +01:00
parent c72fcdda70
commit ef7aa3ff5a
4 changed files with 690 additions and 0 deletions
+6
View File
@@ -5,6 +5,7 @@ import { useChatStore } from './chatStore';
import { useServerStore } from './serverStore';
import { useSocialStore } from './socialStore';
import { useVoiceStore } from './voiceStore';
import { useInstanceStore } from './instanceStore';
interface AuthState {
token: string | null;
@@ -32,6 +33,8 @@ export const useAuthStore = create<AuthState>((set, get) => ({
const response = await api.auth.login({ username, password });
localStorage.setItem('backspace_token', response.token);
set({ token: response.token, user: response.user, isLoading: false });
// Auto-connect to remote instances (fire-and-forget)
useInstanceStore.getState().autoConnectAll().catch(() => {});
} catch (err) {
set({ isLoading: false, error: err instanceof Error ? err.message : 'Login failed' });
throw err;
@@ -57,6 +60,7 @@ export const useAuthStore = create<AuthState>((set, get) => ({
useServerStore.getState().populateFromReady([], [], []);
useSocialStore.getState().reset();
useVoiceStore.getState().clearAllVoiceUsers();
useInstanceStore.getState().reset();
set({ token: null, user: null });
},
@@ -68,6 +72,8 @@ export const useAuthStore = create<AuthState>((set, get) => ({
try {
const user = await api.users.me();
set({ user, isLoading: false });
// Auto-connect to remote instances (fire-and-forget)
useInstanceStore.getState().autoConnectAll().catch(() => {});
} catch {
localStorage.removeItem('backspace_token');
set({ token: null, user: null, isLoading: false });