"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MultiHost = exports.knownProtocols = void 0;
const zod_1 = require("zod");
const Origin_1 = require("./Origin");
exports.knownProtocols = {
    http: {
        secure: null,
        defaultPort: 80,
        withSsl: 'https',
        alpn: { specified: ['http/1.1'] },
        addXForwardedHeaders: true,
    },
    https: {
        secure: { ssl: true },
        defaultPort: 443,
        addXForwardedHeaders: true,
    },
    ws: {
        secure: null,
        defaultPort: 80,
        withSsl: 'wss',
        alpn: { specified: ['http/1.1'] },
        addXForwardedHeaders: true,
    },
    wss: {
        secure: { ssl: true },
        defaultPort: 443,
        addXForwardedHeaders: true,
    },
    ssh: {
        secure: { ssl: false },
        defaultPort: 22,
        addXForwardedHeaders: false,
    },
    dns: {
        secure: { ssl: false },
        defaultPort: 53,
        addXForwardedHeaders: false,
    },
};
const hasStringProtocol = (v) => zod_1.z.object({ protocol: zod_1.z.string() }).safeParse(v).success;
class MultiHost {
    constructor(options) {
        this.options = options;
    }
    /**
     * @description Use this function to bind the host to an internal port and configured options for protocol, security, and external port.
     *
     * @param internalPort - The internal port to be bound.
     * @param options - The protocol options for this binding.
     * @returns A multi-origin that is capable of exporting one or more service interfaces.
     * @example
     * In this example, we bind a previously created multi-host to port 80, then select the http protocol and request an external port of 8332.
     *
     * ```
      const uiMultiOrigin = await uiMulti.bindPort(80, {
        protocol: 'http',
        preferredExternalPort: 8332,
      })
     * ```
     */
    async bindPort(internalPort, options) {
        if (hasStringProtocol(options)) {
            return await this.bindPortForKnown(options, internalPort);
        }
        else {
            return await this.bindPortForUnknown(internalPort, options);
        }
    }
    async bindPortForUnknown(internalPort, options) {
        const binderOptions = {
            id: this.options.id,
            internalPort,
            ...options,
        };
        await this.options.effects.bind(binderOptions);
        return new Origin_1.Origin(this, internalPort, null, null);
    }
    async bindPortForKnown(options, internalPort) {
        const protoInfo = exports.knownProtocols[options.protocol];
        const preferredExternalPort = options.preferredExternalPort ||
            exports.knownProtocols[options.protocol].defaultPort;
        const sslProto = this.getSslProto(options);
        const addSsl = sslProto
            ? {
                addXForwardedHeaders: exports.knownProtocols[sslProto].addXForwardedHeaders,
                preferredExternalPort: exports.knownProtocols[sslProto].defaultPort,
                scheme: sslProto,
                alpn: 'alpn' in protoInfo ? protoInfo.alpn : null,
                ...('addSsl' in options ? options.addSsl : null),
            }
            : options.addSsl
                ? {
                    addXForwardedHeaders: false,
                    preferredExternalPort: 443,
                    scheme: sslProto,
                    alpn: null,
                    ...options.addSsl,
                }
                : null;
        const secure = protoInfo.secure ?? null;
        await this.options.effects.bind({
            id: this.options.id,
            internalPort,
            preferredExternalPort,
            addSsl,
            secure,
        });
        return new Origin_1.Origin(this, internalPort, options.protocol, sslProto);
    }
    getSslProto(options) {
        const proto = options.protocol;
        const protoInfo = exports.knownProtocols[proto];
        if (inObject('noAddSsl', options) && options.noAddSsl)
            return null;
        if ('withSsl' in protoInfo && protoInfo.withSsl)
            return protoInfo.withSsl;
        if (protoInfo.secure?.ssl)
            return proto;
        return null;
    }
}
exports.MultiHost = MultiHost;
function inObject(key, obj) {
    return key in obj;
}
//# sourceMappingURL=Host.js.map