Five more explicit review points, on the same PR branch. ## Every interface key commented Audited all 6 interfaces in the codebase. Two had partially-commented members (violates the "every key gets /** */" rule): AuthResult (apps/api/auth.service.ts) and SafeUserProfile (packages/shared) — both now fully commented. The other four (AuthTokenPayload, AuthContextValue, ErrorHandlingResult, ApiErrorResponse) were already compliant. ## Removed the Express namespace augmentation apps/api/src/types/express.d.ts (renamed to express-request.augment.ts in the last round) is gone entirely. requireAuth now attaches the authenticated profile to `res.locals.userProfile` — Express's own built-in per-request mechanism for exactly this — typed via a new AuthLocals interface and `Response<unknown, AuthLocals>`, instead of a project-wide `declare global` silently changing every Request's type whether or not it went through the middleware. ## ErrorHandlerService confirmed framework-agnostic It already had zero Express import. Documented this explicitly (in the package's index.ts and the new backend-architecture.md spec) as a deliberate split: ErrorHandlerService is framework-agnostic (would work behind Fastify too), ExpressServer/createErrorMiddleware are the actual Express integration layer. ## packages/express-tools: server init + route/middleware utilities New ExpressServer class, modeled on the pattern shared as a reference (adapted, not copied 1:1 — deliberately left out the reference's custom runtime param-type-validation system, since zod already does that job in this codebase and running two parallel validation mechanisms would be redundant, not "propre"): - setupCore() — the common cors/json/cookie-parser stack - addRoute() — registers a route, warns+skips instead of silently double-registering the same method+path - addMiddleware() / mountRouter() / setErrorHandler() - listen() - .instance — the raw Express app, for supertest Also added wrapAsyncHandler() — forwards a thrown/rejected error from an async handler to next(err) automatically, removing the manual try/catch/next(err) every route needed. apps/api/src/app.ts now builds via ExpressServer (createServer(), consumed by both server.ts's .listen() and createApp()'s .instance for tests). auth.routes.ts's signup/login handlers use wrapAsyncHandler instead of manual try/catch. cookie-parser/cors moved out of apps/api's own dependencies entirely — they're express-tools' concern now. ## assertIsNever (packages/shared/src/tools/) Exhaustiveness-check helper for switch/if-chains over a union: takes a `never`-typed value and throws, so a forgotten case in a later-added union member becomes a compile error instead of a silent runtime fallthrough. Verified for real (not just written and assumed correct): wrote a throwaway switch missing a case and confirmed `tsc` rejects it with the exact expected error, then deleted the scratch file. No existing switch/if-chain over a union in the codebase yet to retrofit it into — noted as ready for when one appears (e.g. the not-yet-built batch-cooking calculation module or recipe-import pipeline). ## specs/ updated New specs/backend-architecture.md — ExpressServer, wrapAsyncHandler, the res.locals decision (with the "why not declare global" reasoning spelled out), assertIsNever. error-handling.md and frontend-architecture.md cross-link to it instead of duplicating. README covers the same, briefly. ## Verification Full lint/mocha/cucumber/build green. Re-ran `node dist/server.js` standalone (mirrors Docker, no tsx) after the ExpressServer refactor: /health, a 404 (numeric 4040), and a real signup + GET /me round trip confirming res.locals-based auth actually works at runtime, not just that tsc accepts the types.
17 lines
846 B
TypeScript
17 lines
846 B
TypeScript
// Public entry point of the Express-specific tooling shared across any
|
|
// Express app in this monorepo (currently apps/api). Generic HTTP/Express
|
|
// infrastructure lives here — domain-specific code (auth, business logic)
|
|
// stays in the consuming app.
|
|
//
|
|
// Note the split: ErrorHandlerService (error-handler.service.ts) has zero
|
|
// dependency on Express — it's a plain "map an error to {status, body}"
|
|
// service that would work identically behind Fastify or any other
|
|
// framework. ExpressServer and createErrorMiddleware are the actual
|
|
// Express-specific layer, adapting framework-agnostic pieces (like
|
|
// ErrorHandlerService) onto Express's API.
|
|
|
|
export * from "./async-handler.js";
|
|
export * from "./error-handler.service.js";
|
|
export * from "./error-middleware.js";
|
|
export * from "./express-server.js";
|
|
export * from "./http-error.js";
|