import type { Application, RequestHandler, Response } from "express"; import { Router } from "express"; import { z } from "zod/v4"; import { DirectoryMembershipCommandSchema, DirectoryMembershipQuerySchema, } from "../../../common/directory-memberships"; import type { DirectoryMembershipUseCases } from "../../application/directory-membership.use-cases"; import { buildDirectoryMembershipResponse } from "../../application/directory-membership-response.builder"; const ScopeSchema = z.strictObject({ companyId: z.uuid() }); const AssetScopeSchema = ScopeSchema.extend({ assetId: z.uuid() }); function fail(response: Response, code: string) { response .status(code === "INVALID_REQUEST" ? 400 : code.endsWith("NOT_FOUND") ? 404 : 409) .json({ code, requestId: response.getHeader("x-request-id") }); } export function registerDirectoryMembershipRoutes( app: Application, service: DirectoryMembershipUseCases, authenticate: RequestHandler ) { const router = Router(); router.get("/:companyId", (request, response, next) => { const scope = ScopeSchema.safeParse(request.params); const query = DirectoryMembershipQuerySchema.safeParse(request.query); if (!(scope.success && query.success)) { fail(response, "INVALID_REQUEST"); return; } service .list(scope.data.companyId, query.data) .then((result) => { if (!result.isSuccess) { fail(response, result.error.code); return; } response.json({ memberships: result.data.memberships.map(buildDirectoryMembershipResponse), nextCursor: result.data.nextCursor, }); }) .catch(next); }); router.get("/:companyId/:assetId/current", (request, response, next) => { const scope = AssetScopeSchema.safeParse(request.params); if (!(scope.success && z.strictObject({}).safeParse(request.query).success)) { fail(response, "INVALID_REQUEST"); return; } service .list(scope.data.companyId, { assetId: scope.data.assetId, pageSize: 1 }) .then((result) => { if (!result.isSuccess) { fail(response, result.error.code); return; } const item = result.data.memberships[0]; response.json({ membership: item ? buildDirectoryMembershipResponse(item) : null }); }) .catch(next); }); router.post("/:companyId/:assetId", (request, response, next) => { const scope = AssetScopeSchema.safeParse(request.params); const body = DirectoryMembershipCommandSchema.safeParse(request.body); const actor = z .object({ userId: z.uuid() }) .safeParse("session" in request ? request.session : undefined); if ( !( scope.success && body.success && actor.success && z.strictObject({}).safeParse(request.query).success ) ) { fail(response, "INVALID_REQUEST"); return; } service .execute(scope.data.companyId, scope.data.assetId, body.data, actor.data.userId) .then((result) => { if (!result.isSuccess) { fail(response, result.error.code); return; } response.json({ membership: buildDirectoryMembershipResponse(result.data) }); }) .catch(next); }); app.use("/api/asset-directory-memberships", authenticate, router); }