Daniel Rochetti c3a3c3d21a
chore: upgrade dependencies and tooling (#81)
* chore: remove uuid-random dependency

* chore: upgrade prettier

* chore(client): bump version for release
2024-08-07 15:45:15 -07:00

155 lines
3.7 KiB
JavaScript

#!/usr/bin/env node
import { input } from "@inquirer/prompts";
import select from "@inquirer/select";
import chalk from "chalk";
import childProcess from "child_process";
import { Command } from "commander";
import { execa, execaCommand } from "execa";
import fs from "fs";
import open from "open";
import ora from "ora";
import path from "path";
const program = new Command();
const log = console.log;
const repoUrl = "https://github.com/fal-ai/fal-nextjs-template.git";
const green = chalk.green;
const purple = chalk.hex("#6e40c9");
async function main() {
const spinner = ora({
text: "Creating codebase",
});
try {
const kebabRegez = /^([a-z]+)(-[a-z0-9]+)*$/;
program
.name("The fal.ai App Generator")
.description("Generate full stack AI apps integrated with fal.ai");
program.parse(process.argv);
const args = program.args;
let appName = args[0];
if (!appName || !kebabRegez.test(args[0])) {
appName = await input({
message: "Enter your app name",
default: "model-playground",
validate: (d) => {
if (!kebabRegez.test(d)) {
return "please enter your app name in the format of my-app-name";
}
return true;
},
});
}
const hasFalEnv = await select({
message: "Do you have a fal.ai API key?",
choices: [
{
name: "Yes",
value: true,
},
{
name: "No",
value: false,
},
],
});
if (!hasFalEnv) {
await open("https://www.fal.ai/dashboard");
}
const fal_api_key = await input({ message: "Fal AI API Key" });
const envs = `
# environment, either PRODUCTION or DEVELOPMENT
ENVIRONMENT="PRODUCTION"
# FAL AI API Key
FAL_KEY="${fal_api_key}"
`;
log(`\nInitializing project. \n`);
spinner.start();
await execa("git", ["clone", repoUrl, appName]);
let packageJson = fs.readFileSync(`${appName}/package.json`, "utf8");
const packageObj = JSON.parse(packageJson);
packageObj.name = appName;
packageJson = JSON.stringify(packageObj, null, 2);
fs.writeFileSync(`${appName}/package.json`, packageJson);
fs.writeFileSync(`${appName}/.env.local`, envs);
process.chdir(path.join(process.cwd(), appName));
await execa("rm", ["-rf", ".git"]);
await execa("git", ["init"]);
spinner.text = "";
let startCommand = "";
if (isBunInstalled()) {
spinner.text = "Installing dependencies";
await execaCommand("bun install").pipeStdout(process.stdout);
spinner.text = "";
startCommand = "bun dev";
console.log("\n");
} else if (isYarnInstalled()) {
await execaCommand("yarn").pipeStdout(process.stdout);
startCommand = "yarn dev";
} else {
spinner.text = "Installing dependencies";
await execa("npm", ["install", "--verbose"]).pipeStdout(process.stdout);
spinner.text = "";
startCommand = "npm run dev";
}
spinner.stop();
await execa("git", ["add", "."]);
await execa("git", ["commit", "-m", "Initial commit"]);
process.chdir("../");
log(
`${green.bold("Success!")} Created ${purple.bold(
appName,
)} at ${process.cwd()} \n`,
);
log(
`To get started, change into the new directory and run ${chalk.cyan(
startCommand,
)}\n`,
);
} catch (err) {
log("\n");
if (err.exitCode == 128) {
log("Error: directory already exists.");
}
spinner.stop();
}
}
main();
function isYarnInstalled() {
try {
childProcess.execSync("yarn --version");
return true;
} catch {
return false;
}
}
function isBunInstalled() {
try {
childProcess.execSync("bun --version");
return true;
} catch (err) {
return false;
}
}