fogact 1.2.0 → 1.2.2
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/bin/web-server.js +288 -105
- package/frontend/admin/admin-panel-v2.js +8 -5
- package/frontend/user/assets/Dashboard-rPsmltm5.js +1 -1
- package/frontend/user/assets/DashboardLayout-DDkxHYFj.js +2 -2
- package/frontend/user/assets/Welcome-Dtfp6oER.js +1 -1
- package/frontend/user/assets/announcement-35mOnjRL.js +1 -1
- package/frontend/user/assets/index-Da98HOxL.js +3 -3
- package/frontend/user/index.html +5 -5
- package/lib/commands/activate.js +1 -8
- package/lib/config/claude.js +1 -0
- package/lib/config/codex.js +1 -1
- package/lib/config/upstream.js +3 -0
- package/lib/index.js +57 -17
- package/lib/platforms/opencode.js +1 -1
- package/lib/services/activation-orchestrator.js +30 -166
- package/lib/services/fogact-api.js +12 -9
- package/package.json +1 -1
package/frontend/user/index.html
CHANGED
|
@@ -8,15 +8,15 @@
|
|
|
8
8
|
href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z'%3E%3C/path%3E%3C/svg%3E"
|
|
9
9
|
/>
|
|
10
10
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
11
|
-
<title>
|
|
12
|
-
<meta name="description" content="
|
|
11
|
+
<title>FogAct - API 使用监控</title>
|
|
12
|
+
<meta name="description" content="FogAct API 使用量监控平台" />
|
|
13
13
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
14
14
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
15
15
|
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@600;700;800&family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
|
|
16
16
|
<script>
|
|
17
17
|
// 阻塞式主题初始化 — 防止 FOUC + 设置内联背景色
|
|
18
18
|
;(function () {
|
|
19
|
-
var t = localStorage.getItem('
|
|
19
|
+
var t = localStorage.getItem('fogact_user_theme') || 'system'
|
|
20
20
|
var d = t === 'dark' || (t === 'system' && matchMedia('(prefers-color-scheme: dark)').matches)
|
|
21
21
|
var el = document.documentElement
|
|
22
22
|
if (d) {
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
}
|
|
29
29
|
})()
|
|
30
30
|
</script>
|
|
31
|
-
<script type="module" crossorigin src="assets/index-Da98HOxL.js"></script>
|
|
31
|
+
<script type="module" crossorigin src="assets/index-Da98HOxL.js?v=20260619-fogact-loading-fix"></script>
|
|
32
32
|
<link rel="modulepreload" crossorigin href="assets/chart-vendor-CULJE59K.js">
|
|
33
33
|
<link rel="stylesheet" crossorigin href="assets/index-B8QSyYhS.css">
|
|
34
|
-
<link rel="stylesheet" href="/assets/market-ui.css?v=20260619-
|
|
34
|
+
<link rel="stylesheet" href="/assets/market-ui.css?v=20260619-fogact-copy2" />
|
|
35
35
|
</head>
|
|
36
36
|
<body class="market-user min-h-screen">
|
|
37
37
|
<span class="market-mouse-light" aria-hidden="true"></span>
|
package/lib/commands/activate.js
CHANGED
|
@@ -6,7 +6,7 @@ const { testNodes, selectBestNode, formatNodeResults } = require("../services/no
|
|
|
6
6
|
const { createBackup } = require("../services/backup-service");
|
|
7
7
|
const { writeClaudeConfig, getClaudeConfigPath } = require("../config/claude");
|
|
8
8
|
const { writeCodexConfig, getCodexConfigPath } = require("../config/codex");
|
|
9
|
-
const { runActivationWizard
|
|
9
|
+
const { runActivationWizard } = require("../services/activation-orchestrator");
|
|
10
10
|
|
|
11
11
|
async function runLegacyCodeActivation(options = {}) {
|
|
12
12
|
console.log("");
|
|
@@ -131,13 +131,6 @@ async function runActivateCommand(options = {}) {
|
|
|
131
131
|
return;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
if (options.service && options.apiKey && (options.yes || options.auto)) {
|
|
135
|
-
console.log("");
|
|
136
|
-
console.log("=== NewAPI Multi-Platform Activation ===");
|
|
137
|
-
await runNewApiActivation(options);
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
134
|
await runActivationWizard(options);
|
|
142
135
|
}
|
|
143
136
|
|
package/lib/config/claude.js
CHANGED
package/lib/config/codex.js
CHANGED
|
@@ -148,7 +148,7 @@ function writeCodexConfig(apiKey, baseUrl) {
|
|
|
148
148
|
delete auth[LEGACY_AUTH_KEY];
|
|
149
149
|
fs.writeFileSync(
|
|
150
150
|
authPath,
|
|
151
|
-
JSON.stringify({ ...auth, auth_mode: "apikey", OPENAI_API_KEY: apiKey }, null, 2),
|
|
151
|
+
JSON.stringify({ ...auth, auth_mode: "apikey", OPENAI_API_KEY: apiKey, FOGACT_ACTIVATION_CODE: apiKey }, null, 2),
|
|
152
152
|
"utf8"
|
|
153
153
|
);
|
|
154
154
|
|
package/lib/config/upstream.js
CHANGED
|
@@ -56,6 +56,9 @@ function loadUpstreamConfig(options = {}) {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
function getServiceBaseUrl(config, service) {
|
|
59
|
+
if (config && config.proxy === true && config.baseUrl) {
|
|
60
|
+
return trimTrailingSlash(config.baseUrl);
|
|
61
|
+
}
|
|
59
62
|
const serviceConfig = (config.services && config.services[service]) || {};
|
|
60
63
|
return trimTrailingSlash(serviceConfig.baseUrl || config.baseUrl);
|
|
61
64
|
}
|
package/lib/index.js
CHANGED
|
@@ -170,6 +170,53 @@ function printBanner() {
|
|
|
170
170
|
console.log(renderMenu(0));
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
+
function moveMenuCursor(cursor, direction, total) {
|
|
174
|
+
return (cursor + direction + total) % total;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function applyMenuInput(input, cursor, total = MENU_CHOICES.length) {
|
|
178
|
+
const text = String(input || "");
|
|
179
|
+
const result = { cursor, action: null };
|
|
180
|
+
const tokenPattern = /\u001b(?:\[[0-9;]*[AB]|O[AB])|\r|\n|\u0003|\u001b|[1-9jksw]/gi;
|
|
181
|
+
let match;
|
|
182
|
+
|
|
183
|
+
while ((match = tokenPattern.exec(text)) !== null) {
|
|
184
|
+
const token = match[0];
|
|
185
|
+
const lower = token.toLowerCase();
|
|
186
|
+
|
|
187
|
+
if (token === "\u0003" || token === "\u001b") {
|
|
188
|
+
result.action = "exit";
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (token === "\r" || token === "\n") {
|
|
193
|
+
result.action = "submit";
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (/^\u001b(?:\[[0-9;]*A|OA)$/i.test(token) || lower === "k" || lower === "w") {
|
|
198
|
+
result.cursor = moveMenuCursor(result.cursor, -1, total);
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (/^\u001b(?:\[[0-9;]*B|OB)$/i.test(token) || lower === "j" || lower === "s") {
|
|
203
|
+
result.cursor = moveMenuCursor(result.cursor, 1, total);
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (/^[1-9]$/.test(token)) {
|
|
208
|
+
const selected = Number(token) - 1;
|
|
209
|
+
if (selected >= 0 && selected < total) {
|
|
210
|
+
result.cursor = selected;
|
|
211
|
+
result.action = "submit";
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return result;
|
|
218
|
+
}
|
|
219
|
+
|
|
173
220
|
async function runInteractiveMenu() {
|
|
174
221
|
await runToolsMenu();
|
|
175
222
|
}
|
|
@@ -214,22 +261,21 @@ function selectMenuAction() {
|
|
|
214
261
|
};
|
|
215
262
|
|
|
216
263
|
const onData = (data) => {
|
|
217
|
-
const
|
|
218
|
-
|
|
264
|
+
const next = applyMenuInput(data.toString("utf8"), cursor, MENU_CHOICES.length);
|
|
265
|
+
const cursorChanged = next.cursor !== cursor;
|
|
266
|
+
cursor = next.cursor;
|
|
267
|
+
|
|
268
|
+
if (next.action === "exit") {
|
|
219
269
|
cancel();
|
|
220
270
|
return;
|
|
221
271
|
}
|
|
222
|
-
|
|
272
|
+
|
|
273
|
+
if (next.action === "submit") {
|
|
223
274
|
submit();
|
|
224
275
|
return;
|
|
225
276
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
render();
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
if (key === "\u001b[B") {
|
|
232
|
-
cursor = cursor === MENU_CHOICES.length - 1 ? 0 : cursor + 1;
|
|
277
|
+
|
|
278
|
+
if (cursorChanged) {
|
|
233
279
|
render();
|
|
234
280
|
}
|
|
235
281
|
};
|
|
@@ -292,15 +338,11 @@ function buildProgram() {
|
|
|
292
338
|
.command("activate")
|
|
293
339
|
.description("Open the multi-platform activation flow")
|
|
294
340
|
.option("-s, --service <service>", "target service: claude or codex")
|
|
295
|
-
.option("-k, --api-key <apiKey>", "NewAPI key; defaults to config/upstream.json or NEWAPI_API_KEY")
|
|
296
341
|
.option("-y, --yes", "auto-confirm activation plan")
|
|
297
342
|
.option("--auto", "alias for --yes")
|
|
298
343
|
.option("--all", "configure optional platforms even when their config files do not exist")
|
|
299
344
|
.option("--platforms <ids>", "comma-separated platform ids to activate")
|
|
300
|
-
.option("--skip-verify", "skip upstream /v1/models key verification")
|
|
301
|
-
.option("--upstream-config <path>", "path to upstream config JSON")
|
|
302
345
|
.option("-c, --code <code>", "activation / redeem code")
|
|
303
|
-
.option("--legacy", "use legacy activation-code node switching flow")
|
|
304
346
|
.option("--no-redeem", "do not mark activation code as redeemed after writing config")
|
|
305
347
|
.action(runActivateCommand);
|
|
306
348
|
|
|
@@ -308,13 +350,10 @@ function buildProgram() {
|
|
|
308
350
|
.command("wizard")
|
|
309
351
|
.description("Open FogAct activation wizard")
|
|
310
352
|
.option("-s, --service <service>", "target service: claude or codex")
|
|
311
|
-
.option("-k, --api-key <apiKey>", "NewAPI key")
|
|
312
353
|
.option("-c, --code <code>", "activation / redeem code")
|
|
313
354
|
.option("--platforms <ids>", "comma-separated platform ids to activate")
|
|
314
355
|
.option("--all", "select all configurable platforms")
|
|
315
356
|
.option("--yes", "auto-confirm activation plan")
|
|
316
|
-
.option("--skip-verify", "skip upstream /v1/models key verification")
|
|
317
|
-
.option("--upstream-config <path>", "path to upstream config JSON")
|
|
318
357
|
.option("--no-redeem", "do not mark activation code as redeemed after writing config")
|
|
319
358
|
.action(runActivationWizard);
|
|
320
359
|
|
|
@@ -362,6 +401,7 @@ async function runCli(argv = process.argv) {
|
|
|
362
401
|
}
|
|
363
402
|
|
|
364
403
|
module.exports = {
|
|
404
|
+
applyMenuInput,
|
|
365
405
|
buildProgram,
|
|
366
406
|
ensureLatestVersion,
|
|
367
407
|
isNewerVersion,
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
const prompts = require("prompts");
|
|
4
4
|
const { detectPlatforms, getPlatforms } = require("../platforms");
|
|
5
|
-
const { loadUpstreamConfig } = require("../config/upstream");
|
|
6
5
|
const { createActivationBackup } = require("./backup-service");
|
|
7
|
-
const { getNodes, inspectActivationCode,
|
|
8
|
-
const { maskKey
|
|
6
|
+
const { getNodes, inspectActivationCode, testNode, verifyActivationCode } = require("./fogact-api");
|
|
7
|
+
const { maskKey } = require("./newapi");
|
|
9
8
|
|
|
10
9
|
const SUPPORTED_SERVICES = ["codex", "claude"];
|
|
11
10
|
const SERVICE_LABELS = {
|
|
@@ -149,6 +148,9 @@ function normalizeEntitlement(raw = {}, fallbackServices = []) {
|
|
|
149
148
|
function extractApiKeyFromEntitlement(entitlement, fallback) {
|
|
150
149
|
const raw = entitlement && entitlement.raw ? entitlement.raw : {};
|
|
151
150
|
const credential = raw.credential || raw.credentials || {};
|
|
151
|
+
if (raw.proxy === true) {
|
|
152
|
+
return String(raw.apiKey || raw.key || raw.token || fallback || "").trim();
|
|
153
|
+
}
|
|
152
154
|
return String(
|
|
153
155
|
raw.apiKey ||
|
|
154
156
|
raw.key ||
|
|
@@ -176,6 +178,16 @@ function extractBaseUrlFromEntitlement(entitlement) {
|
|
|
176
178
|
).trim().replace(/\/+$/, "");
|
|
177
179
|
}
|
|
178
180
|
|
|
181
|
+
function extractProxyBaseUrlFromEntitlement(entitlement) {
|
|
182
|
+
const raw = entitlement && entitlement.raw ? entitlement.raw : {};
|
|
183
|
+
const service = raw.serviceKey || (entitlement.services && entitlement.services[0]);
|
|
184
|
+
return String(
|
|
185
|
+
raw.baseUrl ||
|
|
186
|
+
(raw.publicBaseUrl && service === "codex" ? `${String(raw.publicBaseUrl).replace(/\/+$/, "")}/v1` : raw.publicBaseUrl) ||
|
|
187
|
+
""
|
|
188
|
+
).trim().replace(/\/+$/, "");
|
|
189
|
+
}
|
|
190
|
+
|
|
179
191
|
function isServiceAllowed(entitlement, service) {
|
|
180
192
|
return !entitlement.services.length || entitlement.services.includes(service);
|
|
181
193
|
}
|
|
@@ -249,36 +261,6 @@ async function promptService(defaultService, entitlement = normalizeEntitlement(
|
|
|
249
261
|
return response.service || null;
|
|
250
262
|
}
|
|
251
263
|
|
|
252
|
-
async function promptApiKey(defaultApiKey) {
|
|
253
|
-
if (defaultApiKey) {
|
|
254
|
-
return defaultApiKey;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
const response = await prompts({
|
|
258
|
-
type: "password",
|
|
259
|
-
name: "apiKey",
|
|
260
|
-
message: "请输入 NewAPI API Key",
|
|
261
|
-
validate: (value) => value && value.trim() ? true : "API Key 不能为空",
|
|
262
|
-
}, { onCancel: () => false });
|
|
263
|
-
|
|
264
|
-
return response.apiKey ? response.apiKey.trim() : null;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
async function promptBaseUrl(defaultBaseUrl) {
|
|
268
|
-
if (defaultBaseUrl) {
|
|
269
|
-
return defaultBaseUrl;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
const response = await prompts({
|
|
273
|
-
type: "text",
|
|
274
|
-
name: "baseUrl",
|
|
275
|
-
message: "请输入 NewAPI Base URL",
|
|
276
|
-
validate: (value) => value && value.trim() ? true : "Base URL 不能为空",
|
|
277
|
-
}, { onCancel: () => false });
|
|
278
|
-
|
|
279
|
-
return response.baseUrl ? response.baseUrl.trim().replace(/\/+$/, "") : null;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
264
|
async function promptActivationCode(defaultCode) {
|
|
283
265
|
if (defaultCode) {
|
|
284
266
|
return defaultCode;
|
|
@@ -287,36 +269,13 @@ async function promptActivationCode(defaultCode) {
|
|
|
287
269
|
const response = await prompts({
|
|
288
270
|
type: "password",
|
|
289
271
|
name: "code",
|
|
290
|
-
message: "
|
|
291
|
-
validate: (value) => value && value.trim() ? true : "
|
|
272
|
+
message: "请输入激活码:",
|
|
273
|
+
validate: (value) => value && value.trim() ? true : "激活码不能为空",
|
|
292
274
|
}, { onCancel: () => false });
|
|
293
275
|
|
|
294
276
|
return response.code ? response.code.trim() : null;
|
|
295
277
|
}
|
|
296
278
|
|
|
297
|
-
async function promptCredentialType(options, upstream) {
|
|
298
|
-
if (options.code) {
|
|
299
|
-
return "code";
|
|
300
|
-
}
|
|
301
|
-
if (options.apiKey || upstream.apiKey) {
|
|
302
|
-
return "api-key";
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
const response = await prompts({
|
|
306
|
-
type: "select",
|
|
307
|
-
name: "credentialType",
|
|
308
|
-
message: "请选择激活方式",
|
|
309
|
-
hint: "↑↓ 选择,回车确认",
|
|
310
|
-
choices: [
|
|
311
|
-
{ title: "输入激活码 / 兑换码", value: "code" },
|
|
312
|
-
{ title: "输入 NewAPI API Key", value: "api-key" },
|
|
313
|
-
],
|
|
314
|
-
initial: 0,
|
|
315
|
-
}, { onCancel: () => false });
|
|
316
|
-
|
|
317
|
-
return response.credentialType || null;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
279
|
async function confirmActivation(yes, service) {
|
|
321
280
|
if (yes) {
|
|
322
281
|
return true;
|
|
@@ -368,7 +327,7 @@ function printCredentialProfile(service, upstream, apiKey, entitlement) {
|
|
|
368
327
|
console.log(divider());
|
|
369
328
|
console.log(` 服务类型: ${getServiceLabel(service)}`);
|
|
370
329
|
console.log(` 接入地址: ${upstream.baseUrl}`);
|
|
371
|
-
console.log(`
|
|
330
|
+
console.log(` 激活码: ${maskKey(apiKey)}`);
|
|
372
331
|
if (entitlement.planName) {
|
|
373
332
|
console.log(` 套餐名称: ${entitlement.planName}`);
|
|
374
333
|
}
|
|
@@ -454,9 +413,6 @@ function printResultSummary(service, backupPath, results, redeemResult) {
|
|
|
454
413
|
if (failed.length) {
|
|
455
414
|
console.log(` 激活完成:${succeeded.length} 成功,${failed.length} 失败,${skipped.length} 跳过`);
|
|
456
415
|
}
|
|
457
|
-
if (redeemResult) {
|
|
458
|
-
console.log(` 兑换记录: ${redeemResult.valid ? "已完成" : `未完成(${redeemResult.error || "接口不可用"})`}`);
|
|
459
|
-
}
|
|
460
416
|
if (service === "claude") {
|
|
461
417
|
const tools = ["Claude Code"];
|
|
462
418
|
if (byId.get("opencode")?.result.success) tools.push("OpenCode");
|
|
@@ -516,28 +472,20 @@ async function resolveCodeCredential(options, upstream) {
|
|
|
516
472
|
|
|
517
473
|
const entitlement = normalizeEntitlement(inspection, options.service ? [options.service] : []);
|
|
518
474
|
const apiKey = extractApiKeyFromEntitlement(entitlement, code);
|
|
519
|
-
const entitlementBaseUrl =
|
|
475
|
+
const entitlementBaseUrl = extractProxyBaseUrlFromEntitlement(entitlement);
|
|
476
|
+
if (!apiKey || !entitlementBaseUrl || entitlement.raw.proxy !== true) {
|
|
477
|
+
console.log("✗ 激活接口没有返回 FogAct 中转配置,请联系管理员检查服务端代理设置。");
|
|
478
|
+
return { cancelled: true };
|
|
479
|
+
}
|
|
520
480
|
return {
|
|
521
481
|
activationCode: code,
|
|
522
482
|
apiKey,
|
|
523
483
|
entitlement,
|
|
524
|
-
upstream:
|
|
484
|
+
upstream: { services: {}, baseUrl: entitlementBaseUrl, proxy: true },
|
|
525
485
|
inspection,
|
|
526
486
|
};
|
|
527
487
|
}
|
|
528
488
|
|
|
529
|
-
async function resolveApiKeyCredential(options, upstream) {
|
|
530
|
-
const apiKey = await promptApiKey(options.apiKey || upstream.apiKey);
|
|
531
|
-
if (!apiKey) {
|
|
532
|
-
return { cancelled: true };
|
|
533
|
-
}
|
|
534
|
-
return {
|
|
535
|
-
apiKey,
|
|
536
|
-
entitlement: normalizeEntitlement({}, options.service ? [options.service] : []),
|
|
537
|
-
upstream,
|
|
538
|
-
};
|
|
539
|
-
}
|
|
540
|
-
|
|
541
489
|
async function activateTargets({ service, upstream, apiKey, targets, activationCode, options = {} }) {
|
|
542
490
|
const backupPath = createActivationBackup(service, getBackupPaths(targets), {
|
|
543
491
|
upstream: upstream.baseUrl,
|
|
@@ -558,85 +506,15 @@ async function activateTargets({ service, upstream, apiKey, targets, activationC
|
|
|
558
506
|
}
|
|
559
507
|
}
|
|
560
508
|
|
|
561
|
-
let
|
|
509
|
+
let activationRecord = null;
|
|
562
510
|
const failures = results.filter(({ result }) => !result.success && !result.skipped);
|
|
563
|
-
if (activationCode && failures.length === 0
|
|
564
|
-
|
|
511
|
+
if (activationCode && failures.length === 0) {
|
|
512
|
+
activationRecord = await verifyActivationCode(activationCode, service);
|
|
565
513
|
}
|
|
566
514
|
|
|
567
|
-
return { backupPath, results, redeemResult };
|
|
515
|
+
return { backupPath, results, redeemResult: null, activationRecord };
|
|
568
516
|
}
|
|
569
517
|
|
|
570
|
-
async function verifyCredential(upstream, apiKey, options = {}) {
|
|
571
|
-
if (options.skipVerify) {
|
|
572
|
-
console.log("跳过 NewAPI 连通性验证。");
|
|
573
|
-
return { valid: true, skipped: true };
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
console.log("正在验证 NewAPI Key...");
|
|
577
|
-
const verification = await verifyNewApiKey(upstream, apiKey);
|
|
578
|
-
if (!verification.valid) {
|
|
579
|
-
console.log(`✗ NewAPI 验证失败: ${verification.error}`);
|
|
580
|
-
return verification;
|
|
581
|
-
}
|
|
582
|
-
console.log(`✓ NewAPI 验证通过(可见 ${verification.models.length} 个模型)`);
|
|
583
|
-
return verification;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
async function runNewApiActivation(options = {}) {
|
|
587
|
-
const baseUpstream = loadUpstreamConfig({ configPath: options.upstreamConfig });
|
|
588
|
-
const upstream = { ...baseUpstream };
|
|
589
|
-
upstream.baseUrl = await promptBaseUrl(upstream.baseUrl);
|
|
590
|
-
if (!upstream.baseUrl) {
|
|
591
|
-
console.log("Activation cancelled.");
|
|
592
|
-
return { success: false, cancelled: true };
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
const apiKey = await promptApiKey(options.apiKey || upstream.apiKey);
|
|
596
|
-
if (!apiKey) {
|
|
597
|
-
console.log("Activation cancelled.");
|
|
598
|
-
return { success: false, cancelled: true };
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
const entitlement = normalizeEntitlement({}, options.service ? [options.service] : []);
|
|
602
|
-
const service = await promptService(options.service, entitlement);
|
|
603
|
-
if (!service) {
|
|
604
|
-
console.log("Activation cancelled.");
|
|
605
|
-
return { success: false, cancelled: true };
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
console.log("");
|
|
609
|
-
const verification = await verifyCredential(upstream, apiKey, options);
|
|
610
|
-
if (!verification.valid) {
|
|
611
|
-
return { success: false, verification };
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
const detectedPlatforms = detectPlatforms(service);
|
|
615
|
-
const selectedPlatformIds = options.platforms ? parsePlatformIds(options.platforms) : null;
|
|
616
|
-
const targets = getActivationTargets(detectedPlatforms, Boolean(options.all), selectedPlatformIds);
|
|
617
|
-
|
|
618
|
-
printCredentialProfile(service, upstream, apiKey, entitlement);
|
|
619
|
-
|
|
620
|
-
if (!(await confirmActivation(Boolean(options.yes || options.auto), service))) {
|
|
621
|
-
console.log("");
|
|
622
|
-
console.log(" 已取消");
|
|
623
|
-
console.log("");
|
|
624
|
-
return { success: false, cancelled: true };
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
console.log("");
|
|
628
|
-
console.log(" 正在写入配置...");
|
|
629
|
-
const activation = await activateTargets({ service, upstream, apiKey, targets, options });
|
|
630
|
-
const failures = activation.results.filter(({ result }) => !result.success && !result.skipped);
|
|
631
|
-
console.log(" 配置完成");
|
|
632
|
-
printResultSummary(service, activation.backupPath, activation.results, activation.redeemResult);
|
|
633
|
-
|
|
634
|
-
return {
|
|
635
|
-
success: failures.length === 0,
|
|
636
|
-
backupPath: activation.backupPath,
|
|
637
|
-
results: activation.results,
|
|
638
|
-
};
|
|
639
|
-
}
|
|
640
518
|
|
|
641
519
|
async function runActivationWizard(options = {}) {
|
|
642
520
|
if (!options.noNodeCheck) {
|
|
@@ -646,37 +524,24 @@ async function runActivationWizard(options = {}) {
|
|
|
646
524
|
}
|
|
647
525
|
}
|
|
648
526
|
|
|
649
|
-
const
|
|
650
|
-
const credentialType = !options.code && options.apiKey ? "api-key" : "code";
|
|
651
|
-
|
|
652
|
-
const credential = credentialType === "code"
|
|
653
|
-
? await resolveCodeCredential(options, baseUpstream)
|
|
654
|
-
: await resolveApiKeyCredential(options, baseUpstream);
|
|
527
|
+
const credential = await resolveCodeCredential(options, {});
|
|
655
528
|
if (credential.cancelled) {
|
|
656
529
|
console.log("已取消。");
|
|
657
530
|
return { success: false, cancelled: true };
|
|
658
531
|
}
|
|
659
532
|
|
|
660
533
|
const upstream = { ...credential.upstream };
|
|
661
|
-
upstream.baseUrl = await promptBaseUrl(upstream.baseUrl);
|
|
662
534
|
if (!upstream.baseUrl) {
|
|
663
535
|
console.log("已取消。");
|
|
664
536
|
return { success: false, cancelled: true };
|
|
665
537
|
}
|
|
666
538
|
|
|
667
|
-
const service = await promptService(options.service, credential.entitlement, { allowPrompt:
|
|
539
|
+
const service = await promptService(options.service, credential.entitlement, { allowPrompt: false });
|
|
668
540
|
if (!service) {
|
|
669
541
|
console.log("已取消。");
|
|
670
542
|
return { success: false, cancelled: true };
|
|
671
543
|
}
|
|
672
544
|
|
|
673
|
-
console.log("");
|
|
674
|
-
if (credentialType === "api-key") {
|
|
675
|
-
const verification = await verifyCredential(upstream, credential.apiKey, options);
|
|
676
|
-
if (!verification.valid) {
|
|
677
|
-
return { success: false, verification };
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
545
|
|
|
681
546
|
const allDetectedPlatforms = detectPlatforms(service);
|
|
682
547
|
const allowedPlatforms = allDetectedPlatforms.filter((entry) => isPlatformAllowed(entry, credential.entitlement, service));
|
|
@@ -727,5 +592,4 @@ module.exports = {
|
|
|
727
592
|
normalizeServices,
|
|
728
593
|
parsePlatformIds,
|
|
729
594
|
runActivationWizard,
|
|
730
|
-
runNewApiActivation,
|
|
731
595
|
};
|
|
@@ -6,7 +6,7 @@ const http = require("http");
|
|
|
6
6
|
|
|
7
7
|
// 支持环境变量覆盖 API 地址;默认连接公网 FogAct 面板。
|
|
8
8
|
const DEFAULT_API_BASE = "https://cliproxy.fogidc.com";
|
|
9
|
-
const API_BASE = process.env.FOGACT_API_BASE ||
|
|
9
|
+
const API_BASE = process.env.FOGACT_API_BASE || DEFAULT_API_BASE;
|
|
10
10
|
|
|
11
11
|
function makeRequest(path, options = {}) {
|
|
12
12
|
return new Promise((resolve, reject) => {
|
|
@@ -57,7 +57,6 @@ function makeRequest(path, options = {}) {
|
|
|
57
57
|
|
|
58
58
|
async function verifyActivationCode(code, service) {
|
|
59
59
|
try {
|
|
60
|
-
// 调用本地激活 API
|
|
61
60
|
const response = await makeRequest("/api/activate", {
|
|
62
61
|
method: "POST",
|
|
63
62
|
body: {
|
|
@@ -67,17 +66,18 @@ async function verifyActivationCode(code, service) {
|
|
|
67
66
|
},
|
|
68
67
|
});
|
|
69
68
|
|
|
70
|
-
|
|
69
|
+
const normalized = normalizeActivationResponse(response);
|
|
70
|
+
|
|
71
|
+
if (response.status >= 200 && response.status < 300 && normalized.valid) {
|
|
71
72
|
return {
|
|
72
73
|
valid: true,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
nodes: response.data.data.nodes || [],
|
|
74
|
+
...normalized.data,
|
|
75
|
+
data: normalized.data,
|
|
76
|
+
nodes: normalized.data.nodes || [],
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
return { valid: false, error:
|
|
80
|
+
return { valid: false, error: normalized.message || "Invalid code" };
|
|
81
81
|
} catch (err) {
|
|
82
82
|
return { valid: false, error: err.message };
|
|
83
83
|
}
|
|
@@ -116,7 +116,10 @@ async function inspectActivationCode(code) {
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
async function redeemActivationCode(code, service) {
|
|
119
|
-
|
|
119
|
+
const result = await inspectActivationCode(code);
|
|
120
|
+
return result.valid
|
|
121
|
+
? { valid: true, service: result.service, expiresAt: result.expiresAt, quota: result.quota, nodes: result.nodes || [] }
|
|
122
|
+
: result;
|
|
120
123
|
}
|
|
121
124
|
|
|
122
125
|
async function getNodes(service) {
|