toes
Version:
1 lines • 8.85 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.mts","../src/app.mts","../src/utils.ts"],"sourcesContent":["#!/usr/bin/env node\r\nimport meow from \"meow\";\r\nimport app from \"./app.mjs\";\r\nimport { homedir } from \"os\";\r\nimport { loadConfig, saveConfig } from \"./utils.js\";\r\n\r\nconst cli = meow(\r\n `\r\n Usage\r\n $ toad-server --port 3000 --token 1234 --dir /home/user/projects\r\n\r\n Options\r\n --port, -p Port to run the server on\r\n --token, -t Token to authenticate requests with\r\n --dir, -d Directory to watch for projects\r\n \r\n Examples\r\n $ toad-server --port 3000 --token 1234 --dir /home/user/projects\r\n`,\r\n {\r\n importMeta: import.meta,\r\n flags: {\r\n port: {\r\n type: \"string\",\r\n alias: \"p\",\r\n default: \"3535\",\r\n },\r\n token: {\r\n type: \"string\",\r\n alias: \"t\",\r\n },\r\n dir: {\r\n type: \"string\",\r\n alias: \"d\",\r\n default: homedir() + \"/projects\",\r\n },\r\n },\r\n autoHelp: true,\r\n }\r\n);\r\n\r\nlet cfg = loadConfig();\r\n\r\nif (!cfg) {\r\n if (!cli.flags.token) {\r\n console.log(\"No token provided\");\r\n process.exit(1);\r\n }\r\n\r\n cfg = {\r\n port: cli.flags.port,\r\n token: cli.flags.token,\r\n dir: cli.flags.dir,\r\n };\r\n\r\n saveConfig(cfg);\r\n}\r\n\r\napp.run(cfg);\r\n","import type { ServerConfig, UpRequest } from \"./types.js\";\r\nimport type { Request, Response } from \"express\";\r\nimport express from \"express\";\r\nimport fs from \"node:fs\";\r\nimport { sexec } from \"./utils.js\";\r\n\r\ntype Process = {\r\n pid: number;\r\n name: string;\r\n command: string;\r\n};\r\n\r\nlet serverConfig: ServerConfig;\r\nconst runningProcesses: Process[] = [];\r\nconst app = express();\r\n\r\napp.use(express.json());\r\n\r\napp.use((req, res, next) => {\r\n if (req.headers.authorization !== serverConfig.token) {\r\n res.status(401).send(\"Unauthorized\");\r\n return;\r\n }\r\n next();\r\n});\r\n\r\napp.post(\"/up\", async (req: Request<{}, {}, UpRequest>, res: Response) => {\r\n const { project, config } = req.body;\r\n const { domain, port } = config;\r\n const { remote } = project;\r\n\r\n if (!domain || !port) {\r\n res.status(400).json({ error: \"Missing domain or port\" });\r\n return;\r\n }\r\n\r\n if (!remote) {\r\n res.status(400).json({ error: \"Missing remote\" });\r\n return;\r\n }\r\n\r\n const projectName = project.remote.split(\"/\").pop()!.split(\".\").shift()!;\r\n\r\n const projectDir = `${serverConfig.dir}/${projectName}`;\r\n\r\n if (!fs.existsSync(projectDir)) {\r\n try {\r\n console.log(`Cloning ${remote} into ${projectDir}`);\r\n sexec(`git clone ${remote} ${projectDir}`);\r\n sexec(`cd ${projectDir}`);\r\n } catch (e) {\r\n console.log(e);\r\n }\r\n } else {\r\n sexec(`cd ${projectDir}`);\r\n sexec(\"git pull\");\r\n }\r\n\r\n if (config.install) {\r\n console.log(\r\n `Installing dependencies for ${projectName} with ${config.install}`\r\n );\r\n sexec(config.install);\r\n }\r\n\r\n if (config.build) {\r\n console.log(`Building ${projectName} with ${config.build}`);\r\n sexec(config.build);\r\n }\r\n\r\n if (config.start) {\r\n console.log(`Starting ${projectName} with ${config.start}`);\r\n const child = sexec(config.start);\r\n\r\n child.on(\"spawn\", () => {\r\n runningProcesses.push({\r\n pid: child.pid!,\r\n name: projectName,\r\n command: child.spawnargs.join(\" \"),\r\n });\r\n });\r\n\r\n child.on(\"exit\", () => {\r\n runningProcesses.splice(\r\n runningProcesses.findIndex((p) => p.pid === child.pid),\r\n 1\r\n );\r\n });\r\n\r\n child.on(\"error\", (e) => {\r\n console.log(e);\r\n });\r\n }\r\n\r\n res.status(200).json({ success: true });\r\n});\r\n\r\napp.get(\"/ps\", (_, res) => res.json(runningProcesses));\r\n\r\napp.get(\"/\", (_, res) => res.send(\"hi\"));\r\n\r\nexport default {\r\n run: (cfg: ServerConfig) => {\r\n serverConfig = cfg;\r\n app.listen(cfg.port, () => {\r\n console.log(`toad running on port ${cfg.port}`);\r\n });\r\n },\r\n};\r\n","import type { ServerConfig } from \"./types\";\r\nimport { homedir } from \"os\";\r\nimport { promisify } from \"util\";\r\nimport { exec } from \"child_process\";\r\nimport fs from \"node:fs\";\r\nimport os from \"node:os\";\r\n\r\nconst configPath = `${homedir()}/.toad/srv-config`;\r\n\r\nexport function loadConfig(): ServerConfig | undefined {\r\n try {\r\n const cfg = JSON.parse(\r\n fs.readFileSync(configPath).toString()\r\n ) as ServerConfig;\r\n\r\n if (!cfg.token) return;\r\n\r\n cfg.dir = cfg.dir || os.homedir() + \"/projects\";\r\n cfg.port = cfg.port || 3535;\r\n\r\n saveConfig(cfg);\r\n\r\n return cfg;\r\n } catch (e) {\r\n return;\r\n }\r\n}\r\n\r\nexport function saveConfig(cfg: ServerConfig) {\r\n fs.writeFileSync(configPath, JSON.stringify(cfg));\r\n}\r\n\r\nexport const sexec = (...args: Partial<Parameters<typeof exec>>) => {\r\n return exec(args[0], args[1], (err, stdout, stderr) => {\r\n if (err) {\r\n console.error(err);\r\n return;\r\n }\r\n\r\n if (stdout) console.log(stdout);\r\n\r\n if (stderr) console.error(stderr);\r\n });\r\n};\r\n\r\nexport const execa = promisify(exec);\r\n"],"mappings":"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","names":["meow","express","fs","homedir","promisify","exec","fs","os","configPath","loadConfig","cfg","saveConfig","sexec","args","err","stdout","stderr","execa","serverConfig","runningProcesses","app","express","req","res","next","project","config","domain","port","remote","projectName","projectDir","fs","sexec","e","child","p","_","app_default","cfg","homedir","cli","meow","homedir","cfg","loadConfig","saveConfig","app_default"]}