quality / changes (push) Successful in 9s
quality / commitlint (push) Skipped
quality / docker-check (push) Skipped
CD / update-wiki (push) Successful in 6s
quality / web (push) Successful in 1m4s
quality / api (push) Successful in 54s
CD / quality (push) Successful in 2m17s
CD / publish (push) Successful in 2m21s
Worker сам ходит на origin по Cron Trigger; CFDM кладёт цели в KV и забирает результаты без POST /probe. Co-authored-by: Cursor <cursoragent@cursor.com>
148 lines
5.1 KiB
TypeScript
148 lines
5.1 KiB
TypeScript
import { resolve } from "node:path";
|
|
import Fastify from "fastify";
|
|
import {
|
|
serializerCompiler,
|
|
validatorCompiler,
|
|
type ZodTypeProvider,
|
|
} from "@fastify/type-provider-zod";
|
|
import type { AppConfig } from "./config.js";
|
|
import { loadConfig } from "./config.js";
|
|
import authPlugin from "./plugins/auth.js";
|
|
import cfClientPlugin from "./plugins/cf-client.js";
|
|
import { requireAuth } from "./plugins/auth.js";
|
|
import corsPlugin from "./plugins/cors.js";
|
|
import dbPlugin from "./plugins/db.js";
|
|
import errorHandlerPlugin from "./plugins/error-handler.js";
|
|
import { authRoutes, healthRoutes } from "./routes/health.js";
|
|
import { groupRoutes } from "./routes/groups.js";
|
|
import { serviceRoutes } from "./routes/services.js";
|
|
import { serviceGroupRoutes } from "./routes/service-groups.js";
|
|
import { serviceBindingRoutes } from "./routes/service-bindings.js";
|
|
import { domainRoutes } from "./routes/domains.js";
|
|
import { dnsRoutes } from "./routes/dns.js";
|
|
import { subdomainRoutes } from "./routes/subdomains.js";
|
|
import { certificateRoutes } from "./routes/certificates.js";
|
|
import { syncRoutes } from "./routes/sync.js";
|
|
import { originHealthCheckRoutes } from "./routes/origin-health-checks.js";
|
|
import { healthCheckRoutes } from "./routes/health-check.js";
|
|
import {
|
|
domainMonitorRoutes,
|
|
notificationRoutes,
|
|
} from "./routes/domain-monitors.js";
|
|
import { settingsRoutes } from "./routes/settings.js";
|
|
import { integrationsVpsTrackerRoutes } from "./routes/integrations-vps-tracker.js";
|
|
import { auditRoutes } from "./routes/audit.js";
|
|
import * as certificateService from "./services/certificate-service.js";
|
|
import {
|
|
createHealthCheckTask,
|
|
healthEngineFallbacksFromConfig,
|
|
scheduleHealthCheckJob,
|
|
} from "./services/health-check-scheduler.js";
|
|
import { fireEnsureHealthWorker } from "./services/health/health-worker-deploy.js";
|
|
import { AsyncTask, CronJob } from "toad-scheduler";
|
|
|
|
export interface BuildAppOptions {
|
|
config?: AppConfig;
|
|
memory?: boolean;
|
|
}
|
|
|
|
export async function buildApp(opts: BuildAppOptions = {}) {
|
|
const config = opts.config ?? loadConfig();
|
|
|
|
const app = Fastify({
|
|
logger: { level: config.logLevel },
|
|
}).withTypeProvider<ZodTypeProvider>();
|
|
|
|
app.setValidatorCompiler(validatorCompiler);
|
|
app.setSerializerCompiler(serializerCompiler);
|
|
|
|
await app.register(import("@fastify/sensible"));
|
|
await app.register(import("@fastify/helmet"), { contentSecurityPolicy: false });
|
|
await app.register(import("@fastify/rate-limit"), {
|
|
max: 300,
|
|
timeWindow: "1 minute",
|
|
});
|
|
await app.register(corsPlugin);
|
|
await app.register(errorHandlerPlugin);
|
|
await app.register(dbPlugin, { config, memory: opts.memory });
|
|
await app.register(cfClientPlugin, { config });
|
|
await app.register(authPlugin, { config });
|
|
|
|
await app.register(healthRoutes);
|
|
await app.register(authRoutes, { prefix: "/api/v1" });
|
|
await app.register(integrationsVpsTrackerRoutes, { prefix: "/api/v1" });
|
|
|
|
await app.register(
|
|
async (protectedApi) => {
|
|
protectedApi.addHook("onRequest", requireAuth);
|
|
await protectedApi.register(groupRoutes);
|
|
await protectedApi.register(serviceRoutes);
|
|
await protectedApi.register(serviceGroupRoutes);
|
|
await protectedApi.register(serviceBindingRoutes);
|
|
await protectedApi.register(domainRoutes);
|
|
await protectedApi.register(dnsRoutes);
|
|
await protectedApi.register(subdomainRoutes);
|
|
await protectedApi.register(certificateRoutes);
|
|
await protectedApi.register(syncRoutes);
|
|
await protectedApi.register(healthCheckRoutes);
|
|
await protectedApi.register(originHealthCheckRoutes);
|
|
await protectedApi.register(domainMonitorRoutes);
|
|
await protectedApi.register(notificationRoutes);
|
|
await protectedApi.register(settingsRoutes);
|
|
await protectedApi.register(auditRoutes);
|
|
},
|
|
{ prefix: "/api/v1" },
|
|
);
|
|
|
|
const staticDir = config.staticDir ?? resolve(process.cwd(), "static");
|
|
if (config.staticDir !== null) {
|
|
await app.register(import("@fastify/static"), {
|
|
root: staticDir,
|
|
wildcard: false,
|
|
});
|
|
|
|
app.setNotFoundHandler(async (_request, reply) => {
|
|
return reply.sendFile("index.html");
|
|
});
|
|
}
|
|
|
|
if (!opts.memory) {
|
|
await app.register(import("@fastify/schedule"));
|
|
|
|
const certTask = new AsyncTask(
|
|
"certificate-check",
|
|
async () => {
|
|
const n = await certificateService.runAllChecks(app.db);
|
|
app.log.info({ checked: n }, "certificate check completed");
|
|
},
|
|
(err) => {
|
|
app.log.warn({ err }, "certificate check failed");
|
|
},
|
|
);
|
|
|
|
app.scheduler.addCronJob(
|
|
new CronJob(
|
|
{ cronExpression: config.certCheckCron },
|
|
certTask,
|
|
{ preventOverrun: true },
|
|
),
|
|
);
|
|
|
|
const healthTask = createHealthCheckTask(app, config);
|
|
scheduleHealthCheckJob(app, config, healthTask);
|
|
app.decorate("reloadHealthCheckJob", () => {
|
|
scheduleHealthCheckJob(app, config, healthTask);
|
|
});
|
|
if (config.cloudflareApiToken) {
|
|
fireEnsureHealthWorker(
|
|
app.db,
|
|
app.cf,
|
|
healthEngineFallbacksFromConfig(config),
|
|
app.log,
|
|
);
|
|
}
|
|
}
|
|
|
|
return app;
|
|
}
|