import fastify from "fastify";
import owlPlugin from "./owl";
import redisPlugin from "./redis";
import tokensRoute from "./routes/tokens";
import tokensRepoPlugin from "./tokens";
import health from "./routes/health";
import queues from "./routes/queues";
import usageRoute from "./routes/usage";
import swagger from "@fastify/swagger";
import swaggerUi from "@fastify/swagger-ui";
import pack from "../../../package.json";
import basicAuthPlugin from "./basic-auth";
import tokenAuthPlugin from "./token-auth";
import activityPlugin from "./routes/activity";
import blipp from "fastify-blipp";
import cors from "@fastify/cors";
import telemetry from "./telemetry";
import sentryPlugin from "./sentry";
import loggerPlugin from "./logger";
import indexRoute from "./routes/index";
import { StructuredLogger } from "../shared/structured-logger";
import { jobsRepoPlugin } from "./jobs-repo";
import fastifyRateLimit from "@fastify/rate-limit";
import posthogPlugin from "./posthog";
export async function createServer({ port = 9181, host = "0.0.0.0", runningInDocker = false, redisFactory, passphrases, disableTelemetry, logger, jwtPublicKey, rateLimiter, postHogApiKey, }) {
    var _a;
    const app = fastify({
        logger: logger instanceof StructuredLogger ? logger.log : undefined,
        maxParamLength: 500,
    });
    if (!disableTelemetry) {
        app.register(sentryPlugin);
    }
    if (postHogApiKey) {
        app.register(posthogPlugin, {
            apiKey: postHogApiKey,
        });
    }
    app.register(fastifyRateLimit, {
        enableDraftSpec: true,
        max: (_a = rateLimiter === null || rateLimiter === void 0 ? void 0 : rateLimiter.max) !== null && _a !== void 0 ? _a : 10000,
        keyGenerator: (req) => { var _a; return (_a = req.headers.authorization) !== null && _a !== void 0 ? _a : req.ip; },
    });
    app.register(blipp);
    app.register(cors, {
        origin: "*",
    });
    const enableAdminBasedAuth = !!(passphrases === null || passphrases === void 0 ? void 0 : passphrases.length);
    app.decorate("adminBasedAuthEnabled", enableAdminBasedAuth);
    app.register(swagger, {
        openapi: {
            info: {
                title: "Quirrel API",
                description: "The Queueing Solution for Serverless.",
                version: pack.version,
                contact: {
                    email: "info@quirrel.dev",
                    name: "Quirrel",
                    url: "https://quirrel.dev",
                },
                license: {
                    name: "MIT License",
                    url: "https://github.com/quirrel-dev/quirrel/blob/main/LICENSE",
                },
            },
            externalDocs: {
                url: "https://docs.quirrel.dev",
                description: "Find general documentation here",
            },
            components: {
                securitySchemes: {
                    Token: enableAdminBasedAuth || jwtPublicKey
                        ? {
                            type: "http",
                            scheme: "bearer",
                            description: `Main auth scheme. Tokens can be issued via ${enableAdminBasedAuth
                                ? jwtPublicKey
                                    ? "JWT / Admin"
                                    : "Admin"
                                : "JWT"}.`,
                        }
                        : undefined,
                    Admin: enableAdminBasedAuth
                        ? {
                            type: "http",
                            scheme: "basic",
                            description: "Used for admin tasks like issuing new tokens. Username is ignored, password is specified via environment variables.",
                        }
                        : undefined,
                    Impersonation: enableAdminBasedAuth
                        ? {
                            type: "http",
                            scheme: "basic",
                            description: "Username must be the token ID to be impersonated, password is admin password.",
                        }
                        : undefined,
                },
            },
            tags: [
                {
                    name: "Queueing",
                },
                {
                    name: "DX",
                },
                {
                    name: "Admin",
                },
            ],
        },
    });
    app.register(swaggerUi, {
        routePrefix: "/documentation",
    });
    app.register(loggerPlugin, {
        logger,
    });
    app.register(redisPlugin, { redisFactory });
    app.register(owlPlugin);
    app.register(tokenAuthPlugin, {
        enable: enableAdminBasedAuth,
        passphrases: passphrases !== null && passphrases !== void 0 ? passphrases : [],
        jwtPublicKey,
    });
    app.register(jobsRepoPlugin);
    if (!disableTelemetry) {
        app.register(telemetry, { runningInDocker });
    }
    if (passphrases) {
        app.register(basicAuthPlugin, { passphrases });
        app.register(usageRoute, { prefix: "/usage" });
        if (!jwtPublicKey) {
            app.register(tokensRepoPlugin);
            app.register(tokensRoute, { prefix: "/tokens" });
        }
    }
    app.register(health, { prefix: "/health" });
    app.register(queues, { prefix: "/queues" });
    app.register(activityPlugin, { prefix: "/activity" });
    app.register(indexRoute);
    app.ready(async () => {
        var _a, _b, _c;
        const debug = false;
        if (debug) {
            app.blipp();
        }
        app.swagger();
        (_a = app.telemetrist) === null || _a === void 0 ? void 0 : _a.dispatch("ready");
        if (passphrases) {
            (_b = app.telemetrist) === null || _b === void 0 ? void 0 : _b.dispatch("auth enabled");
        }
        if (port !== 9181) {
            (_c = app.telemetrist) === null || _c === void 0 ? void 0 : _c.dispatch("custom port");
        }
    });
    await app.listen({
        port,
        host,
    });
    const { address, port: runningPort } = app.server.address();
    logger === null || logger === void 0 ? void 0 : logger.started(`${address}:${runningPort}`, !disableTelemetry);
    return {
        server: app.server,
        app,
        port,
        async close() {
            app.log.info("Closing.");
            await app.close();
        },
    };
}
//# sourceMappingURL=index.js.map