const assert = require("node:assert/strict"); const { createRequire } = require("node:module"); const nodeRequire = createRequire(__filename); const contextPath = "../src/routes/context.js"; const projectRoutesPath = "../src/routes/projects.js"; const ossClientPath = "../src/ossClient.js"; function passThrough(_req, _res, next) { next(); } function createMockResponse() { const res = {}; res.status = (statusCode) => { res.statusCode = statusCode; return res; }; res.json = (body) => { res.body = body; return res; }; return res; } function loadProjectRouter(pool, ossClient) { const express = nodeRequire("express"); const router = express.Router(); const contextResolvedPath = nodeRequire.resolve(contextPath); const projectsResolvedPath = nodeRequire.resolve(projectRoutesPath); const ossResolvedPath = nodeRequire.resolve(ossClientPath); const originalContextModule = nodeRequire.cache[contextResolvedPath]; const originalProjectsModule = nodeRequire.cache[projectsResolvedPath]; const originalOssModule = nodeRequire.cache[ossResolvedPath]; delete nodeRequire.cache[projectsResolvedPath]; nodeRequire.cache[contextResolvedPath] = { id: contextResolvedPath, filename: contextResolvedPath, loaded: true, exports: { requireAuth: passThrough, pool, withTransaction: async (fn) => fn(pool), computeNextRevision: () => ({ nextRevision: 1 }), normalizeRevisionValue: (value) => Number(value || 0), shouldRejectStaleRevision: () => false, formatGenerationTaskRow: (row) => row, normalizeGenerationTaskPayload: (body) => ({ value: body }), normalizeProjectOssKey: (value) => ({ value }), buildOssPublicUrl: (key) => `https://cdn.example/${key}`, requireOwnedProject: async () => true, upsertGenerationTask: async () => ({}), }, }; nodeRequire.cache[ossResolvedPath] = { id: ossResolvedPath, filename: ossResolvedPath, loaded: true, exports: ossClient, }; nodeRequire(projectRoutesPath).registerProjectRoutes(router); return { router, restore() { if (originalContextModule) nodeRequire.cache[contextResolvedPath] = originalContextModule; else delete nodeRequire.cache[contextResolvedPath]; if (originalProjectsModule) nodeRequire.cache[projectsResolvedPath] = originalProjectsModule; else delete nodeRequire.cache[projectsResolvedPath]; if (originalOssModule) nodeRequire.cache[ossResolvedPath] = originalOssModule; else delete nodeRequire.cache[ossResolvedPath]; }, }; } function getRouteHandler(router, method, routePath) { const layer = router.stack.find( (candidate) => candidate.route?.path === routePath && candidate.route.methods[method.toLowerCase()], ); const handler = layer?.route?.stack.at(-1)?.handle; if (!handler) throw new Error(`Route not found: ${method.toUpperCase()} ${routePath}`); return handler; } async function main() { const missing = new Error("OSS GET failed (404): NoSuchKey"); missing.status = 404; missing.code = "oss_no_such_key"; const { router, restore } = loadProjectRouter( { query: async () => ({ rows: [{ oss_key: "users/1/projects/missing/current/project.json" }] }) }, { isOssConfigured: () => true, getObject: async () => { throw missing; }, putObject: async () => ({}), }, ); try { const handler = getRouteHandler(router, "get", "/projects/:id/content"); const res = createMockResponse(); await handler( { params: { id: "workflow-missing" }, query: { resolveMedia: "1" }, user: { id: 1 } }, res, ); assert.equal(res.statusCode, 404); assert.equal(res.body.code, "project_content_missing"); } finally { restore(); } console.log("project route contract tests passed"); } main().catch((error) => { console.error(error); process.exit(1); });