"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.attachUpstreamResponseTimeout = exports.writeTimeoutResponse = exports.writeForwardResponseHead = exports.buildTimeoutSafeResponseHeaders = exports.UPSTREAM_RESPONSE_TIMEOUT_MESSAGE = void 0;
exports.UPSTREAM_RESPONSE_TIMEOUT_MESSAGE = 'Upstream response timed out while streaming response body';
function buildTimeoutSafeResponseHeaders(headers) {
    const safeHeaders = {};
    for (const [name, value] of Object.entries(headers)) {
        const normalized = name.toLowerCase();
        if (normalized === 'content-length' || normalized === 'transfer-encoding') {
            continue;
        }
        safeHeaders[name] = value;
    }
    return safeHeaders;
}
exports.buildTimeoutSafeResponseHeaders = buildTimeoutSafeResponseHeaders;
function writeForwardResponseHead(clientRes, statusCode, headers) {
    if (clientRes.headersSent)
        return;
    clientRes.writeHead(statusCode, buildTimeoutSafeResponseHeaders(headers));
}
exports.writeForwardResponseHead = writeForwardResponseHead;
function writeTimeoutResponse(clientRes, headers, message = exports.UPSTREAM_RESPONSE_TIMEOUT_MESSAGE) {
    if (clientRes.destroyed || clientRes.writableEnded)
        return;
    const contentType = String(headers['content-type'] ?? '').toLowerCase();
    try {
        if (contentType.includes('text/event-stream')) {
            const payload = {
                type: 'error',
                error: {
                    type: 'timeout_error',
                    message,
                },
            };
            clientRes.write(`event: error\ndata: ${JSON.stringify(payload)}\n\n`);
        }
        else if (!clientRes.headersSent) {
            clientRes.writeHead(504, { 'Content-Type': 'application/json' });
            clientRes.write(JSON.stringify({ error: message }));
        }
        else {
            clientRes.write(`\n${JSON.stringify({ error: message })}`);
        }
        clientRes.end();
    }
    catch {
        // Client may have disconnected while the upstream response was stalled.
    }
}
exports.writeTimeoutResponse = writeTimeoutResponse;
function attachUpstreamResponseTimeout(options) {
    const { upstreamReq, upstreamRes, clientRes, timeoutMs, onTimeout } = options;
    let settled = false;
    const clear = () => {
        settled = true;
        upstreamRes.setTimeout(0);
    };
    upstreamRes.setTimeout(timeoutMs, () => {
        if (settled)
            return;
        settled = true;
        const error = new Error(exports.UPSTREAM_RESPONSE_TIMEOUT_MESSAGE);
        writeTimeoutResponse(clientRes, upstreamRes.headers, error.message);
        onTimeout?.(error);
        upstreamRes.destroy(error);
        upstreamReq.destroy(error);
    });
    return clear;
}
exports.attachUpstreamResponseTimeout = attachUpstreamResponseTimeout;
//# sourceMappingURL=upstream-response-timeout.js.map