UNPKG

fauna-gql-upload

Version:

Manage your FaunaDB resources in within your project and upload them using a single command

535 lines (534 loc) 27.1 kB
"use strict"; 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 __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 __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; exports.__esModule = true; var fs_1 = __importDefault(require("fs")); var path_1 = __importDefault(require("path")); var getConfig_1 = __importStar(require("../util/getConfig")); var logger_1 = require("../util/logger"); var prompts_1 = __importDefault(require("prompts")); var child_process_1 = require("child_process"); var dotenv_1 = __importDefault(require("dotenv")); var error_1 = __importDefault(require("../util/error")); var templatesDir = path_1["default"].join(__dirname, "..", "..", "templates"); var defaultCommand = "fauna"; var fguPkgName = "fauna-gql-upload"; var faunaPkgName = "faunadb"; var setupQuestions = [ { type: "text", name: "secret", message: "Secret admin key for your database (this will be added to your .env file):", validate: function (value) { return !!value || "Secret is required to upload resources, enter a valid admin secret key."; } }, { type: "confirm", name: "development", message: "Do you want FGU to connect to a local development instance of FaunaDB?", initial: false }, { type: "select", name: "region", message: "Select the region for your production database:", choices: [ { title: "classic", value: "classic" }, { title: "us", value: "us" }, { title: "eu", value: "eu" }, { title: "preview", value: "preview" }, { title: "auto", value: "auto", selected: true, description: "Use whatever region works with your secret key" } ] }, { type: "text", name: "command", message: "Name of npm script to upload resources:", initial: defaultCommand }, { type: "confirm", name: "resources", message: "Would you like to create placeholder resources?", initial: true } ]; var configOptions = { "$schema": "node_modules/fauna-gql-upload/config.schema.json" }; var resourceDirs = new Map([ ["schema", getConfig_1.argv.schemaDir || "schema"], ["data", getConfig_1.argv.dataDir || "data"], ["functions", getConfig_1.argv.fnsDir || "functions"], ["indexes", getConfig_1.argv.indexesDir || "indexes"], ["providers", getConfig_1.argv.providersDir || "providers"], ["roles", getConfig_1.argv.rolesDir || "roles"] ]); /** Setup FGU files and folders based on configuration questions. */ function init() { return __awaiter(this, void 0, void 0, function () { var yes, customConfig, configPath, configFileExists, resources, concatSchema, setup, resourcesAnswers, envFile, envFilePath, envJson; return __generator(this, function (_a) { switch (_a.label) { case 0: yes = getConfig_1.argv.yes; customConfig = getConfig_1.argv.config; configPath = customConfig || path_1["default"].join(process.cwd(), ".fauna.json"); configFileExists = fs_1["default"].existsSync(configPath); resources = ["functions", "indexes", "schema"]; concatSchema = false; setup = { command: defaultCommand, secret: undefined, resources: true, development: false, region: "auto" }; if (configFileExists) { (0, error_1["default"])("The current directory already contains a `.fauna.json` file. Cannot run init in an already initialized directory."); } (0, logger_1.status)("Initializing FGU in the current directory...", "info"); if (!!yes) return [3 /*break*/, 6]; return [4 /*yield*/, (0, prompts_1["default"])(setupQuestions)]; case 1: setup = _a.sent(); if (!setup.resources) return [3 /*break*/, 5]; return [4 /*yield*/, (0, prompts_1["default"])({ type: "multiselect", name: "resources", message: "Select resources to create:", choices: [ { title: "Schema", value: "schema", selected: true }, { title: "Functions", value: "functions", selected: true }, { title: "Roles", value: "roles", selected: false }, { title: "Providers", value: "providers", selected: false }, { title: "Indexes", value: "indexes", selected: true }, { title: "Data", value: "data", selected: false } ] })]; case 2: resourcesAnswers = _a.sent(); resources = resourcesAnswers.resources; if (!resourcesAnswers.resources.includes("schema")) return [3 /*break*/, 4]; return [4 /*yield*/, (0, prompts_1["default"])({ name: "concatSchema", type: "confirm", message: "Would you like to enable schema concatenation?", initial: false })]; case 3: concatSchema = (_a.sent()).concatSchema; _a.label = 4; case 4: // If concatenation is enabled, add schemaDir to config. if (concatSchema) configOptions.schemaDir = path_1["default"].join("fauna", "schema"); return [3 /*break*/, 6]; case 5: // User does not want to create resources, so set resources to empty array. resources = []; _a.label = 6; case 6: if (yes) { envFile = getConfig_1.argv.envPath || ".env"; try { envFilePath = path_1["default"].join(process.cwd(), envFile); envJson = dotenv_1["default"].parse(fs_1["default"].readFileSync(envFilePath)); setup.secret = envJson[getConfig_1.argv.secretEnv || getConfig_1.defaultSecretEnv]; } catch (_b) { (0, error_1["default"])("No ".concat(envFile, " file found in the current directory. Please create one and add the admin key to it.")); } } if (!setup.secret) { (0, error_1["default"])("Secret key was not provided, cannot finish initialization."); } if (setup.region !== "auto") { configOptions.region = setup.region; } return [4 /*yield*/, createPackage(setup.command, customConfig)]; case 7: _a.sent(); return [4 /*yield*/, updateEnvFile(setup)]; case 8: _a.sent(); return [4 /*yield*/, createResources(resources, concatSchema)]; case 9: _a.sent(); return [4 /*yield*/, createConfigFile(configPath, configOptions)]; case 10: _a.sent(); (0, logger_1.status)("Fauna GQL Upload has been initialized. To upload resources, run: `npm run ".concat(setup.command, "`"), "success"); return [2 /*return*/]; } }); }); } exports["default"] = init; function addCustomOptions(configOptions) { var acceptedOptions = Object.keys((0, getConfig_1["default"])()).filter(function (opt) { return opt !== "codegen"; }); Object.keys(acceptedOptions).forEach(function (key) { if (getConfig_1.argv[key]) { //@ts-ignore configOptions[key] = getConfig_1.argv[key]; } }); } /** Create a config file using the provided options. */ function createConfigFile(path, config) { return __awaiter(this, void 0, void 0, function () { var configData; return __generator(this, function (_a) { switch (_a.label) { case 0: (0, logger_1.status)("Creating config file at ".concat(path, "..."), "info"); configData = JSON.stringify(config, null, 2); return [4 /*yield*/, fs_1["default"].promises.writeFile(path, configData)]; case 1: _a.sent(); return [2 /*return*/]; } }); }); } function createPackage(script, customConfig) { return __awaiter(this, void 0, void 0, function () { var packagePath, packageExists, packageFile, packageJson, fguInstalled, fdbInstalled, packagesToInstall; return __generator(this, function (_a) { switch (_a.label) { case 0: packagePath = path_1["default"].join(process.cwd(), "package.json"); packageExists = fs_1["default"].existsSync(packagePath); if (!!packageExists) return [3 /*break*/, 3]; (0, logger_1.status)("Initializing package.json...", "info"); return [4 /*yield*/, new Promise(function (resolve) { return (0, child_process_1.exec)("npm init -y", function (error) { if (error) throw error; resolve(undefined); }); })]; case 1: _a.sent(); // Install fauna-gql-upload and faunadb return [4 /*yield*/, installPackages([ { packageName: faunaPkgName, dev: false }, { packageName: fguPkgName, dev: true } ])]; case 2: // Install fauna-gql-upload and faunadb _a.sent(); _a.label = 3; case 3: return [4 /*yield*/, fs_1["default"].promises.readFile(packagePath, "utf8")]; case 4: packageFile = _a.sent(); packageJson = JSON.parse(packageFile); fguInstalled = !!packageJson.devDependencies[fguPkgName]; fdbInstalled = !!packageJson.dependencies[faunaPkgName]; if (!(!fguInstalled || !fdbInstalled)) return [3 /*break*/, 7]; packagesToInstall = []; if (!fdbInstalled) packagesToInstall.push({ packageName: faunaPkgName, dev: false }); if (!fguInstalled) packagesToInstall.push({ packageName: fguPkgName, dev: true }); return [4 /*yield*/, installPackages(packagesToInstall)]; case 5: _a.sent(); return [4 /*yield*/, fs_1["default"].promises.readFile(packagePath, "utf8")]; case 6: // Read package.json again packageFile = _a.sent(); packageJson = JSON.parse(packageFile); _a.label = 7; case 7: // Add upload script to package.json packageJson.scripts[script] = "fgu upload ".concat(customConfig ? "--config ".concat(customConfig) : ""); // Write package.json return [4 /*yield*/, fs_1["default"].promises.writeFile(packagePath, JSON.stringify(packageJson, null, 2))]; case 8: // Write package.json _a.sent(); return [2 /*return*/]; } }); }); } function installPackages(packages) { return __awaiter(this, void 0, void 0, function () { var useYarn, installCommand, _loop_1, packages_1, packages_1_1, _a, packageName, dev, e_1_1; var e_1, _b; return __generator(this, function (_c) { switch (_c.label) { case 0: if (packages.length === 0) return [2 /*return*/]; (0, logger_1.status)("Installing dependencies...", "info"); return [4 /*yield*/, new Promise(function (resolve) { (0, child_process_1.exec)("yarn --version", function (err) { if (err) resolve(false); else resolve(true); }); })]; case 1: useYarn = _c.sent(); installCommand = useYarn ? "yarn add" : "npm install"; _loop_1 = function (packageName, dev) { return __generator(this, function (_d) { switch (_d.label) { case 0: return [4 /*yield*/, new Promise(function (resolve) { (0, logger_1.status)("Installing ".concat(packageName, "..."), "info"); (0, child_process_1.exec)("".concat(installCommand, " ").concat(dev ? "-D " : "").concat(packageName), function (error) { if (error) { (0, logger_1.status)("Failed to install ".concat(packageName), "error"); } resolve(undefined); }); })]; case 1: _d.sent(); return [2 /*return*/]; } }); }; _c.label = 2; case 2: _c.trys.push([2, 7, 8, 9]); packages_1 = __values(packages), packages_1_1 = packages_1.next(); _c.label = 3; case 3: if (!!packages_1_1.done) return [3 /*break*/, 6]; _a = packages_1_1.value, packageName = _a.packageName, dev = _a.dev; return [5 /*yield**/, _loop_1(packageName, dev)]; case 4: _c.sent(); _c.label = 5; case 5: packages_1_1 = packages_1.next(); return [3 /*break*/, 3]; case 6: return [3 /*break*/, 9]; case 7: e_1_1 = _c.sent(); e_1 = { error: e_1_1 }; return [3 /*break*/, 9]; case 8: try { if (packages_1_1 && !packages_1_1.done && (_b = packages_1["return"])) _b.call(packages_1); } finally { if (e_1) throw e_1.error; } return [7 /*endfinally*/]; case 9: return [2 /*return*/]; } }); }); } function updateEnvFile(options) { return __awaiter(this, void 0, void 0, function () { var envPath, envFilePath, envFileExists, env, _a, envJson, secretEnv, newEnv, apiEndpointEnv, graphqlEndpointEnv; return __generator(this, function (_b) { switch (_b.label) { case 0: (0, logger_1.status)("Creating/updating environment file...", "info"); envPath = getConfig_1.argv.envPath || ".env"; envFilePath = path_1["default"].join(process.cwd(), envPath); envFileExists = fs_1["default"].existsSync(envFilePath); if (!envFileExists) return [3 /*break*/, 2]; return [4 /*yield*/, fs_1["default"].promises.readFile(envFilePath, "utf8")]; case 1: _a = _b.sent(); return [3 /*break*/, 3]; case 2: _a = ""; _b.label = 3; case 3: env = _a; envJson = envFileExists ? dotenv_1["default"].parse(env) : {}; secretEnv = getConfig_1.argv.secretEnv || getConfig_1.defaultSecretEnv; newEnv = env; if (!(envJson === null || envJson === void 0 ? void 0 : envJson[secretEnv])) newEnv = env + "\n".concat(secretEnv, "=").concat(options.secret); if (options.development) { apiEndpointEnv = getConfig_1.argv.apiEndpointEnv || getConfig_1.defaultApiEndpointEnv; graphqlEndpointEnv = getConfig_1.argv.graphqlEndpointEnv || getConfig_1.defaultGraphqlEndpointEnv; if (!(envJson === null || envJson === void 0 ? void 0 : envJson[apiEndpointEnv])) newEnv += "\n".concat(apiEndpointEnv, "=http://localhost:8443"); if (!(envJson === null || envJson === void 0 ? void 0 : envJson[graphqlEndpointEnv])) newEnv += "\n".concat(graphqlEndpointEnv, "=http://localhost:8084"); } // write environment file return [4 /*yield*/, fs_1["default"].promises.writeFile(envFilePath, newEnv)]; case 4: // write environment file _b.sent(); return [2 /*return*/]; } }); }); } /** Create the resource directories */ function createResources(resources, concatSchema) { if (concatSchema === void 0) { concatSchema = false; } return __awaiter(this, void 0, void 0, function () { var faunaDir, activeResources; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: // If no resources are selected, exit without doing anything. if (resources.length === 0) return [2 /*return*/]; (0, logger_1.status)("Creating placeholder resources...", "info"); faunaDir = path_1["default"].join(process.cwd(), "fauna"); if (!!fs_1["default"].existsSync(faunaDir)) return [3 /*break*/, 2]; return [4 /*yield*/, fs_1["default"].promises.mkdir(faunaDir)]; case 1: _a.sent(); _a.label = 2; case 2: activeResources = resources .filter(function (resource) { return !concatSchema ? resource !== "schema" : true; }); // Create resources. return [4 /*yield*/, Promise.all(activeResources.map(function (resource) { return __awaiter(_this, void 0, void 0, function () { var destDir, resourceDir, dirExists, resourcesFiles; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: destDir = path_1["default"].join(faunaDir, resourceDirs.get(resource) || resource); resourceDir = path_1["default"].join(templatesDir, resource); dirExists = fs_1["default"].existsSync(destDir); if (!!dirExists) return [3 /*break*/, 2]; return [4 /*yield*/, fs_1["default"].promises.mkdir(destDir, { recursive: true })]; case 1: _a.sent(); _a.label = 2; case 2: return [4 /*yield*/, fs_1["default"].promises.readdir(resourceDir)]; case 3: resourcesFiles = _a.sent(); return [4 /*yield*/, Promise.all(resourcesFiles.map(function (file) { return __awaiter(_this, void 0, void 0, function () { var resourceTemplatePath; return __generator(this, function (_a) { resourceTemplatePath = path_1["default"].join(resourceDir, file); return [2 /*return*/, fs_1["default"].promises.copyFile(resourceTemplatePath, path_1["default"].join(destDir, file))]; }); }); }))]; case 4: _a.sent(); return [2 /*return*/]; } }); }); })) // Create schema file ]; case 3: // Create resources. _a.sent(); // Create schema file if (!concatSchema && resources.includes("schema")) { createSchema(); } return [2 /*return*/]; } }); }); } /** Create a schema file */ function createSchema() { return __awaiter(this, void 0, void 0, function () { var schema, schemaTemplate; return __generator(this, function (_a) { switch (_a.label) { case 0: schema = path_1["default"].join(process.cwd(), "fauna", "schema.gql"); schemaTemplate = path_1["default"].join(templatesDir, "schema.gql"); return [4 /*yield*/, fs_1["default"].promises.copyFile(schemaTemplate, schema)]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }