foco-cli 0.1.5 → 0.1.8
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/dist/commands/activation-codes.d.ts +14 -0
- package/dist/commands/activation-codes.d.ts.map +1 -0
- package/dist/commands/activation-codes.js +29 -0
- package/dist/commands/activation-codes.js.map +1 -0
- package/dist/commands/admins.d.ts +12 -0
- package/dist/commands/admins.d.ts.map +1 -0
- package/dist/commands/admins.js +35 -0
- package/dist/commands/admins.js.map +1 -0
- package/dist/commands/changelogs.d.ts +12 -0
- package/dist/commands/changelogs.d.ts.map +1 -0
- package/dist/commands/changelogs.js +31 -0
- package/dist/commands/changelogs.js.map +1 -0
- package/dist/commands/dashboard.d.ts +11 -0
- package/dist/commands/dashboard.d.ts.map +1 -0
- package/dist/commands/dashboard.js +27 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/exams.d.ts +22 -0
- package/dist/commands/exams.d.ts.map +1 -0
- package/dist/commands/exams.js +58 -0
- package/dist/commands/exams.js.map +1 -0
- package/dist/commands/feedback.d.ts +17 -0
- package/dist/commands/feedback.d.ts.map +1 -0
- package/dist/commands/feedback.js +43 -0
- package/dist/commands/feedback.js.map +1 -0
- package/dist/commands/help-articles.d.ts +28 -0
- package/dist/commands/help-articles.d.ts.map +1 -0
- package/dist/commands/help-articles.js +67 -0
- package/dist/commands/help-articles.js.map +1 -0
- package/dist/commands/knowledge-base.d.ts +28 -0
- package/dist/commands/knowledge-base.d.ts.map +1 -0
- package/dist/commands/knowledge-base.js +67 -0
- package/dist/commands/knowledge-base.js.map +1 -0
- package/dist/commands/knowledge-points.d.ts +29 -0
- package/dist/commands/knowledge-points.d.ts.map +1 -0
- package/dist/commands/knowledge-points.js +64 -0
- package/dist/commands/knowledge-points.js.map +1 -0
- package/dist/commands/login.d.ts +2 -2
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +14 -4
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/orders.d.ts +9 -0
- package/dist/commands/orders.d.ts.map +1 -0
- package/dist/commands/orders.js +15 -0
- package/dist/commands/orders.js.map +1 -0
- package/dist/commands/products.d.ts +22 -0
- package/dist/commands/products.d.ts.map +1 -0
- package/dist/commands/products.js +54 -0
- package/dist/commands/products.js.map +1 -0
- package/dist/commands/projects.d.ts +24 -0
- package/dist/commands/projects.d.ts.map +1 -0
- package/dist/commands/projects.js +61 -0
- package/dist/commands/projects.js.map +1 -0
- package/dist/commands/resource-packs.d.ts +26 -0
- package/dist/commands/resource-packs.d.ts.map +1 -0
- package/dist/commands/resource-packs.js +64 -0
- package/dist/commands/resource-packs.js.map +1 -0
- package/dist/commands/stats.d.ts +2 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +6 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/syllabi.d.ts +26 -0
- package/dist/commands/syllabi.d.ts.map +1 -0
- package/dist/commands/syllabi.js +65 -0
- package/dist/commands/syllabi.js.map +1 -0
- package/dist/commands/threads.d.ts +13 -0
- package/dist/commands/threads.d.ts.map +1 -0
- package/dist/commands/threads.js +33 -0
- package/dist/commands/threads.js.map +1 -0
- package/dist/commands/users.d.ts +7 -0
- package/dist/commands/users.d.ts.map +1 -0
- package/dist/commands/users.js +13 -0
- package/dist/commands/users.js.map +1 -0
- package/dist/index.js +385 -69
- package/dist/index.js.map +1 -1
- package/dist/lib/auth.d.ts +7 -8
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +26 -80
- package/dist/lib/auth.js.map +1 -1
- package/package.json +1 -1
package/dist/lib/auth.d.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* 1. Start device auth → get device_code + user_code
|
|
5
|
-
* 2. Print URL + code, optionally open browser
|
|
6
|
-
* 3. Poll for token
|
|
7
|
-
* 4. Save token to config
|
|
2
|
+
* Login with username and password → get JWT.
|
|
8
3
|
*/
|
|
9
|
-
export declare function
|
|
4
|
+
export declare function passwordLogin(apiUrl: string, username: string, password: string): Promise<void>;
|
|
10
5
|
/**
|
|
11
|
-
*
|
|
6
|
+
* Verify a pre-existing token still works.
|
|
12
7
|
*/
|
|
13
8
|
export declare function tokenLogin(apiUrl: string, token: string): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* Prompt for input from stdin (for password login).
|
|
11
|
+
*/
|
|
12
|
+
export declare function prompt(question: string): Promise<string>;
|
|
14
13
|
//# sourceMappingURL=auth.d.ts.map
|
package/dist/lib/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBrG;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB7E;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQxD"}
|
package/dist/lib/auth.js
CHANGED
|
@@ -1,99 +1,33 @@
|
|
|
1
1
|
import { loadConfig, saveConfig } from "./config.js";
|
|
2
2
|
import { outputJSON } from "./api.js";
|
|
3
|
-
import
|
|
3
|
+
import * as readline from "node:readline";
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
* Returns device_code for polling and user_code for the browser.
|
|
5
|
+
* Login with username and password → get JWT.
|
|
7
6
|
*/
|
|
8
|
-
async function
|
|
7
|
+
export async function passwordLogin(apiUrl, username, password) {
|
|
9
8
|
const baseUrl = apiUrl.replace(/\/+$/, "");
|
|
10
|
-
const res = await fetch(`${baseUrl}/api/admin/v1/auth/
|
|
9
|
+
const res = await fetch(`${baseUrl}/api/admin/v1/auth/login`, {
|
|
10
|
+
method: "POST",
|
|
11
|
+
headers: { "Content-Type": "application/json" },
|
|
12
|
+
body: JSON.stringify({ username, password }),
|
|
13
|
+
});
|
|
11
14
|
const json = await res.json();
|
|
12
15
|
if (json.code !== 0) {
|
|
13
|
-
throw new Error(json.message ?? "
|
|
16
|
+
throw new Error(json.message ?? "登录失败");
|
|
14
17
|
}
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Poll for the access token after the user authorizes in the browser.
|
|
19
|
-
*/
|
|
20
|
-
async function pollForToken(apiUrl, deviceCode, expiresIn, interval) {
|
|
21
|
-
const baseUrl = apiUrl.replace(/\/+$/, "");
|
|
22
|
-
const deadline = Date.now() + expiresIn * 1000;
|
|
23
|
-
const pollUrl = `${baseUrl}/api/admin/v1/auth/device/token`;
|
|
24
|
-
while (Date.now() < deadline) {
|
|
25
|
-
await new Promise((r) => setTimeout(r, interval * 1000));
|
|
26
|
-
const res = await fetch(pollUrl, {
|
|
27
|
-
method: "POST",
|
|
28
|
-
headers: { "Content-Type": "application/json" },
|
|
29
|
-
body: JSON.stringify({ device_code: deviceCode }),
|
|
30
|
-
});
|
|
31
|
-
const json = await res.json();
|
|
32
|
-
if (json.code !== 0)
|
|
33
|
-
continue; // still pending or error
|
|
34
|
-
const data = json.data;
|
|
35
|
-
if (data?.access_token) {
|
|
36
|
-
return data.access_token;
|
|
37
|
-
}
|
|
38
|
-
// "authorization_pending" → keep polling
|
|
39
|
-
}
|
|
40
|
-
throw new Error("授权超时,请重新运行 foco login");
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Browser-based login flow (like gh auth login).
|
|
44
|
-
*
|
|
45
|
-
* 1. Start device auth → get device_code + user_code
|
|
46
|
-
* 2. Print URL + code, optionally open browser
|
|
47
|
-
* 3. Poll for token
|
|
48
|
-
* 4. Save token to config
|
|
49
|
-
*/
|
|
50
|
-
export async function browserLogin(apiUrl) {
|
|
51
|
-
const baseUrl = apiUrl.replace(/\/+$/, "");
|
|
52
|
-
process.stderr.write("正在启动浏览器授权...\n");
|
|
53
|
-
let device;
|
|
54
|
-
try {
|
|
55
|
-
device = await startDeviceAuth(baseUrl);
|
|
56
|
-
}
|
|
57
|
-
catch (err) {
|
|
58
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
59
|
-
throw new Error(`启动授权失败: ${msg}`);
|
|
60
|
-
}
|
|
61
|
-
const authUrl = `${baseUrl}${device.verification_uri}?code=${device.user_code}`;
|
|
62
|
-
process.stderr.write(`\n ✏️ 验证码: ${device.user_code}\n`);
|
|
63
|
-
process.stderr.write(` 🔗 打开浏览器访问:\n`);
|
|
64
|
-
process.stderr.write(` ${authUrl}\n\n`);
|
|
65
|
-
// Try to open the browser automatically
|
|
66
|
-
try {
|
|
67
|
-
const platform = process.platform;
|
|
68
|
-
if (platform === "darwin") {
|
|
69
|
-
execSync("open " + JSON.stringify(authUrl), { stdio: "ignore" });
|
|
70
|
-
}
|
|
71
|
-
else if (platform === "linux") {
|
|
72
|
-
execSync("xdg-open " + JSON.stringify(authUrl), { stdio: "ignore" });
|
|
73
|
-
}
|
|
74
|
-
else if (platform === "win32") {
|
|
75
|
-
execSync('start "" ' + JSON.stringify(authUrl), { stdio: "ignore", shell: true });
|
|
76
|
-
}
|
|
77
|
-
process.stderr.write("已自动打开浏览器...\n");
|
|
78
|
-
}
|
|
79
|
-
catch {
|
|
80
|
-
// Browser open failed, user can manually visit the URL
|
|
81
|
-
}
|
|
82
|
-
process.stderr.write("等待授权中...\n");
|
|
83
|
-
const token = await pollForToken(baseUrl, device.device_code, device.expires_in, device.interval);
|
|
18
|
+
const { token, user } = json.data;
|
|
84
19
|
const config = loadConfig();
|
|
85
20
|
config.apiUrl = baseUrl;
|
|
86
21
|
config.token = token;
|
|
87
|
-
config.username =
|
|
22
|
+
config.username = user.name;
|
|
88
23
|
saveConfig(config);
|
|
89
|
-
outputJSON({ status: "ok", message:
|
|
24
|
+
outputJSON({ status: "ok", message: `登录成功 (${user.name})`, apiUrl: baseUrl });
|
|
90
25
|
}
|
|
91
26
|
/**
|
|
92
|
-
*
|
|
27
|
+
* Verify a pre-existing token still works.
|
|
93
28
|
*/
|
|
94
29
|
export async function tokenLogin(apiUrl, token) {
|
|
95
30
|
const baseUrl = apiUrl.replace(/\/+$/, "");
|
|
96
|
-
// Verify the token works
|
|
97
31
|
const res = await fetch(`${baseUrl}/api/admin/v1/admins`, {
|
|
98
32
|
headers: { Authorization: `Bearer ${token}` },
|
|
99
33
|
});
|
|
@@ -107,8 +41,20 @@ export async function tokenLogin(apiUrl, token) {
|
|
|
107
41
|
const config = loadConfig();
|
|
108
42
|
config.apiUrl = baseUrl;
|
|
109
43
|
config.token = token;
|
|
110
|
-
config.username = "
|
|
44
|
+
config.username = "jwt-auth";
|
|
111
45
|
saveConfig(config);
|
|
112
46
|
outputJSON({ status: "ok", message: "登录成功", apiUrl: baseUrl });
|
|
113
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Prompt for input from stdin (for password login).
|
|
50
|
+
*/
|
|
51
|
+
export function prompt(question) {
|
|
52
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
53
|
+
return new Promise((resolve) => {
|
|
54
|
+
rl.question(question, (answer) => {
|
|
55
|
+
rl.close();
|
|
56
|
+
resolve(answer.trim());
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
114
60
|
//# sourceMappingURL=auth.js.map
|
package/dist/lib/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"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"}
|