From 8a7682e953a1df0487f003225f46733477c6e873 Mon Sep 17 00:00:00 2001 From: Michael Wolf Date: Sat, 17 Jan 2026 16:19:32 -0600 Subject: [PATCH] Split services into core and request --- TODO.md | 2 -- express/app.ts | 18 ++++++++-------- express/auth/routes.ts | 16 +++++++-------- express/basic/login.ts | 6 +++--- express/basic/logout.ts | 8 ++++---- express/basic/routes.ts | 8 ++++---- express/{services => core}/index.ts | 32 ++++++++--------------------- express/handlers.ts | 4 ++-- express/request/index.ts | 25 ++++++++++++++++++++++ express/request/util.ts | 19 ++++++++--------- express/routes.ts | 4 ++-- express/util.ts | 7 +------ 12 files changed, 76 insertions(+), 73 deletions(-) rename express/{services => core}/index.ts (53%) create mode 100644 express/request/index.ts diff --git a/TODO.md b/TODO.md index cdf1df1..b4f24ad 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,5 @@ ## high importance -- [ ] nix services/ and split it up into core/ request/ - - [ ] Add unit tests all over the place. - ⚠️ Huge task - needs breakdown before starting diff --git a/express/app.ts b/express/app.ts index 417ad99..eb044aa 100644 --- a/express/app.ts +++ b/express/app.ts @@ -7,9 +7,11 @@ import { Session } from "./auth"; import { cli } from "./cli"; import { contentTypes } from "./content-types"; import { runWithContext } from "./context"; +import { core } from "./core"; import { httpCodes } from "./http-codes"; +import { request } from "./request"; import { routes } from "./routes"; -import { services } from "./services"; + // import { URLPattern } from 'node:url'; import { AuthenticationRequired, @@ -31,7 +33,7 @@ const app = express(); app.use(express.json()); app.use(express.urlencoded({ extended: true })); -services.logging.log({ source: "logging", text: ["1"] }); +core.logging.log({ source: "logging", text: ["1"] }); const processedRoutes: { [K in Method]: ProcessedRoute[] } = { GET: [], POST: [], @@ -50,9 +52,9 @@ routes.forEach((route: Route, _idx: number, _allRoutes: Route[]) => { const methodList = route.methods; const handler: InternalHandler = async ( - request: ExpressRequest, + expressRequest: ExpressRequest, ): Promise => { - const method = massageMethod(request.method); + const method = massageMethod(expressRequest.method); console.log("method", method); @@ -60,17 +62,17 @@ routes.forEach((route: Route, _idx: number, _allRoutes: Route[]) => { // XXX: Worth asserting this? } - console.log("request.originalUrl", request.originalUrl); + console.log("request.originalUrl", expressRequest.originalUrl); // Authenticate the request - const auth = await services.auth.validateRequest(request); + const auth = await request.auth.validateRequest(expressRequest); const req: Call = { pattern: route.path, - path: request.originalUrl, + path: expressRequest.originalUrl, method, parameters: { one: 1, two: 2 }, - request, + request: expressRequest, user: auth.user, session: new Session(auth.session, auth.user), }; diff --git a/express/auth/routes.ts b/express/auth/routes.ts index ae93c8f..b1787a2 100644 --- a/express/auth/routes.ts +++ b/express/auth/routes.ts @@ -5,7 +5,7 @@ import { z } from "zod"; import { contentTypes } from "../content-types"; import { httpCodes } from "../http-codes"; -import { services } from "../services"; +import { request } from "../request"; import type { Call, Result, Route } from "../types"; import { forgotPasswordInputParser, @@ -39,7 +39,7 @@ const loginHandler = async (call: Call): Promise => { const body = call.request.body; const { email, password } = loginInputParser.parse(body); - const result = await services.auth.login(email, password, "cookie", { + const result = await request.auth.login(email, password, "cookie", { userAgent: call.request.get("User-Agent"), ipAddress: call.request.ip, }); @@ -72,9 +72,9 @@ const loginHandler = async (call: Call): Promise => { // POST /auth/logout const logoutHandler = async (call: Call): Promise => { - const token = services.auth.extractToken(call.request); + const token = request.auth.extractToken(call.request); if (token) { - await services.auth.logout(token); + await request.auth.logout(token); } return jsonResponse(httpCodes.success.OK, { message: "Logged out" }); @@ -87,7 +87,7 @@ const registerHandler = async (call: Call): Promise => { const { email, password, displayName } = registerInputParser.parse(body); - const result = await services.auth.register( + const result = await request.auth.register( email, password, displayName, @@ -128,7 +128,7 @@ const forgotPasswordHandler = async (call: Call): Promise => { const body = call.request.body; const { email } = forgotPasswordInputParser.parse(body); - const result = await services.auth.createPasswordResetToken(email); + const result = await request.auth.createPasswordResetToken(email); // Always return success (don't reveal if email exists) if (result) { @@ -159,7 +159,7 @@ const resetPasswordHandler = async (call: Call): Promise => { const body = call.request.body; const { token, password } = resetPasswordInputParser.parse(body); - const result = await services.auth.resetPassword(token, password); + const result = await request.auth.resetPassword(token, password); if (!result.success) { return errorResponse( @@ -195,7 +195,7 @@ const verifyEmailHandler = async (call: Call): Promise => { ); } - const result = await services.auth.verifyEmail(token); + const result = await request.auth.verifyEmail(token); if (!result.success) { return errorResponse(httpCodes.clientErrors.BadRequest, result.error); diff --git a/express/basic/login.ts b/express/basic/login.ts index 7977a2b..dd9ac74 100644 --- a/express/basic/login.ts +++ b/express/basic/login.ts @@ -1,8 +1,8 @@ import { SESSION_COOKIE_NAME } from "../auth/token"; import { tokenLifetimes } from "../auth/types"; -import { services } from "../services"; -import type { Call, Result, Route } from "../types"; +import { request } from "../request"; import { html, redirect, render } from "../request/util"; +import type { Call, Result, Route } from "../types"; const loginHandler = async (call: Call): Promise => { if (call.method === "GET") { @@ -21,7 +21,7 @@ const loginHandler = async (call: Call): Promise => { return html(c); } - const result = await services.auth.login(email, password, "cookie", { + const result = await request.auth.login(email, password, "cookie", { userAgent: call.request.get("User-Agent"), ipAddress: call.request.ip, }); diff --git a/express/basic/logout.ts b/express/basic/logout.ts index 85a3e80..fcae1d8 100644 --- a/express/basic/logout.ts +++ b/express/basic/logout.ts @@ -1,13 +1,13 @@ import { SESSION_COOKIE_NAME } from "../auth/token"; -import { services } from "../services"; -import type { Call, Result, Route } from "../types"; +import { request } from "../request"; import { redirect } from "../request/util"; +import type { Call, Result, Route } from "../types"; const logoutHandler = async (call: Call): Promise => { // Extract token from cookie and invalidate the session - const token = services.auth.extractToken(call.request); + const token = request.auth.extractToken(call.request); if (token) { - await services.auth.logout(token); + await request.auth.logout(token); } // Clear the cookie and redirect to login diff --git a/express/basic/routes.ts b/express/basic/routes.ts index b68b139..c051397 100644 --- a/express/basic/routes.ts +++ b/express/basic/routes.ts @@ -1,7 +1,7 @@ import { DateTime } from "ts-luxon"; -import { services } from "../services"; -import type { Call, Result, Route } from "../types"; +import { request } from "../request"; import { html, render } from "../request/util"; +import type { Call, Result, Route } from "../types"; import { loginRoute } from "./login"; import { logoutRoute } from "./logout"; @@ -20,8 +20,8 @@ const routes: Record = { path: "/", methods: ["GET"], handler: async (_call: Call): Promise => { - const auth = services.auth; - const me = services.session.getUser(); + const _auth = request.auth; + const me = request.session.getUser(); const email = me.toString(); const c = await render("basic/home", { email }); diff --git a/express/services/index.ts b/express/core/index.ts similarity index 53% rename from express/services/index.ts rename to express/core/index.ts index daed08f..0aa8d49 100644 --- a/express/services/index.ts +++ b/express/core/index.ts @@ -1,20 +1,16 @@ -// services.ts - -import { AuthService } from "../auth"; -import { getCurrentUser } from "../context"; -import { db, migrate, migrationStatus, PostgresAuthStore } from "../database"; +import nunjucks from "nunjucks"; +import { db, migrate, migrationStatus } from "../database"; import { getLogs, log } from "../logging"; -import type { MaybeUser } from "../user"; -import nunjucks from 'nunjucks' +// FIXME: This doesn't belong here; move it somewhere else. const conf = { - templateEngine: () => { + templateEngine: () => { return { renderTemplate: (template: string, context: object) => { return nunjucks.renderString(template, context); }, - } - } + }; + }, }; const database = { @@ -40,25 +36,13 @@ const misc = { }, }; -const session = { - getUser: (): MaybeUser => { - return getCurrentUser(); - }, -}; - -// Initialize auth with PostgreSQL store -const authStore = new PostgresAuthStore(); -const auth = new AuthService(authStore); - // Keep this asciibetically sorted -const services = { - auth, +const core = { conf, database, logging, misc, random, - session, }; -export { services }; +export { core }; diff --git a/express/handlers.ts b/express/handlers.ts index 9a15231..adbaee1 100644 --- a/express/handlers.ts +++ b/express/handlers.ts @@ -1,11 +1,11 @@ import { contentTypes } from "./content-types"; +import { core } from "./core"; import { httpCodes } from "./http-codes"; -import { services } from "./services"; import type { Call, Handler, Result } from "./types"; const multiHandler: Handler = async (call: Call): Promise => { const code = httpCodes.success.OK; - const rn = services.random.randomNumber(); + const rn = core.random.randomNumber(); const retval: Result = { code, diff --git a/express/request/index.ts b/express/request/index.ts new file mode 100644 index 0000000..6f98811 --- /dev/null +++ b/express/request/index.ts @@ -0,0 +1,25 @@ +import { AuthService } from "../auth"; +import { getCurrentUser } from "../context"; +import { PostgresAuthStore } from "../database"; +import type { MaybeUser } from "../user"; +import { html, redirect, render } from "./util"; + +const util = { html, redirect, render }; + +const session = { + getUser: (): MaybeUser => { + return getCurrentUser(); + }, +}; + +// Initialize auth with PostgreSQL store +const authStore = new PostgresAuthStore(); +const auth = new AuthService(authStore); + +const request = { + auth, + session, + util, +}; + +export { request }; diff --git a/express/request/util.ts b/express/request/util.ts index e5b445d..e1d01f9 100644 --- a/express/request/util.ts +++ b/express/request/util.ts @@ -1,24 +1,23 @@ import { contentTypes } from "../content-types"; +import { core } from "../core"; import { executionContext } from "../execution-context"; import { httpCodes } from "../http-codes"; import type { RedirectResult, Result } from "../types"; -import {services} from '../services' +import { loadFile } from "../util"; +import { request } from "./index"; -import{loadFile}from'../util' - - -type NoUser={ +type NoUser = { [key: string]: unknown; } & { user?: never; -} +}; const render = async (path: string, ctx?: NoUser): Promise => { const fullPath = `${executionContext.diachron_root}/templates/${path}.html.njk`; const template = await loadFile(fullPath); - const user = services.session.getUser(); - const context = {user, ...ctx} - const engine = services.conf.templateEngine() + const user = request.session.getUser(); + const context = { user, ...ctx }; + const engine = core.conf.templateEngine(); const retval = engine.renderTemplate(template, context); return retval; @@ -43,4 +42,4 @@ const redirect = (location: string): RedirectResult => { }; }; -export { render, html, redirect }; +export { html, redirect, render }; diff --git a/express/routes.ts b/express/routes.ts index 8fa77ca..090b7aa 100644 --- a/express/routes.ts +++ b/express/routes.ts @@ -5,9 +5,9 @@ import { DateTime } from "ts-luxon"; import { authRoutes } from "./auth/routes"; import { routes as basicRoutes } from "./basic/routes"; import { contentTypes } from "./content-types"; +import { core } from "./core"; import { multiHandler } from "./handlers"; import { httpCodes } from "./http-codes"; -import { services } from "./services"; import type { Call, Result, Route } from "./types"; // FIXME: Obviously put this somewhere else @@ -35,7 +35,7 @@ const routes: Route[] = [ handler: async (_call: Call): Promise => { console.log("starting slow request"); - await services.misc.sleep(2); + await core.misc.sleep(2); console.log("finishing slow request"); const retval = okText("that was slow"); diff --git a/express/util.ts b/express/util.ts index 6aba4e9..e818ad8 100644 --- a/express/util.ts +++ b/express/util.ts @@ -1,5 +1,4 @@ import { readFile } from "node:fs/promises"; -import nunjucks from "nunjucks"; // FIXME: Handle the error here const loadFile = async (path: string): Promise => { @@ -9,8 +8,4 @@ const loadFile = async (path: string): Promise => { return data; }; - - -export { - loadFile, -} +export { loadFile };