···77import { STATE_STORE } from '$lib/server/cache';
88import { logger } from '$lib/server/logger';
99import { HOUR } from '@atproto/common';
1010-import { getSessionManager } from '$lib/server/session';
1010+import { getSessionManager, SessionRestorationError } from '$lib/server/session';
11111212const clearExpiredStates = async () => {
1313 try {
···5050 event.locals.atpAgent = null;
5151 return resolve(event);
5252 }
5353+5354 const sessionManager = await getSessionManager();
5454- const { atpAgent, did, handle } = await sessionManager.getSessionFromRequest(event);
55555656- if(atpAgent == null){
5656+ try {
5757+ const { atpAgent, did, handle } = await sessionManager.getSessionFromRequest(event);
5858+5959+ if(atpAgent == null){
6060+ event.locals.session = null;
6161+ event.locals.atpAgent = null;
6262+ return resolve(event);
6363+ }
6464+6565+ // Store atpAgent in locals (server-side only, not serialized)
6666+ event.locals.atpAgent = atpAgent;
6767+6868+ // Store only serializable data in session (gets passed to client via load functions)
6969+ event.locals.session = {
7070+ did,
7171+ handle
7272+ };
7373+ } catch (err) {
7474+ if (err instanceof SessionRestorationError) {
7575+ //You can propagate this error to the frontend to let your users know their session unexpectedly ended
7676+ //I opted out of not completely implementing this since everyone may have a different idea of what to do in their apps
7777+ //For instance I would use the cache to create a flash message that when loaded it deletes and show it on the layout
7878+ } else {
7979+ // Unexpected error, re-throw
8080+ throw err;
8181+ }
8282+5783 event.locals.session = null;
5884 event.locals.atpAgent = null;
5959- return resolve(event);
6085 }
6161-6262- // Store atpAgent in locals (server-side only, not serialized)
6363- event.locals.atpAgent = atpAgent;
6464-6565- // Store only serializable data in session (gets passed to client via load functions)
6666- event.locals.session = {
6767- did,
6868- handle
6969- };
70867187 return resolve(event);
7288};
+25-4
src/lib/server/session.ts
···1313import type { NodeOAuthClient } from '@atproto/oauth-client-node';
1414import { logger } from '$lib/server/logger';
15151616+export class SessionRestorationError extends Error {
1717+ constructor(message: string) {
1818+ super(message);
1919+ this.name = 'SessionRestorationError';
2020+ }
2121+}
16221723// This is a sliding expiration for the cookie session. Can change it if you want it to be less or more.
1824// The actual atproto session goes for a while if it's a confidential client as long as it's refreshed
···5258 session.expiresAt = new Date(Date.now() + DEFAULT_EXPIRY);
5359 await this.db.update(sessionStore).set(session).where(eq(sessionStore.id, sessionId));
5460 }
6161+ try{
6262+ const oAuthSession = await this.atpOAuthClient.restore(session.did);
55635656- const oAuthSession = await this.atpOAuthClient.restore(session.did);
5757- const agent = new Agent(oAuthSession);
5858- return { atpAgent: agent, did: session.did, handle: session.handle };
6464+ const agent = new Agent(oAuthSession);
6565+ return { atpAgent: agent, did: session.did, handle: session.handle };
6666+ }catch (err){
6767+ const errorMessage = (err as Error).message;
6868+ logger.warn(`Error restoring session for did: ${session.did}, error: ${errorMessage}`);
6969+ //Counting any error when restoring a session as a failed session resume and deleting the users web browser session
7070+ //You can go further and capture different types of errors
7171+ await this.invalidateUserSessions(session.did);
7272+ throw new SessionRestorationError(`Failed to restore your session: ${errorMessage}. Please log in again.`);
7373+ }
5974 }
60756176 private setSessionTokenCookie(event: RequestEvent, token: string, expiresAt: Date): void {
···117132 if (!token) {
118133 return NULL_SESSION_RESPONSE;
119134 }
120120- return this.validateSessionToken(token);
135135+ try {
136136+ return await this.validateSessionToken(token);
137137+ } catch (err) {
138138+ //We delete the cookie on any error and pass along the error
139139+ this.deleteSessionTokenCookie(event);
140140+ throw err;
141141+ }
121142 }
122143123144}