@spfn/cli 0.0.2 → 0.0.3

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.
Files changed (2) hide show
  1. package/lib/login.js +133 -65
  2. package/package.json +1 -1
package/lib/login.js CHANGED
@@ -3,93 +3,154 @@ import open from "open";
3
3
  import fs from "fs";
4
4
  import os from "os";
5
5
  import path from "path";
6
+ import { execSync } from "child_process";
6
7
 
7
8
  const PORT = 5678;
8
9
 
9
- /**
10
- * templates 폴더에서 templateName 파일을 읽고,
11
- * {{KEY}} 플레이스홀더를 vars[KEY]로 치환하여 outputPath에 씁니다.
12
- */
13
- function applyTemplate(
14
- templateName,
15
- outputPath,
16
- vars
17
- ) {
18
- const src = path.join(process.cwd(), "templates", templateName);
19
- if (!fs.existsSync(src)) {
20
- throw new Error(`Template not found: ${src}`);
10
+ function mergeNetrc(
11
+ username,
12
+ token
13
+ )
14
+ {
15
+ const name = process.platform === "win32" ? "_netrc" : ".netrc";
16
+ const file = path.join(os.homedir(), name);
17
+ let lines = [];
18
+
19
+ if (fs.existsSync(file))
20
+ {
21
+ lines = fs.readFileSync(file, "utf-8").split(/\r?\n/);
22
+ const filtered = [];
23
+ let skip = false;
24
+ for (const l of lines)
25
+ {
26
+ if (l.trim().startsWith("machine git.superfunctions.ai"))
27
+ {
28
+ skip = true;
29
+ }
30
+ if (!skip)
31
+ {
32
+ filtered.push(l);
33
+ }
34
+ if (skip && l.trim() === "")
35
+ {
36
+ skip = false;
37
+ }
38
+ }
39
+ lines = filtered;
21
40
  }
22
- const template = fs.readFileSync(src, "utf-8");
23
- const result = template.replace(/\{\{(\w+)\}\}/g, (_, key) =>
24
- vars[key] ?? ""
41
+
42
+ lines.push(
43
+ "",
44
+ "machine git.superfunctions.ai",
45
+ ` login ${username}`,
46
+ ` password ${token}`,
47
+ ""
25
48
  );
26
49
 
27
- fs.mkdirSync(path.dirname(outputPath), { recursive: true });
28
- fs.writeFileSync(outputPath, result, "utf-8");
29
- console.log(`✔️ Applied template ${templateName} → ${outputPath}`);
50
+ fs.writeFileSync(file, lines.join("\n"), "utf-8");
51
+ if (process.platform !== "win32")
52
+ {
53
+ fs.chmodSync(file, 0o600);
54
+ }
55
+ console.log(`✔️ Merged netrc: ${file}`);
30
56
  }
31
57
 
32
- export function login() {
33
- try {
34
- const server = http.createServer((req, res) => {
35
- // CORS headers
58
+ function mergeGradleInit()
59
+ {
60
+ const dir = path.join(os.homedir(), ".gradle");
61
+ const file = path.join(dir, "init.gradle");
62
+ const startMarker = "// sf-cli start";
63
+ const endMarker = "// sf-cli end";
64
+
65
+ let content = "";
66
+ if (fs.existsSync(file))
67
+ {
68
+ content = fs.readFileSync(file, "utf-8");
69
+ const regex = new RegExp(
70
+ `${startMarker}[\\s\\S]*?${endMarker}\n?`,
71
+ "m"
72
+ );
73
+ content = content.replace(regex, "");
74
+ }
75
+
76
+ const block = [
77
+ startMarker,
78
+ "allprojects {",
79
+ " repositories {",
80
+ " maven {",
81
+ " name = 'Gitea'",
82
+ " url = uri('https://git.superfunctions.ai/api/packages/sf/maven')",
83
+ " credentials {",
84
+ " username = System.getenv('SF_USERNAME')",
85
+ " password = System.getenv('SF_AUTH_TOKEN')'",
86
+ " }",
87
+ " }",
88
+ " mavenCentral()",
89
+ " }",
90
+ "}",
91
+ endMarker,
92
+ ""
93
+ ].join("\n");
94
+
95
+ fs.mkdirSync(dir, { recursive: true });
96
+ fs.writeFileSync(file, content + "\n" + block, "utf-8");
97
+ console.log(`✔️ Merged Gradle init script: ${file}`);
98
+ }
99
+
100
+ export function login()
101
+ {
102
+ try
103
+ {
104
+ const server = http.createServer((req, res) =>
105
+ {
36
106
  res.setHeader("Access-Control-Allow-Origin", "*");
37
107
  res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
38
108
  res.setHeader("Access-Control-Allow-Headers", "Content-Type");
39
109
 
40
- if (req.method === "OPTIONS") {
110
+ if (req.method === "OPTIONS")
111
+ {
41
112
  res.writeHead(200);
42
113
  res.end();
43
114
  return;
44
115
  }
45
116
 
46
- if (req.url === "/callback" && req.method === "POST") {
117
+ if (req.url === "/callback" && req.method === "POST")
118
+ {
47
119
  let body = "";
48
120
  req.on("data", (chunk) => (body += chunk));
49
- req.on("end", () => {
50
- try {
121
+ req.on("end", () =>
122
+ {
123
+ try
124
+ {
51
125
  const { username, token, projectSlug } = JSON.parse(body);
52
- if (!username || !token) {
126
+ if (!username || !token)
127
+ {
53
128
  res.writeHead(400).end("Missing username or token");
54
129
  return;
55
130
  }
56
131
 
57
- // 1) 템플릿 적용
58
- // 1-1) Gradle init
59
- const gradleDest = path.join(
60
- os.homedir(),
61
- ".gradle",
62
- "init.gradle"
63
- );
64
- applyTemplate("gradle.tmpl", gradleDest, {
65
- SF_USERNAME: username,
66
- SF_AUTH_TOKEN: token,
67
- });
68
-
69
- // 1-2) npmrc
70
- const npmDest = path.join(os.homedir(), ".npmrc");
71
- applyTemplate("npm.tmpl", npmDest, {
72
- SF_AUTH_TOKEN: token,
73
- });
74
- if (process.platform !== "win32") {
75
- try {
76
- fs.chmodSync(npmDest, 0o600);
77
- } catch {}
132
+ mergeGradleInit();
133
+ try
134
+ {
135
+ execSync(
136
+ `npm config set @sf:registry https://git.superfunctions.ai/api/packages/sf/npm/`,
137
+ { stdio: "inherit", env: process.env }
138
+ );
139
+ execSync(
140
+ `npm config set //git.superfunctions.ai/api/packages/sf/npm/:_authToken "${token}"`,
141
+ { stdio: "inherit", env: process.env }
142
+ );
143
+ console.log(
144
+ "✔️ npm registry and authToken set via npm config"
145
+ );
78
146
  }
79
-
80
- // 1-3) netrc (_netrc on Windows)
81
- const netrcName =
82
- process.platform === "win32" ? "_netrc" : ".netrc";
83
- const netrcDest = path.join(os.homedir(), netrcName);
84
- applyTemplate("netrc.tmpl", netrcDest, {
85
- SF_USERNAME: username,
86
- SF_AUTH_TOKEN: token,
87
- });
88
- if (process.platform !== "win32") {
89
- fs.chmodSync(netrcDest, 0o600);
147
+ catch (e)
148
+ {
149
+ console.error("❌ npm config set failed:", e);
90
150
  }
91
151
 
92
- // 3) 응답 & 팁
152
+ mergeNetrc(username, token);
153
+
93
154
  res.writeHead(200, { "Content-Type": "text/plain" });
94
155
  res.end("✅ Login successful! You can now close this window.");
95
156
 
@@ -104,22 +165,29 @@ export function login() {
104
165
  console.log();
105
166
 
106
167
  server.close();
107
- } catch (err) {
168
+ }
169
+ catch (err)
170
+ {
108
171
  console.error(err);
109
172
  res.writeHead(500).end("Error during login callback");
110
173
  server.close();
111
174
  }
112
175
  });
113
- } else {
176
+ }
177
+ else
178
+ {
114
179
  res.writeHead(404).end("Not Found");
115
180
  }
116
181
  });
117
182
 
118
- server.listen(PORT, () => {
183
+ server.listen(PORT, () =>
184
+ {
119
185
  console.log("🌐 Opening browser for login...");
120
186
  open(`https://console.superfunctions.ai/cli-login?port=${PORT}`);
121
187
  });
122
- } catch (err) {
188
+ }
189
+ catch (err)
190
+ {
123
191
  console.error(err);
124
192
  }
125
- }
193
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spfn/cli",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "Superfunction CLI",
5
5
  "keywords": [
6
6
  "cli",