···11+// Initialize all stores with shared KV instance
22+import { getKv } from "./kv.ts";
33+import { SessionStore } from "./session-store.ts";
44+import { OAuthStateStore } from "./oauth-state-store.ts";
55+66+const kv = await getKv();
77+88+export const sessionStore = new SessionStore(kv);
99+export const oauthStateStore = new OAuthStateStore(kv);
+8-12
frontend/src/routes/middleware.ts
···11-import { UserSessionManager, atprotoClient } from "../config.ts";
11+import { atprotoClient } from "../config.ts";
22+import { sessionStore } from "../lib/stores.ts";
2334export interface AuthenticatedUser {
45 handle?: string;
···13141415export async function withAuth(req: Request): Promise<RouteContext> {
1516 // Get current user info (this already restores tokens from session)
1616- const currentUser = await UserSessionManager.getCurrentUser(req);
1717+ const currentUser = await sessionStore.getCurrentUser(req);
17181818- // Check if we need to refresh the session cookie with updated tokens
1919+ // Check if we need to update the session with refreshed tokens
1920 let sessionCookieHeader: string | undefined;
2021 if (currentUser.isAuthenticated) {
2122 const tokens = atprotoClient.getTokenStorage();
2223 if (tokens && tokens.accessToken) {
2323- // Refresh the session cookie to extend expiration and update any refreshed tokens
2424- const userData = {
2525- handle: currentUser.handle,
2626- sub: currentUser.sub,
2727- tokens: tokens,
2828- };
2929- sessionCookieHeader = await UserSessionManager.createSessionCookie(
3030- userData
3131- );
2424+ // Update the session with any refreshed tokens
2525+ await sessionStore.updateTokensFromRequest(req, tokens);
2626+2727+ // No need to set cookie header since session ID remains the same
3228 }
3329 }
3430
+31-12
frontend/src/routes/oauth.ts
···22import {
33 atprotoClient,
44 oauthConfig,
55- OAuthStateManager,
66- UserSessionManager,
75} from "../config.ts";
66+import { sessionStore, oauthStateStore } from "../lib/stores.ts";
77+import { createSessionCookie, clearSessionCookie } from "../lib/session-store.ts";
8899async function handleOAuthAuthorize(req: Request): Promise<Response> {
1010 try {
1111 // Clear any existing auth state before new login attempt
1212- atprotoClient.oauth.logout();
1212+ atprotoClient.oauth?.logout();
13131414 const formData = await req.formData();
1515 const loginHint = formData.get("loginHint") as string;
···1818 return new Response("Missing login hint", { status: 400 });
1919 }
20202121+ if (!atprotoClient.oauth) {
2222+ return new Response("OAuth client not configured", { status: 500 });
2323+ }
2424+2125 const authResult = await atprotoClient.oauth.authorize({
2226 loginHint,
2327 redirectUri: oauthConfig.redirectUri,
···2529 });
26302731 // Store OAuth state for later verification
2828- OAuthStateManager.store(authResult.state, authResult.codeVerifier);
3232+ await oauthStateStore.store(authResult.state, authResult.codeVerifier);
29333034 // Redirect to authorization URL
3135 return Response.redirect(authResult.authorizationUrl, 302);
···5862 }
59636064 // Retrieve stored code verifier
6161- const codeVerifier = OAuthStateManager.retrieve(state);
6565+ const codeVerifier = await oauthStateStore.retrieve(state);
6266 if (!codeVerifier) {
6367 return Response.redirect(
6468 new URL(
···7074 );
7175 }
72767777+ if (!atprotoClient.oauth) {
7878+ return Response.redirect(
7979+ new URL(
8080+ "/login?error=" + encodeURIComponent("OAuth client not configured"),
8181+ req.url
8282+ ),
8383+ 302
8484+ );
8585+ }
8686+7387 // Exchange code for tokens
7488 await atprotoClient.oauth.handleCallback({
7589 code,
···7993 });
80948195 // Fetch and store user info
8282- const userData = await UserSessionManager.refreshUserInfo();
9696+ const userData = await sessionStore.refreshUserInfo();
83978484- // Redirect to main app on successful login with session cookie
8585- const sessionCookie = await UserSessionManager.createSessionCookie(
8686- userData
8787- );
9898+ // Create new session and get session cookie
9999+ const sessionId = await sessionStore.createSessionFromUserData(userData);
100100+ const sessionCookie = createSessionCookie(sessionId);
101101+88102 return new Response(null, {
89103 status: 302,
90104 headers: {
···105119}
106120107121async function handleLogout(req: Request): Promise<Response> {
108108- atprotoClient.oauth.logout();
122122+ // Delete the session from KV store
123123+ await sessionStore.deleteSessionFromRequest(req);
124124+125125+ // Logout from OAuth client
126126+ atprotoClient.oauth?.logout();
127127+109128 return new Response(null, {
110129 status: 302,
111130 headers: {
112131 Location: new URL("/login", req.url).toString(),
113113- "Set-Cookie": UserSessionManager.createClearCookie(),
132132+ "Set-Cookie": clearSessionCookie(),
114133 },
115134 });
116135}
+3-1
frontend/src/routes/pages.tsx
···11import type { Route } from "@std/http/unstable-route";
22import { render } from "preact-render-to-string";
33-import { withAuth } from "./middleware.ts";
33+import { withAuth, requireAuth } from "./middleware.ts";
44import { atprotoClient } from "../config.ts";
55import { buildAtUri } from "../utils/at-uri.ts";
66import { IndexPage } from "../pages/IndexPage.tsx";
···15151616async function handleIndexPage(req: Request): Promise<Response> {
1717 const context = await withAuth(req);
1818+ const authResponse = requireAuth(context, req);
1919+ if (authResponse) return authResponse;
18201921 // Slice list page - get real slices from AT Protocol
2022 let slices: Array<{ id: string; name: string; createdAt: string }> = [];