foco-cli 0.1.0 → 0.1.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 +4 -61
- package/dist/commands/login.d.ts +6 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +21 -24
- package/dist/commands/login.js.map +1 -1
- package/dist/index.js +8 -10
- package/dist/index.js.map +1 -1
- package/dist/lib/api.d.ts +1 -10
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +8 -18
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/auth.d.ts +9 -18
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +92 -48
- package/dist/lib/auth.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,8 +4,6 @@ FOCO 备考平台的命令行工具,供团队成员通过 Cursor、Codex 等 A
|
|
|
4
4
|
|
|
5
5
|
## 安装
|
|
6
6
|
|
|
7
|
-
### 方式一:从 npm 安装(推荐)
|
|
8
|
-
|
|
9
7
|
```bash
|
|
10
8
|
npm install -g foco-cli
|
|
11
9
|
```
|
|
@@ -16,42 +14,10 @@ npm install -g foco-cli
|
|
|
16
14
|
foco login
|
|
17
15
|
```
|
|
18
16
|
|
|
19
|
-
### 方式二:npx 临时使用(无需安装)
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
npx foco-cli
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
### 方式三:从本地构建安装(开发者)
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
# 构建并打包
|
|
29
|
-
cd cli && npm run dist
|
|
30
|
-
|
|
31
|
-
# 全局安装
|
|
32
|
-
npm install -g ../app/cli-dist/foco-cli-*.tgz
|
|
33
|
-
|
|
34
|
-
# 或使用 npm link(开发模式)
|
|
35
|
-
cd cli && npm link
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
### 方式四:从自建服务器安装(无 npm 环境时备用)
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
npm install -g https://你的-foco-服务器地址/api/cli/download
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
> 如果服务器地址是 `https://foco.example.com`,则命令为:
|
|
45
|
-
> `npm install -g https://foco.example.com/api/cli/download`
|
|
46
|
-
|
|
47
17
|
## 更新
|
|
48
18
|
|
|
49
19
|
```bash
|
|
50
|
-
# npm 安装的版本
|
|
51
20
|
npm update -g foco-cli
|
|
52
|
-
|
|
53
|
-
# 或直接重新安装
|
|
54
|
-
npm install -g foco-cli@latest
|
|
55
21
|
```
|
|
56
22
|
|
|
57
23
|
## 配置
|
|
@@ -149,33 +115,10 @@ npm run dist # 构建 + 打包为 .tgz(输出到 app/cli-dist/)
|
|
|
149
115
|
npm link # 链接到全局 foco 命令
|
|
150
116
|
```
|
|
151
117
|
|
|
152
|
-
##
|
|
153
|
-
|
|
154
|
-
### 发布到 npm(推荐)
|
|
118
|
+
## 发布
|
|
155
119
|
|
|
156
120
|
```bash
|
|
157
|
-
|
|
158
|
-
npm
|
|
159
|
-
|
|
160
|
-
# 发布新版本(自动运行 npm version 和 npm publish)
|
|
161
|
-
npm version patch # 0.1.0 → 0.1.1(小修小改)
|
|
162
|
-
npm version minor # 0.1.0 → 0.2.0(新增功能)
|
|
163
|
-
npm version major # 0.1.0 → 1.0.0(不兼容变更)
|
|
164
|
-
|
|
165
|
-
# 或手动发布
|
|
166
|
-
npm run build
|
|
167
|
-
npm publish
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
### 自建服务器部署(备用)
|
|
171
|
-
|
|
172
|
-
```bash
|
|
173
|
-
# 1. 构建并打包
|
|
174
|
-
cd cli && npm run dist
|
|
175
|
-
|
|
176
|
-
# 2. 将 .tgz 部署到生产服务器的 app/cli-dist/ 目录
|
|
177
|
-
scp ../app/cli-dist/foco-cli-*.tgz user@server:/path/to/app/cli-dist/
|
|
178
|
-
|
|
179
|
-
# 3. 团队成员即可通过以下命令安装/更新
|
|
180
|
-
npm install -g https://你的-foco-服务器地址/api/cli/download
|
|
121
|
+
cd cli
|
|
122
|
+
npm version patch # 0.1.0 → 0.1.1
|
|
123
|
+
npm publish --registry=https://registry.npmjs.org
|
|
181
124
|
```
|
package/dist/commands/login.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* foco login — browser-based device auth (default)
|
|
3
|
+
* foco login --token <token> — use existing token
|
|
4
|
+
* foco login <apiUrl> — specify server URL
|
|
5
|
+
*/
|
|
6
|
+
export declare function handleLogin(apiUrl?: string, token?: string): Promise<void>;
|
|
2
7
|
export declare function handleStatus(): Promise<void>;
|
|
3
8
|
export declare function handleLogout(): Promise<void>;
|
|
4
9
|
//# sourceMappingURL=login.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAef;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAElD;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAMlD"}
|
package/dist/commands/login.js
CHANGED
|
@@ -1,26 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { stdin as input, stdout as output } from "node:process";
|
|
3
|
-
import { loginAndSave } from "../lib/auth.js";
|
|
1
|
+
import { browserLogin, tokenLogin } from "../lib/auth.js";
|
|
4
2
|
import { outputJSON, printError, getConfigInfo } from "../lib/api.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
3
|
+
import { loadConfig, saveConfig } from "../lib/config.js";
|
|
4
|
+
/**
|
|
5
|
+
* foco login — browser-based device auth (default)
|
|
6
|
+
* foco login --token <token> — use existing token
|
|
7
|
+
* foco login <apiUrl> — specify server URL
|
|
8
|
+
*/
|
|
9
|
+
export async function handleLogin(apiUrl, token) {
|
|
10
|
+
const url = apiUrl || process.env.FOCO_API_URL || "http://localhost:3001";
|
|
11
|
+
const tkn = token || process.env.FOCO_TOKEN;
|
|
12
|
+
try {
|
|
13
|
+
if (tkn) {
|
|
14
|
+
await tokenLogin(url, tkn);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
await browserLogin(url);
|
|
18
|
+
}
|
|
21
19
|
}
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
catch (err) {
|
|
21
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
22
|
+
printError(msg);
|
|
24
23
|
process.exit(1);
|
|
25
24
|
}
|
|
26
25
|
}
|
|
@@ -28,10 +27,8 @@ export async function handleStatus() {
|
|
|
28
27
|
outputJSON({ status: "ok", data: getConfigInfo() });
|
|
29
28
|
}
|
|
30
29
|
export async function handleLogout() {
|
|
31
|
-
// Just clear the cookie from config
|
|
32
|
-
const { loadConfig, saveConfig } = await import("../lib/config.js");
|
|
33
30
|
const config = loadConfig();
|
|
34
|
-
config.
|
|
31
|
+
config.token = undefined;
|
|
35
32
|
config.username = undefined;
|
|
36
33
|
saveConfig(config);
|
|
37
34
|
outputJSON({ status: "ok", message: "已登出" });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE1D;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAe,EACf,KAAc;IAEd,MAAM,GAAG,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,uBAAuB,CAAC;IAC1E,MAAM,GAAG,GAAG,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;IAE5C,IAAI,CAAC;QACH,IAAI,GAAG,EAAE,CAAC;YACR,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,UAAU,CAAC,GAAG,CAAC,CAAC;QAChB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,UAAU,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,CAAC,KAAK,GAAG,SAAS,CAAC;IACzB,MAAM,CAAC,QAAQ,GAAG,SAAS,CAAC;IAC5B,UAAU,CAAC,MAAM,CAAC,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;AAC/C,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -14,12 +14,11 @@ program
|
|
|
14
14
|
const auth = program.command("auth").description("认证管理");
|
|
15
15
|
auth
|
|
16
16
|
.command("login")
|
|
17
|
-
.description("登录到 FOCO
|
|
17
|
+
.description("登录到 FOCO 服务器(浏览器授权)")
|
|
18
18
|
.argument("[apiUrl]", "API 服务器地址")
|
|
19
|
-
.
|
|
20
|
-
.
|
|
21
|
-
|
|
22
|
-
await handleLogin(apiUrl, username, password);
|
|
19
|
+
.option("-t, --token <token>", "使用已有的 API token(跳过浏览器)")
|
|
20
|
+
.action(async (apiUrl, options) => {
|
|
21
|
+
await handleLogin(apiUrl, options?.token);
|
|
23
22
|
});
|
|
24
23
|
auth
|
|
25
24
|
.command("status")
|
|
@@ -36,12 +35,11 @@ auth
|
|
|
36
35
|
// Alias: foco login = foco auth login
|
|
37
36
|
program
|
|
38
37
|
.command("login")
|
|
39
|
-
.description("登录到 FOCO
|
|
38
|
+
.description("登录到 FOCO 服务器(浏览器授权)")
|
|
40
39
|
.argument("[apiUrl]", "API 服务器地址")
|
|
41
|
-
.
|
|
42
|
-
.
|
|
43
|
-
|
|
44
|
-
await handleLogin(apiUrl, username, password);
|
|
40
|
+
.option("-t, --token <token>", "使用已有的 API token")
|
|
41
|
+
.action(async (apiUrl, options) => {
|
|
42
|
+
await handleLogin(apiUrl, options?.token);
|
|
45
43
|
});
|
|
46
44
|
// ── Banks (题库) ──────────────────────────────────────────────
|
|
47
45
|
const banks = program.command("banks").description("题库管理");
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE/G,MAAM,GAAG,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,2BAA2B,EAAE,CAAC;AAE3E,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,MAAM,CAAC;KACZ,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;KACpB,WAAW,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AAEhC,iEAAiE;AACjE,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AAEzD,IAAI;KACD,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE/G,MAAM,GAAG,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,2BAA2B,EAAE,CAAC;AAE3E,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,MAAM,CAAC;KACZ,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;KACpB,WAAW,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AAEhC,iEAAiE;AACjE,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AAEzD,IAAI;KACD,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,qBAAqB,CAAC;KAClC,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;KACjC,MAAM,CAAC,qBAAqB,EAAE,wBAAwB,CAAC;KACvD,MAAM,CAAC,KAAK,EAAE,MAAe,EAAE,OAA4B,EAAE,EAAE;IAC9D,MAAM,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;AAC5C,CAAC,CAAC,CAAC;AAEL,IAAI;KACD,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,UAAU,CAAC;KACvB,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,YAAY,EAAE,CAAC;AACvB,CAAC,CAAC,CAAC;AAEL,IAAI;KACD,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,SAAS,CAAC;KACtB,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,YAAY,EAAE,CAAC;AACvB,CAAC,CAAC,CAAC;AAEL,sCAAsC;AACtC,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,qBAAqB,CAAC;KAClC,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;KACjC,MAAM,CAAC,qBAAqB,EAAE,iBAAiB,CAAC;KAChD,MAAM,CAAC,KAAK,EAAE,MAAe,EAAE,OAA4B,EAAE,EAAE;IAC9D,MAAM,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;AAC5C,CAAC,CAAC,CAAC;AAEL,+DAA+D;AAC/D,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AAE3D,KAAK;KACF,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,QAAQ,CAAC;KACrB,MAAM,CAAC,mBAAmB,EAAE,kCAAkC,CAAC;KAC/D,MAAM,CAAC,gBAAgB,EAAE,OAAO,CAAC;KACjC,MAAM,CAAC,qBAAqB,EAAE,UAAU,CAAC;KACzC,MAAM,CAAC,eAAe,EAAE,IAAI,EAAE,GAAG,CAAC;KAClC,MAAM,CAAC,oBAAoB,EAAE,MAAM,EAAE,IAAI,CAAC;KAC1C,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,eAAe,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC,CAAC,CAAC;AAEL,KAAK;KACF,OAAO,CAAC,eAAe,CAAC;KACxB,WAAW,CAAC,QAAQ,CAAC;KACrB,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,EAAE;IAC/B,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC,CAAC,CAAC;AAEL,+DAA+D;AAC/D,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AAEnE,SAAS;KACN,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,QAAQ,CAAC;KACrB,MAAM,CAAC,gBAAgB,EAAE,OAAO,CAAC;KACjC,MAAM,CAAC,eAAe,EAAE,OAAO,CAAC;KAChC,MAAM,CAAC,sBAAsB,EAAE,aAAa,CAAC;KAC7C,MAAM,CAAC,qBAAqB,EAAE,UAAU,CAAC;KACzC,MAAM,CAAC,eAAe,EAAE,IAAI,EAAE,GAAG,CAAC;KAClC,MAAM,CAAC,oBAAoB,EAAE,MAAM,EAAE,IAAI,CAAC;KAC1C,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,mBAAmB,CAAC,OAAO,CAAC,CAAC;AACrC,CAAC,CAAC,CAAC;AAEL,SAAS;KACN,OAAO,CAAC,mBAAmB,CAAC;KAC5B,WAAW,CAAC,QAAQ,CAAC;KACrB,MAAM,CAAC,KAAK,EAAE,UAAkB,EAAE,EAAE;IACnC,MAAM,kBAAkB,CAAC,UAAU,CAAC,CAAC;AACvC,CAAC,CAAC,CAAC;AAEL,+DAA+D;AAC/D,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AAE7D,MAAM;KACH,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,QAAQ,CAAC;KACrB,MAAM,CAAC,mBAAmB,EAAE,iDAAiD,CAAC;KAC9E,MAAM,CAAC,uBAAuB,EAAE,sCAAsC,CAAC;KACvE,MAAM,CAAC,oBAAoB,EAAE,uBAAuB,CAAC;KACrD,MAAM,CAAC,mBAAmB,EAAE,OAAO,CAAC;KACpC,MAAM,CAAC,mBAAmB,EAAE,aAAa,CAAC;KAC1C,MAAM,CAAC,mBAAmB,EAAE,OAAO,CAAC;KACpC,MAAM,CAAC,oBAAoB,EAAE,SAAS,CAAC;KACvC,MAAM,CAAC,eAAe,EAAE,IAAI,EAAE,GAAG,CAAC;KAClC,MAAM,CAAC,oBAAoB,EAAE,MAAM,EAAE,IAAI,CAAC;KAC1C,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC;AAClC,CAAC,CAAC,CAAC;AAEL,MAAM;KACH,OAAO,CAAC,WAAW,CAAC;KACpB,WAAW,CAAC,QAAQ,CAAC;KACrB,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,EAAE;IAC3B,MAAM,eAAe,CAAC,EAAE,CAAC,CAAC;AAC5B,CAAC,CAAC,CAAC;AAEL,MAAM;KACH,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,MAAM,CAAC;KACnB,cAAc,CAAC,iBAAiB,EAAE,MAAM,CAAC;KACzC,MAAM,CAAC,sBAAsB,EAAE,MAAM,CAAC;KACtC,MAAM,CAAC,uBAAuB,EAAE,mCAAmC,CAAC;KACpE,MAAM,CAAC,mBAAmB,EAAE,UAAU,CAAC;KACvC,MAAM,CAAC,mBAAmB,EAAE,SAAS,CAAC;KACtC,MAAM,CAAC,oBAAoB,EAAE,QAAQ,CAAC;KACtC,MAAM,CAAC,kBAAkB,EAAE,QAAQ,CAAC;KACpC,MAAM,CAAC,mBAAmB,EAAE,iBAAiB,CAAC;KAC9C,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,iBAAiB,CAAC,OAAO,CAAC,CAAC;AACnC,CAAC,CAAC,CAAC;AAEL,MAAM;KACH,OAAO,CAAC,aAAa,CAAC;KACtB,WAAW,CAAC,MAAM,CAAC;KACnB,MAAM,CAAC,mBAAmB,EAAE,8CAA8C,CAAC;KAC3E,MAAM,CAAC,uBAAuB,EAAE,mCAAmC,CAAC;KACpE,MAAM,CAAC,oBAAoB,EAAE,kBAAkB,CAAC;KAChD,MAAM,CAAC,mBAAmB,EAAE,mBAAmB,CAAC;KAChD,MAAM,CAAC,mBAAmB,EAAE,UAAU,CAAC;KACvC,MAAM,CAAC,iBAAiB,EAAE,IAAI,CAAC;KAC/B,MAAM,CAAC,sBAAsB,EAAE,IAAI,CAAC;KACpC,MAAM,CAAC,mBAAmB,EAAE,cAAc,CAAC;KAC3C,MAAM,CAAC,kBAAkB,EAAE,MAAM,CAAC;KAClC,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,OAAO,EAAE,EAAE;IACpC,MAAM,iBAAiB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;AACvC,CAAC,CAAC,CAAC;AAEL,iEAAiE;AACjE,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
|
package/dist/lib/api.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ApiResponse } from "../types.js";
|
|
2
2
|
/**
|
|
3
3
|
* Call the FOCO admin API.
|
|
4
|
-
*
|
|
4
|
+
* Sends stored token as Authorization: Bearer header.
|
|
5
5
|
* Returns parsed JSON response or exits on error.
|
|
6
6
|
*/
|
|
7
7
|
export declare function apiCall<T>(path: string, options?: {
|
|
@@ -12,16 +12,7 @@ export declare function apiCall<T>(path: string, options?: {
|
|
|
12
12
|
data: T;
|
|
13
13
|
raw: ApiResponse<T>;
|
|
14
14
|
}>;
|
|
15
|
-
/**
|
|
16
|
-
* Print error message to stderr.
|
|
17
|
-
*/
|
|
18
15
|
export declare function printError(message: string): void;
|
|
19
|
-
/**
|
|
20
|
-
* Output JSON result to stdout (for AI tools to parse).
|
|
21
|
-
*/
|
|
22
16
|
export declare function outputJSON(data: unknown): void;
|
|
23
|
-
/**
|
|
24
|
-
* Get config diagnostics.
|
|
25
|
-
*/
|
|
26
17
|
export declare function getConfigInfo(): Record<string, string>;
|
|
27
18
|
//# sourceMappingURL=api.d.ts.map
|
package/dist/lib/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,CAAC,EAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IACP,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CACxC,GACL,OAAO,CAAC;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,CAAA;CAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,CAAC,EAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IACP,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CACxC,GACL,OAAO,CAAC;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,CAAA;CAAE,CAAC,CAsD3C;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEhD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAE9C;AAED,wBAAgB,aAAa,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQtD"}
|
package/dist/lib/api.js
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import { loadConfig, getConfigPath } from "./config.js";
|
|
2
2
|
/**
|
|
3
3
|
* Call the FOCO admin API.
|
|
4
|
-
*
|
|
4
|
+
* Sends stored token as Authorization: Bearer header.
|
|
5
5
|
* Returns parsed JSON response or exits on error.
|
|
6
6
|
*/
|
|
7
7
|
export async function apiCall(path, options = {}) {
|
|
8
8
|
const config = loadConfig();
|
|
9
|
-
if (!config.
|
|
10
|
-
printError("
|
|
9
|
+
if (!config.token) {
|
|
10
|
+
printError("未登录。请运行 foco login");
|
|
11
11
|
process.exit(1);
|
|
12
12
|
}
|
|
13
13
|
const baseUrl = config.apiUrl.replace(/\/+$/, "");
|
|
14
14
|
const url = new URL(`${baseUrl}${path.startsWith("/") ? path : `/${path}`}`);
|
|
15
|
-
// Append query params (skip undefined values)
|
|
16
15
|
if (options.params) {
|
|
17
16
|
for (const [key, value] of Object.entries(options.params)) {
|
|
18
17
|
if (value !== undefined && value !== "") {
|
|
@@ -21,7 +20,7 @@ export async function apiCall(path, options = {}) {
|
|
|
21
20
|
}
|
|
22
21
|
}
|
|
23
22
|
const headers = {
|
|
24
|
-
|
|
23
|
+
Authorization: `Bearer ${config.token}`,
|
|
25
24
|
Accept: "application/json",
|
|
26
25
|
};
|
|
27
26
|
if (options.body !== undefined) {
|
|
@@ -32,9 +31,9 @@ export async function apiCall(path, options = {}) {
|
|
|
32
31
|
headers,
|
|
33
32
|
body: options.body ? JSON.stringify(options.body) : undefined,
|
|
34
33
|
});
|
|
35
|
-
//
|
|
36
|
-
if (res.status
|
|
37
|
-
printError("
|
|
34
|
+
// 401 → token expired or invalid
|
|
35
|
+
if (res.status === 401) {
|
|
36
|
+
printError("登录已过期,请重新运行 foco login");
|
|
38
37
|
process.exit(1);
|
|
39
38
|
}
|
|
40
39
|
const text = await res.text();
|
|
@@ -51,28 +50,19 @@ export async function apiCall(path, options = {}) {
|
|
|
51
50
|
}
|
|
52
51
|
return { data: parsed.data, raw: parsed };
|
|
53
52
|
}
|
|
54
|
-
/**
|
|
55
|
-
* Print error message to stderr.
|
|
56
|
-
*/
|
|
57
53
|
export function printError(message) {
|
|
58
54
|
process.stderr.write(`Error: ${message}\n`);
|
|
59
55
|
}
|
|
60
|
-
/**
|
|
61
|
-
* Output JSON result to stdout (for AI tools to parse).
|
|
62
|
-
*/
|
|
63
56
|
export function outputJSON(data) {
|
|
64
57
|
process.stdout.write(JSON.stringify(data, null, 2) + "\n");
|
|
65
58
|
}
|
|
66
|
-
/**
|
|
67
|
-
* Get config diagnostics.
|
|
68
|
-
*/
|
|
69
59
|
export function getConfigInfo() {
|
|
70
60
|
const config = loadConfig();
|
|
71
61
|
return {
|
|
72
62
|
apiUrl: config.apiUrl,
|
|
73
63
|
username: config.username ?? "(未设置)",
|
|
74
64
|
configPath: getConfigPath(),
|
|
75
|
-
|
|
65
|
+
hasToken: config.token ? `是 (${config.token.slice(0, 14)}...)` : "否",
|
|
76
66
|
};
|
|
77
67
|
}
|
|
78
68
|
//# sourceMappingURL=api.js.map
|
package/dist/lib/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGxD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,IAAY,EACZ,UAII,EAAE;IAEN,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,IAAI,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/auth.d.ts
CHANGED
|
@@ -1,23 +1,14 @@
|
|
|
1
|
-
interface LoginResult {
|
|
2
|
-
success: boolean;
|
|
3
|
-
cookie?: string;
|
|
4
|
-
error?: string;
|
|
5
|
-
}
|
|
6
1
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
2
|
+
* Browser-based login flow (like gh auth login).
|
|
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
|
|
9
8
|
*/
|
|
10
|
-
export declare function
|
|
9
|
+
export declare function browserLogin(apiUrl: string): Promise<void>;
|
|
11
10
|
/**
|
|
12
|
-
*
|
|
11
|
+
* Store a pre-existing token (generated from admin dashboard).
|
|
13
12
|
*/
|
|
14
|
-
export declare function
|
|
15
|
-
/**
|
|
16
|
-
* Login and save credentials to config.
|
|
17
|
-
*/
|
|
18
|
-
export declare function loginAndSave(apiUrl: string, username: string, password: string): Promise<{
|
|
19
|
-
ok: boolean;
|
|
20
|
-
message: string;
|
|
21
|
-
}>;
|
|
22
|
-
export {};
|
|
13
|
+
export declare function tokenLogin(apiUrl: string, token: string): Promise<void>;
|
|
23
14
|
//# 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":"AA4DA;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA4ChE;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB7E"}
|
package/dist/lib/auth.js
CHANGED
|
@@ -1,70 +1,114 @@
|
|
|
1
1
|
import { loadConfig, saveConfig } from "./config.js";
|
|
2
|
+
import { outputJSON } from "./api.js";
|
|
3
|
+
import { execSync } from "node:child_process";
|
|
2
4
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
+
* Device auth: start a CLI login session.
|
|
6
|
+
* Returns device_code for polling and user_code for the browser.
|
|
5
7
|
*/
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
async function startDeviceAuth(apiUrl) {
|
|
9
|
+
const baseUrl = apiUrl.replace(/\/+$/, "");
|
|
10
|
+
const res = await fetch(`${baseUrl}/api/admin/v1/auth/device`, { method: "POST" });
|
|
11
|
+
const json = await res.json();
|
|
12
|
+
if (json.code !== 0) {
|
|
13
|
+
throw new Error(json.message ?? "启动设备授权失败");
|
|
14
|
+
}
|
|
15
|
+
return json.data;
|
|
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, {
|
|
10
27
|
method: "POST",
|
|
11
|
-
headers: {
|
|
12
|
-
|
|
13
|
-
},
|
|
14
|
-
body: new URLSearchParams({ username, password }),
|
|
15
|
-
redirect: "manual", // don't follow redirect — we want the Set-Cookie
|
|
28
|
+
headers: { "Content-Type": "application/json" },
|
|
29
|
+
body: JSON.stringify({ device_code: deviceCode }),
|
|
16
30
|
});
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (cookieHeaders.length === 0) {
|
|
24
|
-
return { success: false, error: "认证失败:用户名或密码错误" };
|
|
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;
|
|
25
37
|
}
|
|
26
|
-
//
|
|
27
|
-
const relevantCookies = cookieHeaders
|
|
28
|
-
.map((c) => c.split(";")[0]) // name=value part only
|
|
29
|
-
.filter((c) => c.startsWith("next-auth.") || c.startsWith("__Secure-next-auth."))
|
|
30
|
-
.join("; ");
|
|
31
|
-
if (!relevantCookies) {
|
|
32
|
-
return { success: false, error: "认证失败:未获取到会话令牌" };
|
|
33
|
-
}
|
|
34
|
-
return { success: true, cookie: relevantCookies };
|
|
35
|
-
}
|
|
36
|
-
catch (err) {
|
|
37
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
38
|
-
return { success: false, error: `连接失败: ${message}` };
|
|
38
|
+
// "authorization_pending" → keep polling
|
|
39
39
|
}
|
|
40
|
+
throw new Error("授权超时,请重新运行 foco login");
|
|
40
41
|
}
|
|
41
42
|
/**
|
|
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
|
|
43
49
|
*/
|
|
44
|
-
export async function
|
|
50
|
+
export async function browserLogin(apiUrl) {
|
|
51
|
+
const baseUrl = apiUrl.replace(/\/+$/, "");
|
|
52
|
+
process.stderr.write("正在启动浏览器授权...\n");
|
|
53
|
+
let device;
|
|
45
54
|
try {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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");
|
|
50
78
|
}
|
|
51
79
|
catch {
|
|
52
|
-
|
|
80
|
+
// Browser open failed, user can manually visit the URL
|
|
53
81
|
}
|
|
82
|
+
process.stderr.write("等待授权中...\n");
|
|
83
|
+
const token = await pollForToken(baseUrl, device.device_code, device.expires_in, device.interval);
|
|
84
|
+
const config = loadConfig();
|
|
85
|
+
config.apiUrl = baseUrl;
|
|
86
|
+
config.token = token;
|
|
87
|
+
config.username = "token-auth";
|
|
88
|
+
saveConfig(config);
|
|
89
|
+
outputJSON({ status: "ok", message: "登录成功", apiUrl: baseUrl });
|
|
54
90
|
}
|
|
55
91
|
/**
|
|
56
|
-
*
|
|
92
|
+
* Store a pre-existing token (generated from admin dashboard).
|
|
57
93
|
*/
|
|
58
|
-
export async function
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
94
|
+
export async function tokenLogin(apiUrl, token) {
|
|
95
|
+
const baseUrl = apiUrl.replace(/\/+$/, "");
|
|
96
|
+
// Verify the token works
|
|
97
|
+
const res = await fetch(`${baseUrl}/api/admin/v1/admins`, {
|
|
98
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
99
|
+
});
|
|
100
|
+
if (res.status === 401 || res.status === 403) {
|
|
101
|
+
throw new Error("Token 无效或已过期");
|
|
102
|
+
}
|
|
103
|
+
const json = await res.json();
|
|
104
|
+
if (json.code !== 0) {
|
|
105
|
+
throw new Error(json.message ?? "Token 验证失败");
|
|
62
106
|
}
|
|
63
107
|
const config = loadConfig();
|
|
64
|
-
config.apiUrl =
|
|
65
|
-
config.
|
|
66
|
-
config.username =
|
|
108
|
+
config.apiUrl = baseUrl;
|
|
109
|
+
config.token = token;
|
|
110
|
+
config.username = "token-auth";
|
|
67
111
|
saveConfig(config);
|
|
68
|
-
|
|
112
|
+
outputJSON({ status: "ok", message: "登录成功", apiUrl: baseUrl });
|
|
69
113
|
}
|
|
70
114
|
//# 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;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -12,8 +12,8 @@ export interface PaginatedData<T> {
|
|
|
12
12
|
}
|
|
13
13
|
export interface FocoConfig {
|
|
14
14
|
apiUrl: string;
|
|
15
|
-
/**
|
|
16
|
-
|
|
15
|
+
/** API token (foco_xxxxx) for Bearer auth */
|
|
16
|
+
token?: string;
|
|
17
17
|
/** The username used when logging in (informational) */
|
|
18
18
|
username?: string;
|
|
19
19
|
}
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;CAChB;AAED,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|