Split up server.ts

This commit is contained in:
CaptOrb 2025-09-07 18:49:06 +01:00
parent 47827494e3
commit 8e44fe7d7d
4 changed files with 127 additions and 103 deletions

30
server/src/api/openapi.ts Normal file
View File

@ -0,0 +1,30 @@
import type {
Request as ExpressRequest,
Response as ExpressResponse,
} from "express";
import { OpenAPIBackend, type Request } from "openapi-backend";
import { listAvailableRepos } from "./repositories";
export function createOpenAPIBackend(): OpenAPIBackend {
const api = new OpenAPIBackend({
definition: "./openapi.yaml",
validate: true,
});
api.register({
listAvailableRepos,
notFound: (_c, _req, res) => res.status(404).json({ err: "not found" }),
validationFail: (c, _req, res) =>
res.status(400).json({ err: c.validation.errors }),
});
api.init();
return api;
}
export function createOpenAPIMiddleware(api: OpenAPIBackend) {
return (req: ExpressRequest, res: ExpressResponse): void => {
api.handleRequest(req as Request, req, res);
};
}

View File

@ -0,0 +1,35 @@
import type {
Request as ExpressRequest,
Response as ExpressResponse,
} from "express";
import type { Context } from "openapi-backend";
import { createForge } from "../services/forges";
import { getAccessToken } from "../types/user";
export async function listAvailableRepos(
_c: Context,
req: ExpressRequest,
res: ExpressResponse,
): Promise<ExpressResponse> {
try {
const userId = req.session?.userId;
const forgeType = req.session?.forgeType;
if (!userId || !forgeType) {
return res.status(401).json({ error: "Not authenticated" });
}
const accessToken = await getAccessToken(userId);
if (!accessToken) {
return res.status(401).json({ error: "Missing or expired access token" });
}
const forge = createForge(forgeType);
const repos = await forge.listRepositories(accessToken);
return res.json(repos);
} catch (err) {
console.error("Failed to fetch repos:", err);
return res.status(500).json({ error: "Failed to list repositories" });
}
}

View File

@ -1,114 +1,36 @@
import express, {
type Request as ExpressRequest,
type Response as ExpressResponse,
} from "express";
import express from "express";
import session from "express-session";
import { OpenAPIBackend, type Request } from "openapi-backend";
import { connectDB, pool } from "./config/db";
import { createOpenAPIBackend, createOpenAPIMiddleware } from "./api/openapi";
import { connectDB } from "./config/db";
import { config, isProduction } from "./config/env";
import authRouter from "./routes/auth";
import { createForge } from "./services/forges";
import { FORGE_IDS } from "./services/forges/constants";
import { getAccessToken } from "./types/user";
const app = express();
app.use(express.json());
// express session for Session cookie on the browser and Session object on the server
app.use(
session({
secret: config.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: config.IS_PRODUCTION,
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000, // 1 day
},
}),
);
app.use("/auth", authRouter);
async function seedForges() {
for (const forgeType of config.FORGE_TYPES) {
const forgeId = FORGE_IDS[forgeType];
if (forgeId === undefined) {
console.warn(`Skipping unknown forge type: ${forgeType}`);
continue;
}
let baseUrl: string;
switch (forgeType) {
case "gitea":
baseUrl = config.GITEA_URL;
break;
default:
console.warn(`Forge type ${forgeType} not supported`);
continue;
}
try {
await pool.query(
`INSERT INTO forges (forge_id, display_name, base_url)
VALUES ($1, $2, $3)
ON CONFLICT (forge_id)
DO UPDATE SET base_url = EXCLUDED.base_url`,
[forgeId, forgeType, baseUrl],
);
console.log(`Forge seeded: ${forgeType} (${baseUrl})`);
} catch (err) {
console.error(`Failed to seed forge ${forgeType}:`, err);
throw err;
}
}
}
// OpenAPI backend
const api = new OpenAPIBackend({
definition: "./openapi.yaml",
validate: true,
});
api.register({
listAvailableRepos: async (_c, req: ExpressRequest, res: ExpressResponse) => {
try {
const userId = req.session?.userId;
const forgeType = req.session?.forgeType;
if (!userId || !forgeType) {
return res.status(401).json({ error: "Not authenticated" });
}
const accessToken = await getAccessToken(userId);
if (!accessToken) {
return res
.status(401)
.json({ error: "Missing or expired access token" });
}
const forge = createForge(forgeType);
const repos = await forge.listRepositories(accessToken);
return res.json(repos);
} catch (err) {
console.error("Failed to fetch repos:", err);
return res.status(500).json({ error: "Failed to list repositories" });
}
},
notFound: (_c, _req, res) => res.status(404).json({ err: "not found" }),
validationFail: (c, _req, res) =>
res.status(400).json({ err: c.validation.errors }),
});
api.init();
app.use((req, res) => api.handleRequest(req as Request, req, res));
import { seedForges } from "./util/seedforges";
async function startServer() {
await connectDB();
await seedForges();
const app = express();
app.use(express.json());
// express session for Session cookie on the browser and Session object on the server
app.use(
session({
secret: config.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: config.IS_PRODUCTION,
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000, // 1 day
},
}),
);
app.use("/auth", authRouter);
const openapi = createOpenAPIBackend();
app.use(createOpenAPIMiddleware(openapi));
const PORT = config.APP_PORT;
app.listen(PORT, () => {
console.log(

View File

@ -0,0 +1,37 @@
import { pool } from "../config/db";
import { config } from "../config/env";
import { FORGE_IDS } from "../services/forges/constants";
export async function seedForges(): Promise<void> {
for (const forgeType of config.FORGE_TYPES) {
const forgeId = FORGE_IDS[forgeType];
if (forgeId === undefined) {
console.warn(`Skipping unknown forge type: ${forgeType}`);
continue;
}
let baseUrl: string;
switch (forgeType) {
case "gitea":
baseUrl = config.GITEA_URL;
break;
default:
console.warn(`Forge type ${forgeType} not supported`);
continue;
}
try {
await pool.query(
`INSERT INTO forges (forge_id, display_name, base_url)
VALUES ($1, $2, $3)
ON CONFLICT (forge_id)
DO UPDATE SET base_url = EXCLUDED.base_url`,
[forgeId, forgeType, baseUrl],
);
console.log(`Forge seeded: ${forgeType} (${baseUrl})`);
} catch (err) {
console.error(`Failed to seed forge ${forgeType}:`, err);
throw err;
}
}
}