mobbdev 1.1.39 → 1.1.41
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/args/commands/upload_ai_blame.mjs +351 -221
- package/dist/index.mjs +999 -128
- package/package.json +1 -1
|
@@ -12,7 +12,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
12
12
|
|
|
13
13
|
// src/features/analysis/scm/env.ts
|
|
14
14
|
import { z as z16 } from "zod";
|
|
15
|
-
var EnvVariablesZod, GITLAB_API_TOKEN, GITHUB_API_TOKEN, GIT_PROXY_HOST, MAX_UPLOAD_FILE_SIZE_MB;
|
|
15
|
+
var EnvVariablesZod, GITLAB_API_TOKEN, GITHUB_API_TOKEN, GIT_PROXY_HOST, MAX_UPLOAD_FILE_SIZE_MB, GITHUB_API_CONCURRENCY;
|
|
16
16
|
var init_env = __esm({
|
|
17
17
|
"src/features/analysis/scm/env.ts"() {
|
|
18
18
|
"use strict";
|
|
@@ -20,13 +20,15 @@ var init_env = __esm({
|
|
|
20
20
|
GITLAB_API_TOKEN: z16.string().optional(),
|
|
21
21
|
GITHUB_API_TOKEN: z16.string().optional(),
|
|
22
22
|
GIT_PROXY_HOST: z16.string().optional().default("http://tinyproxy:8888"),
|
|
23
|
-
MAX_UPLOAD_FILE_SIZE_MB: z16.coerce.number().gt(0).default(5)
|
|
23
|
+
MAX_UPLOAD_FILE_SIZE_MB: z16.coerce.number().gt(0).default(5),
|
|
24
|
+
GITHUB_API_CONCURRENCY: z16.coerce.number().gt(0).optional().default(10)
|
|
24
25
|
});
|
|
25
26
|
({
|
|
26
27
|
GITLAB_API_TOKEN,
|
|
27
28
|
GITHUB_API_TOKEN,
|
|
28
29
|
GIT_PROXY_HOST,
|
|
29
|
-
MAX_UPLOAD_FILE_SIZE_MB
|
|
30
|
+
MAX_UPLOAD_FILE_SIZE_MB,
|
|
31
|
+
GITHUB_API_CONCURRENCY
|
|
30
32
|
} = EnvVariablesZod.parse(process.env));
|
|
31
33
|
}
|
|
32
34
|
});
|
|
@@ -1369,15 +1371,141 @@ import { withFile } from "tmp-promise";
|
|
|
1369
1371
|
import z26 from "zod";
|
|
1370
1372
|
|
|
1371
1373
|
// src/commands/handleMobbLogin.ts
|
|
1372
|
-
import crypto from "crypto";
|
|
1373
|
-
import os from "os";
|
|
1374
1374
|
import chalk2 from "chalk";
|
|
1375
1375
|
import Debug6 from "debug";
|
|
1376
|
-
import open from "open";
|
|
1377
1376
|
|
|
1378
|
-
// src/
|
|
1377
|
+
// src/utils/dirname.ts
|
|
1378
|
+
import fs from "fs";
|
|
1379
|
+
import path from "path";
|
|
1380
|
+
import { fileURLToPath } from "url";
|
|
1381
|
+
function getModuleRootDir() {
|
|
1382
|
+
let manifestDir = getDirName();
|
|
1383
|
+
for (let i = 0; i < 10; i++) {
|
|
1384
|
+
const manifestPath = path.join(manifestDir, "package.json");
|
|
1385
|
+
if (fs.existsSync(manifestPath)) {
|
|
1386
|
+
return manifestDir;
|
|
1387
|
+
}
|
|
1388
|
+
manifestDir = path.join(manifestDir, "..");
|
|
1389
|
+
}
|
|
1390
|
+
throw new Error("Cannot locate package.json file");
|
|
1391
|
+
}
|
|
1392
|
+
function getDirName() {
|
|
1393
|
+
if (typeof __filename !== "undefined") {
|
|
1394
|
+
return path.dirname(__filename);
|
|
1395
|
+
} else {
|
|
1396
|
+
try {
|
|
1397
|
+
const getImportMetaUrl = new Function("return import.meta.url");
|
|
1398
|
+
const importMetaUrl = getImportMetaUrl();
|
|
1399
|
+
return path.dirname(fileURLToPath(importMetaUrl));
|
|
1400
|
+
} catch (e) {
|
|
1401
|
+
try {
|
|
1402
|
+
const err = new Error();
|
|
1403
|
+
const stack = err.stack || "";
|
|
1404
|
+
const match = stack.match(/file:\/\/[^\s)]+/);
|
|
1405
|
+
if (match) {
|
|
1406
|
+
const fileUrl = match[0];
|
|
1407
|
+
return path.dirname(fileURLToPath(fileUrl));
|
|
1408
|
+
}
|
|
1409
|
+
} catch {
|
|
1410
|
+
}
|
|
1411
|
+
throw new Error("Unable to determine directory name in this environment");
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
// src/utils/keypress.ts
|
|
1417
|
+
import readline from "readline";
|
|
1418
|
+
async function keypress() {
|
|
1419
|
+
const rl = readline.createInterface({
|
|
1420
|
+
input: process.stdin,
|
|
1421
|
+
output: process.stdout
|
|
1422
|
+
});
|
|
1423
|
+
return new Promise((resolve) => {
|
|
1424
|
+
rl.question("", (answer) => {
|
|
1425
|
+
rl.close();
|
|
1426
|
+
process.stderr.moveCursor(0, -1);
|
|
1427
|
+
process.stderr.clearLine(1);
|
|
1428
|
+
resolve(answer);
|
|
1429
|
+
});
|
|
1430
|
+
});
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
// src/utils/spinner.ts
|
|
1434
|
+
import {
|
|
1435
|
+
createSpinner as _createSpinner
|
|
1436
|
+
} from "nanospinner";
|
|
1437
|
+
function printToStdError(opts) {
|
|
1438
|
+
if (opts?.text) console.error(opts.text);
|
|
1439
|
+
}
|
|
1440
|
+
var mockSpinner = {
|
|
1441
|
+
success: (opts) => {
|
|
1442
|
+
printToStdError(opts);
|
|
1443
|
+
return mockSpinner;
|
|
1444
|
+
},
|
|
1445
|
+
error: (opts) => {
|
|
1446
|
+
printToStdError(opts);
|
|
1447
|
+
return mockSpinner;
|
|
1448
|
+
},
|
|
1449
|
+
warn: (opts) => {
|
|
1450
|
+
printToStdError(opts);
|
|
1451
|
+
return mockSpinner;
|
|
1452
|
+
},
|
|
1453
|
+
stop: (opts) => {
|
|
1454
|
+
printToStdError(opts);
|
|
1455
|
+
return mockSpinner;
|
|
1456
|
+
},
|
|
1457
|
+
start: (opts) => {
|
|
1458
|
+
printToStdError(opts);
|
|
1459
|
+
return mockSpinner;
|
|
1460
|
+
},
|
|
1461
|
+
update: (opts) => {
|
|
1462
|
+
printToStdError(opts);
|
|
1463
|
+
return mockSpinner;
|
|
1464
|
+
},
|
|
1465
|
+
reset: () => mockSpinner,
|
|
1466
|
+
clear: () => mockSpinner,
|
|
1467
|
+
spin: () => mockSpinner
|
|
1468
|
+
};
|
|
1469
|
+
function Spinner({ ci = false } = {}) {
|
|
1470
|
+
return {
|
|
1471
|
+
createSpinner: (text, options) => ci ? mockSpinner : _createSpinner(text, options)
|
|
1472
|
+
};
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
// src/utils/check_node_version.ts
|
|
1379
1476
|
import fs2 from "fs";
|
|
1380
1477
|
import path2 from "path";
|
|
1478
|
+
import semver from "semver";
|
|
1479
|
+
function getPackageJson() {
|
|
1480
|
+
return JSON.parse(
|
|
1481
|
+
fs2.readFileSync(path2.join(getModuleRootDir(), "package.json"), "utf8")
|
|
1482
|
+
);
|
|
1483
|
+
}
|
|
1484
|
+
var packageJson = getPackageJson();
|
|
1485
|
+
if (!semver.satisfies(process.version, packageJson.engines.node)) {
|
|
1486
|
+
console.error(
|
|
1487
|
+
`
|
|
1488
|
+
\u26A0\uFE0F ${packageJson.name} requires node version ${packageJson.engines.node}, but running ${process.version}.`
|
|
1489
|
+
);
|
|
1490
|
+
process.exit(1);
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
// src/utils/gitUtils.ts
|
|
1494
|
+
import simpleGit from "simple-git";
|
|
1495
|
+
|
|
1496
|
+
// src/utils/index.ts
|
|
1497
|
+
var sleep = (ms = 2e3) => new Promise((r) => setTimeout(r, ms));
|
|
1498
|
+
var CliError = class extends Error {
|
|
1499
|
+
};
|
|
1500
|
+
|
|
1501
|
+
// src/commands/AuthManager.ts
|
|
1502
|
+
import crypto from "crypto";
|
|
1503
|
+
import os from "os";
|
|
1504
|
+
import open from "open";
|
|
1505
|
+
|
|
1506
|
+
// src/constants.ts
|
|
1507
|
+
import fs3 from "fs";
|
|
1508
|
+
import path3 from "path";
|
|
1381
1509
|
import chalk from "chalk";
|
|
1382
1510
|
import Debug from "debug";
|
|
1383
1511
|
import * as dotenv from "dotenv";
|
|
@@ -3479,56 +3607,17 @@ var ScmType = /* @__PURE__ */ ((ScmType2) => {
|
|
|
3479
3607
|
return ScmType2;
|
|
3480
3608
|
})(ScmType || {});
|
|
3481
3609
|
|
|
3482
|
-
// src/utils/dirname.ts
|
|
3483
|
-
import fs from "fs";
|
|
3484
|
-
import path from "path";
|
|
3485
|
-
import { fileURLToPath } from "url";
|
|
3486
|
-
function getModuleRootDir() {
|
|
3487
|
-
let manifestDir = getDirName();
|
|
3488
|
-
for (let i = 0; i < 10; i++) {
|
|
3489
|
-
const manifestPath = path.join(manifestDir, "package.json");
|
|
3490
|
-
if (fs.existsSync(manifestPath)) {
|
|
3491
|
-
return manifestDir;
|
|
3492
|
-
}
|
|
3493
|
-
manifestDir = path.join(manifestDir, "..");
|
|
3494
|
-
}
|
|
3495
|
-
throw new Error("Cannot locate package.json file");
|
|
3496
|
-
}
|
|
3497
|
-
function getDirName() {
|
|
3498
|
-
if (typeof __filename !== "undefined") {
|
|
3499
|
-
return path.dirname(__filename);
|
|
3500
|
-
} else {
|
|
3501
|
-
try {
|
|
3502
|
-
const getImportMetaUrl = new Function("return import.meta.url");
|
|
3503
|
-
const importMetaUrl = getImportMetaUrl();
|
|
3504
|
-
return path.dirname(fileURLToPath(importMetaUrl));
|
|
3505
|
-
} catch (e) {
|
|
3506
|
-
try {
|
|
3507
|
-
const err = new Error();
|
|
3508
|
-
const stack = err.stack || "";
|
|
3509
|
-
const match = stack.match(/file:\/\/[^\s)]+/);
|
|
3510
|
-
if (match) {
|
|
3511
|
-
const fileUrl = match[0];
|
|
3512
|
-
return path.dirname(fileURLToPath(fileUrl));
|
|
3513
|
-
}
|
|
3514
|
-
} catch {
|
|
3515
|
-
}
|
|
3516
|
-
throw new Error("Unable to determine directory name in this environment");
|
|
3517
|
-
}
|
|
3518
|
-
}
|
|
3519
|
-
}
|
|
3520
|
-
|
|
3521
3610
|
// src/constants.ts
|
|
3522
3611
|
var debug = Debug("mobbdev:constants");
|
|
3523
|
-
var runtimeConfigPath =
|
|
3612
|
+
var runtimeConfigPath = path3.join(
|
|
3524
3613
|
getModuleRootDir(),
|
|
3525
3614
|
"out",
|
|
3526
3615
|
"runtime.config.json"
|
|
3527
3616
|
);
|
|
3528
|
-
if (
|
|
3617
|
+
if (fs3.existsSync(runtimeConfigPath)) {
|
|
3529
3618
|
try {
|
|
3530
3619
|
const runtimeConfig = JSON.parse(
|
|
3531
|
-
|
|
3620
|
+
fs3.readFileSync(runtimeConfigPath, "utf-8")
|
|
3532
3621
|
);
|
|
3533
3622
|
Object.assign(process.env, runtimeConfig);
|
|
3534
3623
|
debug("Loaded runtime config from %s", runtimeConfigPath);
|
|
@@ -3536,7 +3625,7 @@ if (fs2.existsSync(runtimeConfigPath)) {
|
|
|
3536
3625
|
debug("Failed to load runtime config: %o", e);
|
|
3537
3626
|
}
|
|
3538
3627
|
}
|
|
3539
|
-
dotenv.config({ path:
|
|
3628
|
+
dotenv.config({ path: path3.join(getModuleRootDir(), ".env") });
|
|
3540
3629
|
var DEFAULT_API_URL = "https://api.mobb.ai/v1/graphql";
|
|
3541
3630
|
var DEFAULT_WEB_APP_URL = "https://app.mobb.ai";
|
|
3542
3631
|
var scmFriendlyText = {
|
|
@@ -3633,91 +3722,6 @@ var ScanContext = {
|
|
|
3633
3722
|
BUGSY: "BUGSY"
|
|
3634
3723
|
};
|
|
3635
3724
|
|
|
3636
|
-
// src/utils/keypress.ts
|
|
3637
|
-
import readline from "readline";
|
|
3638
|
-
async function keypress() {
|
|
3639
|
-
const rl = readline.createInterface({
|
|
3640
|
-
input: process.stdin,
|
|
3641
|
-
output: process.stdout
|
|
3642
|
-
});
|
|
3643
|
-
return new Promise((resolve) => {
|
|
3644
|
-
rl.question("", (answer) => {
|
|
3645
|
-
rl.close();
|
|
3646
|
-
process.stderr.moveCursor(0, -1);
|
|
3647
|
-
process.stderr.clearLine(1);
|
|
3648
|
-
resolve(answer);
|
|
3649
|
-
});
|
|
3650
|
-
});
|
|
3651
|
-
}
|
|
3652
|
-
|
|
3653
|
-
// src/utils/spinner.ts
|
|
3654
|
-
import {
|
|
3655
|
-
createSpinner as _createSpinner
|
|
3656
|
-
} from "nanospinner";
|
|
3657
|
-
function printToStdError(opts) {
|
|
3658
|
-
if (opts?.text) console.error(opts.text);
|
|
3659
|
-
}
|
|
3660
|
-
var mockSpinner = {
|
|
3661
|
-
success: (opts) => {
|
|
3662
|
-
printToStdError(opts);
|
|
3663
|
-
return mockSpinner;
|
|
3664
|
-
},
|
|
3665
|
-
error: (opts) => {
|
|
3666
|
-
printToStdError(opts);
|
|
3667
|
-
return mockSpinner;
|
|
3668
|
-
},
|
|
3669
|
-
warn: (opts) => {
|
|
3670
|
-
printToStdError(opts);
|
|
3671
|
-
return mockSpinner;
|
|
3672
|
-
},
|
|
3673
|
-
stop: (opts) => {
|
|
3674
|
-
printToStdError(opts);
|
|
3675
|
-
return mockSpinner;
|
|
3676
|
-
},
|
|
3677
|
-
start: (opts) => {
|
|
3678
|
-
printToStdError(opts);
|
|
3679
|
-
return mockSpinner;
|
|
3680
|
-
},
|
|
3681
|
-
update: (opts) => {
|
|
3682
|
-
printToStdError(opts);
|
|
3683
|
-
return mockSpinner;
|
|
3684
|
-
},
|
|
3685
|
-
reset: () => mockSpinner,
|
|
3686
|
-
clear: () => mockSpinner,
|
|
3687
|
-
spin: () => mockSpinner
|
|
3688
|
-
};
|
|
3689
|
-
function Spinner({ ci = false } = {}) {
|
|
3690
|
-
return {
|
|
3691
|
-
createSpinner: (text, options) => ci ? mockSpinner : _createSpinner(text, options)
|
|
3692
|
-
};
|
|
3693
|
-
}
|
|
3694
|
-
|
|
3695
|
-
// src/utils/check_node_version.ts
|
|
3696
|
-
import fs3 from "fs";
|
|
3697
|
-
import path3 from "path";
|
|
3698
|
-
import semver from "semver";
|
|
3699
|
-
function getPackageJson() {
|
|
3700
|
-
return JSON.parse(
|
|
3701
|
-
fs3.readFileSync(path3.join(getModuleRootDir(), "package.json"), "utf8")
|
|
3702
|
-
);
|
|
3703
|
-
}
|
|
3704
|
-
var packageJson = getPackageJson();
|
|
3705
|
-
if (!semver.satisfies(process.version, packageJson.engines.node)) {
|
|
3706
|
-
console.error(
|
|
3707
|
-
`
|
|
3708
|
-
\u26A0\uFE0F ${packageJson.name} requires node version ${packageJson.engines.node}, but running ${process.version}.`
|
|
3709
|
-
);
|
|
3710
|
-
process.exit(1);
|
|
3711
|
-
}
|
|
3712
|
-
|
|
3713
|
-
// src/utils/gitUtils.ts
|
|
3714
|
-
import simpleGit from "simple-git";
|
|
3715
|
-
|
|
3716
|
-
// src/utils/index.ts
|
|
3717
|
-
var sleep = (ms = 2e3) => new Promise((r) => setTimeout(r, ms));
|
|
3718
|
-
var CliError = class extends Error {
|
|
3719
|
-
};
|
|
3720
|
-
|
|
3721
3725
|
// src/utils/subscribe/subscribe.ts
|
|
3722
3726
|
import { createClient } from "graphql-ws";
|
|
3723
3727
|
import WebsocketNode from "isomorphic-ws";
|
|
@@ -5915,11 +5919,17 @@ var REPORT_DEFAULT_FILE_NAME = "report.json";
|
|
|
5915
5919
|
init_env();
|
|
5916
5920
|
|
|
5917
5921
|
// src/features/analysis/scm/github/GithubSCMLib.ts
|
|
5918
|
-
|
|
5922
|
+
init_env();
|
|
5923
|
+
import pLimit2 from "p-limit";
|
|
5919
5924
|
import { z as z22 } from "zod";
|
|
5920
5925
|
|
|
5921
5926
|
// src/features/analysis/scm/github/github.ts
|
|
5922
5927
|
import { RequestError } from "@octokit/request-error";
|
|
5928
|
+
import pLimit from "p-limit";
|
|
5929
|
+
|
|
5930
|
+
// src/utils/contextLogger.ts
|
|
5931
|
+
import debugModule from "debug";
|
|
5932
|
+
var debug4 = debugModule("mobb:shared");
|
|
5923
5933
|
|
|
5924
5934
|
// src/features/analysis/scm/github/utils/encrypt_secret.ts
|
|
5925
5935
|
import sodium from "libsodium-wrappers";
|
|
@@ -5928,9 +5938,6 @@ import sodium from "libsodium-wrappers";
|
|
|
5928
5938
|
import { Octokit } from "octokit";
|
|
5929
5939
|
import { fetch as fetch2, ProxyAgent } from "undici";
|
|
5930
5940
|
|
|
5931
|
-
// src/features/analysis/scm/github/GithubSCMLib.ts
|
|
5932
|
-
var GITHUB_COMMIT_FETCH_CONCURRENCY = parseInt(process.env["GITHUB_COMMIT_CONCURRENCY"] || "10", 10) || 10;
|
|
5933
|
-
|
|
5934
5941
|
// src/features/analysis/scm/gitlab/gitlab.ts
|
|
5935
5942
|
import querystring3 from "querystring";
|
|
5936
5943
|
import {
|
|
@@ -5946,12 +5953,6 @@ import {
|
|
|
5946
5953
|
fetch as undiciFetch,
|
|
5947
5954
|
ProxyAgent as ProxyAgent2
|
|
5948
5955
|
} from "undici";
|
|
5949
|
-
|
|
5950
|
-
// src/utils/contextLogger.ts
|
|
5951
|
-
import debugModule from "debug";
|
|
5952
|
-
var debug4 = debugModule("mobb:shared");
|
|
5953
|
-
|
|
5954
|
-
// src/features/analysis/scm/gitlab/gitlab.ts
|
|
5955
5956
|
init_env();
|
|
5956
5957
|
|
|
5957
5958
|
// src/features/analysis/scm/gitlab/types.ts
|
|
@@ -6494,10 +6495,174 @@ function getConfigStore() {
|
|
|
6494
6495
|
}
|
|
6495
6496
|
var configStore = getConfigStore();
|
|
6496
6497
|
|
|
6497
|
-
// src/commands/
|
|
6498
|
-
var debug7 = Debug6("mobbdev:commands");
|
|
6498
|
+
// src/commands/AuthManager.ts
|
|
6499
6499
|
var LOGIN_MAX_WAIT = 10 * 60 * 1e3;
|
|
6500
6500
|
var LOGIN_CHECK_DELAY = 5 * 1e3;
|
|
6501
|
+
var AuthManager = class {
|
|
6502
|
+
constructor(webAppUrl, apiUrl) {
|
|
6503
|
+
__publicField(this, "publicKey");
|
|
6504
|
+
__publicField(this, "privateKey");
|
|
6505
|
+
__publicField(this, "loginId");
|
|
6506
|
+
__publicField(this, "gqlClient");
|
|
6507
|
+
__publicField(this, "currentBrowserUrl");
|
|
6508
|
+
__publicField(this, "authenticated", null);
|
|
6509
|
+
__publicField(this, "resolvedWebAppUrl");
|
|
6510
|
+
__publicField(this, "resolvedApiUrl");
|
|
6511
|
+
this.resolvedWebAppUrl = webAppUrl || WEB_APP_URL;
|
|
6512
|
+
this.resolvedApiUrl = apiUrl || API_URL;
|
|
6513
|
+
}
|
|
6514
|
+
openUrlInBrowser() {
|
|
6515
|
+
if (this.currentBrowserUrl) {
|
|
6516
|
+
open(this.currentBrowserUrl);
|
|
6517
|
+
return true;
|
|
6518
|
+
}
|
|
6519
|
+
return false;
|
|
6520
|
+
}
|
|
6521
|
+
async waitForAuthentication() {
|
|
6522
|
+
let newApiToken = null;
|
|
6523
|
+
for (let i = 0; i < LOGIN_MAX_WAIT / LOGIN_CHECK_DELAY; i++) {
|
|
6524
|
+
newApiToken = await this.getApiToken();
|
|
6525
|
+
if (newApiToken) {
|
|
6526
|
+
break;
|
|
6527
|
+
}
|
|
6528
|
+
await sleep(LOGIN_CHECK_DELAY);
|
|
6529
|
+
}
|
|
6530
|
+
if (!newApiToken) {
|
|
6531
|
+
return false;
|
|
6532
|
+
}
|
|
6533
|
+
this.gqlClient = new GQLClient({
|
|
6534
|
+
apiKey: newApiToken,
|
|
6535
|
+
type: "apiKey",
|
|
6536
|
+
apiUrl: this.resolvedApiUrl
|
|
6537
|
+
});
|
|
6538
|
+
const loginSuccess = await this.gqlClient.validateUserToken();
|
|
6539
|
+
if (loginSuccess) {
|
|
6540
|
+
configStore.set("apiToken", newApiToken);
|
|
6541
|
+
this.authenticated = true;
|
|
6542
|
+
return true;
|
|
6543
|
+
}
|
|
6544
|
+
return false;
|
|
6545
|
+
}
|
|
6546
|
+
/**
|
|
6547
|
+
* Checks if the user is already authenticated
|
|
6548
|
+
*/
|
|
6549
|
+
async isAuthenticated() {
|
|
6550
|
+
if (this.authenticated === null) {
|
|
6551
|
+
const result = await this.checkAuthentication();
|
|
6552
|
+
this.authenticated = result.isAuthenticated;
|
|
6553
|
+
}
|
|
6554
|
+
return this.authenticated;
|
|
6555
|
+
}
|
|
6556
|
+
/**
|
|
6557
|
+
* Private function to check if the user is authenticated with the server
|
|
6558
|
+
*/
|
|
6559
|
+
async checkAuthentication(apiKey) {
|
|
6560
|
+
try {
|
|
6561
|
+
if (!this.gqlClient) {
|
|
6562
|
+
this.gqlClient = this.getGQLClient(apiKey);
|
|
6563
|
+
}
|
|
6564
|
+
const isConnected = await this.gqlClient.verifyApiConnection();
|
|
6565
|
+
if (!isConnected) {
|
|
6566
|
+
return {
|
|
6567
|
+
isAuthenticated: false,
|
|
6568
|
+
message: "Failed to connect to Mobb server"
|
|
6569
|
+
};
|
|
6570
|
+
}
|
|
6571
|
+
const userVerify = await this.gqlClient.validateUserToken();
|
|
6572
|
+
if (!userVerify) {
|
|
6573
|
+
return {
|
|
6574
|
+
isAuthenticated: false,
|
|
6575
|
+
message: "User token validation failed"
|
|
6576
|
+
};
|
|
6577
|
+
}
|
|
6578
|
+
} catch (error) {
|
|
6579
|
+
return {
|
|
6580
|
+
isAuthenticated: false,
|
|
6581
|
+
message: error instanceof Error ? error.message : "Unknown authentication error"
|
|
6582
|
+
};
|
|
6583
|
+
}
|
|
6584
|
+
return { isAuthenticated: true, message: "Successfully authenticated" };
|
|
6585
|
+
}
|
|
6586
|
+
/**
|
|
6587
|
+
* Generates a login URL for manual authentication
|
|
6588
|
+
*/
|
|
6589
|
+
async generateLoginUrl(loginContext) {
|
|
6590
|
+
try {
|
|
6591
|
+
if (!this.gqlClient) {
|
|
6592
|
+
this.gqlClient = this.getGQLClient();
|
|
6593
|
+
}
|
|
6594
|
+
const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
|
|
6595
|
+
modulusLength: 2048
|
|
6596
|
+
});
|
|
6597
|
+
this.publicKey = publicKey;
|
|
6598
|
+
this.privateKey = privateKey;
|
|
6599
|
+
this.loginId = await this.gqlClient.createCliLogin({
|
|
6600
|
+
publicKey: this.publicKey.export({ format: "pem", type: "pkcs1" }).toString()
|
|
6601
|
+
});
|
|
6602
|
+
const webLoginUrl = `${this.resolvedWebAppUrl}/cli-login`;
|
|
6603
|
+
const browserUrl = loginContext ? buildLoginUrl(webLoginUrl, this.loginId, os.hostname(), loginContext) : `${webLoginUrl}/${this.loginId}?hostname=${os.hostname()}`;
|
|
6604
|
+
this.currentBrowserUrl = browserUrl;
|
|
6605
|
+
return browserUrl;
|
|
6606
|
+
} catch (error) {
|
|
6607
|
+
console.error("Failed to generate login URL:", error);
|
|
6608
|
+
return null;
|
|
6609
|
+
}
|
|
6610
|
+
}
|
|
6611
|
+
/**
|
|
6612
|
+
* Retrieves and decrypts the API token after authentication
|
|
6613
|
+
*/
|
|
6614
|
+
async getApiToken() {
|
|
6615
|
+
if (!this.gqlClient || !this.loginId || !this.privateKey) {
|
|
6616
|
+
return null;
|
|
6617
|
+
}
|
|
6618
|
+
const encryptedApiToken = await this.gqlClient.getEncryptedApiToken({
|
|
6619
|
+
loginId: this.loginId
|
|
6620
|
+
});
|
|
6621
|
+
if (encryptedApiToken) {
|
|
6622
|
+
return crypto.privateDecrypt(
|
|
6623
|
+
this.privateKey,
|
|
6624
|
+
Buffer.from(encryptedApiToken, "base64")
|
|
6625
|
+
).toString("utf-8");
|
|
6626
|
+
}
|
|
6627
|
+
return null;
|
|
6628
|
+
}
|
|
6629
|
+
/**
|
|
6630
|
+
* Gets the current GQL client (if authenticated)
|
|
6631
|
+
*/
|
|
6632
|
+
getGQLClient(inputApiKey) {
|
|
6633
|
+
if (this.gqlClient === void 0) {
|
|
6634
|
+
this.gqlClient = new GQLClient({
|
|
6635
|
+
apiKey: inputApiKey || configStore.get("apiToken") || "",
|
|
6636
|
+
type: "apiKey",
|
|
6637
|
+
apiUrl: this.resolvedApiUrl
|
|
6638
|
+
});
|
|
6639
|
+
}
|
|
6640
|
+
return this.gqlClient;
|
|
6641
|
+
}
|
|
6642
|
+
/**
|
|
6643
|
+
* Assigns a GQL client instance to the AuthManager, and resets auth state
|
|
6644
|
+
* @param gqlClient The GQL client instance to set
|
|
6645
|
+
*/
|
|
6646
|
+
setGQLClient(gqlClient) {
|
|
6647
|
+
this.gqlClient = gqlClient;
|
|
6648
|
+
this.cleanup();
|
|
6649
|
+
}
|
|
6650
|
+
/**
|
|
6651
|
+
* Cleans up any active login session
|
|
6652
|
+
*/
|
|
6653
|
+
cleanup() {
|
|
6654
|
+
this.publicKey = void 0;
|
|
6655
|
+
this.privateKey = void 0;
|
|
6656
|
+
this.loginId = void 0;
|
|
6657
|
+
this.authenticated = null;
|
|
6658
|
+
this.currentBrowserUrl = null;
|
|
6659
|
+
}
|
|
6660
|
+
};
|
|
6661
|
+
|
|
6662
|
+
// src/commands/handleMobbLogin.ts
|
|
6663
|
+
var debug7 = Debug6("mobbdev:commands");
|
|
6664
|
+
var LOGIN_MAX_WAIT2 = 10 * 60 * 1e3;
|
|
6665
|
+
var LOGIN_CHECK_DELAY2 = 5 * 1e3;
|
|
6501
6666
|
var MOBB_LOGIN_REQUIRED_MSG = `\u{1F513} Login to Mobb is Required, you will be redirected to our login page, once the authorization is complete return to this prompt, ${chalk2.bgBlue(
|
|
6502
6667
|
"press any key to continue"
|
|
6503
6668
|
)};`;
|
|
@@ -6512,11 +6677,8 @@ async function getAuthenticatedGQLClient({
|
|
|
6512
6677
|
apiUrl || "undefined",
|
|
6513
6678
|
webAppUrl || "undefined"
|
|
6514
6679
|
);
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
type: "apiKey",
|
|
6518
|
-
apiUrl
|
|
6519
|
-
});
|
|
6680
|
+
const authManager = new AuthManager(webAppUrl, apiUrl);
|
|
6681
|
+
let gqlClient = authManager.getGQLClient(inputApiKey);
|
|
6520
6682
|
gqlClient = await handleMobbLogin({
|
|
6521
6683
|
inGqlClient: gqlClient,
|
|
6522
6684
|
skipPrompts: isSkipPrompts,
|
|
@@ -6533,35 +6695,28 @@ async function handleMobbLogin({
|
|
|
6533
6695
|
webAppUrl,
|
|
6534
6696
|
loginContext
|
|
6535
6697
|
}) {
|
|
6536
|
-
const resolvedWebAppUrl = webAppUrl || WEB_APP_URL;
|
|
6537
|
-
const resolvedApiUrl = apiUrl || API_URL;
|
|
6538
6698
|
debug7(
|
|
6539
6699
|
"handleMobbLogin: resolved URLs - apiUrl=%s (from param: %s), webAppUrl=%s (from param: %s)",
|
|
6540
|
-
resolvedApiUrl,
|
|
6541
6700
|
apiUrl || "fallback",
|
|
6542
|
-
|
|
6701
|
+
apiUrl || "fallback",
|
|
6702
|
+
webAppUrl || "fallback",
|
|
6543
6703
|
webAppUrl || "fallback"
|
|
6544
6704
|
);
|
|
6545
6705
|
const { createSpinner } = Spinner({ ci: skipPrompts });
|
|
6546
|
-
const
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6706
|
+
const authManager = new AuthManager(webAppUrl, apiUrl);
|
|
6707
|
+
authManager.setGQLClient(inGqlClient);
|
|
6708
|
+
try {
|
|
6709
|
+
const isAuthenticated = await authManager.isAuthenticated();
|
|
6710
|
+
if (isAuthenticated) {
|
|
6711
|
+
createSpinner().start().success({
|
|
6712
|
+
text: `\u{1F513} Login to Mobb succeeded. Already authenticated`
|
|
6713
|
+
});
|
|
6714
|
+
return authManager.getGQLClient();
|
|
6715
|
+
}
|
|
6716
|
+
} catch (error) {
|
|
6717
|
+
debug7("Authentication check failed:", error);
|
|
6554
6718
|
}
|
|
6555
|
-
|
|
6556
|
-
text: `\u{1F513} Connection to Mobb: succeeded`
|
|
6557
|
-
});
|
|
6558
|
-
const userVerify = await inGqlClient.validateUserToken();
|
|
6559
|
-
if (userVerify) {
|
|
6560
|
-
createSpinner().start().success({
|
|
6561
|
-
text: `\u{1F513} Login to Mobb succeeded. ${typeof userVerify === "string" ? `Logged in as ${userVerify}` : ""}`
|
|
6562
|
-
});
|
|
6563
|
-
return inGqlClient;
|
|
6564
|
-
} else if (apiKey) {
|
|
6719
|
+
if (apiKey) {
|
|
6565
6720
|
createSpinner().start().error({
|
|
6566
6721
|
text: "\u{1F513} Login to Mobb failed: The provided API key does not match any configured API key on the system"
|
|
6567
6722
|
});
|
|
@@ -6577,57 +6732,32 @@ async function handleMobbLogin({
|
|
|
6577
6732
|
loginSpinner.update({
|
|
6578
6733
|
text: "\u{1F513} Waiting for Mobb login..."
|
|
6579
6734
|
});
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
6598
|
-
if (encryptedApiToken) {
|
|
6599
|
-
debug7("encrypted API token received %s", encryptedApiToken);
|
|
6600
|
-
newApiToken = crypto.privateDecrypt(privateKey, Buffer.from(encryptedApiToken, "base64")).toString("utf-8");
|
|
6601
|
-
debug7("API token decrypted");
|
|
6602
|
-
break;
|
|
6735
|
+
try {
|
|
6736
|
+
const loginUrl = await authManager.generateLoginUrl(loginContext);
|
|
6737
|
+
if (!loginUrl) {
|
|
6738
|
+
loginSpinner.error({
|
|
6739
|
+
text: "Failed to generate login URL"
|
|
6740
|
+
});
|
|
6741
|
+
throw new CliError("Failed to generate login URL");
|
|
6742
|
+
}
|
|
6743
|
+
!skipPrompts && console.log(
|
|
6744
|
+
`If the page does not open automatically, kindly access it through ${loginUrl}.`
|
|
6745
|
+
);
|
|
6746
|
+
authManager.openUrlInBrowser();
|
|
6747
|
+
const authSuccess = await authManager.waitForAuthentication();
|
|
6748
|
+
if (!authSuccess) {
|
|
6749
|
+
loginSpinner.error({
|
|
6750
|
+
text: "Login timeout error"
|
|
6751
|
+
});
|
|
6752
|
+
throw new CliError("Login timeout error");
|
|
6603
6753
|
}
|
|
6604
|
-
await sleep(LOGIN_CHECK_DELAY);
|
|
6605
|
-
}
|
|
6606
|
-
if (!newApiToken) {
|
|
6607
|
-
loginSpinner.error({
|
|
6608
|
-
text: "Login timeout error"
|
|
6609
|
-
});
|
|
6610
|
-
throw new CliError();
|
|
6611
|
-
}
|
|
6612
|
-
const newGqlClient = new GQLClient({
|
|
6613
|
-
apiKey: newApiToken,
|
|
6614
|
-
type: "apiKey",
|
|
6615
|
-
apiUrl: resolvedApiUrl
|
|
6616
|
-
});
|
|
6617
|
-
const loginSuccess = await newGqlClient.validateUserToken();
|
|
6618
|
-
if (loginSuccess) {
|
|
6619
|
-
debug7(`set api token ${newApiToken}`);
|
|
6620
|
-
configStore.set("apiToken", newApiToken);
|
|
6621
6754
|
loginSpinner.success({
|
|
6622
|
-
text: `\u{1F513} Login to Mobb successful
|
|
6623
|
-
});
|
|
6624
|
-
} else {
|
|
6625
|
-
loginSpinner.error({
|
|
6626
|
-
text: "Something went wrong, API token is invalid."
|
|
6755
|
+
text: `\u{1F513} Login to Mobb successful!`
|
|
6627
6756
|
});
|
|
6628
|
-
|
|
6757
|
+
return authManager.getGQLClient();
|
|
6758
|
+
} finally {
|
|
6759
|
+
authManager.cleanup();
|
|
6629
6760
|
}
|
|
6630
|
-
return newGqlClient;
|
|
6631
6761
|
}
|
|
6632
6762
|
|
|
6633
6763
|
// src/args/commands/upload_ai_blame.ts
|