"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.HttpCors = exports.HttpCorsOptionsMulti = exports.HttpCorsOptions = exports.CorsHeaders = void 0;
exports.resolveCorsOptions = resolveCorsOptions;
exports.handleCorsPreflight = handleCorsPreflight;
exports.prepareCorsResponseHeaders = prepareCorsResponseHeaders;
exports.applyCorsResponseHeaders = applyCorsResponseHeaders;
const tslib_1 = require("tslib");
const _a = tslib_1.__importStar(require("@zyno-io/ts-reflection/type-metadata-runtime"));
const headers_1 = require("./headers");
const __tsf_metadata_type = _a.createCompactMetadataRegistryV1("[1,[{\"kind\":14,\"type\":{\"kind\":6}},{\"kind\":8}]]", []);
exports.CorsHeaders = Symbol('CorsHeaders');
let _HttpCorsOptionsMetadata_1;
class HttpCorsOptions {
    hosts;
    paths;
    methods;
    credentials;
    allowHeaders;
    exposeHeaders;
    static __tsfType = _HttpCorsOptionsMetadata_1 = _a.decodeCompactMetadataV1("[1,{\"kind\":16,\"name\":\"HttpCorsOptions\",\"typeName\":\"HttpCorsOptions\",\"classType\":{\"$tsf\":0},\"properties\":[{\"name\":\"hosts\",\"type\":{\"kind\":14,\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":16,\"typeName\":\"RegExp\",\"classType\":{\"$tsf\":1}}]}},\"optional\":false},{\"name\":\"paths\",\"type\":{\"kind\":14,\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":16,\"typeName\":\"RegExp\",\"classType\":{\"$tsf\":1}}]}},\"optional\":true},{\"name\":\"methods\",\"type\":{\"$tsfType\":0},\"optional\":true},{\"name\":\"credentials\",\"type\":{\"$tsfType\":1},\"optional\":true},{\"name\":\"allowHeaders\",\"type\":{\"$tsfType\":0},\"optional\":true},{\"name\":\"exposeHeaders\",\"type\":{\"$tsfType\":0},\"optional\":true}],\"methods\":[],\"hasConstructor\":false,\"constructorParameters\":[]}]", [() => HttpCorsOptions, () => (typeof RegExp !== "undefined" ? RegExp : (typeof exports !== "undefined" ? exports.RegExp : undefined))], __tsf_metadata_type);
}
exports.HttpCorsOptions = HttpCorsOptions;
_HttpCorsOptionsMetadata_1.classType = HttpCorsOptions;
HttpCorsOptions.__tsfType = _HttpCorsOptionsMetadata_1;
let _HttpCorsOptionsMultiMetadata_1;
class HttpCorsOptionsMulti {
    options;
    constructor(options) {
        this.options = options;
    }
    static __tsfType = _HttpCorsOptionsMultiMetadata_1 = _a.decodeCompactMetadataV1("[1,{\"kind\":16,\"name\":\"HttpCorsOptionsMulti\",\"typeName\":\"HttpCorsOptionsMulti\",\"classType\":{\"$tsf\":0},\"properties\":[],\"methods\":[],\"hasConstructor\":true,\"constructorParameters\":[{\"name\":\"options\",\"type\":{\"kind\":14,\"type\":{\"kind\":16,\"typeName\":\"HttpCorsOptions\",\"classType\":{\"$tsf\":1}}},\"optional\":false,\"default\":false}]}]", [() => HttpCorsOptionsMulti, () => (typeof HttpCorsOptions !== "undefined" ? HttpCorsOptions : (typeof exports !== "undefined" ? exports.HttpCorsOptions : undefined))], __tsf_metadata_type);
}
exports.HttpCorsOptionsMulti = HttpCorsOptionsMulti;
_HttpCorsOptionsMultiMetadata_1.classType = HttpCorsOptionsMulti;
HttpCorsOptionsMulti.__tsfType = _HttpCorsOptionsMultiMetadata_1;
let _HttpCorsMetadata_1;
class HttpCors {
    static getResponseHeaders(response) {
        return response[exports.CorsHeaders];
    }
    static __tsfType = _HttpCorsMetadata_1 = _a.decodeCompactMetadataV1("[1,{\"kind\":16,\"name\":\"HttpCors\",\"typeName\":\"HttpCors\",\"classType\":{\"$tsf\":0},\"properties\":[],\"methods\":[],\"hasConstructor\":false,\"constructorParameters\":[]}]", [() => HttpCors], __tsf_metadata_type);
}
exports.HttpCors = HttpCors;
_HttpCorsMetadata_1.classType = HttpCors;
HttpCors.__tsfType = _HttpCorsMetadata_1;
function resolveCorsOptions(config, cors) {
    if (!cors)
        return [];
    const options = typeof cors === 'function' ? cors(config) : cors;
    return Array.isArray(options) ? options : [options];
}
function handleCorsPreflight(request, response, options) {
    if (request.method !== 'OPTIONS')
        return false;
    const descriptor = findMatchingCors(request, options);
    if (!descriptor)
        return false;
    response.writeHead(204, getCorsPreflightHeaders(request, descriptor));
    response.end();
    return true;
}
function prepareCorsResponseHeaders(request, response, options) {
    const descriptor = findMatchingCors(request, options);
    if (!descriptor)
        return undefined;
    const headers = getCorsResponseHeaders(request, descriptor);
    response[exports.CorsHeaders] = headers;
    return headers;
}
function applyCorsResponseHeaders(request, response, options) {
    const headers = HttpCors.getResponseHeaders(response) ?? prepareCorsResponseHeaders(request, response, options);
    if (!headers)
        return;
    for (const [name, value] of Object.entries(headers)) {
        response.setHeader(name, value);
    }
}
function findMatchingCors(request, options) {
    const origin = (0, headers_1.getRequestHeader)(request, 'origin');
    if (typeof origin !== 'string')
        return undefined;
    return options.find(option => {
        const hostMatches = option.hosts.some(host => {
            if (host === '*')
                return true;
            if (host instanceof RegExp)
                return host.test(origin);
            return host === origin;
        });
        if (!hostMatches)
            return false;
        return (!option.paths ||
            option.paths.some(path => {
                if (path instanceof RegExp)
                    return path.test(request.path);
                return request.path.startsWith(path);
            }));
    });
}
function getCorsPreflightHeaders(request, options) {
    const headers = {
        ...getCorsResponseHeaders(request, options),
        'Access-Control-Allow-Methods': options.methods?.join(',') ?? 'GET,HEAD,PUT,PATCH,POST,DELETE',
        'Content-Length': '0'
    };
    const requestedHeaders = (0, headers_1.getRequestHeader)(request, 'access-control-request-headers');
    if (options.allowHeaders)
        headers['Access-Control-Allow-Headers'] = options.allowHeaders.join(', ');
    else if (typeof requestedHeaders === 'string')
        headers['Access-Control-Allow-Headers'] = requestedHeaders;
    return headers;
}
function getCorsResponseHeaders(request, options) {
    const origin = (0, headers_1.getRequestHeader)(request, 'origin');
    const headers = {
        'Access-Control-Allow-Origin': typeof origin === 'string' ? origin : '*'
    };
    if (options.credentials)
        headers['Access-Control-Allow-Credentials'] = 'true';
    if (options.exposeHeaders)
        headers['Access-Control-Expose-Headers'] = options.exposeHeaders.join(', ');
    return headers;
}
//# sourceMappingURL=cors.js.map