Split up server.ts
This commit is contained in:
parent
47827494e3
commit
8e44fe7d7d
30
server/src/api/openapi.ts
Normal file
30
server/src/api/openapi.ts
Normal 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);
|
||||
};
|
||||
}
|
||||
35
server/src/api/repositories.ts
Normal file
35
server/src/api/repositories.ts
Normal 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" });
|
||||
}
|
||||
}
|
||||
@ -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(
|
||||
|
||||
37
server/src/util/seedforges.ts
Normal file
37
server/src/util/seedforges.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user