"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ApiClient = exports.APIPromise = void 0;
const agentkeepalive_1 = __importDefault(require("agentkeepalive"));
const constants_1 = require("./constants");
const error_1 = require("./error");
const streaming_1 = require("./streaming");
const utils_1 = require("./utils");
const version_1 = require("./version");
const defaultHttpAgent = new agentkeepalive_1.default({ keepAlive: true, timeout: 5 * 60 * 1000 });
function defaultParseResponse(props) {
    return __awaiter(this, void 0, void 0, function* () {
        const { response } = props;
        if (props.options.stream) {
            return new streaming_1.Stream(response);
        }
        const contentType = response.headers.get('content-type');
        if (contentType === null || contentType === void 0 ? void 0 : contentType.includes('application/json')) {
            const json = yield response.json();
            return json;
        }
        const text = yield response.text();
        return text;
    });
}
class APIPromise extends Promise {
    constructor(responsePromise, parseResponse = defaultParseResponse) {
        super((resolve) => {
            // this is maybe a bit weird but this has to be a no-op to not implicitly
            // parse the response body; instead .then, .catch, .finally are overridden
            // to parse the response
            resolve(null);
        });
        this.responsePromise = responsePromise;
        this.parseResponse = parseResponse;
    }
    parse() {
        if (!this.parsedPromise) {
            this.parsedPromise = this.responsePromise.then(this.parseResponse);
        }
        return this.parsedPromise;
    }
    then(onfulfilled, onrejected) {
        return this.parse().then(onfulfilled, onrejected);
    }
    catch(onrejected) {
        return this.parse().catch(onrejected);
    }
    finally(onfinally) {
        return this.parse().finally(onfinally);
    }
}
exports.APIPromise = APIPromise;
class ApiClient {
    constructor({ apiKey, baseURL }) {
        this.apiKey = apiKey;
        this.baseURL = baseURL || "";
        this.fetch = fetch;
    }
    defaultHeaders() {
        return Object.assign({ "Content-Type": "application/json", [`${constants_1.PORTKEY_HEADER_PREFIX}api-key`]: this.apiKey || "", [`${constants_1.PORTKEY_HEADER_PREFIX}package-version`]: `portkey-${version_1.VERSION}` }, (0, utils_1.getPlatformProperties)());
    }
    post(path, opts) {
        return this.methodRequest("post", path, opts);
    }
    generateError(status, errorResponse, message, headers) {
        return error_1.APIError.generate(status, errorResponse, message, headers);
    }
    request(opts) {
        return __awaiter(this, void 0, void 0, function* () {
            // Build the request.
            const { req, url } = this.buildRequest(opts);
            // Make the call to rubeus.
            const response = yield this.fetch(url, req).catch(utils_1.castToError);
            // Parse the response and check for errors.
            if (response instanceof Error) {
                if (response.name === 'AbortError') {
                    throw new error_1.APIConnectionTimeoutError();
                }
                throw new error_1.APIConnectionError({ cause: response });
            }
            if (!response.ok) {
                const errText = yield response.text().catch(() => 'Unknown');
                const errJSON = (0, streaming_1.safeJSON)(errText);
                const errMessage = errJSON ? undefined : errText;
                throw this.generateError(response.status, errJSON, errMessage, (0, streaming_1.createResponseHeaders)(response.headers));
            }
            // Receive and format the response.
            return { response, options: opts };
        });
    }
    buildRequest(opts) {
        const url = new URL(this.baseURL + opts.path);
        const { method, path, query, headers: headers = {}, body } = opts;
        const reqHeaders = Object.assign({}, this.defaultHeaders());
        const httpAgent = defaultHttpAgent;
        const req = Object.assign({ method, body: JSON.stringify(body), headers: reqHeaders }, (httpAgent && { agent: httpAgent }));
        return { req: req, url: url.toString() };
    }
    methodRequest(method, path, opts) {
        return new APIPromise(this.request(Object.assign({ method, path }, opts)));
    }
}
exports.ApiClient = ApiClient;
//# sourceMappingURL=baseClient.js.map