anygate 0.6.2 → 0.6.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.
- package/dist/{chunk-EMBABL33.js → chunk-NU4KMZIM.js} +911 -239
- package/dist/chunk-NU4KMZIM.js.map +1 -0
- package/dist/{chunk-S5WL3M5G.js → chunk-RNW2MGKL.js} +4 -2
- package/dist/chunk-RNW2MGKL.js.map +1 -0
- package/dist/cli.js +17 -15
- package/dist/cli.js.map +1 -1
- package/dist/{command-N3R2ZVVS.js → command-JOEFUFLD.js} +291 -116
- package/dist/command-JOEFUFLD.js.map +1 -0
- package/dist/{constants-U356SKNS.js → constants-7DBGCJ34.js} +4 -2
- package/dist/registry/data/templates/claude-code.json +1 -3
- package/dist/registry/data/templates/openai.json +13 -0
- package/dist/ui/dist/assets/index-CsUw6OG3.js +7 -0
- package/dist/ui/dist/index.html +1 -1
- package/package.json +1 -1
- package/dist/chunk-EMBABL33.js.map +0 -1
- package/dist/chunk-S5WL3M5G.js.map +0 -1
- package/dist/command-N3R2ZVVS.js.map +0 -1
- package/dist/ui/dist/assets/index-q6tXB_gH.js +0 -7
- /package/dist/{constants-U356SKNS.js.map → constants-7DBGCJ34.js.map} +0 -0
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
ISSUER,
|
|
3
4
|
addCustomEndpointProvider,
|
|
4
5
|
addProviderFromTemplate,
|
|
5
6
|
aggregateAnalytics,
|
|
6
7
|
buildAntigravityAuthUrl,
|
|
7
8
|
buildDedupedModelRows,
|
|
9
|
+
buildOpenAiBrowserAuthUrl,
|
|
8
10
|
checkForUpdates,
|
|
9
11
|
completeAntigravityExchange,
|
|
10
12
|
createGatewayModelCatalog,
|
|
11
13
|
detectConflicts,
|
|
12
14
|
emitAppEvent,
|
|
15
|
+
exchangeOpenAiBrowserToken,
|
|
13
16
|
favoriteProviderDisplayName,
|
|
14
17
|
fetchProviderCatalog,
|
|
15
18
|
filterServerModelsByFavorites,
|
|
@@ -53,6 +56,7 @@ import {
|
|
|
53
56
|
requestXaiDeviceCode,
|
|
54
57
|
resolveInputTypes,
|
|
55
58
|
resolveProviderCredential,
|
|
59
|
+
resolveReasoning,
|
|
56
60
|
resolveServerUpstreamApiKey,
|
|
57
61
|
saveLaunchPresets,
|
|
58
62
|
saveNativeOAuthCredential,
|
|
@@ -66,17 +70,19 @@ import {
|
|
|
66
70
|
setServerFreeModelsOnly,
|
|
67
71
|
setServerListenMode,
|
|
68
72
|
setServerMaskGatewayIds,
|
|
73
|
+
startCallbackServer,
|
|
69
74
|
startServer,
|
|
70
75
|
subscribeToAppEvents,
|
|
71
76
|
summarizeServerProviders,
|
|
72
77
|
validateCustomEndpointUrl,
|
|
73
78
|
writeSecureLogLine
|
|
74
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-NU4KMZIM.js";
|
|
75
80
|
import {
|
|
76
81
|
BACKENDS,
|
|
77
82
|
GATEWAY_PORT,
|
|
78
|
-
MAX_MODEL_CATALOG
|
|
79
|
-
|
|
83
|
+
MAX_MODEL_CATALOG,
|
|
84
|
+
VERSION
|
|
85
|
+
} from "./chunk-RNW2MGKL.js";
|
|
80
86
|
import {
|
|
81
87
|
getTemplateById,
|
|
82
88
|
listAddableTemplates,
|
|
@@ -86,7 +92,6 @@ import "./chunk-UT3JLF3M.js";
|
|
|
86
92
|
|
|
87
93
|
// src/ui/command.ts
|
|
88
94
|
import { createServer as createServer2 } from "http";
|
|
89
|
-
import { execSync } from "child_process";
|
|
90
95
|
import {
|
|
91
96
|
readFileSync,
|
|
92
97
|
readdirSync,
|
|
@@ -785,6 +790,8 @@ function handleUiApiRequest(req, res, opts = {}) {
|
|
|
785
790
|
handleGetPresets(res);
|
|
786
791
|
} else if (url === "/api/presets" && req.method === "POST") {
|
|
787
792
|
handleSavePresets(req, res);
|
|
793
|
+
} else if (url === "/api/ping" && req.method === "GET") {
|
|
794
|
+
handleGetPing(res);
|
|
788
795
|
} else if (url === "/api/health" && req.method === "GET") {
|
|
789
796
|
handleGetHealth(res);
|
|
790
797
|
} else if (url.startsWith("/api/analytics") && req.method === "GET") {
|
|
@@ -865,6 +872,9 @@ async function handleSavePresets(req, res) {
|
|
|
865
872
|
sendJson(res, 500, { error: String(err) });
|
|
866
873
|
}
|
|
867
874
|
}
|
|
875
|
+
function handleGetPing(res) {
|
|
876
|
+
sendJson(res, 200, { app: "anygate", version: VERSION, pid: process.pid });
|
|
877
|
+
}
|
|
868
878
|
async function handleGetHealth(res) {
|
|
869
879
|
try {
|
|
870
880
|
const gatewayRunning = (await getServerStatus()).running;
|
|
@@ -945,7 +955,8 @@ async function handleGetModels(res) {
|
|
|
945
955
|
contextWindow: m.contextWindow,
|
|
946
956
|
cost: m.cost,
|
|
947
957
|
providerId: p2.id,
|
|
948
|
-
inputTypes: resolveInputTypes(m.family, p2.id, m.id)
|
|
958
|
+
inputTypes: resolveInputTypes(m.family, p2.id, m.id),
|
|
959
|
+
reasoning: m.reasoning ?? resolveReasoning(p2.id, m.id)
|
|
949
960
|
}))
|
|
950
961
|
}));
|
|
951
962
|
const materializedIds = new Set(catalog.map((p2) => p2.id));
|
|
@@ -1367,12 +1378,141 @@ async function handleAddProvider(req, res) {
|
|
|
1367
1378
|
sendJson(res, 400, { error: "templateId required" });
|
|
1368
1379
|
return;
|
|
1369
1380
|
}
|
|
1370
|
-
const {
|
|
1371
|
-
const template =
|
|
1381
|
+
const { getTemplateById: getTemplateById2 } = await import("./provider-templates-336QE7ZV.js");
|
|
1382
|
+
const template = getTemplateById2(templateId);
|
|
1372
1383
|
if (!template) {
|
|
1373
1384
|
sendJson(res, 404, { error: `Template '${templateId}' not found` });
|
|
1374
1385
|
return;
|
|
1375
1386
|
}
|
|
1387
|
+
if (template.authType === "oauth") {
|
|
1388
|
+
if (templateId === "claude-code") {
|
|
1389
|
+
sendJson(res, 400, {
|
|
1390
|
+
error: "Claude Code OAuth must be completed in the terminal: anygate providers auth claude-code"
|
|
1391
|
+
});
|
|
1392
|
+
return;
|
|
1393
|
+
}
|
|
1394
|
+
const host = req.headers.host ?? "127.0.0.1";
|
|
1395
|
+
const sessionId = randomUUID();
|
|
1396
|
+
if (templateId === "xai-oauth") {
|
|
1397
|
+
const device2 = await requestXaiDeviceCode();
|
|
1398
|
+
const url2 = device2.verification_uri_complete ?? device2.verification_uri;
|
|
1399
|
+
const session2 = {
|
|
1400
|
+
status: "pending",
|
|
1401
|
+
url: url2,
|
|
1402
|
+
userCode: device2.user_code,
|
|
1403
|
+
providerId: templateId
|
|
1404
|
+
};
|
|
1405
|
+
oauthSessions.set(sessionId, session2);
|
|
1406
|
+
pollXaiDeviceCodeToken(device2).then(async (tokens) => {
|
|
1407
|
+
await saveNativeOAuthCredential(templateId, tokens);
|
|
1408
|
+
await refreshOAuthProviderModels(templateId);
|
|
1409
|
+
oauthSessions.set(sessionId, { ...session2, status: "done" });
|
|
1410
|
+
}).catch((err) => {
|
|
1411
|
+
oauthSessions.set(sessionId, { ...session2, status: "error", error: String(err) });
|
|
1412
|
+
});
|
|
1413
|
+
sendJson(res, 200, { oauth: true, sessionId, url: url2, userCode: device2.user_code });
|
|
1414
|
+
return;
|
|
1415
|
+
}
|
|
1416
|
+
if (templateId === "github-copilot") {
|
|
1417
|
+
const device2 = await requestGithubDeviceCode();
|
|
1418
|
+
const url2 = device2.verification_uri;
|
|
1419
|
+
const session2 = {
|
|
1420
|
+
status: "pending",
|
|
1421
|
+
url: url2,
|
|
1422
|
+
userCode: device2.user_code,
|
|
1423
|
+
providerId: templateId
|
|
1424
|
+
};
|
|
1425
|
+
oauthSessions.set(sessionId, session2);
|
|
1426
|
+
pollGithubDeviceCodeToken(device2).then(async (tokens) => {
|
|
1427
|
+
await saveNativeOAuthCredential(templateId, tokens);
|
|
1428
|
+
await refreshOAuthProviderModels(templateId);
|
|
1429
|
+
oauthSessions.set(sessionId, { ...session2, status: "done" });
|
|
1430
|
+
}).catch((err) => {
|
|
1431
|
+
oauthSessions.set(sessionId, { ...session2, status: "error", error: String(err) });
|
|
1432
|
+
});
|
|
1433
|
+
sendJson(res, 200, { oauth: true, sessionId, url: url2, userCode: device2.user_code });
|
|
1434
|
+
return;
|
|
1435
|
+
}
|
|
1436
|
+
if (templateId === "antigravity") {
|
|
1437
|
+
const redirectUri = guiCallbackRedirectUri(host);
|
|
1438
|
+
const pkce = await buildAntigravityAuthUrl(redirectUri);
|
|
1439
|
+
const { authUrl, codeVerifier, oauthState } = pkce;
|
|
1440
|
+
const session2 = {
|
|
1441
|
+
status: "pending",
|
|
1442
|
+
url: authUrl,
|
|
1443
|
+
providerId: templateId,
|
|
1444
|
+
codeVerifier,
|
|
1445
|
+
oauthState
|
|
1446
|
+
};
|
|
1447
|
+
oauthSessions.set(sessionId, session2);
|
|
1448
|
+
const codePromise = new Promise((resolve, reject) => {
|
|
1449
|
+
session2.codeResolver = resolve;
|
|
1450
|
+
session2.errorRejecter = (err) => reject(err);
|
|
1451
|
+
setTimeout(() => reject(new Error("OAuth timeout \u2014 sign-in not completed")), 10 * 60 * 1e3);
|
|
1452
|
+
});
|
|
1453
|
+
oauthSessions.set(sessionId, session2);
|
|
1454
|
+
codePromise.then(async (code) => {
|
|
1455
|
+
const result2 = await completeAntigravityExchange(code, codeVerifier, redirectUri);
|
|
1456
|
+
const tokens = result2.tokens;
|
|
1457
|
+
const accountId = result2.userInfo.email;
|
|
1458
|
+
const providerData = {};
|
|
1459
|
+
if (result2.projectId) providerData.projectId = result2.projectId;
|
|
1460
|
+
if (result2.tierId) providerData.tier = result2.tierId;
|
|
1461
|
+
await saveNativeOAuthCredential(templateId, tokens, accountId, providerData);
|
|
1462
|
+
await refreshOAuthProviderModels(templateId);
|
|
1463
|
+
oauthSessions.set(sessionId, { ...session2, status: "done" });
|
|
1464
|
+
}).catch((err) => {
|
|
1465
|
+
oauthSessions.set(sessionId, { ...session2, status: "error", error: String(err) });
|
|
1466
|
+
});
|
|
1467
|
+
sendJson(res, 200, { oauth: true, sessionId, authUrl, pkce: true });
|
|
1468
|
+
return;
|
|
1469
|
+
}
|
|
1470
|
+
if (templateId === "openai-oauth") {
|
|
1471
|
+
const redirectUri = `${ISSUER}/deviceauth/callback`;
|
|
1472
|
+
const { authUrl, codeVerifier, oauthState } = await buildOpenAiBrowserAuthUrl(redirectUri);
|
|
1473
|
+
const server = await startCallbackServer();
|
|
1474
|
+
let session2;
|
|
1475
|
+
try {
|
|
1476
|
+
session2 = {
|
|
1477
|
+
status: "pending",
|
|
1478
|
+
url: authUrl,
|
|
1479
|
+
providerId: templateId,
|
|
1480
|
+
codeVerifier,
|
|
1481
|
+
oauthState
|
|
1482
|
+
};
|
|
1483
|
+
oauthSessions.set(sessionId, session2);
|
|
1484
|
+
open(authUrl)?.catch(() => {
|
|
1485
|
+
});
|
|
1486
|
+
const { code } = await server.waitForCallback();
|
|
1487
|
+
if (!code) {
|
|
1488
|
+
throw new Error("No authorization code received from callback");
|
|
1489
|
+
}
|
|
1490
|
+
const { tokens, accountId } = await exchangeOpenAiBrowserToken(code, codeVerifier);
|
|
1491
|
+
await saveNativeOAuthCredential(templateId, tokens, accountId);
|
|
1492
|
+
await refreshOAuthProviderModels(templateId);
|
|
1493
|
+
oauthSessions.set(sessionId, { ...session2, status: "done" });
|
|
1494
|
+
} catch (err) {
|
|
1495
|
+
oauthSessions.set(sessionId, { ...session2 ?? {}, status: "error", error: String(err) });
|
|
1496
|
+
} finally {
|
|
1497
|
+
server.close();
|
|
1498
|
+
}
|
|
1499
|
+
sendJson(res, 200, { oauth: true, sessionId, url: authUrl, pkce: true });
|
|
1500
|
+
return;
|
|
1501
|
+
}
|
|
1502
|
+
const device = await requestOpenAiDeviceCode();
|
|
1503
|
+
const url = openAiDeviceCodeUrl();
|
|
1504
|
+
const session = { status: "pending", url, userCode: device.user_code, providerId: templateId };
|
|
1505
|
+
oauthSessions.set(sessionId, session);
|
|
1506
|
+
pollOpenAiDeviceCodeToken(device).then(async ({ tokens, accountId }) => {
|
|
1507
|
+
await saveNativeOAuthCredential(templateId, tokens, accountId);
|
|
1508
|
+
await refreshOAuthProviderModels(templateId);
|
|
1509
|
+
oauthSessions.set(sessionId, { ...session, status: "done" });
|
|
1510
|
+
}).catch((err) => {
|
|
1511
|
+
oauthSessions.set(sessionId, { ...session, status: "error", error: String(err) });
|
|
1512
|
+
});
|
|
1513
|
+
sendJson(res, 200, { oauth: true, sessionId, url, userCode: device.user_code });
|
|
1514
|
+
return;
|
|
1515
|
+
}
|
|
1376
1516
|
const rawKey = typeof key === "string" ? key.trim() : "";
|
|
1377
1517
|
if (!rawKey && !template.anonymousFreeModels && !template.apiKeyOptional) {
|
|
1378
1518
|
sendJson(res, 400, { error: "key must be a non-empty string" });
|
|
@@ -1499,43 +1639,47 @@ async function handleOAuthStart(req, res) {
|
|
|
1499
1639
|
}
|
|
1500
1640
|
const sessionId = randomUUID();
|
|
1501
1641
|
if (providerId === "xai-oauth") {
|
|
1502
|
-
|
|
1503
|
-
const url2 = device2.verification_uri_complete ?? device2.verification_uri;
|
|
1504
|
-
const session2 = {
|
|
1505
|
-
status: "pending",
|
|
1506
|
-
url: url2,
|
|
1507
|
-
userCode: device2.user_code,
|
|
1508
|
-
providerId
|
|
1509
|
-
};
|
|
1642
|
+
let session2 = { status: "error", url: "", providerId };
|
|
1510
1643
|
oauthSessions.set(sessionId, session2);
|
|
1511
|
-
|
|
1512
|
-
await
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1644
|
+
try {
|
|
1645
|
+
const device = await requestXaiDeviceCode();
|
|
1646
|
+
const url = device.verification_uri_complete ?? device.verification_uri;
|
|
1647
|
+
session2 = { status: "pending", url, userCode: device.user_code, providerId };
|
|
1648
|
+
oauthSessions.set(sessionId, session2);
|
|
1649
|
+
pollXaiDeviceCodeToken(device).then(async (tokens) => {
|
|
1650
|
+
await saveNativeOAuthCredential(providerId, tokens);
|
|
1651
|
+
await refreshOAuthProviderModels(providerId);
|
|
1652
|
+
oauthSessions.set(sessionId, { ...session2, status: "done" });
|
|
1653
|
+
}).catch((err) => {
|
|
1654
|
+
oauthSessions.set(sessionId, { ...session2, status: "error", error: String(err) });
|
|
1655
|
+
});
|
|
1656
|
+
sendJson(res, 200, { sessionId, url, userCode: device.user_code });
|
|
1657
|
+
} catch (err) {
|
|
1658
|
+
oauthSessions.set(sessionId, { ...session2, error: String(err) });
|
|
1659
|
+
sendJson(res, 500, { error: String(err) });
|
|
1660
|
+
}
|
|
1519
1661
|
return;
|
|
1520
1662
|
}
|
|
1521
1663
|
if (providerId === "github-copilot") {
|
|
1522
|
-
|
|
1523
|
-
const url2 = device2.verification_uri;
|
|
1524
|
-
const session2 = {
|
|
1525
|
-
status: "pending",
|
|
1526
|
-
url: url2,
|
|
1527
|
-
userCode: device2.user_code,
|
|
1528
|
-
providerId
|
|
1529
|
-
};
|
|
1664
|
+
let session2 = { status: "error", url: "", providerId };
|
|
1530
1665
|
oauthSessions.set(sessionId, session2);
|
|
1531
|
-
|
|
1532
|
-
await
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1666
|
+
try {
|
|
1667
|
+
const device = await requestGithubDeviceCode();
|
|
1668
|
+
const url = device.verification_uri;
|
|
1669
|
+
session2 = { status: "pending", url, userCode: device.user_code, providerId };
|
|
1670
|
+
oauthSessions.set(sessionId, session2);
|
|
1671
|
+
pollGithubDeviceCodeToken(device).then(async (tokens) => {
|
|
1672
|
+
await saveNativeOAuthCredential(providerId, tokens);
|
|
1673
|
+
await refreshOAuthProviderModels(providerId);
|
|
1674
|
+
oauthSessions.set(sessionId, { ...session2, status: "done" });
|
|
1675
|
+
}).catch((err) => {
|
|
1676
|
+
oauthSessions.set(sessionId, { ...session2, status: "error", error: String(err) });
|
|
1677
|
+
});
|
|
1678
|
+
sendJson(res, 200, { sessionId, url, userCode: device.user_code });
|
|
1679
|
+
} catch (err) {
|
|
1680
|
+
oauthSessions.set(sessionId, { ...session2, error: String(err) });
|
|
1681
|
+
sendJson(res, 500, { error: String(err) });
|
|
1682
|
+
}
|
|
1539
1683
|
return;
|
|
1540
1684
|
}
|
|
1541
1685
|
if (PKCE_PROVIDER_IDS.has(providerId)) {
|
|
@@ -1545,64 +1689,72 @@ async function handleOAuthStart(req, res) {
|
|
|
1545
1689
|
});
|
|
1546
1690
|
return;
|
|
1547
1691
|
}
|
|
1548
|
-
|
|
1549
|
-
const redirectUri = guiCallbackRedirectUri(host);
|
|
1550
|
-
let pkce;
|
|
1551
|
-
if (providerId === "antigravity") {
|
|
1552
|
-
pkce = await buildAntigravityAuthUrl(redirectUri);
|
|
1553
|
-
} else {
|
|
1554
|
-
sendJson(res, 400, { error: `PKCE flow for "${providerId}" not yet implemented` });
|
|
1555
|
-
return;
|
|
1556
|
-
}
|
|
1557
|
-
const { authUrl, codeVerifier, oauthState } = pkce;
|
|
1558
|
-
const session2 = {
|
|
1559
|
-
status: "pending",
|
|
1560
|
-
url: authUrl,
|
|
1561
|
-
providerId,
|
|
1562
|
-
codeVerifier,
|
|
1563
|
-
oauthState
|
|
1564
|
-
};
|
|
1565
|
-
oauthSessions.set(sessionId, session2);
|
|
1566
|
-
const codePromise = new Promise((resolve, reject) => {
|
|
1567
|
-
session2.codeResolver = resolve;
|
|
1568
|
-
session2.errorRejecter = (err) => reject(new Error(err));
|
|
1569
|
-
setTimeout(() => reject(new Error("OAuth timeout \u2014 sign-in not completed")), 10 * 60 * 1e3);
|
|
1570
|
-
});
|
|
1692
|
+
let session2 = { status: "error", url: "", providerId };
|
|
1571
1693
|
oauthSessions.set(sessionId, session2);
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
let
|
|
1694
|
+
try {
|
|
1695
|
+
const host = req.headers.host ?? "127.0.0.1";
|
|
1696
|
+
const redirectUri = guiCallbackRedirectUri(host);
|
|
1697
|
+
let pkce;
|
|
1576
1698
|
if (providerId === "antigravity") {
|
|
1577
|
-
|
|
1578
|
-
tokens = result.tokens;
|
|
1579
|
-
accountId = result.userInfo.email;
|
|
1580
|
-
if (result.projectId) providerData.projectId = result.projectId;
|
|
1581
|
-
if (result.tierId) providerData.tier = result.tierId;
|
|
1699
|
+
pkce = await buildAntigravityAuthUrl(redirectUri);
|
|
1582
1700
|
} else {
|
|
1583
|
-
|
|
1701
|
+
sendJson(res, 400, { error: `PKCE flow for "${providerId}" not yet implemented` });
|
|
1702
|
+
return;
|
|
1584
1703
|
}
|
|
1585
|
-
|
|
1704
|
+
const { authUrl, codeVerifier, oauthState } = pkce;
|
|
1705
|
+
session2 = { status: "pending", url: authUrl, providerId, codeVerifier, oauthState };
|
|
1706
|
+
oauthSessions.set(sessionId, session2);
|
|
1707
|
+
const codePromise = new Promise((resolve, reject) => {
|
|
1708
|
+
session2.codeResolver = resolve;
|
|
1709
|
+
session2.errorRejecter = (err) => reject(new Error(err));
|
|
1710
|
+
setTimeout(() => reject(new Error("OAuth timeout \u2014 sign-in not completed")), 10 * 60 * 1e3);
|
|
1711
|
+
});
|
|
1712
|
+
oauthSessions.set(sessionId, session2);
|
|
1713
|
+
codePromise.then(async (code) => {
|
|
1714
|
+
let providerData = {};
|
|
1715
|
+
let accountId;
|
|
1716
|
+
let tokens;
|
|
1717
|
+
if (providerId === "antigravity") {
|
|
1718
|
+
const result = await completeAntigravityExchange(code, codeVerifier, redirectUri);
|
|
1719
|
+
tokens = result.tokens;
|
|
1720
|
+
accountId = result.userInfo.email;
|
|
1721
|
+
if (result.projectId) providerData.projectId = result.projectId;
|
|
1722
|
+
if (result.tierId) providerData.tier = result.tierId;
|
|
1723
|
+
} else {
|
|
1724
|
+
throw new Error(`Unknown PKCE provider: ${providerId}`);
|
|
1725
|
+
}
|
|
1726
|
+
await saveNativeOAuthCredential(providerId, tokens, accountId, providerData);
|
|
1727
|
+
await refreshOAuthProviderModels(providerId);
|
|
1728
|
+
oauthSessions.set(sessionId, { ...session2, status: "done" });
|
|
1729
|
+
}).catch((err) => {
|
|
1730
|
+
oauthSessions.set(sessionId, { ...session2, status: "error", error: String(err) });
|
|
1731
|
+
});
|
|
1732
|
+
sendJson(res, 200, { sessionId, authUrl, pkce: true });
|
|
1733
|
+
} catch (err) {
|
|
1734
|
+
oauthSessions.set(sessionId, { ...session2, error: String(err) });
|
|
1735
|
+
sendJson(res, 500, { error: String(err) });
|
|
1736
|
+
}
|
|
1737
|
+
return;
|
|
1738
|
+
}
|
|
1739
|
+
let session = { status: "error", url: "", providerId };
|
|
1740
|
+
oauthSessions.set(sessionId, session);
|
|
1741
|
+
try {
|
|
1742
|
+
const device = await requestOpenAiDeviceCode();
|
|
1743
|
+
const url = openAiDeviceCodeUrl();
|
|
1744
|
+
session = { status: "pending", url, userCode: device.user_code, providerId };
|
|
1745
|
+
oauthSessions.set(sessionId, session);
|
|
1746
|
+
pollOpenAiDeviceCodeToken(device).then(async ({ tokens, accountId }) => {
|
|
1747
|
+
await saveNativeOAuthCredential(providerId, tokens, accountId);
|
|
1586
1748
|
await refreshOAuthProviderModels(providerId);
|
|
1587
|
-
oauthSessions.set(sessionId, { ...
|
|
1749
|
+
oauthSessions.set(sessionId, { ...session, status: "done" });
|
|
1588
1750
|
}).catch((err) => {
|
|
1589
|
-
oauthSessions.set(sessionId, { ...
|
|
1751
|
+
oauthSessions.set(sessionId, { ...session, status: "error", error: String(err) });
|
|
1590
1752
|
});
|
|
1591
|
-
sendJson(res, 200, { sessionId,
|
|
1592
|
-
|
|
1753
|
+
sendJson(res, 200, { sessionId, url, userCode: device.user_code });
|
|
1754
|
+
} catch (err) {
|
|
1755
|
+
oauthSessions.set(sessionId, { ...session, error: String(err) });
|
|
1756
|
+
sendJson(res, 500, { error: String(err) });
|
|
1593
1757
|
}
|
|
1594
|
-
const device = await requestOpenAiDeviceCode();
|
|
1595
|
-
const url = openAiDeviceCodeUrl();
|
|
1596
|
-
const session = { status: "pending", url, userCode: device.user_code, providerId };
|
|
1597
|
-
oauthSessions.set(sessionId, session);
|
|
1598
|
-
pollOpenAiDeviceCodeToken(device).then(async ({ tokens, accountId }) => {
|
|
1599
|
-
await saveNativeOAuthCredential(providerId, tokens, accountId);
|
|
1600
|
-
await refreshOAuthProviderModels(providerId);
|
|
1601
|
-
oauthSessions.set(sessionId, { ...session, status: "done" });
|
|
1602
|
-
}).catch((err) => {
|
|
1603
|
-
oauthSessions.set(sessionId, { ...session, status: "error", error: String(err) });
|
|
1604
|
-
});
|
|
1605
|
-
sendJson(res, 200, { sessionId, url, userCode: device.user_code });
|
|
1606
1758
|
} catch (err) {
|
|
1607
1759
|
sendJson(res, 500, { error: String(err) });
|
|
1608
1760
|
}
|
|
@@ -1975,30 +2127,41 @@ function removeLock() {
|
|
|
1975
2127
|
} catch {
|
|
1976
2128
|
}
|
|
1977
2129
|
}
|
|
1978
|
-
function
|
|
2130
|
+
function parseUiLock(raw) {
|
|
2131
|
+
try {
|
|
2132
|
+
const { pid, port } = JSON.parse(raw);
|
|
2133
|
+
if (!Number.isInteger(pid) || !Number.isInteger(port)) return null;
|
|
2134
|
+
if (port < 1 || port > 65535) return null;
|
|
2135
|
+
return { pid, port };
|
|
2136
|
+
} catch {
|
|
2137
|
+
return null;
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
var PROBE_TIMEOUT_MS = 1500;
|
|
2141
|
+
async function probeUiServer(port, fetchImpl = fetch) {
|
|
2142
|
+
const controller = new AbortController();
|
|
2143
|
+
const timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
|
|
2144
|
+
try {
|
|
2145
|
+
const res = await fetchImpl(`http://127.0.0.1:${port}/api/ping`, { signal: controller.signal });
|
|
2146
|
+
if (!res.ok) return false;
|
|
2147
|
+
const body = await res.json();
|
|
2148
|
+
return body?.app === "anygate";
|
|
2149
|
+
} catch {
|
|
2150
|
+
return false;
|
|
2151
|
+
} finally {
|
|
2152
|
+
clearTimeout(timer);
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
async function checkExistingServer(fetchImpl = fetch) {
|
|
1979
2156
|
if (!existsSync3(LOCK_FILE)) return null;
|
|
2157
|
+
let lock = null;
|
|
1980
2158
|
try {
|
|
1981
|
-
|
|
1982
|
-
const isWindows2 = process.platform === "win32";
|
|
1983
|
-
let processExists = false;
|
|
1984
|
-
if (isWindows2) {
|
|
1985
|
-
try {
|
|
1986
|
-
const output = execSync(`tasklist /FI "PID eq ${pid}"`, {
|
|
1987
|
-
encoding: "utf8",
|
|
1988
|
-
stdio: ["pipe", "pipe", "ignore"]
|
|
1989
|
-
});
|
|
1990
|
-
processExists = output.includes(String(pid));
|
|
1991
|
-
} catch {
|
|
1992
|
-
processExists = false;
|
|
1993
|
-
}
|
|
1994
|
-
} else {
|
|
1995
|
-
process.kill(pid, 0);
|
|
1996
|
-
processExists = true;
|
|
1997
|
-
}
|
|
1998
|
-
if (processExists) {
|
|
1999
|
-
return `http://127.0.0.1:${port}`;
|
|
2000
|
-
}
|
|
2159
|
+
lock = parseUiLock(readFileSync(LOCK_FILE, "utf8"));
|
|
2001
2160
|
} catch {
|
|
2161
|
+
lock = null;
|
|
2162
|
+
}
|
|
2163
|
+
if (lock && await probeUiServer(lock.port, fetchImpl)) {
|
|
2164
|
+
return `http://127.0.0.1:${lock.port}`;
|
|
2002
2165
|
}
|
|
2003
2166
|
removeLock();
|
|
2004
2167
|
return null;
|
|
@@ -2022,11 +2185,19 @@ async function resolveUiShutdownDecision(signal, promptClose = () => p.confirm({
|
|
|
2022
2185
|
return shouldClose ? "close" : "keep";
|
|
2023
2186
|
}
|
|
2024
2187
|
async function runUiCommand(opts = {}) {
|
|
2025
|
-
const existing = checkExistingServer();
|
|
2188
|
+
const existing = await checkExistingServer();
|
|
2026
2189
|
if (existing) {
|
|
2027
|
-
console.log(
|
|
2190
|
+
console.log(
|
|
2191
|
+
`
|
|
2028
2192
|
${pc2.bold("anygate UI")} already running at ${pc2.cyan(existing)}
|
|
2029
|
-
|
|
2193
|
+
${pc2.dim("Press Ctrl+C in that terminal to stop it")}
|
|
2194
|
+
`
|
|
2195
|
+
);
|
|
2196
|
+
try {
|
|
2197
|
+
const { default: open2 } = await import("open");
|
|
2198
|
+
await open2(existing);
|
|
2199
|
+
} catch {
|
|
2200
|
+
}
|
|
2030
2201
|
return 0;
|
|
2031
2202
|
}
|
|
2032
2203
|
if (opts.trace) {
|
|
@@ -2081,6 +2252,7 @@ async function runUiCommand(opts = {}) {
|
|
|
2081
2252
|
const url = `http://127.0.0.1:${port}`;
|
|
2082
2253
|
mkdirSync(getAppHome(), { recursive: true });
|
|
2083
2254
|
writeFileSync2(LOCK_FILE, JSON.stringify({ pid: process.pid, port }));
|
|
2255
|
+
process.on("exit", removeLock);
|
|
2084
2256
|
const cleanup = () => {
|
|
2085
2257
|
removeLock();
|
|
2086
2258
|
server.close();
|
|
@@ -2115,8 +2287,8 @@ async function runUiCommand(opts = {}) {
|
|
|
2115
2287
|
trace?.(`ui server listening ${url}`);
|
|
2116
2288
|
}
|
|
2117
2289
|
try {
|
|
2118
|
-
const { default:
|
|
2119
|
-
await
|
|
2290
|
+
const { default: open2 } = await import("open");
|
|
2291
|
+
await open2(url);
|
|
2120
2292
|
trace?.(`browser open ${url}`);
|
|
2121
2293
|
} catch {
|
|
2122
2294
|
trace?.(`browser open failed ${url}`);
|
|
@@ -2126,9 +2298,12 @@ async function runUiCommand(opts = {}) {
|
|
|
2126
2298
|
return 0;
|
|
2127
2299
|
}
|
|
2128
2300
|
export {
|
|
2301
|
+
checkExistingServer,
|
|
2129
2302
|
formatUiServerLifecycleMessage,
|
|
2130
2303
|
isUiApiRoute,
|
|
2304
|
+
parseUiLock,
|
|
2305
|
+
probeUiServer,
|
|
2131
2306
|
resolveUiShutdownDecision,
|
|
2132
2307
|
runUiCommand
|
|
2133
2308
|
};
|
|
2134
|
-
//# sourceMappingURL=command-
|
|
2309
|
+
//# sourceMappingURL=command-JOEFUFLD.js.map
|