Something went wrong. Try again.
A social knowledge tool for research trails, built on ATProto semble.so
research-tool social-network tools-for-thought atproto
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495import { Response } from 'express';import { AuthenticationError, PdsUnavailableError,} from '../../core/AuthenticationError';
export abstract class Controller { protected abstract executeImpl(req: any, res: Response): Promise<any>;
public async execute(req: any, res: Response): Promise<void> { try { await this.executeImpl(req, res); } catch (err) { console.log(`[Controller]: Uncaught controller error`); console.log(err); this.fail(res, 'An unexpected error occurred'); } }
public static jsonResponse(res: Response, code: number, message: string) { return res.status(code).json({ message }); }
public ok<T>(res: Response, dto?: T) { if (dto) { return res.status(200).json(dto); } else { return res.sendStatus(200); } }
public created<T>(res: Response, dto?: T) { if (dto) { return res.status(201).json(dto); } else { return res.sendStatus(201); } }
public badRequest(res: Response, message?: string) { return Controller.jsonResponse(res, 400, message || 'Bad request'); }
public unauthorized(res: Response, message?: string, code?: string) { if (code) { return res.status(401).json({ message: message || 'Unauthorized', code }); } return Controller.jsonResponse(res, 401, message || 'Unauthorized'); }
public forbidden(res: Response, message?: string) { return Controller.jsonResponse(res, 403, message || 'Forbidden'); }
public notFound(res: Response, message?: string, code?: string) { if (code) { return res.status(404).json({ message: message || 'Not found', code }); } return Controller.jsonResponse(res, 404, message || 'Not found'); }
public conflict(res: Response, message?: string) { return Controller.jsonResponse(res, 409, message || 'Conflict'); }
public tooMany(res: Response, message?: string) { return Controller.jsonResponse(res, 429, message || 'Too many requests'); }
public fail(res: Response, error: Error | string) { console.log(error); return res.status(500).json({ message: error.toString(), }); }
protected handleError(res: Response, error: Error): Response { // Must precede the AuthenticationError check (it is a subclass). A // transient PDS failure: keep the user signed in and let them retry. if (error instanceof PdsUnavailableError) { return res .status(503) .json({ message: error.message, code: 'PDS_UNAVAILABLE' }); } if (error instanceof AuthenticationError) { // AuthenticationError originates from PDS agent authentication (the // server-side ATProto OAuth session), not from the app's own JWT. // The distinct code lets the frontend prompt re-authentication // instead of treating this as a generic session expiry. return this.unauthorized(res, error.message, 'PDS_SESSION_EXPIRED'); } return this.fail(res, error); }}