"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());
    });
};
const { join } = require("path");
const { ObjectStoreBuckets } = require("../../constants");
const fs = require("fs");
const { upload, retrieveToTmp, streamUpload } = require("./utilities");
const { resolve } = require("../centralPath");
const env = require("../../environment");
const TOP_LEVEL_PATH = join(__dirname, "..", "..", "..");
/**
 * Client library paths in the object store:
 * Previously, the entire client library package was downloaded from NPM
 * as a tarball and extracted to the object store, even though only the manifest
 * was ever needed. Therefore we need to support old apps which may still have
 * the manifest at this location for the first update.
 *
 * The new paths for the in-use version are:
 * {appId}/manifest.json
 * {appId}/budibase-client.js
 *
 * The paths for the backups are:
 * {appId}/manifest.json.bak
 * {appId}/budibase-client.js.bak
 *
 * We don't rely on NPM at all any more, as when updating to the latest version
 * we pull both the manifest and client bundle from the server's dependencies
 * in the local file system.
 */
/**
 * Backs up the current client library version by copying both the manifest
 * and client bundle to .bak extensions in the object store. Only the one
 * previous version is stored as a backup, which can be reverted to.
 * @param appId The app ID to backup
 * @returns {Promise<void>}
 */
exports.backupClientLibrary = (appId) => __awaiter(void 0, void 0, void 0, function* () {
    // Copy existing manifest to tmp
    let tmpManifestPath;
    try {
        // Try to load the manifest from the new file location
        tmpManifestPath = yield retrieveToTmp(ObjectStoreBuckets.APPS, join(appId, "manifest.json"));
    }
    catch (error) {
        // Fallback to loading it from the old location for old apps
        tmpManifestPath = yield retrieveToTmp(ObjectStoreBuckets.APPS, join(appId, "node_modules", "budibase", "standard-components", "package", "manifest.json"));
    }
    // Copy existing client lib to tmp
    const tmpClientPath = yield retrieveToTmp(ObjectStoreBuckets.APPS, join(appId, "budibase-client.js"));
    // Upload manifest and client library as backups
    const manifestUpload = upload({
        bucket: ObjectStoreBuckets.APPS,
        filename: join(appId, "manifest.json.bak"),
        path: tmpManifestPath,
        type: "application/json",
    });
    const clientUpload = upload({
        bucket: ObjectStoreBuckets.APPS,
        filename: join(appId, "budibase-client.js.bak"),
        path: tmpClientPath,
        type: "application/javascript",
    });
    yield Promise.all([manifestUpload, clientUpload]);
});
/**
 * Uploads the latest version of the component manifest and the client library
 * to the object store, overwriting the existing version.
 * @param appId The app ID to update
 * @returns {Promise<void>}
 */
exports.updateClientLibrary = (appId) => __awaiter(void 0, void 0, void 0, function* () {
    let manifest, client;
    if (env.isDev()) {
        // Load the symlinked version in dev which is always the newest
        manifest = require.resolve("@devlego/client/manifest.json");
        client = require.resolve("@devlego/client");
    }
    else {
        // Load the bundled version in prod
        manifest = resolve(TOP_LEVEL_PATH, "client", "manifest.json");
        client = resolve(TOP_LEVEL_PATH, "client", "budibase-client.js");
    }
    // Upload latest manifest and client library
    const manifestUpload = streamUpload(ObjectStoreBuckets.APPS, join(appId, "manifest.json"), fs.createReadStream(manifest), {
        ContentType: "application/json",
    });
    const clientUpload = streamUpload(ObjectStoreBuckets.APPS, join(appId, "budibase-client.js"), fs.createReadStream(client), {
        ContentType: "application/javascript",
    });
    yield Promise.all([manifestUpload, clientUpload]);
});
/**
 * Reverts the version of the client library and manifest to the previously
 * used version for an app.
 * @param appId The app ID to revert
 * @returns {Promise<void>}
 */
exports.revertClientLibrary = (appId) => __awaiter(void 0, void 0, void 0, function* () {
    // Copy backups manifest to tmp directory
    const tmpManifestPath = yield retrieveToTmp(ObjectStoreBuckets.APPS, join(appId, "manifest.json.bak"));
    // Copy backup client lib to tmp
    const tmpClientPath = yield retrieveToTmp(ObjectStoreBuckets.APPS, join(appId, "budibase-client.js.bak"));
    // Upload backups as new versions
    const manifestUpload = upload({
        bucket: ObjectStoreBuckets.APPS,
        filename: join(appId, "manifest.json"),
        path: tmpManifestPath,
        type: "application/json",
    });
    const clientUpload = upload({
        bucket: ObjectStoreBuckets.APPS,
        filename: join(appId, "budibase-client.js"),
        path: tmpClientPath,
        type: "application/javascript",
    });
    yield Promise.all([manifestUpload, clientUpload]);
});
