pingql/apps/api/src/index.ts

55 lines
1.6 KiB
TypeScript

import { Elysia } from "elysia";
import { ingest } from "./routes/pings";
import { monitors } from "./routes/monitors";
import { account } from "./routes/auth";
import { internal } from "./routes/internal";
import { migrate } from "./db";
await migrate();
const SECURITY_HEADERS = {
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "DENY",
"Strict-Transport-Security": "max-age=63072000; includeSubDomains",
"X-XSS-Protection": "0",
"Referrer-Policy": "strict-origin-when-cross-origin",
};
const elysia = new Elysia()
.get("/", () => ({
name: "PingQL API",
version: "1",
docs: "https://pingql.com/docs",
}))
.use(account)
.use(monitors)
.use(ingest)
.use(internal);
// Wrap Elysia with Bun.serve to guarantee CORS + security headers on every response
const server = Bun.serve({
port: 3001,
async fetch(req) {
const origin = req.headers.get("origin") || "*";
const corsHeaders: Record<string, string> = {
"access-control-allow-origin": origin,
"access-control-allow-credentials": "true",
"access-control-allow-methods": "GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS",
"access-control-allow-headers": "Content-Type, Authorization",
...SECURITY_HEADERS,
};
if (req.method === "OPTIONS") {
return new Response(null, { status: 204, headers: corsHeaders });
}
const res = await elysia.handle(req);
for (const [k, v] of Object.entries(corsHeaders)) {
res.headers.set(k, v);
}
return res;
},
});
console.log(`PingQL API running at http://localhost:${server.port}`);