* chore: remove uuid-random dependency * chore: upgrade prettier * chore(client): bump version for release
155 lines
3.7 KiB
JavaScript
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;
|
|
}
|
|
}
|