UNPKG

fauna-gql-upload

Version:

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

142 lines (111 loc) 4.1 kB
import fs from "fs"; import path from "path"; import createOrUpdateResources from "../util/createOrUpdateResources"; import * as esbuild from "esbuild"; import { IndexResource, ProviderResource, Resource, ResourceType, UploadResourcesOptions } from "../types"; import { detailedError, status } from "../util/logger"; import getProviders from "../util/getProviders"; import updateIndexes from "../util/updateIndexes"; import CLISpinner from "cli-spinner"; import { errors } from "faunadb"; const Spinner = CLISpinner.Spinner; const cwd = process.cwd(); const allowedExts = [".js", ".ts"]; async function uploadResources(dir: string, type: ResourceType, options?: UploadResourcesOptions){ const failedUploadError = `Failed to upload ${type}\n`; const resourceDir = path.join(dir, "output"); const files = await fs.promises.readdir(dir).catch(err => { return null; }); if(!files || (files && files.length === 0)){ return; } const entries = files.filter(file =>{ const ext = getExt(file) if(allowedExts.includes(ext)){ return true } return false }).map( file => path.join(dir, file)); const containsTs = files.some( file => getExt(file) === ".ts"); if(containsTs) { const { typeCheck } = require("../util/typescript"); const ok = await typeCheck(entries, dir); if(!ok){ // Log status message for failed upload. status(failedUploadError, "error"); // Cancel execution. return; } } // Build resources before reading data. try{ await esbuild.build({ entryPoints: entries, outdir: resourceDir, bundle: true, platform: "node", outExtension: { ".js": ".cjs" }, target: ["esnext"] }); }catch(err){ status(failedUploadError, "error"); return; } const resourceFiles: Resource[] = (await Promise.all(files.map( async file => { try{ if(!allowedExts.includes(getExt(file))) return null; const resourcePath = path.join(cwd, resourceDir, removeExt(file) + ".cjs"); const resource = await import(resourcePath); // Handle default exports return resource.default || resource; }catch(err){ status(`Error reading file ${dir}/${file}`, "error"); console.error(err); return null; } }))).filter( value => value !== null); // Remove out directory after reading files await fs.promises.rm(resourceDir, { recursive: true }); try{ const result = await createOrUpdateResources(resourceFiles, type, options); // Don't log success message on first function pass. if(type === "functions" && !options?.fnsWithRoles) return; status(`successfully uploaded ${type}`, "success"); // Get and log the audience value of the uploaded providers if(type === "providers"){ const providers = await getProviders(result as ProviderResource[]); providers.forEach( provider => { status(`audience for ${provider.name}: ${provider.audience}`, "info"); }) } }catch(err){ // Don't log error message on first function pass. if(type === "functions" && !options?.fnsWithRoles) return; if(type === "indexes" && (err as any)?.requestResult?.responseRaw?.includes("Index sources, terms, values, and partition count may not be updated.")){ status("Index sources, terms, values, and partition count cannot be updated normally. We must first delete the index and create it again. This will happen automatically, hold on...", "info"); try{ const indexes = resourceFiles.filter(val => !!val.source); const spinner = new Spinner("Updating mutated indexes... %s"); spinner.start(); await updateIndexes(indexes as IndexResource[]); spinner.stop(); console.log(); status("Successfully updated mutated indexes", "success"); return; }catch(err){ status("Failed to update mutated indexes", "error"); console.error(err); } } detailedError(err as errors.FaunaHTTPError, type); throw "Upload operation failed. See logged errors above for more info." } } function removeExt(str: string){ return str.split(".").slice(0, -1).join(""); } function getExt(str: string){ return path.extname(str); } export default uploadResources;