"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const getRegistryAuthInfo = require("registry-auth-token");
const memoize = require("lodash.memoize");
const pLimit = require("p-limit");
const crypto = require("crypto");
const mkdirp = require("mkdirp-promise");
const path = require("path");
const createWriteStreamAtomic = require("fs-write-stream-atomic");
exports.default = (client, opts) => {
    const limit = pLimit(opts.networkConcurrency);
    function getJSON(url) {
        return __awaiter(this, void 0, void 0, function* () {
            return limit(() => new Promise((resolve, reject) => {
                client.get(url, createOptions(url), (err, data, raw, res) => {
                    if (err)
                        return reject(err);
                    resolve(data);
                });
            }));
        });
    }
    function download(url, saveto, opts) {
        return limit(() => __awaiter(this, void 0, void 0, function* () {
            yield mkdirp(path.dirname(saveto));
            return new Promise((resolve, reject) => {
                client.fetch(url, createOptions(url), (err, res) => __awaiter(this, void 0, void 0, function* () {
                    if (err)
                        return reject(err);
                    const writeStream = createWriteStreamAtomic(saveto);
                    const actualShasum = crypto.createHash('sha1');
                    res
                        .on('response', start)
                        .on('data', (_) => { actualShasum.update(_); })
                        .on('error', reject)
                        .pipe(writeStream)
                        .on('error', reject)
                        .on('finish', finish);
                    function start(res) {
                        if (res.statusCode !== 200) {
                            return reject(new Error(`Invalid response: ${res.statusCode}`));
                        }
                        if (opts.onStart)
                            opts.onStart();
                        if (opts.onProgress && ('content-length' in res.headers)) {
                            const onProgress = opts.onProgress;
                            let downloaded = 0;
                            let size = +res.headers['content-length'];
                            res.on('data', (chunk) => {
                                downloaded += chunk.length;
                                onProgress(downloaded, size);
                            });
                        }
                    }
                    function finish() {
                        return __awaiter(this, void 0, void 0, function* () {
                            const digest = actualShasum.digest('hex');
                            if (opts.shasum && digest !== opts.shasum) {
                                reject(new Error(`Incorrect shasum (expected ${opts.shasum}, got ${digest})`));
                                return;
                            }
                            resolve();
                        });
                    }
                }));
            });
        }));
    }
    function createOptions(url) {
        const authInfo = getRegistryAuthInfo(url, { recursive: true });
        if (!authInfo)
            return {};
        switch (authInfo.type) {
            case 'Bearer':
                return {
                    auth: {
                        token: authInfo.token
                    }
                };
            case 'Basic':
                return {
                    auth: {
                        username: authInfo.username,
                        password: authInfo.password
                    }
                };
            default:
                throw new Error(`Unsupported authorization type '${authInfo.type}'`);
        }
    }
    return {
        getJSON: memoize(getJSON),
        download,
    };
};
//# sourceMappingURL=got.js.map