"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.__tsfTypeAliases = void 0;
exports.resolveStaticFilesOptions = resolveStaticFilesOptions;
exports.serveStaticFile = serveStaticFile;
const promises_1 = require("node:fs/promises");
const node_path_1 = require("node:path");
function resolveStaticFilesOptions(options, fallbackControllerEnabled = false) {
    if (!options)
        return undefined;
    const config = options === true ? {} : options;
    if (fallbackControllerEnabled && 'spaFallback' in config) {
        throw new Error('staticFiles.spaFallback cannot be used with fallbackController');
    }
    const index = config.index ?? 'index.html';
    const spaFallback = fallbackControllerEnabled || config.spaFallback === false ? undefined : (config.spaFallback ?? index);
    return {
        directory: config.directory ?? 'static',
        index,
        spaFallback,
        serveIndex: !fallbackControllerEnabled
    };
}
async function serveStaticFile(request, response, options) {
    const base = (0, node_path_1.resolve)(options.directory);
    let path = request.path;
    try {
        path = decodeURIComponent(path);
    }
    catch {
        response.writeHead(400, { 'content-type': 'text/plain' });
        response.end('Bad request');
        return response;
    }
    if (path === '/' && !options.serveIndex)
        return undefined;
    const relative = path === '/' ? options.index : path.replace(/^\/+/, '');
    let file = (0, node_path_1.resolve)(base, relative);
    if (!isPathInside(base, file)) {
        response.writeHead(400, { 'content-type': 'text/plain' });
        response.end('Bad request');
        return response;
    }
    try {
        const details = await (0, promises_1.stat)(file);
        if (!details.isFile())
            throw Object.assign(new Error('Not a file'), { code: 'ENOENT' });
    }
    catch (error) {
        if (!isNotFoundError(error))
            throw error;
        if (!options.spaFallback)
            return undefined;
        file = (0, node_path_1.resolve)(base, options.spaFallback);
        if (!isPathInside(base, file)) {
            response.writeHead(400, { 'content-type': 'text/plain' });
            response.end('Bad request');
            return response;
        }
    }
    let body;
    try {
        body = await (0, promises_1.readFile)(file);
    }
    catch (error) {
        if (isNotFoundError(error))
            return undefined;
        throw error;
    }
    response.writeHead(200, {
        'content-length': String(body.length),
        'content-type': getStaticContentType(file)
    });
    response.end(body);
    return response;
}
function isPathInside(base, candidate) {
    return candidate === base || candidate.startsWith(base.endsWith(node_path_1.sep) ? base : `${base}${node_path_1.sep}`);
}
function isNotFoundError(error) {
    return !!error && typeof error === 'object' && error.code === 'ENOENT';
}
function getStaticContentType(path) {
    switch ((0, node_path_1.extname)(path).toLowerCase()) {
        case '.html':
            return 'text/html; charset=utf-8';
        case '.js':
        case '.mjs':
            return 'text/javascript; charset=utf-8';
        case '.css':
            return 'text/css; charset=utf-8';
        case '.json':
            return 'application/json; charset=utf-8';
        case '.svg':
            return 'image/svg+xml';
        case '.png':
            return 'image/png';
        case '.jpg':
        case '.jpeg':
            return 'image/jpeg';
        case '.gif':
            return 'image/gif';
        case '.webp':
            return 'image/webp';
        case '.ico':
            return 'image/x-icon';
        case '.txt':
            return 'text/plain; charset=utf-8';
        case '.woff':
            return 'font/woff';
        case '.woff2':
            return 'font/woff2';
        default:
            return 'application/octet-stream';
    }
}
exports.__tsfTypeAliases = JSON.parse("[1,{\"ResolvedStaticFilesOptions\":{\"kind\":18,\"typeName\":\"ResolvedStaticFilesOptions\",\"types\":[{\"kind\":20,\"name\":\"directory\",\"type\":{\"kind\":6},\"optional\":false},{\"kind\":20,\"name\":\"index\",\"type\":{\"kind\":6},\"optional\":false},{\"kind\":20,\"name\":\"spaFallback\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"serveIndex\",\"type\":{\"kind\":8},\"optional\":false}]},\"StaticFilesOptions\":{\"kind\":18,\"typeName\":\"StaticFilesOptions\",\"types\":[{\"kind\":20,\"name\":\"directory\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"index\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"spaFallback\",\"type\":{\"kind\":12,\"types\":[{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":10,\"literal\":false}]},{\"kind\":4}]},\"optional\":true}]}}]")[1];
//# sourceMappingURL=static-files.js.map