| sessionId |
|---|
| session-261005-211542-1soe |
To maximize application utility and deliver an optimal user experience, users should not have to manually reconnect their Freighter wallet or re-authenticate after every browser refresh. The objective is to enhance src/composables/useSession.ts to manage and persist wallet connection data and authentication tokens across page reloads, making session state globally available and reactive across all UI components.
src/composables/useSession.ts into a reactive session composable managing wallet address, user ID, auth token, and connection lifecycle.localStorage on initial application load and browser refresh.useSession.ts for connecting, disconnecting, checking Freighter status, and formatting wallet displays.src/components/BrandBar.vue and src/App.vue to leverage useSession() for unified session state management.useSession.ts so that components across the application can reliably access authentication details without duplicate storage or Freighter queries.useSession checks localStorage for existing authToken and cached wallet address, verifies Freighter extension availability, and synchronizes reactive state.connectWallet() requests Freighter permission (setAllowed()), retrieves the public key (getAddress()), logs in via AuthService.loginFreighter, stores the token in localStorage, and updates reactive state.disconnectWallet() removes authentication and wallet data from localStorage and resets reactive variables to unauthenticated state.BrandBar.vue dynamically displays either “Connect Wallet” or the truncated address based on useSession reactive state.useSession safely resets state without throwing unhandled exceptions.src/composables/useSession.ts is currently a minimal stub containing only hasFreighter = async () => freighter.isConnected().src/components/BrandBar.vue independently executes Freighter login, sets localStorage.setItem("authToken", ...), and updates a local component ref userText. When the user refreshes, this component state is lost and resets to 'Connect Wallet'.src/App.vue calls freighter.getAddress() in onBeforeMount and stores it in an isolated local ref address.src/utils/auth.ts provides getAuthToken(), parseJwt(), and getUserIdFromJwt(), retrieving tokens from localStorage.useSession.ts:
walletAddress, authToken, userId, isConnecting, and isInitialized as module-level refs within useSession.ts (consistent with patterns used in useModal.ts and useLoading.ts).authToken under the standard 'authToken' key in localStorage and derive/cache stellarAddress and userId directly from JWT payload parsing (parseJwt) and Freighter sync.localStorage minimal, avoids stale divergent data, and maintains full compatibility with src/main.ts (OpenAPI.TOKEN) and src/utils/auth.ts.localStorage on initial access, followed by asynchronous verification with Freighter (freighter.isAllowed()).src/composables/useSession.ts:
walletAddress: ref<string | null>, authToken: ref<string | null>, userId: ref<number | undefined>, isConnecting: ref<boolean>.isAuthenticated: computed(() => !!authToken.value && !!walletAddress.value), truncatedAddress: computed(() => walletAddress.value ? truncateWallet(walletAddress.value) : '').initSession() to restore token from localStorage, decode JWT for stellarAddress / userId, and verify with Freighter if available.connectWallet() and disconnectWallet().hasFreighter() to check extension availability.src/components/BrandBar.vue:
userText logic with const { isAuthenticated, truncatedAddress, isConnecting, connectWallet, disconnectWallet } = useSession().truncatedAddress if authenticated, "Connecting..." if connecting, or "Connect Wallet".src/App.vue:
initSession() in onBeforeMount / onMounted.address ref.export interface SessionState {
walletAddress: string | null;
authToken: string | null;
userId: number | undefined;
isAuthenticated: boolean;
isConnecting: boolean;
hasFreighter: () => Promise<boolean>;
connectWallet: () => Promise<boolean>;
disconnectWallet: () => void;
initSession: () => Promise<void>;
truncatedAddress: string;
}
src/composables/useSession.ts: Core session state, persistence, and wallet connection management.src/components/BrandBar.vue: Primary consumer for wallet connect button and truncated address display.src/App.vue: Top-level application shell invoking session initialization during application bootstrap.src/utils/auth.ts: Helper utilities utilized by useSession.ts for token resolution and JWT decoding.src/composables/useSession.ts (Modified: add full reactive session management and local persistence)src/components/BrandBar.vue (Modified: wire to useSession)src/App.vue (Modified: initialize session on mount and clean up duplicate state)graph LR
subgraph UI Layer
BB[BrandBar.vue]
APP[App.vue]
MOD[Proposal/Amendment Modals]
end
subgraph State & Session
US[useSession.ts Composable]
AUTH[src/utils/auth.ts]
end
subgraph External & Storage
LS[(localStorage)]
FR[Freighter Wallet Extension]
API[AuthService / Backend]
end
APP -->|initSession| US
BB -->|connect / display| US
MOD -->|read wallet / auth| US
US -->|read / write token| LS
US -->|parse JWT| AUTH
US -->|getAddress / setAllowed| FR
US -->|loginFreighter| API
useSession will catch the error, log a warning, and keep or revert the state cleanly without crashing the UI.localStorage contains an invalid JWT string, parseJwt() returns null, prompting useSession to clear the bad token and reset state.Verify that the user’s wallet connection and JWT authentication remain intact and reactive across page refreshes, and that connection/disconnection lifecycles function properly without regressions in API request authorization.
BrandBar.vue and approve connection.authToken is saved in localStorage.BrandBar.vue immediately displays the truncated wallet address without requiring the user to click “Connect Wallet” again.Authorization: Bearer <token> header without authentication failure.localStorage items are cleared, reactive state resets, and BrandBar.vue updates to “Connect Wallet”.localStorage renders “Connect Wallet” cleanly with no errors.hasFreighter() returns false and clicking connect displays a descriptive message rather than throwing unhandled rejections.localStorage is safely purged during hydration.useSession.ts provides a centralized reactive store for wallet address, authentication token, user ID, and connection status, with automatic local persistence and hydration.
walletAddress, authToken, userId, isConnecting, isInitialized) to maintain shared session state across all consumer components.initSession() to restore saved credentials (authToken and walletAddress) from localStorage, validate with parseJwt(), and verify Freighter extension availability via freighter.isConnected() and freighter.isAllowed().connectWallet() to orchestrate permission request via freighter.setAllowed(), fetch public address via freighter.getAddress(), execute AuthService.loginFreighter, store authToken and walletAddress in localStorage, and update reactive session state.disconnectWallet() to clear stored tokens and wallet data from localStorage and reset reactive state.isAuthenticated, truncatedAddress, hasFreighter, and connection status flags.BrandBar.vue and App.vue consume useSession.ts, automatically restoring and displaying the active wallet address upon reload without user intervention.
App.vue on-mount lifecycle to invoke initSession() from useSession, ensuring wallet and auth state are restored immediately during startup.BrandBar.vue to bind wallet button text and connection trigger directly to useSession's isAuthenticated, truncatedAddress, isConnecting, and connectWallet / disconnectWallet.BrandBar.vue and App.vue in favor of centralized composable methods.The complete wallet persistence flow is verified across reloads, active voting/proposal actions, and logout scenarios.
CommentService, ProposalService, AmendmentService) continue to attach the bearer token after page reload.localStorage tokens, expired JWTs, Freighter wallet disconnection, and missing browser extensions to ensure graceful fallback without runtime errors.