@spfn/cli 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
File without changes
package/lib/index.js ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { login } from "./login.js";
4
+
5
+ const program = new Command();
6
+
7
+ program
8
+ .name("sf")
9
+ .description("Superfunction CLI")
10
+ .version("0.1.0");
11
+
12
+ program
13
+ .command("login")
14
+ .description("Authenticate via browser login")
15
+ .action(() => {
16
+ login();
17
+ });
18
+
19
+ program.parse();
package/lib/login.js ADDED
@@ -0,0 +1,81 @@
1
+ import http from "http";
2
+ import open from "open";
3
+ import fs from "fs";
4
+ import os from "os";
5
+ import path from "path";
6
+
7
+ const PORT = 5678;
8
+
9
+ export function login() {
10
+ try {
11
+ const server = http.createServer((req, res) => {
12
+ // CORS 헤더 공통 추가
13
+ res.setHeader("Access-Control-Allow-Origin", "*");
14
+ res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
15
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type");
16
+
17
+ if (req.method === "OPTIONS") {
18
+ res.writeHead(200);
19
+ res.end();
20
+ return;
21
+ }
22
+
23
+ if (req.url === "/callback" && req.method === "POST") {
24
+ let body = "";
25
+
26
+ req.on("data", chunk => {
27
+ body += chunk;
28
+ });
29
+
30
+ req.on("end", () => {
31
+ try {
32
+ const { username, token, projectSlug } = JSON.parse(body);
33
+
34
+ if (!token || !username) {
35
+ res.writeHead(400).end("Missing username or token");
36
+ return;
37
+ }
38
+
39
+ const shell = process.env.SHELL?.includes("zsh") ? ".zshrc" : ".bashrc";
40
+ const rcFile = path.join(os.homedir(), shell);
41
+ const exportUsername = `export SF_USERNAME=${username}`;
42
+ const exportToken = `export SF_AUTH_TOKEN=${token}`;
43
+
44
+ let content = fs.readFileSync(rcFile, "utf-8");
45
+ content = content
46
+ .replace(/^# Added by sf-cli[\s\S]*?export SF_USERNAME=.*\n?/m, "")
47
+ .replace(/^export SF_AUTH_TOKEN=.*\n?/m, "");
48
+
49
+ content += `\n# Added by sf-cli\n${exportUsername}\n${exportToken}\n`;
50
+ fs.writeFileSync(rcFile, content, "utf-8");
51
+
52
+ res.writeHead(200, { "Content-Type": "text/plain" });
53
+ res.end("✅ Login successful! You can now close this window.");
54
+
55
+ console.log("✔️ Login approved via browser.");
56
+ console.log(`✔️ Credentials updated in ~/${shell}`);
57
+ console.log(`👉 Run: source ~/${shell}`);
58
+ console.log();
59
+ console.log(`💡 Tip: Run \`git clone git.superfunctions.ai/${projectSlug}/${projectSlug}-server\` to start your server project.`);
60
+ console.log(`💡 Tip: Run \`git clone git.superfunctions.ai/${projectSlug}/${projectSlug}-app\` to start your app project.`);
61
+
62
+ server.close();
63
+ } catch (err) {
64
+ res.writeHead(500).end("Invalid request format");
65
+ console.error(err);
66
+ server.close();
67
+ }
68
+ });
69
+ } else {
70
+ res.writeHead(404).end("Not Found");
71
+ }
72
+ });
73
+
74
+ server.listen(PORT, () => {
75
+ console.log("🌐 Opening browser for login...");
76
+ open(`http://localhost:3000/cli-login?port=${PORT}`);
77
+ });
78
+ } catch (err) {
79
+ console.error(err);
80
+ }
81
+ }
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@spfn/cli",
3
+ "version": "0.0.1",
4
+ "description": "Superfunction CLI",
5
+ "keywords": [
6
+ "cli",
7
+ "superfunction",
8
+ "sf",
9
+ "devtools",
10
+ "automation"
11
+ ],
12
+ "homepage": "https://superfunctions.ai",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://git.superfunctions.ai/sf/sf-cli.git"
16
+ },
17
+ "license": "MIT",
18
+ "author": "Superfunction Ray <rayim@superfunctions.ai>",
19
+ "type": "module",
20
+ "main": "lib/index.js",
21
+ "bin": {
22
+ "sf": "lib/index.js"
23
+ },
24
+ "directories": {
25
+ "lib": "lib"
26
+ },
27
+ "files": [
28
+ "lib/**/*"
29
+ ],
30
+ "scripts": {
31
+ "start": "node lib/index.js"
32
+ },
33
+ "dependencies": {
34
+ "commander": "^13.1.0",
35
+ "open": "^10.1.1"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^22.15.3",
39
+ "typescript": "^5.0.0"
40
+ },
41
+ "engines": {
42
+ "node": ">=18"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public"
46
+ }
47
+ }