pingql/apps/pay/src/index.ts

60 lines
2.0 KiB
TypeScript

import { Elysia } from "elysia";
import { migrate } from "./db";
import { routes } from "./routes";
import { checkPayments, expireProPlans } from "./monitor";
await migrate();
const SECURITY_HEADERS = {
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "DENY",
"Strict-Transport-Security": "max-age=63072000; includeSubDomains",
"Referrer-Policy": "strict-origin-when-cross-origin",
};
const CORS_ORIGIN = process.env.CORS_ORIGINS?.split(",") ?? ["https://pingql.com"];
const app = new Elysia()
.onAfterHandle(({ set }) => {
Object.assign(set.headers, SECURITY_HEADERS);
})
// CORS for web app
.onRequest(({ request, set }) => {
const origin = request.headers.get("origin") ?? "";
if (CORS_ORIGIN.includes(origin)) {
set.headers["access-control-allow-origin"] = origin;
set.headers["access-control-allow-credentials"] = "true";
set.headers["access-control-allow-methods"] = "GET, POST, OPTIONS";
set.headers["access-control-allow-headers"] = "Content-Type, Authorization";
}
})
.options("/*", ({ request }) => {
const origin = request.headers.get("origin") ?? "";
const allowed = CORS_ORIGIN.includes(origin) ? origin : CORS_ORIGIN[0];
return new Response(null, {
status: 204,
headers: {
"access-control-allow-origin": allowed,
"access-control-allow-credentials": "true",
"access-control-allow-methods": "GET, POST, OPTIONS",
"access-control-allow-headers": "Content-Type, Authorization",
},
});
})
.get("/", () => ({ name: "PingQL Pay", version: "1" }))
.use(routes)
.listen(3002);
console.log(`PingQL Pay running at http://localhost:${app.server?.port}`);
// Run immediately on startup, then every 30 seconds
checkPayments().catch((err) => console.error("Payment check failed:", err));
setInterval(() => {
checkPayments().catch((err) => console.error("Payment check failed:", err));
}, 30_000);
// Expire pro plans every hour
setInterval(() => {
expireProPlans().catch((err) => console.error("Plan expiry check failed:", err));
}, 60 * 60_000);