"use strict";
/*
api.github.com is very nice to use to get info, but

"Unauthenticated clients can make **60 requests per hour**."
https://docs.github.com/en/rest/guides/getting-started-with-the-rest-api

So it's completely useless for our purposes without authentication.

"When authenticating, you should see your rate limit bumped to 5,000 requests an hour,"

which is also hopefully sufficient, but worrisome.

Thoughts:

- Since all rendering could be done client side, I could actually have
the client browser grab content instead of the server, then render there to
massively reduce api load, although even users could quickly hit "60 requests
per hour", so the api still wouldn't help.

- If we do hit the 5K/hour limit, maybe we can use more than one api key?

- Upgrading to enterprise doesn't increase this much.

- We could switch to mirroring and cloning files locally, and that might
  work around this problem in practice, but be a lot of work. We'll see.


Get at https://github.com/settings/tokens
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.fileInGist = exports.repos = exports.defaultBranch = exports.contents = exports.api = exports.rawText = exports.RAW_MAX_SIZE_BYTES = void 0;
const node_fetch_1 = __importStar(require("node-fetch"));
const base_64_1 = require("base-64");
const path_1 = require("path");
const pool_1 = __importDefault(require("@cocalc/database/pool"));
// We don't allow just fetching content that is arbitrarily large, since that could cause
// the server to just run out of memory.  However, we want this to reasonably big.
exports.RAW_MAX_SIZE_BYTES = 10000000; // 10MB
// TODO: we will also have a raw blob or stream or something for serving up images, etc.,
async function rawText(githubOrg, githubRepo, segments) {
    const url = rawURL(githubOrg, githubRepo, segments);
    //console.log("raw:", { url });
    return await (await (0, node_fetch_1.default)(url, { size: exports.RAW_MAX_SIZE_BYTES })).text();
}
exports.rawText = rawText;
function rawURL(githubOrg, githubRepo, segments) {
    return `https://raw.githubusercontent.com/${githubOrg}/${githubRepo}/${(0, path_1.join)(...segments.slice(1))}`;
}
async function credentials() {
    const pool = (0, pool_1.default)("long");
    const { rows } = await pool.query("SELECT name, value FROM server_settings WHERE name='github_username' OR name='github_token'");
    let result = {};
    for (const row of rows) {
        result[row.name] = row.value;
    }
    return result;
}
async function api(path) {
    const url = `https://api.github.com/${path}`;
    const options = {};
    const { github_username, github_token } = await credentials();
    if (github_username && github_token) {
        options.headers = new node_fetch_1.Headers({
            Authorization: "Basic " + (0, base_64_1.encode)(`${github_username}:${github_token}`),
            "Content-Type": "application/json",
        });
    }
    //console.log(options);
    const response = await (0, node_fetch_1.default)(url, options);
    //console.log(response.headers);
    const data = await response.json();
    //console.log({ url, response });
    if (data.message) {
        throw Error(`${data.message}  (see ${data.documentation_url})`);
    }
    return data;
}
exports.api = api;
// Use the github api to get the contents of a path on github.
// We are planning to use this just to get directory listings,
// since individual files have their content base64 encoded, etc.,
// and that has to be much slower than just grabbing the
// file form raw (and also only works up to 1MB according to
// github docs).
// How to do auth + fetch with node: https://stackoverflow.com/questions/43842793/basic-authentication-with-fetch
async function contents(githubOrg, githubRepo, segments) {
    let ref, path;
    if (segments.length == 0) {
        ref = ""; // the default;
        path = ""; // root
    }
    else {
        // tree/[ref]/[path ...]
        ref = segments[1];
        path = (0, path_1.join)(...segments.slice(2));
    }
    const result = await api(`repos/${githubOrg}/${githubRepo}/contents/${path}${ref ? "?ref=" + ref : ""}`);
    if (result.name != null) {
        throw Error("only use contents to get directory listing, not to get file contents");
    }
    return result;
}
exports.contents = contents;
async function defaultBranch(githubOrg, githubRepo) {
    return (await api(`repos/${githubOrg}/${githubRepo}`)).default_branch;
}
exports.defaultBranch = defaultBranch;
// Return all the repositories in a GitHub organization or user:
async function repos(githubOrg) {
    let result;
    try {
        result = await api(`orgs/${githubOrg}/repos`);
    }
    catch (err) {
        result = await api(`users/${githubOrg}/repos`);
    }
    return result
        .filter((repo) => !repo.private)
        .map((repo) => {
        return {
            isdir: true,
            name: repo.name,
            mtime: new Date(repo.updated_at).valueOf(),
            url: `/github/${githubOrg}/${repo.name}`,
        };
    });
}
exports.repos = repos;
async function fileInGist(gistId) {
    const info = await api(`gists/${gistId}`);
    for (const filename in info.files) {
        return filename;
    }
    throw Error("no files in the gist");
}
exports.fileInGist = fileInGist;
//# sourceMappingURL=api.js.map