core/coordinators/payload.coordinator.ts

core/coordinators/payload.coordinator.ts is a file in Bane's Lab Build Scripts. 134 lines of code and 28 definitions.

import type { CatalogSource, DiscoverySource, PayloadAddress } from "#types/payload.types";
import {
    FULL_TEXT_FOLDER,
    FULL_TEXT_ROUTE,
    JSON_ROUTE,
    MARKDOWN_EXTENSION,
} from "#configuration/constants/site.constants";
import type { IncomingMessage, ServerResponse } from "node:http";
import { fullTextParts, fullTextRoutes, routeOf } from "#core/selectors/site.selector";
import { markdownRouteOf, pageIdOf, pathOf } from "#core/resolvers/payload.resolver";
import { renderFullText, renderMarkdownPage } from "#core/formatters/page.formatter";
import type { Discovery } from "#types/site.types";
import { MISSING_PAGE_ERROR } from "#configuration/strings/payload.strings";
import { renderRoutePayload } from "#core/formatters/site.formatter";

type Next = () => void;
type Handler = (request: IncomingMessage, response: ServerResponse, next: Next) => void;

const JSON_TYPE = "application/json; charset=utf-8";
const MARKDOWN_TYPE = "text/markdown; charset=utf-8";
const SLASH = "/";
const NOT_FOUND = 404;
const OK = 200;
const JSON_INDENT = 2;

const HEADERS: readonly (readonly [string, string])[] = [
    ["Access-Control-Allow-Origin", "*"],
    ["Cache-Control", "no-store"],
];

const renderMissing = function renderMissing(id: string): string {
    return `${JSON.stringify({ error: MISSING_PAGE_ERROR, id }, null, JSON_INDENT)}\n`;
};

const answer = function answer(response: ServerResponse, status: number, type: string, body: string): void {
    for (const [name, value] of HEADERS) {
        response.setHeader(name, value);
    }
    response.setHeader("Content-Type", type);
    response.statusCode = status;
    response.end(body);
};

const respondJson = async function respondJson(
    source: DiscoverySource,
    address: PayloadAddress,
    response: ServerResponse,
): Promise<void> {
    const discovery = await source();
    const route = routeOf(discovery, address.page, address.tab);
    if (route === undefined) {
        answer(response, NOT_FOUND, JSON_TYPE, renderMissing(address.page));
        return;
    }
    answer(response, OK, JSON_TYPE, renderRoutePayload(discovery, route));
};

const fullTextOf = function fullTextOf(discovery: Discovery, path: string): string | null {
    if (path === SLASH + FULL_TEXT_ROUTE) {
        return renderFullText(discovery, fullTextRoutes(discovery));
    }
    const part = fullTextParts(discovery).find((candidate) => SLASH + candidate.file === path);
    return part === undefined ? null : renderFullText(discovery, part.routes);
};

const isFullTextPath = function isFullTextPath(path: string): boolean {
    return path === SLASH + FULL_TEXT_ROUTE || path.startsWith(SLASH + FULL_TEXT_FOLDER + SLASH);
};

const respondMarkdown = async function respondMarkdown(
    source: DiscoverySource,
    path: string,
    response: ServerResponse,
    next: Next,
): Promise<void> {
    const discovery = await source();
    const full = fullTextOf(discovery, path);
    if (full !== null) {
        answer(response, OK, MARKDOWN_TYPE, full);
        return;
    }
    const route = discovery.routes.find((candidate) => candidate.path === path);
    if (route === undefined) {
        next();
        return;
    }
    answer(response, OK, MARKDOWN_TYPE, renderMarkdownPage(discovery.site, route));
};

const isRoutePath = function isRoutePath(discovery: Discovery, path: string): boolean {
    const address = pageIdOf(path);
    if (address !== null) {
        return routeOf(discovery, address.page, address.tab) !== undefined;
    }
    const markdown = markdownRouteOf(path);
    return isFullTextPath(path) || discovery.routes.some((route) => route.path === markdown);
};

const respondCatalog = async function respondCatalog(
    discoveries: DiscoverySource,
    catalog: CatalogSource,
    path: string,
    response: ServerResponse,
    next: Next,
): Promise<void> {
    if (isRoutePath(await discoveries(), path)) {
        next();
        return;
    }
    const body = (await catalog()).get(path);
    if (body === undefined) {
        next();
        return;
    }
    answer(response, OK, path.startsWith(JSON_ROUTE) ? JSON_TYPE : MARKDOWN_TYPE, body);
};

export const catalogMiddleware = function catalogMiddleware(
    discoveries: DiscoverySource,
    catalog: CatalogSource,
): Handler {
    return function serve(request, response, next): void {
        const path = pathOf(request.url ?? "");
        if (!path.startsWith(JSON_ROUTE) && !path.endsWith(MARKDOWN_EXTENSION)) {
            next();
            return;
        }
        void respondCatalog(discoveries, catalog, path, response, next);
    };
};

export const payloadMiddleware = function payloadMiddleware(source: DiscoverySource): Handler {
    return function serve(request, response, next): void {
        const url = request.url ?? "";
        const address = pageIdOf(url);
        if (address !== null) {
            void respondJson(source, address, response);
            return;
        }
        const markdown = isFullTextPath(pathOf(url)) ? pathOf(url) : markdownRouteOf(url);
        if (markdown === null) {
            next();
            return;
        }
        void respondMarkdown(source, markdown, response, next);
    };
};