import { HttpError } from "@batch-cooking/error-tools"; import { wrapAsyncHandler } from "@batch-cooking/express-tools"; import { browseSourceSchema, createRecipeSchema, ErrorCode } from "@batch-cooking/shared"; import { Router } from "express"; import { type AuthLocals, requireAuth } from "../../middlewares/require-auth.js"; import { browseSource, importSourceItem, previewSourceItem } from "./sources.service.js"; /** * Router mounted at `/sources` in app.ts — browsing/previewing a * household's *enabled* external recipe sources (see `sources.service.ts`). * Every route requires a session, same posture as `/recipes`/`/house`: this * is app content scoped to the viewer's household, not signup-time * reference data (contrast `/reference/sources`, which just lists what * exists, public, no auth needed). */ export const sourcesRouter = Router(); /** Route params are typed `string | undefined` by Express even for a segment that always matches when the route does — this just satisfies TS, the branch is unreachable in practice. */ function requireParam(value: string | undefined): string { if (value === undefined) { throw new HttpError(400, ErrorCode.VALIDATION_ERROR, "Missing route parameter"); } return value; } sourcesRouter.get( "/:sourceKey/browse", requireAuth, wrapAsyncHandler(async (req, res) => { const input = browseSourceSchema.parse(req.query); const { houseId } = res.locals.userProfile; res.status(200).json(await browseSource(requireParam(req.params.sourceKey), houseId, input)); }), ); sourcesRouter.get( "/:sourceKey/preview/:externalId", requireAuth, wrapAsyncHandler(async (req, res) => { const { houseId } = res.locals.userProfile; res .status(200) .json( await previewSourceItem( requireParam(req.params.sourceKey), requireParam(req.params.externalId), houseId, ), ); }), ); sourcesRouter.post( "/:sourceKey/import/:externalId", requireAuth, wrapAsyncHandler(async (req, res) => { const input = createRecipeSchema.parse(req.body); const { id: authorId, houseId } = res.locals.userProfile; res .status(201) .json( await importSourceItem( requireParam(req.params.sourceKey), requireParam(req.params.externalId), input, authorId, houseId, ), ); }), );