UNPKG

hardhat-forta

Version:
151 lines 6.67 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.generateAgents = void 0; const fs_1 = __importDefault(require("fs")); const colors_1 = require("kleur/colors"); const node_fetch_1 = __importDefault(require("node-fetch")); const path_1 = __importDefault(require("path")); const prompts_1 = __importDefault(require("prompts")); const shelljs_1 = __importDefault(require("shelljs")); const forta_agent_1 = require("forta-agent"); const descriptions_1 = require("./descriptions"); const TEMPLATES_REPO_OWNER = "arbitraryexecution"; const TEMPLATES_REPO_NAME = "forta-bot-templates"; const TEMPLATES_REPO_COMMIT = "de5f1f272d906e3ceb8a1a2747c1600aa03a734e"; /** * Retrieves the folders in the repository root. * @returns The template directory subtree SHA. */ async function getTemplates() { const treeUrl = `https://api.github.com/repos/${TEMPLATES_REPO_OWNER}/${TEMPLATES_REPO_NAME}/git/trees/${TEMPLATES_REPO_COMMIT}`; const directories = (await (await (0, node_fetch_1.default)(treeUrl)).json()); const templateDirectories = directories.tree.filter((el) => { return el.type === "tree"; }); if (!templateDirectories.length) { throw new Error("Template not found"); } return templateDirectories; } /** * Retrieves data about the files inside the template directory. * @param templateName - The name of the template, that should also be the * name of one of the directories inside the `forta-bot-templates` * repository root. * @returns An array containing each of the files' relative path and download * url. */ async function getTemplateFiles(template) { const templateSubtreeUrl = `https://api.github.com/repos/${TEMPLATES_REPO_OWNER}/${TEMPLATES_REPO_NAME}/git/trees/${template.sha}?recursive=true`; const templateSubtree = (await (await (0, node_fetch_1.default)(templateSubtreeUrl)).json()); return templateSubtree.tree .filter((el) => el.type === "blob") .map((el) => ({ path: el.path, url: `https://raw.githubusercontent.com/${TEMPLATES_REPO_OWNER}/${TEMPLATES_REPO_NAME}/${TEMPLATES_REPO_COMMIT}/${template.path}/${el.path}`, })); } /** * Checks if the provided path has any files. * @param path - Path to be checked. */ function pathHasFiles(pathStr) { return fs_1.default.existsSync(pathStr) && shelljs_1.default.ls(pathStr).length; } /** * Checks if destinationPath is empty or not and, if not, notifies the user * and asks for confirmation. * @param destinationPath - Path to be checked. * @returns A boolean indicating whether the user agreed to write in the * specified path. */ async function shouldWrite(destinationPath) { if (pathHasFiles(destinationPath)) { const response = await (0, prompts_1.default)({ type: "confirm", name: "shouldContinue", message: `The directory ${(0, colors_1.underline)(destinationPath)} is not empty and files may be overwritten. Continue?`, }); if (!response.shouldContinue) { return false; } } return true; } /** * Fetches an agents files based on its repository tree node. * @param node - Repository tree node with information about the agent folder. * @param destinationPath - Path in which the agent files should be written. */ async function fetchAgent(node, destinationPath) { if (!(await shouldWrite(destinationPath))) { console.log((0, colors_1.bold)(`Skipping agent download.`)); return; } console.log(`Initializing ${node.path} template...`); const files = await getTemplateFiles(node); await Promise.all(files.map(async (file) => { const filePath = path_1.default.join(destinationPath, file.path); shelljs_1.default.mkdir("-p", path_1.default.dirname(filePath)); const writeStream = fs_1.default.createWriteStream(filePath); const res = await (0, node_fetch_1.default)(file.url); return new Promise((resolve, reject) => { var _a, _b; (_a = res.body) === null || _a === void 0 ? void 0 : _a.pipe(writeStream); (_b = res.body) === null || _b === void 0 ? void 0 : _b.on("error", reject); writeStream.on("finish", resolve); }); })); console.log(`Running npm install...`); shelljs_1.default.cd(destinationPath); shelljs_1.default.exec("npm install"); console.log((0, colors_1.bold)((0, colors_1.blue)(`Agent successfully generated at ${(0, colors_1.underline)(destinationPath)}`))); } /** * Generates an agent or more based on the available templates in the * arbitraryexecution/forta-bot-templates github repository. * @param destinationPath - The path in which the forta agent project(s) will * be placed. */ async function generateAgents(destinationPath) { const availableTemplates = await getTemplates(); const templatePrompt = await (0, prompts_1.default)({ type: "multiselect", name: "agents", message: "Templates:", choices: availableTemplates.map((node) => ({ title: node.path, value: node, description: (0, descriptions_1.getDescription)(node.path), })), initial: 0, }); if (templatePrompt.agents.length === 0) { throw new Error("no templates selected"); } const selectedMultipleAgents = templatePrompt.agents.length > 1; if (!selectedMultipleAgents) { // initialize the template in the root folder await fetchAgent(templatePrompt.agents[0], destinationPath); } else { // create separate folders for each template for (const agent of templatePrompt.agents) { await fetchAgent(agent, path_1.default.join(destinationPath, agent.path)); } } const diContainer = (0, forta_agent_1.configureContainer)(); const initKeystore = diContainer.resolve("initKeystore"); await initKeystore(); const initConfig = diContainer.resolve("initConfig"); await initConfig(); const initKeyfile = diContainer.resolve("initKeyfile"); await initKeyfile(); console.log(`You agree that your use is subject to the terms and conditions found at https://forta.org/legal`); console.log((0, colors_1.bold)((0, colors_1.green)(`\n**Make sure to configure the template${selectedMultipleAgents ? 's' : ''} by following SETUP.md inside the agent folder${selectedMultipleAgents ? 's' : ''}!**`))); } exports.generateAgents = generateAgents; //# sourceMappingURL=index.js.map