githits 0.2.3 → 0.3.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.plugin/plugin.json +1 -1
- package/GEMINI.md +4 -6
- package/README.md +31 -17
- package/commands/help.md +4 -4
- package/dist/cli.js +718 -238
- package/dist/index.js +1 -1
- package/dist/shared/{chunk-a9js75mw.js → chunk-0s7mxdt3.js} +1702 -678
- package/dist/shared/{chunk-js72s35a.js → chunk-m1xx8hzw.js} +1 -1
- package/dist/shared/chunk-zg5dnven.js +11 -0
- package/gemini-extension.json +1 -1
- package/package.json +4 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/commands/help.md +4 -4
- package/plugins/claude/skills/search/SKILL.md +2 -2
- package/skills/search/SKILL.md +2 -2
- package/dist/shared/chunk-9zze00cp.js +0 -11
|
@@ -1,7 +1,94 @@
|
|
|
1
1
|
import {
|
|
2
|
+
__require,
|
|
2
3
|
version
|
|
3
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-m1xx8hzw.js";
|
|
4
5
|
|
|
6
|
+
// src/services/app-config-paths.ts
|
|
7
|
+
var APP_DIR = "githits";
|
|
8
|
+
function getAppConfigDir(fs) {
|
|
9
|
+
const home = fs.getHomeDir();
|
|
10
|
+
switch (process.platform) {
|
|
11
|
+
case "win32":
|
|
12
|
+
return fs.joinPath(process.env.APPDATA ?? fs.joinPath(home, "AppData", "Roaming"), APP_DIR);
|
|
13
|
+
case "darwin":
|
|
14
|
+
return fs.joinPath(home, "Library", "Application Support", APP_DIR);
|
|
15
|
+
default:
|
|
16
|
+
return fs.joinPath(process.env.XDG_CONFIG_HOME ?? fs.joinPath(home, ".config"), APP_DIR);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function getAuthConfigPath(fs) {
|
|
20
|
+
return fs.joinPath(getAppConfigDir(fs), "config.toml");
|
|
21
|
+
}
|
|
22
|
+
function getAuthFileStorageDir(fs) {
|
|
23
|
+
return fs.joinPath(getAppConfigDir(fs), "auth");
|
|
24
|
+
}
|
|
25
|
+
function getLegacyAuthStorageDir(fs) {
|
|
26
|
+
return fs.joinPath(fs.getHomeDir(), ".githits");
|
|
27
|
+
}
|
|
28
|
+
// src/services/auth-config.ts
|
|
29
|
+
import { parse as parseToml } from "smol-toml";
|
|
30
|
+
import { z } from "zod";
|
|
31
|
+
var AUTH_STORAGE_MODES = ["keychain", "file"];
|
|
32
|
+
var AUTH_STORAGE_MODE_VALUES = new Set(AUTH_STORAGE_MODES);
|
|
33
|
+
var CONFIG_SCHEMA = z.object({
|
|
34
|
+
auth: z.object({
|
|
35
|
+
storage: z.string().optional()
|
|
36
|
+
}).optional()
|
|
37
|
+
}).passthrough();
|
|
38
|
+
|
|
39
|
+
class AuthConfigError extends Error {
|
|
40
|
+
constructor(message) {
|
|
41
|
+
super(message);
|
|
42
|
+
this.name = "AuthConfigError";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function parseAuthStorageMode(value) {
|
|
46
|
+
const normalized = value.trim().toLowerCase();
|
|
47
|
+
if (AUTH_STORAGE_MODE_VALUES.has(normalized)) {
|
|
48
|
+
return normalized;
|
|
49
|
+
}
|
|
50
|
+
throw new AuthConfigError(`Invalid auth storage mode "${value}". Use "keychain" or "file". File mode stores OAuth credentials unencrypted on disk.`);
|
|
51
|
+
}
|
|
52
|
+
async function loadAuthConfig(fs) {
|
|
53
|
+
const configPath = getAuthConfigPath(fs);
|
|
54
|
+
const envMode = process.env.GITHITS_AUTH_STORAGE;
|
|
55
|
+
if (envMode !== undefined && envMode.trim() !== "") {
|
|
56
|
+
try {
|
|
57
|
+
return { storage: parseAuthStorageMode(envMode), configPath };
|
|
58
|
+
} catch (error) {
|
|
59
|
+
if (error instanceof AuthConfigError) {
|
|
60
|
+
throw new AuthConfigError(`Invalid GITHITS_AUTH_STORAGE: ${error.message}`);
|
|
61
|
+
}
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (!await fs.exists(configPath)) {
|
|
66
|
+
return { storage: "keychain", configPath };
|
|
67
|
+
}
|
|
68
|
+
let rawConfig;
|
|
69
|
+
try {
|
|
70
|
+
rawConfig = parseToml(await fs.readFile(configPath));
|
|
71
|
+
} catch (error) {
|
|
72
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
73
|
+
throw new AuthConfigError(`Cannot parse GitHits config at ${configPath}: ${message}`);
|
|
74
|
+
}
|
|
75
|
+
const parsed = CONFIG_SCHEMA.safeParse(rawConfig);
|
|
76
|
+
if (!parsed.success) {
|
|
77
|
+
throw new AuthConfigError(`Invalid GitHits config at ${configPath}: ${z.prettifyError(parsed.error)}`);
|
|
78
|
+
}
|
|
79
|
+
const configuredMode = parsed.data.auth?.storage;
|
|
80
|
+
if (configuredMode === undefined || configuredMode.trim() === "") {
|
|
81
|
+
return { storage: "keychain", configPath };
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
return { storage: parseAuthStorageMode(configuredMode), configPath };
|
|
85
|
+
} catch (error) {
|
|
86
|
+
if (error instanceof AuthConfigError) {
|
|
87
|
+
throw new AuthConfigError(`Invalid GitHits config at ${configPath}: ${error.message}`);
|
|
88
|
+
}
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
5
92
|
// src/services/auth-service.ts
|
|
6
93
|
import { createServer } from "node:http";
|
|
7
94
|
|
|
@@ -164,7 +251,7 @@ class AuthServiceImpl {
|
|
|
164
251
|
const error = await response.text();
|
|
165
252
|
throw new Error(`Token refresh failed: ${error}`);
|
|
166
253
|
}
|
|
167
|
-
return
|
|
254
|
+
return parseRefreshTokenResponse(await response.json());
|
|
168
255
|
}
|
|
169
256
|
}
|
|
170
257
|
function parseTokenResponse(data) {
|
|
@@ -178,6 +265,17 @@ function parseTokenResponse(data) {
|
|
|
178
265
|
expiresIn: d.expires_in || 3600
|
|
179
266
|
};
|
|
180
267
|
}
|
|
268
|
+
function parseRefreshTokenResponse(data) {
|
|
269
|
+
const d = data;
|
|
270
|
+
if (!d.access_token) {
|
|
271
|
+
throw new Error("Token response missing required fields");
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
accessToken: d.access_token,
|
|
275
|
+
refreshToken: typeof d.refresh_token === "string" ? d.refresh_token : undefined,
|
|
276
|
+
expiresIn: d.expires_in || 3600
|
|
277
|
+
};
|
|
278
|
+
}
|
|
181
279
|
function successHtml(title = "Authentication successful") {
|
|
182
280
|
return `<!DOCTYPE html>
|
|
183
281
|
<html><head><title>GitHits CLI</title>
|
|
@@ -310,11 +408,9 @@ function escapeHtml(text) {
|
|
|
310
408
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
311
409
|
}
|
|
312
410
|
// src/services/auth-storage.ts
|
|
313
|
-
var CONFIG_DIR = ".githits";
|
|
314
411
|
var AUTH_FILE = "auth.json";
|
|
315
412
|
var CLIENT_FILE = "client.json";
|
|
316
413
|
var DIR_MODE = 448;
|
|
317
|
-
var FILE_MODE = 384;
|
|
318
414
|
|
|
319
415
|
class AuthStorageImpl {
|
|
320
416
|
fs;
|
|
@@ -323,7 +419,7 @@ class AuthStorageImpl {
|
|
|
323
419
|
clientPath;
|
|
324
420
|
constructor(fs, configDir) {
|
|
325
421
|
this.fs = fs;
|
|
326
|
-
this.configDir = configDir ??
|
|
422
|
+
this.configDir = configDir ?? getAuthFileStorageDir(fs);
|
|
327
423
|
this.authPath = fs.joinPath(this.configDir, AUTH_FILE);
|
|
328
424
|
this.clientPath = fs.joinPath(this.configDir, CLIENT_FILE);
|
|
329
425
|
}
|
|
@@ -343,7 +439,14 @@ class AuthStorageImpl {
|
|
|
343
439
|
};
|
|
344
440
|
stored.tokens[normalizeBaseUrl(baseUrl)] = data;
|
|
345
441
|
await this.fs.ensureDir(this.configDir, DIR_MODE);
|
|
346
|
-
await this.fs.
|
|
442
|
+
await this.fs.atomicWriteFile(this.authPath, JSON.stringify(stored, null, 2));
|
|
443
|
+
}
|
|
444
|
+
async saveTokensIfUnchanged(baseUrl, expected, data) {
|
|
445
|
+
const current = await this.loadTokens(baseUrl);
|
|
446
|
+
if (!sameTokenData(current, expected))
|
|
447
|
+
return false;
|
|
448
|
+
await this.saveTokens(baseUrl, data);
|
|
449
|
+
return true;
|
|
347
450
|
}
|
|
348
451
|
async clearTokens(baseUrl) {
|
|
349
452
|
const stored = await this.loadAuthFile();
|
|
@@ -353,9 +456,16 @@ class AuthStorageImpl {
|
|
|
353
456
|
if (Object.keys(stored.tokens).length === 0) {
|
|
354
457
|
await this.fs.deleteFile(this.authPath);
|
|
355
458
|
} else {
|
|
356
|
-
await this.fs.
|
|
459
|
+
await this.fs.atomicWriteFile(this.authPath, JSON.stringify(stored, null, 2));
|
|
357
460
|
}
|
|
358
461
|
}
|
|
462
|
+
async clearTokensIfUnchanged(baseUrl, expected) {
|
|
463
|
+
const current = await this.loadTokens(baseUrl);
|
|
464
|
+
if (!sameTokenData(current, expected))
|
|
465
|
+
return false;
|
|
466
|
+
await this.clearTokens(baseUrl);
|
|
467
|
+
return true;
|
|
468
|
+
}
|
|
359
469
|
async loadClient(baseUrl) {
|
|
360
470
|
const stored = await this.loadClientFile();
|
|
361
471
|
if (!stored)
|
|
@@ -370,7 +480,7 @@ class AuthStorageImpl {
|
|
|
370
480
|
if (Object.keys(stored.clients).length === 0) {
|
|
371
481
|
await this.fs.deleteFile(this.clientPath);
|
|
372
482
|
} else {
|
|
373
|
-
await this.fs.
|
|
483
|
+
await this.fs.atomicWriteFile(this.clientPath, JSON.stringify(stored, null, 2));
|
|
374
484
|
}
|
|
375
485
|
}
|
|
376
486
|
async saveClient(baseUrl, data) {
|
|
@@ -380,7 +490,14 @@ class AuthStorageImpl {
|
|
|
380
490
|
};
|
|
381
491
|
stored.clients[normalizeBaseUrl(baseUrl)] = data;
|
|
382
492
|
await this.fs.ensureDir(this.configDir, DIR_MODE);
|
|
383
|
-
await this.fs.
|
|
493
|
+
await this.fs.atomicWriteFile(this.clientPath, JSON.stringify(stored, null, 2));
|
|
494
|
+
}
|
|
495
|
+
async saveAuthSession(baseUrl, client, tokens) {
|
|
496
|
+
await this.saveClient(baseUrl, client);
|
|
497
|
+
await this.saveTokens(baseUrl, tokens);
|
|
498
|
+
}
|
|
499
|
+
async clearAuthSession(baseUrl) {
|
|
500
|
+
await clearAuthSessionBestEffort(() => this.clearTokens(baseUrl), () => this.clearClient(baseUrl));
|
|
384
501
|
}
|
|
385
502
|
async loadAuthFile() {
|
|
386
503
|
if (!await this.fs.exists(this.authPath))
|
|
@@ -412,6 +529,26 @@ class AuthStorageImpl {
|
|
|
412
529
|
function normalizeBaseUrl(url) {
|
|
413
530
|
return url.replace(/\/+$/, "");
|
|
414
531
|
}
|
|
532
|
+
function sameTokenData(a, b) {
|
|
533
|
+
if (a === null || b === null)
|
|
534
|
+
return a === b;
|
|
535
|
+
return a.accessToken === b.accessToken && a.refreshToken === b.refreshToken && a.expiresAt === b.expiresAt && a.createdAt === b.createdAt;
|
|
536
|
+
}
|
|
537
|
+
async function clearAuthSessionBestEffort(clearTokens, clearClient) {
|
|
538
|
+
let firstError;
|
|
539
|
+
try {
|
|
540
|
+
await clearTokens();
|
|
541
|
+
} catch (error) {
|
|
542
|
+
firstError = error;
|
|
543
|
+
}
|
|
544
|
+
try {
|
|
545
|
+
await clearClient();
|
|
546
|
+
} catch (error) {
|
|
547
|
+
firstError ??= error;
|
|
548
|
+
}
|
|
549
|
+
if (firstError)
|
|
550
|
+
throw firstError;
|
|
551
|
+
}
|
|
415
552
|
// src/services/browser-service.ts
|
|
416
553
|
import open from "open";
|
|
417
554
|
|
|
@@ -531,54 +668,34 @@ class ChunkingKeyringService {
|
|
|
531
668
|
}
|
|
532
669
|
}
|
|
533
670
|
}
|
|
534
|
-
// src/services/
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
}
|
|
546
|
-
function extractFeatureFlags(payload) {
|
|
547
|
-
if (isStringArray(payload.feature_flags)) {
|
|
548
|
-
return payload.feature_flags;
|
|
549
|
-
}
|
|
550
|
-
if (payload.claims && isStringArray(payload.claims.feature_flags)) {
|
|
551
|
-
return payload.claims.feature_flags;
|
|
671
|
+
// src/services/client-update-required-error.ts
|
|
672
|
+
var CLIENT_UPDATE_REQUIRED_REASON = "Backend protocol changed";
|
|
673
|
+
|
|
674
|
+
class ClientUpdateRequiredError extends Error {
|
|
675
|
+
reason;
|
|
676
|
+
currentVersion;
|
|
677
|
+
constructor(message = `Update required: ${CLIENT_UPDATE_REQUIRED_REASON}`, reason = CLIENT_UPDATE_REQUIRED_REASON, currentVersion = version) {
|
|
678
|
+
super(message);
|
|
679
|
+
this.reason = reason;
|
|
680
|
+
this.currentVersion = currentVersion;
|
|
681
|
+
this.name = "ClientUpdateRequiredError";
|
|
552
682
|
}
|
|
553
|
-
return null;
|
|
554
|
-
}
|
|
555
|
-
function isStringArray(value) {
|
|
556
|
-
return Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
557
683
|
}
|
|
558
|
-
function
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
566
|
-
return null;
|
|
567
|
-
}
|
|
568
|
-
return parsed;
|
|
569
|
-
} catch {
|
|
570
|
-
return null;
|
|
684
|
+
function isClientUpdateRequiredGraphQLError(input) {
|
|
685
|
+
if (input.code === "CLIENT_UPDATE_REQUIRED") {
|
|
686
|
+
return true;
|
|
687
|
+
}
|
|
688
|
+
const message = input.message;
|
|
689
|
+
if (!isGraphQLSchemaMismatchMessage(message)) {
|
|
690
|
+
return false;
|
|
571
691
|
}
|
|
692
|
+
return !input.code || input.code === "GRAPHQL_VALIDATION_FAILED" || input.code === "BAD_USER_INPUT";
|
|
572
693
|
}
|
|
573
|
-
function
|
|
574
|
-
|
|
575
|
-
const padding = normalized.length % 4;
|
|
576
|
-
if (padding === 0)
|
|
577
|
-
return normalized;
|
|
578
|
-
return normalized.padEnd(normalized.length + (4 - padding), "=");
|
|
694
|
+
function isGraphQLSchemaMismatchMessage(message) {
|
|
695
|
+
return /Cannot query field|Field .* does not exist|Unknown argument|Unknown type|Unknown field/i.test(message);
|
|
579
696
|
}
|
|
580
697
|
// src/services/code-navigation-service.ts
|
|
581
|
-
import { z } from "zod";
|
|
698
|
+
import { z as z2 } from "zod";
|
|
582
699
|
|
|
583
700
|
// src/shared/debug-log.ts
|
|
584
701
|
function debugLog(area, payload) {
|
|
@@ -903,17 +1020,6 @@ async function withTelemetrySpan(name, operation, attributes) {
|
|
|
903
1020
|
throw error;
|
|
904
1021
|
}
|
|
905
1022
|
}
|
|
906
|
-
function withTelemetrySpanSync(name, operation, attributes) {
|
|
907
|
-
const handle = telemetryCollector.startSpan(name, attributes);
|
|
908
|
-
try {
|
|
909
|
-
const result = operation();
|
|
910
|
-
telemetryCollector.endSpan(handle);
|
|
911
|
-
return result;
|
|
912
|
-
} catch (error) {
|
|
913
|
-
telemetryCollector.endSpan(handle, { error: true });
|
|
914
|
-
throw error;
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
1023
|
function startTelemetrySpan(name, attributes) {
|
|
918
1024
|
return telemetryCollector.startSpan(name, attributes);
|
|
919
1025
|
}
|
|
@@ -1420,80 +1526,80 @@ function asRecord(value) {
|
|
|
1420
1526
|
}
|
|
1421
1527
|
return;
|
|
1422
1528
|
}
|
|
1423
|
-
var availableVersionSchema =
|
|
1424
|
-
version:
|
|
1425
|
-
ref:
|
|
1529
|
+
var availableVersionSchema = z2.object({
|
|
1530
|
+
version: z2.string().nullable().optional(),
|
|
1531
|
+
ref: z2.string()
|
|
1426
1532
|
});
|
|
1427
|
-
var unifiedSearchSourceSchema =
|
|
1428
|
-
var unifiedSearchResultTypeSchema =
|
|
1533
|
+
var unifiedSearchSourceSchema = z2.enum(["AUTO", "DOCS", "CODE", "SYMBOL"]);
|
|
1534
|
+
var unifiedSearchResultTypeSchema = z2.enum([
|
|
1429
1535
|
"DOCUMENTATION_PAGE",
|
|
1430
1536
|
"REPOSITORY_SYMBOL",
|
|
1431
1537
|
"REPOSITORY_CODE",
|
|
1432
1538
|
"REPOSITORY_DOC"
|
|
1433
1539
|
]);
|
|
1434
|
-
var unifiedSearchLocatorSchema =
|
|
1435
|
-
registry:
|
|
1436
|
-
packageName:
|
|
1437
|
-
version:
|
|
1438
|
-
pageId:
|
|
1439
|
-
sourceKind:
|
|
1440
|
-
sourceUrl:
|
|
1441
|
-
repoUrl:
|
|
1442
|
-
gitRef:
|
|
1443
|
-
requestedRef:
|
|
1444
|
-
filePath:
|
|
1445
|
-
startLine:
|
|
1446
|
-
endLine:
|
|
1447
|
-
fileContentHash:
|
|
1448
|
-
symbolRef:
|
|
1449
|
-
qualifiedPath:
|
|
1450
|
-
kind:
|
|
1451
|
-
category:
|
|
1452
|
-
language:
|
|
1540
|
+
var unifiedSearchLocatorSchema = z2.object({
|
|
1541
|
+
registry: z2.string().nullable().optional(),
|
|
1542
|
+
packageName: z2.string().nullable().optional(),
|
|
1543
|
+
version: z2.string().nullable().optional(),
|
|
1544
|
+
pageId: z2.string().nullable().optional(),
|
|
1545
|
+
sourceKind: z2.string().nullable().optional(),
|
|
1546
|
+
sourceUrl: z2.string().nullable().optional(),
|
|
1547
|
+
repoUrl: z2.string().nullable().optional(),
|
|
1548
|
+
gitRef: z2.string().nullable().optional(),
|
|
1549
|
+
requestedRef: z2.string().nullable().optional(),
|
|
1550
|
+
filePath: z2.string().nullable().optional(),
|
|
1551
|
+
startLine: z2.number().int().nullable().optional(),
|
|
1552
|
+
endLine: z2.number().int().nullable().optional(),
|
|
1553
|
+
fileContentHash: z2.string().nullable().optional(),
|
|
1554
|
+
symbolRef: z2.string().nullable().optional(),
|
|
1555
|
+
qualifiedPath: z2.string().nullable().optional(),
|
|
1556
|
+
kind: z2.string().nullable().optional(),
|
|
1557
|
+
category: z2.string().nullable().optional(),
|
|
1558
|
+
language: z2.string().nullable().optional()
|
|
1453
1559
|
});
|
|
1454
|
-
var unifiedSearchHitSchema =
|
|
1455
|
-
id:
|
|
1560
|
+
var unifiedSearchHitSchema = z2.object({
|
|
1561
|
+
id: z2.string(),
|
|
1456
1562
|
resultType: unifiedSearchResultTypeSchema,
|
|
1457
|
-
targetLabel:
|
|
1458
|
-
title:
|
|
1459
|
-
summary:
|
|
1460
|
-
score:
|
|
1461
|
-
highlights:
|
|
1462
|
-
title:
|
|
1463
|
-
summary:
|
|
1563
|
+
targetLabel: z2.string(),
|
|
1564
|
+
title: z2.string().nullable().optional(),
|
|
1565
|
+
summary: z2.string().nullable().optional(),
|
|
1566
|
+
score: z2.number().nullable().optional(),
|
|
1567
|
+
highlights: z2.object({
|
|
1568
|
+
title: z2.array(z2.tuple([z2.number().int(), z2.number().int()])).nullable().optional(),
|
|
1569
|
+
summary: z2.array(z2.tuple([z2.number().int(), z2.number().int()])).nullable().optional()
|
|
1464
1570
|
}).nullable().optional(),
|
|
1465
1571
|
locator: unifiedSearchLocatorSchema
|
|
1466
1572
|
});
|
|
1467
|
-
var unifiedSearchPageInfoSchema =
|
|
1468
|
-
offset:
|
|
1469
|
-
limit:
|
|
1470
|
-
returned:
|
|
1471
|
-
hasMore:
|
|
1573
|
+
var unifiedSearchPageInfoSchema = z2.object({
|
|
1574
|
+
offset: z2.number().int(),
|
|
1575
|
+
limit: z2.number().int(),
|
|
1576
|
+
returned: z2.number().int(),
|
|
1577
|
+
hasMore: z2.boolean()
|
|
1472
1578
|
});
|
|
1473
|
-
var unifiedSearchSourceStatusSchema =
|
|
1579
|
+
var unifiedSearchSourceStatusSchema = z2.object({
|
|
1474
1580
|
source: unifiedSearchSourceSchema,
|
|
1475
|
-
targetLabel:
|
|
1476
|
-
indexingStatus:
|
|
1477
|
-
codeIndexState:
|
|
1478
|
-
resultCount:
|
|
1479
|
-
appliedFilters:
|
|
1480
|
-
ignoredFilters:
|
|
1481
|
-
incompatibleFilters:
|
|
1482
|
-
appliedQueryFeatures:
|
|
1483
|
-
ignoredQueryFeatures:
|
|
1484
|
-
incompatibleQueryFeatures:
|
|
1485
|
-
note:
|
|
1581
|
+
targetLabel: z2.string(),
|
|
1582
|
+
indexingStatus: z2.string().nullable().optional(),
|
|
1583
|
+
codeIndexState: z2.string().nullable().optional(),
|
|
1584
|
+
resultCount: z2.number().int().nullable().optional(),
|
|
1585
|
+
appliedFilters: z2.array(z2.string()),
|
|
1586
|
+
ignoredFilters: z2.array(z2.string()),
|
|
1587
|
+
incompatibleFilters: z2.array(z2.string()),
|
|
1588
|
+
appliedQueryFeatures: z2.array(z2.string()),
|
|
1589
|
+
ignoredQueryFeatures: z2.array(z2.string()),
|
|
1590
|
+
incompatibleQueryFeatures: z2.array(z2.string()),
|
|
1591
|
+
note: z2.string().nullable().optional()
|
|
1486
1592
|
});
|
|
1487
|
-
var unifiedSearchResultSchema =
|
|
1488
|
-
query:
|
|
1489
|
-
queryWarnings:
|
|
1490
|
-
sources:
|
|
1491
|
-
results:
|
|
1593
|
+
var unifiedSearchResultSchema = z2.object({
|
|
1594
|
+
query: z2.string(),
|
|
1595
|
+
queryWarnings: z2.array(z2.string()),
|
|
1596
|
+
sources: z2.array(unifiedSearchSourceSchema),
|
|
1597
|
+
results: z2.array(unifiedSearchHitSchema),
|
|
1492
1598
|
page: unifiedSearchPageInfoSchema,
|
|
1493
|
-
partialResults:
|
|
1494
|
-
sourceStatus:
|
|
1599
|
+
partialResults: z2.boolean(),
|
|
1600
|
+
sourceStatus: z2.array(unifiedSearchSourceStatusSchema)
|
|
1495
1601
|
});
|
|
1496
|
-
var unifiedSearchSessionStatusSchema =
|
|
1602
|
+
var unifiedSearchSessionStatusSchema = z2.enum([
|
|
1497
1603
|
"PENDING",
|
|
1498
1604
|
"INDEXING",
|
|
1499
1605
|
"SEARCHING",
|
|
@@ -1501,60 +1607,60 @@ var unifiedSearchSessionStatusSchema = z.enum([
|
|
|
1501
1607
|
"TIMEOUT",
|
|
1502
1608
|
"FAILED"
|
|
1503
1609
|
]);
|
|
1504
|
-
var unifiedSearchProgressSchema =
|
|
1505
|
-
searchRef:
|
|
1610
|
+
var unifiedSearchProgressSchema = z2.object({
|
|
1611
|
+
searchRef: z2.string(),
|
|
1506
1612
|
status: unifiedSearchSessionStatusSchema,
|
|
1507
|
-
targetsTotal:
|
|
1508
|
-
targetsReady:
|
|
1509
|
-
elapsedMs:
|
|
1510
|
-
query:
|
|
1511
|
-
queryWarnings:
|
|
1512
|
-
sources:
|
|
1513
|
-
expiresAt:
|
|
1613
|
+
targetsTotal: z2.number().int(),
|
|
1614
|
+
targetsReady: z2.number().int(),
|
|
1615
|
+
elapsedMs: z2.number().int(),
|
|
1616
|
+
query: z2.string(),
|
|
1617
|
+
queryWarnings: z2.array(z2.string()),
|
|
1618
|
+
sources: z2.array(unifiedSearchSourceSchema),
|
|
1619
|
+
expiresAt: z2.string().nullable().optional(),
|
|
1514
1620
|
results: unifiedSearchResultSchema.nullable().optional()
|
|
1515
1621
|
});
|
|
1516
|
-
var asyncUnifiedSearchResultSchema =
|
|
1517
|
-
completed:
|
|
1518
|
-
searchRef:
|
|
1622
|
+
var asyncUnifiedSearchResultSchema = z2.object({
|
|
1623
|
+
completed: z2.boolean(),
|
|
1624
|
+
searchRef: z2.string().nullable().optional(),
|
|
1519
1625
|
result: unifiedSearchResultSchema.nullable().optional(),
|
|
1520
1626
|
progress: unifiedSearchProgressSchema.nullable().optional()
|
|
1521
1627
|
});
|
|
1522
|
-
var graphQLErrorSchema =
|
|
1523
|
-
message:
|
|
1524
|
-
extensions:
|
|
1628
|
+
var graphQLErrorSchema = z2.object({
|
|
1629
|
+
message: z2.string(),
|
|
1630
|
+
extensions: z2.record(z2.string(), z2.unknown()).optional()
|
|
1525
1631
|
});
|
|
1526
|
-
var navigationResolutionSchema =
|
|
1527
|
-
requestedVersion:
|
|
1528
|
-
requestedRef:
|
|
1529
|
-
resolvedRef:
|
|
1530
|
-
commitSha:
|
|
1632
|
+
var navigationResolutionSchema = z2.object({
|
|
1633
|
+
requestedVersion: z2.string().nullable().optional(),
|
|
1634
|
+
requestedRef: z2.string().nullable().optional(),
|
|
1635
|
+
resolvedRef: z2.string().nullable().optional(),
|
|
1636
|
+
commitSha: z2.string().nullable().optional()
|
|
1531
1637
|
}).nullable().optional();
|
|
1532
|
-
var navigationDiagnosticsSchema =
|
|
1533
|
-
hint:
|
|
1638
|
+
var navigationDiagnosticsSchema = z2.object({
|
|
1639
|
+
hint: z2.string().nullable().optional()
|
|
1534
1640
|
}).nullable().optional();
|
|
1535
|
-
var repoFileEntrySchema =
|
|
1536
|
-
path:
|
|
1537
|
-
name:
|
|
1538
|
-
language:
|
|
1539
|
-
fileType:
|
|
1540
|
-
byteSize:
|
|
1641
|
+
var repoFileEntrySchema = z2.object({
|
|
1642
|
+
path: z2.string(),
|
|
1643
|
+
name: z2.string().nullable().optional(),
|
|
1644
|
+
language: z2.string().nullable().optional(),
|
|
1645
|
+
fileType: z2.string().nullable().optional(),
|
|
1646
|
+
byteSize: z2.number().int().nullable().optional()
|
|
1541
1647
|
});
|
|
1542
|
-
var listRepoFilesResponseSchema =
|
|
1543
|
-
files:
|
|
1544
|
-
total:
|
|
1545
|
-
hasMore:
|
|
1546
|
-
indexedVersion:
|
|
1648
|
+
var listRepoFilesResponseSchema = z2.object({
|
|
1649
|
+
files: z2.array(repoFileEntrySchema),
|
|
1650
|
+
total: z2.number().int(),
|
|
1651
|
+
hasMore: z2.boolean(),
|
|
1652
|
+
indexedVersion: z2.string().nullable().optional(),
|
|
1547
1653
|
resolution: navigationResolutionSchema,
|
|
1548
1654
|
diagnostics: navigationDiagnosticsSchema,
|
|
1549
|
-
codeIndexState:
|
|
1550
|
-
indexingRef:
|
|
1551
|
-
availableVersions:
|
|
1655
|
+
codeIndexState: z2.string(),
|
|
1656
|
+
indexingRef: z2.string().nullable().optional(),
|
|
1657
|
+
availableVersions: z2.array(availableVersionSchema).nullable().optional()
|
|
1552
1658
|
});
|
|
1553
|
-
var listRepoFilesGraphQLResponseSchema =
|
|
1554
|
-
data:
|
|
1659
|
+
var listRepoFilesGraphQLResponseSchema = z2.object({
|
|
1660
|
+
data: z2.object({
|
|
1555
1661
|
listRepoFiles: listRepoFilesResponseSchema.nullable().optional()
|
|
1556
1662
|
}).nullable().optional(),
|
|
1557
|
-
errors:
|
|
1663
|
+
errors: z2.array(graphQLErrorSchema).optional()
|
|
1558
1664
|
});
|
|
1559
1665
|
var LIST_REPO_FILES_QUERY = `
|
|
1560
1666
|
query ListRepoFiles(
|
|
@@ -1604,24 +1710,24 @@ query ListRepoFiles(
|
|
|
1604
1710
|
}
|
|
1605
1711
|
}
|
|
1606
1712
|
}`;
|
|
1607
|
-
var codeContextResponseSchema =
|
|
1608
|
-
content:
|
|
1609
|
-
filePath:
|
|
1610
|
-
language:
|
|
1611
|
-
totalLines:
|
|
1612
|
-
startLine:
|
|
1613
|
-
endLine:
|
|
1614
|
-
repoUrl:
|
|
1615
|
-
gitRef:
|
|
1616
|
-
isBinary:
|
|
1617
|
-
codeIndexState:
|
|
1618
|
-
indexingRef:
|
|
1713
|
+
var codeContextResponseSchema = z2.object({
|
|
1714
|
+
content: z2.string().nullable().optional(),
|
|
1715
|
+
filePath: z2.string().nullable().optional(),
|
|
1716
|
+
language: z2.string().nullable().optional(),
|
|
1717
|
+
totalLines: z2.number().int().nullable().optional(),
|
|
1718
|
+
startLine: z2.number().int().nullable().optional(),
|
|
1719
|
+
endLine: z2.number().int().nullable().optional(),
|
|
1720
|
+
repoUrl: z2.string().nullable().optional(),
|
|
1721
|
+
gitRef: z2.string().nullable().optional(),
|
|
1722
|
+
isBinary: z2.boolean().nullable().optional(),
|
|
1723
|
+
codeIndexState: z2.string(),
|
|
1724
|
+
indexingRef: z2.string().nullable().optional()
|
|
1619
1725
|
});
|
|
1620
|
-
var fetchCodeContextGraphQLResponseSchema =
|
|
1621
|
-
data:
|
|
1726
|
+
var fetchCodeContextGraphQLResponseSchema = z2.object({
|
|
1727
|
+
data: z2.object({
|
|
1622
1728
|
fetchCodeContext: codeContextResponseSchema.nullable().optional()
|
|
1623
1729
|
}).nullable().optional(),
|
|
1624
|
-
errors:
|
|
1730
|
+
errors: z2.array(graphQLErrorSchema).optional()
|
|
1625
1731
|
});
|
|
1626
1732
|
var FETCH_CODE_CONTEXT_QUERY = `
|
|
1627
1733
|
query FetchCodeContext(
|
|
@@ -1659,63 +1765,63 @@ query FetchCodeContext(
|
|
|
1659
1765
|
indexingRef
|
|
1660
1766
|
}
|
|
1661
1767
|
}`;
|
|
1662
|
-
var grepRepoMatchSchema =
|
|
1663
|
-
filePath:
|
|
1664
|
-
line:
|
|
1665
|
-
matchStartByte:
|
|
1666
|
-
matchEndByte:
|
|
1667
|
-
lineContent:
|
|
1668
|
-
contextBefore:
|
|
1669
|
-
contextAfter:
|
|
1670
|
-
fileContentHash:
|
|
1671
|
-
fileIntent:
|
|
1672
|
-
symbolRowId:
|
|
1673
|
-
symbol:
|
|
1674
|
-
symbolRef:
|
|
1675
|
-
name:
|
|
1676
|
-
qualifiedPath:
|
|
1677
|
-
kind:
|
|
1678
|
-
category:
|
|
1679
|
-
arity:
|
|
1680
|
-
isPublic:
|
|
1681
|
-
filePath:
|
|
1682
|
-
startLine:
|
|
1683
|
-
endLine:
|
|
1684
|
-
code:
|
|
1685
|
-
callerCount:
|
|
1686
|
-
contentHash:
|
|
1687
|
-
parentSymbolRef:
|
|
1688
|
-
parentPath:
|
|
1768
|
+
var grepRepoMatchSchema = z2.object({
|
|
1769
|
+
filePath: z2.string(),
|
|
1770
|
+
line: z2.number().int(),
|
|
1771
|
+
matchStartByte: z2.number().int(),
|
|
1772
|
+
matchEndByte: z2.number().int(),
|
|
1773
|
+
lineContent: z2.string(),
|
|
1774
|
+
contextBefore: z2.array(z2.string()).nullable().optional(),
|
|
1775
|
+
contextAfter: z2.array(z2.string()).nullable().optional(),
|
|
1776
|
+
fileContentHash: z2.string().nullable().optional(),
|
|
1777
|
+
fileIntent: z2.string().nullable().optional(),
|
|
1778
|
+
symbolRowId: z2.string().nullable().optional(),
|
|
1779
|
+
symbol: z2.object({
|
|
1780
|
+
symbolRef: z2.string().optional(),
|
|
1781
|
+
name: z2.string().optional(),
|
|
1782
|
+
qualifiedPath: z2.string().nullable().optional(),
|
|
1783
|
+
kind: z2.string().nullable().optional(),
|
|
1784
|
+
category: z2.string().nullable().optional(),
|
|
1785
|
+
arity: z2.number().int().nullable().optional(),
|
|
1786
|
+
isPublic: z2.boolean().nullable().optional(),
|
|
1787
|
+
filePath: z2.string().nullable().optional(),
|
|
1788
|
+
startLine: z2.number().int().nullable().optional(),
|
|
1789
|
+
endLine: z2.number().int().nullable().optional(),
|
|
1790
|
+
code: z2.string().nullable().optional(),
|
|
1791
|
+
callerCount: z2.number().int().nullable().optional(),
|
|
1792
|
+
contentHash: z2.string().nullable().optional(),
|
|
1793
|
+
parentSymbolRef: z2.string().nullable().optional(),
|
|
1794
|
+
parentPath: z2.string().nullable().optional()
|
|
1689
1795
|
}).nullable().optional()
|
|
1690
1796
|
});
|
|
1691
|
-
var grepRepoResponseSchema =
|
|
1692
|
-
matches:
|
|
1693
|
-
nextCursor:
|
|
1694
|
-
hasMore:
|
|
1695
|
-
truncatedReason:
|
|
1797
|
+
var grepRepoResponseSchema = z2.object({
|
|
1798
|
+
matches: z2.array(grepRepoMatchSchema),
|
|
1799
|
+
nextCursor: z2.string().nullable().optional(),
|
|
1800
|
+
hasMore: z2.boolean(),
|
|
1801
|
+
truncatedReason: z2.enum([
|
|
1696
1802
|
"NONE",
|
|
1697
1803
|
"MAX_MATCHES",
|
|
1698
1804
|
"MAX_MATCHES_PER_FILE",
|
|
1699
1805
|
"DEADLINE"
|
|
1700
1806
|
]),
|
|
1701
|
-
routeTaken:
|
|
1702
|
-
filesScanned:
|
|
1703
|
-
filesInScope:
|
|
1704
|
-
binaryFilesSkipped:
|
|
1705
|
-
filesTooLargeSkipped:
|
|
1706
|
-
totalMatches:
|
|
1707
|
-
uniqueFilesMatched:
|
|
1708
|
-
indexedVersion:
|
|
1807
|
+
routeTaken: z2.enum(["SINGLE_FILE", "CONTENT_INDEX"]).nullable().optional(),
|
|
1808
|
+
filesScanned: z2.number().int(),
|
|
1809
|
+
filesInScope: z2.number().int(),
|
|
1810
|
+
binaryFilesSkipped: z2.number().int(),
|
|
1811
|
+
filesTooLargeSkipped: z2.number().int(),
|
|
1812
|
+
totalMatches: z2.number().int(),
|
|
1813
|
+
uniqueFilesMatched: z2.number().int(),
|
|
1814
|
+
indexedVersion: z2.string().nullable().optional(),
|
|
1709
1815
|
resolution: navigationResolutionSchema,
|
|
1710
|
-
codeIndexState:
|
|
1711
|
-
indexingRef:
|
|
1712
|
-
availableVersions:
|
|
1816
|
+
codeIndexState: z2.string(),
|
|
1817
|
+
indexingRef: z2.string().nullable().optional(),
|
|
1818
|
+
availableVersions: z2.array(availableVersionSchema).nullable().optional()
|
|
1713
1819
|
});
|
|
1714
|
-
var grepRepoGraphQLResponseSchema =
|
|
1715
|
-
data:
|
|
1820
|
+
var grepRepoGraphQLResponseSchema = z2.object({
|
|
1821
|
+
data: z2.object({
|
|
1716
1822
|
grepRepo: grepRepoResponseSchema.nullable().optional()
|
|
1717
1823
|
}).nullable().optional(),
|
|
1718
|
-
errors:
|
|
1824
|
+
errors: z2.array(graphQLErrorSchema).optional()
|
|
1719
1825
|
});
|
|
1720
1826
|
var GREP_REPO_SYMBOL_SELECTIONS = {
|
|
1721
1827
|
symbol_ref: "symbolRef",
|
|
@@ -1824,17 +1930,17 @@ query GrepRepo(
|
|
|
1824
1930
|
}
|
|
1825
1931
|
}`;
|
|
1826
1932
|
}
|
|
1827
|
-
var unifiedSearchGraphQLResponseSchema =
|
|
1828
|
-
data:
|
|
1933
|
+
var unifiedSearchGraphQLResponseSchema = z2.object({
|
|
1934
|
+
data: z2.object({
|
|
1829
1935
|
search: asyncUnifiedSearchResultSchema.nullable().optional()
|
|
1830
1936
|
}).nullable().optional(),
|
|
1831
|
-
errors:
|
|
1937
|
+
errors: z2.array(graphQLErrorSchema).optional()
|
|
1832
1938
|
});
|
|
1833
|
-
var unifiedSearchStatusGraphQLResponseSchema =
|
|
1834
|
-
data:
|
|
1939
|
+
var unifiedSearchStatusGraphQLResponseSchema = z2.object({
|
|
1940
|
+
data: z2.object({
|
|
1835
1941
|
discoverySearchProgress: unifiedSearchProgressSchema.nullable().optional()
|
|
1836
1942
|
}).nullable().optional(),
|
|
1837
|
-
errors:
|
|
1943
|
+
errors: z2.array(graphQLErrorSchema).optional()
|
|
1838
1944
|
});
|
|
1839
1945
|
|
|
1840
1946
|
class CodeNavigationServiceImpl {
|
|
@@ -1987,6 +2093,9 @@ class CodeNavigationServiceImpl {
|
|
|
1987
2093
|
const code = typeof extensions?.code === "string" ? extensions.code : undefined;
|
|
1988
2094
|
const retryable = typeof extensions?.retryable === "boolean" ? extensions.retryable : undefined;
|
|
1989
2095
|
const indexingRef = getGraphQLIndexingRef(errors);
|
|
2096
|
+
if (isClientUpdateRequiredGraphQLError({ message, code })) {
|
|
2097
|
+
return new ClientUpdateRequiredError;
|
|
2098
|
+
}
|
|
1990
2099
|
switch (code) {
|
|
1991
2100
|
case "PACKAGE_INDEXING":
|
|
1992
2101
|
return new CodeNavigationIndexingError(this.createIndexingMessage(indexingRef), indexingRef, parseAvailableVersions(extensions));
|
|
@@ -2481,19 +2590,11 @@ function getCodeNavigationUrl() {
|
|
|
2481
2590
|
if (explicitUrl) {
|
|
2482
2591
|
return explicitUrl;
|
|
2483
2592
|
}
|
|
2484
|
-
|
|
2485
|
-
return usingDefaultEnvironment ? DEFAULT_CODE_NAV_URL : undefined;
|
|
2593
|
+
return DEFAULT_CODE_NAV_URL;
|
|
2486
2594
|
}
|
|
2487
2595
|
function getEnvApiToken() {
|
|
2488
2596
|
return process.env.GITHITS_API_TOKEN;
|
|
2489
2597
|
}
|
|
2490
|
-
function isCodeNavigationCliOverrideEnabled() {
|
|
2491
|
-
const raw = process.env.GITHITS_CODE_NAVIGATION;
|
|
2492
|
-
if (!raw)
|
|
2493
|
-
return false;
|
|
2494
|
-
const normalized = raw.toLowerCase();
|
|
2495
|
-
return normalized !== "0" && normalized !== "false" && normalized !== "";
|
|
2496
|
-
}
|
|
2497
2598
|
// src/services/exec-service.ts
|
|
2498
2599
|
import { spawn } from "node:child_process";
|
|
2499
2600
|
|
|
@@ -2523,6 +2624,7 @@ class ExecServiceImpl {
|
|
|
2523
2624
|
}
|
|
2524
2625
|
}
|
|
2525
2626
|
// src/services/filesystem-service.ts
|
|
2627
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
2526
2628
|
import {
|
|
2527
2629
|
mkdir,
|
|
2528
2630
|
readdir,
|
|
@@ -2586,7 +2688,7 @@ class FileSystemServiceImpl {
|
|
|
2586
2688
|
}
|
|
2587
2689
|
}
|
|
2588
2690
|
async atomicWriteFile(path, contents) {
|
|
2589
|
-
const tmpPath = `${path}.${process.pid}.${
|
|
2691
|
+
const tmpPath = `${path}.${process.pid}.${randomUUID2()}.tmp`;
|
|
2590
2692
|
let mode = 384;
|
|
2591
2693
|
try {
|
|
2592
2694
|
const existing = await stat(path);
|
|
@@ -2649,10 +2751,24 @@ class KeychainAuthStorage {
|
|
|
2649
2751
|
const key = `${TOKEN_PREFIX}${normalizeBaseUrl(baseUrl2)}`;
|
|
2650
2752
|
this.keyring.setPassword(SERVICE_NAME, key, JSON.stringify(data));
|
|
2651
2753
|
}
|
|
2754
|
+
async saveTokensIfUnchanged(baseUrl2, expected, data) {
|
|
2755
|
+
const current = await this.loadTokens(baseUrl2);
|
|
2756
|
+
if (!sameTokenData(current, expected))
|
|
2757
|
+
return false;
|
|
2758
|
+
await this.saveTokens(baseUrl2, data);
|
|
2759
|
+
return true;
|
|
2760
|
+
}
|
|
2652
2761
|
async clearTokens(baseUrl2) {
|
|
2653
2762
|
const key = `${TOKEN_PREFIX}${normalizeBaseUrl(baseUrl2)}`;
|
|
2654
2763
|
this.keyring.deletePassword(SERVICE_NAME, key);
|
|
2655
2764
|
}
|
|
2765
|
+
async clearTokensIfUnchanged(baseUrl2, expected) {
|
|
2766
|
+
const current = await this.loadTokens(baseUrl2);
|
|
2767
|
+
if (!sameTokenData(current, expected))
|
|
2768
|
+
return false;
|
|
2769
|
+
await this.clearTokens(baseUrl2);
|
|
2770
|
+
return true;
|
|
2771
|
+
}
|
|
2656
2772
|
async loadClient(baseUrl2) {
|
|
2657
2773
|
const key = `${CLIENT_PREFIX}${normalizeBaseUrl(baseUrl2)}`;
|
|
2658
2774
|
const json = this.keyring.getPassword(SERVICE_NAME, key);
|
|
@@ -2669,6 +2785,13 @@ class KeychainAuthStorage {
|
|
|
2669
2785
|
const key = `${CLIENT_PREFIX}${normalizeBaseUrl(baseUrl2)}`;
|
|
2670
2786
|
this.keyring.deletePassword(SERVICE_NAME, key);
|
|
2671
2787
|
}
|
|
2788
|
+
async saveAuthSession(baseUrl2, client, tokens) {
|
|
2789
|
+
await this.saveClient(baseUrl2, client);
|
|
2790
|
+
await this.saveTokens(baseUrl2, tokens);
|
|
2791
|
+
}
|
|
2792
|
+
async clearAuthSession(baseUrl2) {
|
|
2793
|
+
await clearAuthSessionBestEffort(() => this.clearTokens(baseUrl2), () => this.clearClient(baseUrl2));
|
|
2794
|
+
}
|
|
2672
2795
|
getStorageLocation() {
|
|
2673
2796
|
switch (process.platform) {
|
|
2674
2797
|
case "darwin":
|
|
@@ -2718,179 +2841,644 @@ class KeyringServiceImpl {
|
|
|
2718
2841
|
}
|
|
2719
2842
|
}
|
|
2720
2843
|
}
|
|
2721
|
-
// src/services/
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2844
|
+
// src/services/locked-auth-storage.ts
|
|
2845
|
+
import { execFile } from "node:child_process";
|
|
2846
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
2847
|
+
import { mkdir as mkdir2, readFile as readFile2, rm, writeFile as writeFile2 } from "node:fs/promises";
|
|
2848
|
+
import { dirname as dirname2 } from "node:path";
|
|
2849
|
+
import { promisify } from "node:util";
|
|
2850
|
+
var LOCK_DIR = "auth.lock";
|
|
2851
|
+
var LOCK_TIMEOUT_MS = 1e4;
|
|
2852
|
+
var LOCK_RETRY_MS = 25;
|
|
2853
|
+
var ORPHANED_LOCK_MS = 5000;
|
|
2854
|
+
var OWNER_FILE = "owner.json";
|
|
2855
|
+
var execFileAsync = promisify(execFile);
|
|
2856
|
+
|
|
2857
|
+
class AuthStorageLockTimeoutError extends Error {
|
|
2858
|
+
constructor(message) {
|
|
2859
|
+
super(message);
|
|
2860
|
+
this.name = "AuthStorageLockTimeoutError";
|
|
2732
2861
|
}
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2862
|
+
}
|
|
2863
|
+
|
|
2864
|
+
class LockedAuthStorage {
|
|
2865
|
+
storage;
|
|
2866
|
+
lockPath;
|
|
2867
|
+
lockTimeoutMs;
|
|
2868
|
+
isOwnerAlive;
|
|
2869
|
+
currentOwner = null;
|
|
2870
|
+
constructor(storage, fileSystemService, options = {}) {
|
|
2871
|
+
this.storage = storage;
|
|
2872
|
+
this.lockTimeoutMs = options.lockTimeoutMs ?? LOCK_TIMEOUT_MS;
|
|
2873
|
+
this.isOwnerAlive = options.isOwnerAlive ?? isOriginalProcessAlive;
|
|
2874
|
+
this.lockPath = fileSystemService.joinPath(getAppConfigDir(fileSystemService), LOCK_DIR);
|
|
2875
|
+
}
|
|
2876
|
+
loadTokens(baseUrl2) {
|
|
2877
|
+
return this.storage.loadTokens(baseUrl2);
|
|
2878
|
+
}
|
|
2879
|
+
saveTokens(baseUrl2, data) {
|
|
2880
|
+
return this.withLock(() => this.storage.saveTokens(baseUrl2, data));
|
|
2881
|
+
}
|
|
2882
|
+
saveTokensIfUnchanged(baseUrl2, expected, data) {
|
|
2883
|
+
return this.withLock(() => this.storage.saveTokensIfUnchanged(baseUrl2, expected, data));
|
|
2884
|
+
}
|
|
2885
|
+
clearTokens(baseUrl2) {
|
|
2886
|
+
return this.withLock(() => this.storage.clearTokens(baseUrl2));
|
|
2887
|
+
}
|
|
2888
|
+
clearTokensIfUnchanged(baseUrl2, expected) {
|
|
2889
|
+
return this.withLock(() => this.storage.clearTokensIfUnchanged(baseUrl2, expected));
|
|
2890
|
+
}
|
|
2891
|
+
loadClient(baseUrl2) {
|
|
2892
|
+
return this.storage.loadClient(baseUrl2);
|
|
2893
|
+
}
|
|
2894
|
+
saveClient(baseUrl2, data) {
|
|
2895
|
+
return this.withLock(() => this.storage.saveClient(baseUrl2, data));
|
|
2896
|
+
}
|
|
2897
|
+
clearClient(baseUrl2) {
|
|
2898
|
+
return this.withLock(() => this.storage.clearClient(baseUrl2));
|
|
2899
|
+
}
|
|
2900
|
+
saveAuthSession(baseUrl2, client, tokens) {
|
|
2901
|
+
return this.withLock(() => this.storage.saveAuthSession(baseUrl2, client, tokens));
|
|
2902
|
+
}
|
|
2903
|
+
clearAuthSession(baseUrl2) {
|
|
2904
|
+
return this.withLock(() => this.storage.clearAuthSession(baseUrl2));
|
|
2905
|
+
}
|
|
2906
|
+
getStorageLocation() {
|
|
2907
|
+
return this.storage.getStorageLocation();
|
|
2908
|
+
}
|
|
2909
|
+
async withLock(fn) {
|
|
2910
|
+
await this.acquireLock();
|
|
2749
2911
|
try {
|
|
2750
|
-
await
|
|
2751
|
-
}
|
|
2752
|
-
|
|
2753
|
-
throw error;
|
|
2754
|
-
return legacyTokens;
|
|
2912
|
+
return await fn();
|
|
2913
|
+
} finally {
|
|
2914
|
+
await this.releaseLock();
|
|
2755
2915
|
}
|
|
2756
|
-
try {
|
|
2757
|
-
await this.legacy.clearTokens(baseUrl2);
|
|
2758
|
-
} catch {}
|
|
2759
|
-
return legacyTokens;
|
|
2760
2916
|
}
|
|
2761
|
-
async
|
|
2762
|
-
|
|
2917
|
+
async acquireLock() {
|
|
2918
|
+
const startedAt = Date.now();
|
|
2919
|
+
await mkdir2(dirname2(this.lockPath), { recursive: true, mode: 448 });
|
|
2920
|
+
while (true) {
|
|
2763
2921
|
try {
|
|
2764
|
-
await this.
|
|
2922
|
+
await mkdir2(this.lockPath, { recursive: false, mode: 448 });
|
|
2923
|
+
try {
|
|
2924
|
+
await this.writeOwner();
|
|
2925
|
+
} catch (error) {
|
|
2926
|
+
await rm(this.lockPath, { recursive: true, force: true }).catch(() => {
|
|
2927
|
+
return;
|
|
2928
|
+
});
|
|
2929
|
+
throw error;
|
|
2930
|
+
}
|
|
2765
2931
|
return;
|
|
2766
2932
|
} catch (error) {
|
|
2767
|
-
if (
|
|
2933
|
+
if (error.code !== "EEXIST")
|
|
2768
2934
|
throw error;
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
}
|
|
2773
|
-
async clearTokens(baseUrl2) {
|
|
2774
|
-
let primaryError;
|
|
2775
|
-
if (this.primaryAvailable) {
|
|
2776
|
-
try {
|
|
2777
|
-
await this.primary.clearTokens(baseUrl2);
|
|
2778
|
-
} catch (error) {
|
|
2779
|
-
if (!this.handlePrimaryFailure(error)) {
|
|
2780
|
-
primaryError = error;
|
|
2935
|
+
await this.reclaimStaleLock();
|
|
2936
|
+
if (Date.now() - startedAt >= this.lockTimeoutMs) {
|
|
2937
|
+
throw new AuthStorageLockTimeoutError(`Timed out waiting for GitHits auth storage lock at ${this.lockPath}. If no githits process is running, remove this directory and retry.`);
|
|
2781
2938
|
}
|
|
2939
|
+
await sleep(LOCK_RETRY_MS);
|
|
2782
2940
|
}
|
|
2783
2941
|
}
|
|
2784
|
-
try {
|
|
2785
|
-
await this.legacy.clearTokens(baseUrl2);
|
|
2786
|
-
} catch {}
|
|
2787
|
-
if (primaryError)
|
|
2788
|
-
throw primaryError;
|
|
2789
2942
|
}
|
|
2790
|
-
async
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
}
|
|
2800
|
-
}
|
|
2801
|
-
const legacyClient = await this.legacy.loadClient(baseUrl2);
|
|
2802
|
-
if (!legacyClient)
|
|
2803
|
-
return null;
|
|
2804
|
-
if (!this.primaryAvailable)
|
|
2805
|
-
return legacyClient;
|
|
2806
|
-
try {
|
|
2807
|
-
await this.primary.saveClient(baseUrl2, legacyClient);
|
|
2808
|
-
} catch (error) {
|
|
2809
|
-
if (!this.handlePrimaryFailure(error))
|
|
2810
|
-
throw error;
|
|
2811
|
-
return legacyClient;
|
|
2812
|
-
}
|
|
2813
|
-
try {
|
|
2814
|
-
await this.legacy.clearClient(baseUrl2);
|
|
2815
|
-
} catch {}
|
|
2816
|
-
return legacyClient;
|
|
2943
|
+
async writeOwner() {
|
|
2944
|
+
const owner = {
|
|
2945
|
+
id: randomUUID3(),
|
|
2946
|
+
pid: process.pid,
|
|
2947
|
+
createdAt: new Date().toISOString(),
|
|
2948
|
+
processStartedAt: await getProcessStartedAt(process.pid)
|
|
2949
|
+
};
|
|
2950
|
+
this.currentOwner = owner;
|
|
2951
|
+
await writeFile2(this.ownerPath(), JSON.stringify(owner), { mode: 384 });
|
|
2817
2952
|
}
|
|
2818
|
-
async
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
} catch (error) {
|
|
2824
|
-
if (!this.handlePrimaryFailure(error))
|
|
2825
|
-
throw error;
|
|
2826
|
-
}
|
|
2953
|
+
async reclaimStaleLock() {
|
|
2954
|
+
const owner = await this.readOwner();
|
|
2955
|
+
if (!owner) {
|
|
2956
|
+
await this.reclaimOldOwnerlessLock();
|
|
2957
|
+
return;
|
|
2827
2958
|
}
|
|
2828
|
-
await this.
|
|
2959
|
+
const ownerDead = !await this.isOwnerAlive(owner.pid, owner.processStartedAt);
|
|
2960
|
+
if (!ownerDead)
|
|
2961
|
+
return;
|
|
2962
|
+
const currentOwner = await this.readOwner();
|
|
2963
|
+
if (!currentOwner || currentOwner.id !== owner.id)
|
|
2964
|
+
return;
|
|
2965
|
+
await rm(this.lockPath, { recursive: true, force: true }).catch(() => {
|
|
2966
|
+
return;
|
|
2967
|
+
});
|
|
2829
2968
|
}
|
|
2830
|
-
async
|
|
2831
|
-
|
|
2832
|
-
if (
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2969
|
+
async reclaimOldOwnerlessLock() {
|
|
2970
|
+
const createdAtMs = await lockCreatedAtMs(this.lockPath);
|
|
2971
|
+
if (Date.now() - createdAtMs < ORPHANED_LOCK_MS)
|
|
2972
|
+
return;
|
|
2973
|
+
await rm(this.lockPath, { recursive: true, force: true }).catch(() => {
|
|
2974
|
+
return;
|
|
2975
|
+
});
|
|
2976
|
+
}
|
|
2977
|
+
async readOwner() {
|
|
2978
|
+
try {
|
|
2979
|
+
const raw = await readFile2(this.ownerPath(), "utf8");
|
|
2980
|
+
const parsed = JSON.parse(raw);
|
|
2981
|
+
if (typeof parsed.id !== "string" || typeof parsed.pid !== "number" || typeof parsed.createdAt !== "string" || !(typeof parsed.processStartedAt === "string" || parsed.processStartedAt === null)) {
|
|
2982
|
+
return null;
|
|
2839
2983
|
}
|
|
2984
|
+
return {
|
|
2985
|
+
id: parsed.id,
|
|
2986
|
+
pid: parsed.pid,
|
|
2987
|
+
createdAt: parsed.createdAt,
|
|
2988
|
+
processStartedAt: parsed.processStartedAt
|
|
2989
|
+
};
|
|
2990
|
+
} catch {
|
|
2991
|
+
return null;
|
|
2840
2992
|
}
|
|
2841
|
-
try {
|
|
2842
|
-
await this.legacy.clearClient(baseUrl2);
|
|
2843
|
-
} catch {}
|
|
2844
|
-
if (primaryError)
|
|
2845
|
-
throw primaryError;
|
|
2846
2993
|
}
|
|
2847
|
-
|
|
2848
|
-
|
|
2994
|
+
async releaseLock() {
|
|
2995
|
+
const owner = this.currentOwner;
|
|
2996
|
+
this.currentOwner = null;
|
|
2997
|
+
if (!owner)
|
|
2998
|
+
return;
|
|
2999
|
+
const currentOwner = await this.readOwner();
|
|
3000
|
+
if (!currentOwner || currentOwner.id !== owner.id)
|
|
3001
|
+
return;
|
|
3002
|
+
await rm(this.lockPath, { recursive: true, force: true }).catch(() => {
|
|
3003
|
+
return;
|
|
3004
|
+
});
|
|
2849
3005
|
}
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
return false;
|
|
2853
|
-
}
|
|
2854
|
-
this.primaryAvailable = false;
|
|
2855
|
-
if (!this.warnedOnPrimaryFailure) {
|
|
2856
|
-
this.warnedOnPrimaryFailure = true;
|
|
2857
|
-
this.onPrimaryUnavailable(error);
|
|
2858
|
-
}
|
|
2859
|
-
return true;
|
|
3006
|
+
ownerPath() {
|
|
3007
|
+
return `${this.lockPath}/${OWNER_FILE}`;
|
|
2860
3008
|
}
|
|
2861
3009
|
}
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
// src/services/promote-version-not-found.ts
|
|
2866
|
-
function promoteGenericVersionNotFound(error, params) {
|
|
2867
|
-
if (!(error instanceof PackageIntelligenceBackendError))
|
|
2868
|
-
return error;
|
|
2869
|
-
if (error.graphqlCode !== undefined)
|
|
2870
|
-
return error;
|
|
2871
|
-
const requestedVersion = pickRequestedVersion(params);
|
|
2872
|
-
if (!requestedVersion)
|
|
2873
|
-
return error;
|
|
2874
|
-
if (!/no matching version/i.test(error.message))
|
|
2875
|
-
return error;
|
|
2876
|
-
const qualifiedName = synthesizeQualifiedName(params);
|
|
2877
|
-
return new PackageIntelligenceVersionNotFoundError(error.message, qualifiedName, requestedVersion, undefined);
|
|
3010
|
+
function sleep(ms) {
|
|
3011
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2878
3012
|
}
|
|
2879
|
-
function
|
|
2880
|
-
if (
|
|
2881
|
-
return
|
|
2882
|
-
if (
|
|
2883
|
-
return
|
|
2884
|
-
|
|
2885
|
-
return params.toVersion;
|
|
2886
|
-
return;
|
|
2887
|
-
}
|
|
2888
|
-
function synthesizeQualifiedName(params) {
|
|
2889
|
-
if (!params.registry || !params.packageName)
|
|
2890
|
-
return;
|
|
2891
|
-
return `${params.registry.toLowerCase()}:${params.packageName}`;
|
|
3013
|
+
async function isOriginalProcessAlive(pid, processStartedAt) {
|
|
3014
|
+
if (!isProcessAlive(pid))
|
|
3015
|
+
return false;
|
|
3016
|
+
if (!processStartedAt)
|
|
3017
|
+
return true;
|
|
3018
|
+
return await getProcessStartedAt(pid) === processStartedAt;
|
|
2892
3019
|
}
|
|
2893
|
-
|
|
3020
|
+
function isProcessAlive(pid) {
|
|
3021
|
+
if (pid <= 0)
|
|
3022
|
+
return false;
|
|
3023
|
+
try {
|
|
3024
|
+
process.kill(pid, 0);
|
|
3025
|
+
return true;
|
|
3026
|
+
} catch (error) {
|
|
3027
|
+
const code = error.code;
|
|
3028
|
+
return code === "EPERM";
|
|
3029
|
+
}
|
|
3030
|
+
}
|
|
3031
|
+
async function getProcessStartedAt(pid) {
|
|
3032
|
+
try {
|
|
3033
|
+
if (process.platform === "win32") {
|
|
3034
|
+
const { stdout: stdout2 } = await execFileAsync("powershell.exe", [
|
|
3035
|
+
"-NoProfile",
|
|
3036
|
+
"-Command",
|
|
3037
|
+
`(Get-Process -Id ${pid}).StartTime.ToUniversalTime().ToString('o')`
|
|
3038
|
+
]);
|
|
3039
|
+
return stdout2.trim() || null;
|
|
3040
|
+
}
|
|
3041
|
+
const { stdout } = await execFileAsync("ps", [
|
|
3042
|
+
"-p",
|
|
3043
|
+
String(pid),
|
|
3044
|
+
"-o",
|
|
3045
|
+
"lstart="
|
|
3046
|
+
]);
|
|
3047
|
+
const parsed = Date.parse(stdout.trim());
|
|
3048
|
+
return Number.isNaN(parsed) ? null : new Date(parsed).toISOString();
|
|
3049
|
+
} catch {
|
|
3050
|
+
return null;
|
|
3051
|
+
}
|
|
3052
|
+
}
|
|
3053
|
+
async function lockCreatedAtMs(path) {
|
|
3054
|
+
try {
|
|
3055
|
+
const { stat: stat2 } = await import("node:fs/promises");
|
|
3056
|
+
return (await stat2(path)).mtimeMs;
|
|
3057
|
+
} catch {
|
|
3058
|
+
return 0;
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
// src/services/mode-aware-file-auth-storage.ts
|
|
3062
|
+
class AuthStoragePolicyError extends Error {
|
|
3063
|
+
constructor(message) {
|
|
3064
|
+
super(message);
|
|
3065
|
+
this.name = "AuthStoragePolicyError";
|
|
3066
|
+
}
|
|
3067
|
+
}
|
|
3068
|
+
function createFileAuthStorageGuidance(configPath) {
|
|
3069
|
+
return `OAuth credentials were not saved to plaintext file storage.
|
|
3070
|
+
|
|
3071
|
+
Options:
|
|
3072
|
+
1. Unlock or fix your system keychain.
|
|
3073
|
+
2. Use GITHITS_API_TOKEN for CI/automation.
|
|
3074
|
+
3. If you accept storing OAuth credentials unencrypted on disk, set:
|
|
3075
|
+
|
|
3076
|
+
[auth]
|
|
3077
|
+
storage = "file"
|
|
3078
|
+
|
|
3079
|
+
in ${configPath}, or run with GITHITS_AUTH_STORAGE=file.
|
|
3080
|
+
|
|
3081
|
+
Warning: file storage is plaintext. Use it only on machines where local file access is trusted.`;
|
|
3082
|
+
}
|
|
3083
|
+
|
|
3084
|
+
class ModeAwareFileAuthStorage {
|
|
3085
|
+
storage;
|
|
3086
|
+
mode;
|
|
3087
|
+
configPath;
|
|
3088
|
+
constructor(storage, mode, configPath = "your GitHits config.toml") {
|
|
3089
|
+
this.storage = storage;
|
|
3090
|
+
this.mode = mode;
|
|
3091
|
+
this.configPath = configPath;
|
|
3092
|
+
}
|
|
3093
|
+
loadTokens(baseUrl2) {
|
|
3094
|
+
return this.storage.loadTokens(baseUrl2);
|
|
3095
|
+
}
|
|
3096
|
+
async saveTokens(baseUrl2, data) {
|
|
3097
|
+
this.assertFileMode();
|
|
3098
|
+
await this.storage.saveTokens(baseUrl2, data);
|
|
3099
|
+
}
|
|
3100
|
+
async saveTokensIfUnchanged(baseUrl2, expected, data) {
|
|
3101
|
+
this.assertFileMode();
|
|
3102
|
+
return this.storage.saveTokensIfUnchanged(baseUrl2, expected, data);
|
|
3103
|
+
}
|
|
3104
|
+
clearTokens(baseUrl2) {
|
|
3105
|
+
return this.storage.clearTokens(baseUrl2);
|
|
3106
|
+
}
|
|
3107
|
+
clearTokensIfUnchanged(baseUrl2, expected) {
|
|
3108
|
+
return this.storage.clearTokensIfUnchanged(baseUrl2, expected);
|
|
3109
|
+
}
|
|
3110
|
+
loadClient(baseUrl2) {
|
|
3111
|
+
return this.storage.loadClient(baseUrl2);
|
|
3112
|
+
}
|
|
3113
|
+
async saveClient(baseUrl2, data) {
|
|
3114
|
+
this.assertFileMode();
|
|
3115
|
+
await this.storage.saveClient(baseUrl2, data);
|
|
3116
|
+
}
|
|
3117
|
+
clearClient(baseUrl2) {
|
|
3118
|
+
return this.storage.clearClient(baseUrl2);
|
|
3119
|
+
}
|
|
3120
|
+
async saveAuthSession(baseUrl2, client, tokens) {
|
|
3121
|
+
this.assertFileMode();
|
|
3122
|
+
await this.storage.saveAuthSession(baseUrl2, client, tokens);
|
|
3123
|
+
}
|
|
3124
|
+
clearAuthSession(baseUrl2) {
|
|
3125
|
+
return this.storage.clearAuthSession(baseUrl2);
|
|
3126
|
+
}
|
|
3127
|
+
getStorageLocation() {
|
|
3128
|
+
return this.storage.getStorageLocation();
|
|
3129
|
+
}
|
|
3130
|
+
assertFileMode() {
|
|
3131
|
+
if (this.mode === "file")
|
|
3132
|
+
return;
|
|
3133
|
+
throw new AuthStoragePolicyError(createFileAuthStorageGuidance(this.configPath));
|
|
3134
|
+
}
|
|
3135
|
+
}
|
|
3136
|
+
|
|
3137
|
+
// src/services/migrating-auth-storage.ts
|
|
3138
|
+
class MigratingAuthStorage {
|
|
3139
|
+
primary;
|
|
3140
|
+
file;
|
|
3141
|
+
legacy;
|
|
3142
|
+
mode;
|
|
3143
|
+
configPath;
|
|
3144
|
+
onWarning;
|
|
3145
|
+
warnedFileModeKeychainExport = false;
|
|
3146
|
+
warnedAmbiguousPlaintext = false;
|
|
3147
|
+
constructor(primary, file, legacy, mode, configPath = "your GitHits config.toml", onWarning = () => {}) {
|
|
3148
|
+
this.primary = primary;
|
|
3149
|
+
this.file = file;
|
|
3150
|
+
this.legacy = legacy;
|
|
3151
|
+
this.mode = mode;
|
|
3152
|
+
this.configPath = configPath;
|
|
3153
|
+
this.onWarning = onWarning;
|
|
3154
|
+
}
|
|
3155
|
+
async loadTokens(baseUrl2) {
|
|
3156
|
+
if (this.mode === "file") {
|
|
3157
|
+
return this.loadTokensFileMode(baseUrl2);
|
|
3158
|
+
}
|
|
3159
|
+
return this.loadTokensKeychainMode(baseUrl2);
|
|
3160
|
+
}
|
|
3161
|
+
async saveTokens(baseUrl2, data) {
|
|
3162
|
+
if (this.mode === "file") {
|
|
3163
|
+
await this.file.saveTokens(baseUrl2, data);
|
|
3164
|
+
return;
|
|
3165
|
+
}
|
|
3166
|
+
try {
|
|
3167
|
+
await this.primary.saveTokens(baseUrl2, data);
|
|
3168
|
+
} catch (error) {
|
|
3169
|
+
throw this.toPolicyError(error);
|
|
3170
|
+
}
|
|
3171
|
+
}
|
|
3172
|
+
async saveTokensIfUnchanged(baseUrl2, expected, data) {
|
|
3173
|
+
const current = await this.loadTokens(baseUrl2);
|
|
3174
|
+
if (!this.sameTokenData(current, expected))
|
|
3175
|
+
return false;
|
|
3176
|
+
await this.saveTokens(baseUrl2, data);
|
|
3177
|
+
return true;
|
|
3178
|
+
}
|
|
3179
|
+
async clearTokens(baseUrl2) {
|
|
3180
|
+
const primaryError = await this.clearBestEffort(() => this.primary.clearTokens(baseUrl2));
|
|
3181
|
+
await this.clearBestEffort(() => this.file.clearTokens(baseUrl2));
|
|
3182
|
+
await this.clearBestEffort(() => this.legacy.clearTokens(baseUrl2));
|
|
3183
|
+
if (primaryError && !(primaryError instanceof KeychainUnavailableError)) {
|
|
3184
|
+
throw primaryError;
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3187
|
+
async clearTokensIfUnchanged(baseUrl2, expected) {
|
|
3188
|
+
const current = await this.loadTokens(baseUrl2);
|
|
3189
|
+
if (!this.sameTokenData(current, expected))
|
|
3190
|
+
return false;
|
|
3191
|
+
await this.clearTokens(baseUrl2);
|
|
3192
|
+
return true;
|
|
3193
|
+
}
|
|
3194
|
+
async loadClient(baseUrl2) {
|
|
3195
|
+
if (this.mode === "file") {
|
|
3196
|
+
return this.loadClientFileMode(baseUrl2);
|
|
3197
|
+
}
|
|
3198
|
+
return this.loadClientKeychainMode(baseUrl2);
|
|
3199
|
+
}
|
|
3200
|
+
async saveClient(baseUrl2, data) {
|
|
3201
|
+
if (this.mode === "file") {
|
|
3202
|
+
await this.file.saveClient(baseUrl2, data);
|
|
3203
|
+
return;
|
|
3204
|
+
}
|
|
3205
|
+
try {
|
|
3206
|
+
await this.primary.saveClient(baseUrl2, data);
|
|
3207
|
+
} catch (error) {
|
|
3208
|
+
throw this.toPolicyError(error);
|
|
3209
|
+
}
|
|
3210
|
+
}
|
|
3211
|
+
async clearClient(baseUrl2) {
|
|
3212
|
+
const primaryError = await this.clearBestEffort(() => this.primary.clearClient(baseUrl2));
|
|
3213
|
+
await this.clearBestEffort(() => this.file.clearClient(baseUrl2));
|
|
3214
|
+
await this.clearBestEffort(() => this.legacy.clearClient(baseUrl2));
|
|
3215
|
+
if (primaryError && !(primaryError instanceof KeychainUnavailableError)) {
|
|
3216
|
+
throw primaryError;
|
|
3217
|
+
}
|
|
3218
|
+
}
|
|
3219
|
+
async saveAuthSession(baseUrl2, client, tokens) {
|
|
3220
|
+
if (this.mode === "file") {
|
|
3221
|
+
await this.file.saveAuthSession(baseUrl2, client, tokens);
|
|
3222
|
+
return;
|
|
3223
|
+
}
|
|
3224
|
+
try {
|
|
3225
|
+
await this.primary.saveAuthSession(baseUrl2, client, tokens);
|
|
3226
|
+
} catch (error) {
|
|
3227
|
+
throw this.toPolicyError(error);
|
|
3228
|
+
}
|
|
3229
|
+
}
|
|
3230
|
+
async clearAuthSession(baseUrl2) {
|
|
3231
|
+
const primaryError = await this.clearBestEffort(() => this.primary.clearAuthSession(baseUrl2));
|
|
3232
|
+
await this.clearBestEffort(() => this.file.clearAuthSession(baseUrl2));
|
|
3233
|
+
await this.clearBestEffort(() => this.legacy.clearAuthSession(baseUrl2));
|
|
3234
|
+
if (primaryError && !(primaryError instanceof KeychainUnavailableError)) {
|
|
3235
|
+
throw primaryError;
|
|
3236
|
+
}
|
|
3237
|
+
}
|
|
3238
|
+
getStorageLocation() {
|
|
3239
|
+
return this.mode === "file" ? this.file.getStorageLocation() : this.primary.getStorageLocation();
|
|
3240
|
+
}
|
|
3241
|
+
async loadTokensKeychainMode(baseUrl2) {
|
|
3242
|
+
try {
|
|
3243
|
+
const primaryTokens = await this.primary.loadTokens(baseUrl2);
|
|
3244
|
+
if (primaryTokens)
|
|
3245
|
+
return primaryTokens;
|
|
3246
|
+
} catch (error) {
|
|
3247
|
+
if (!(error instanceof KeychainUnavailableError))
|
|
3248
|
+
throw error;
|
|
3249
|
+
}
|
|
3250
|
+
const candidate = await this.selectPlaintextTokenCandidate(baseUrl2);
|
|
3251
|
+
if (!candidate)
|
|
3252
|
+
return null;
|
|
3253
|
+
try {
|
|
3254
|
+
await this.primary.saveTokens(baseUrl2, candidate.data);
|
|
3255
|
+
} catch (error) {
|
|
3256
|
+
if (error instanceof KeychainUnavailableError)
|
|
3257
|
+
return candidate.data;
|
|
3258
|
+
throw error;
|
|
3259
|
+
}
|
|
3260
|
+
await this.clearMigratedPlaintext(baseUrl2, "tokens", candidate.source, candidate.ambiguous);
|
|
3261
|
+
return candidate.data;
|
|
3262
|
+
}
|
|
3263
|
+
async loadTokensFileMode(baseUrl2) {
|
|
3264
|
+
const candidate = await this.selectPlaintextTokenCandidate(baseUrl2);
|
|
3265
|
+
if (candidate) {
|
|
3266
|
+
if (candidate.source === "legacy") {
|
|
3267
|
+
await this.file.saveTokens(baseUrl2, candidate.data);
|
|
3268
|
+
await this.clearBestEffort(() => this.legacy.clearTokens(baseUrl2));
|
|
3269
|
+
}
|
|
3270
|
+
return candidate.data;
|
|
3271
|
+
}
|
|
3272
|
+
let primaryTokens = null;
|
|
3273
|
+
try {
|
|
3274
|
+
primaryTokens = await this.primary.loadTokens(baseUrl2);
|
|
3275
|
+
} catch (error) {
|
|
3276
|
+
if (!(error instanceof KeychainUnavailableError))
|
|
3277
|
+
throw error;
|
|
3278
|
+
}
|
|
3279
|
+
if (!primaryTokens)
|
|
3280
|
+
return null;
|
|
3281
|
+
this.warnKeychainExport();
|
|
3282
|
+
await this.file.saveTokens(baseUrl2, primaryTokens);
|
|
3283
|
+
return primaryTokens;
|
|
3284
|
+
}
|
|
3285
|
+
async loadClientKeychainMode(baseUrl2) {
|
|
3286
|
+
try {
|
|
3287
|
+
const primaryClient = await this.primary.loadClient(baseUrl2);
|
|
3288
|
+
if (primaryClient)
|
|
3289
|
+
return primaryClient;
|
|
3290
|
+
} catch (error) {
|
|
3291
|
+
if (!(error instanceof KeychainUnavailableError))
|
|
3292
|
+
throw error;
|
|
3293
|
+
}
|
|
3294
|
+
const candidate = await this.selectPlaintextClientCandidate(baseUrl2);
|
|
3295
|
+
if (!candidate)
|
|
3296
|
+
return null;
|
|
3297
|
+
try {
|
|
3298
|
+
await this.primary.saveClient(baseUrl2, candidate.data);
|
|
3299
|
+
} catch (error) {
|
|
3300
|
+
if (error instanceof KeychainUnavailableError)
|
|
3301
|
+
return candidate.data;
|
|
3302
|
+
throw error;
|
|
3303
|
+
}
|
|
3304
|
+
await this.clearMigratedPlaintext(baseUrl2, "client", candidate.source, candidate.ambiguous);
|
|
3305
|
+
return candidate.data;
|
|
3306
|
+
}
|
|
3307
|
+
async loadClientFileMode(baseUrl2) {
|
|
3308
|
+
const candidate = await this.selectPlaintextClientCandidate(baseUrl2);
|
|
3309
|
+
if (candidate) {
|
|
3310
|
+
if (candidate.source === "legacy") {
|
|
3311
|
+
await this.file.saveClient(baseUrl2, candidate.data);
|
|
3312
|
+
await this.clearBestEffort(() => this.legacy.clearClient(baseUrl2));
|
|
3313
|
+
}
|
|
3314
|
+
return candidate.data;
|
|
3315
|
+
}
|
|
3316
|
+
let primaryClient = null;
|
|
3317
|
+
try {
|
|
3318
|
+
primaryClient = await this.primary.loadClient(baseUrl2);
|
|
3319
|
+
} catch (error) {
|
|
3320
|
+
if (!(error instanceof KeychainUnavailableError))
|
|
3321
|
+
throw error;
|
|
3322
|
+
}
|
|
3323
|
+
if (!primaryClient)
|
|
3324
|
+
return null;
|
|
3325
|
+
this.warnKeychainExport();
|
|
3326
|
+
await this.file.saveClient(baseUrl2, primaryClient);
|
|
3327
|
+
return primaryClient;
|
|
3328
|
+
}
|
|
3329
|
+
async selectPlaintextTokenCandidate(baseUrl2) {
|
|
3330
|
+
const candidates = [];
|
|
3331
|
+
const fileTokens = await this.file.loadTokens(baseUrl2);
|
|
3332
|
+
if (fileTokens) {
|
|
3333
|
+
candidates.push({
|
|
3334
|
+
data: fileTokens,
|
|
3335
|
+
source: "file",
|
|
3336
|
+
timestamp: fileTokens.createdAt,
|
|
3337
|
+
ambiguous: false
|
|
3338
|
+
});
|
|
3339
|
+
}
|
|
3340
|
+
const legacyTokens = await this.legacy.loadTokens(baseUrl2);
|
|
3341
|
+
if (legacyTokens) {
|
|
3342
|
+
candidates.push({
|
|
3343
|
+
data: legacyTokens,
|
|
3344
|
+
source: "legacy",
|
|
3345
|
+
timestamp: legacyTokens.createdAt,
|
|
3346
|
+
ambiguous: false
|
|
3347
|
+
});
|
|
3348
|
+
}
|
|
3349
|
+
return this.selectNewestCandidate(candidates);
|
|
3350
|
+
}
|
|
3351
|
+
async selectPlaintextClientCandidate(baseUrl2) {
|
|
3352
|
+
const candidates = [];
|
|
3353
|
+
const fileClient = await this.file.loadClient(baseUrl2);
|
|
3354
|
+
if (fileClient) {
|
|
3355
|
+
candidates.push({
|
|
3356
|
+
data: fileClient,
|
|
3357
|
+
source: "file",
|
|
3358
|
+
timestamp: fileClient.registeredAt,
|
|
3359
|
+
ambiguous: false
|
|
3360
|
+
});
|
|
3361
|
+
}
|
|
3362
|
+
const legacyClient = await this.legacy.loadClient(baseUrl2);
|
|
3363
|
+
if (legacyClient) {
|
|
3364
|
+
candidates.push({
|
|
3365
|
+
data: legacyClient,
|
|
3366
|
+
source: "legacy",
|
|
3367
|
+
timestamp: legacyClient.registeredAt,
|
|
3368
|
+
ambiguous: false
|
|
3369
|
+
});
|
|
3370
|
+
}
|
|
3371
|
+
return this.selectNewestCandidate(candidates);
|
|
3372
|
+
}
|
|
3373
|
+
selectNewestCandidate(candidates) {
|
|
3374
|
+
if (candidates.length === 0)
|
|
3375
|
+
return null;
|
|
3376
|
+
if (candidates.length === 1)
|
|
3377
|
+
return candidates[0] ?? null;
|
|
3378
|
+
const parsed = candidates.map((candidate) => ({
|
|
3379
|
+
candidate,
|
|
3380
|
+
timestampMs: Date.parse(candidate.timestamp)
|
|
3381
|
+
}));
|
|
3382
|
+
if (parsed.some((entry) => Number.isNaN(entry.timestampMs))) {
|
|
3383
|
+
this.warnAmbiguousPlaintext();
|
|
3384
|
+
const selected = candidates.find((candidate) => candidate.source === "file") ?? candidates[0] ?? null;
|
|
3385
|
+
if (selected)
|
|
3386
|
+
selected.ambiguous = true;
|
|
3387
|
+
return selected;
|
|
3388
|
+
}
|
|
3389
|
+
const sorted = [...parsed].sort((a, b) => b.timestampMs - a.timestampMs);
|
|
3390
|
+
const first = sorted[0];
|
|
3391
|
+
const second = sorted[1];
|
|
3392
|
+
if (!first)
|
|
3393
|
+
return candidates[0] ?? null;
|
|
3394
|
+
if (second && first.timestampMs === second.timestampMs) {
|
|
3395
|
+
this.warnAmbiguousPlaintext();
|
|
3396
|
+
const selected = candidates.find((candidate) => candidate.source === "file") ?? first.candidate;
|
|
3397
|
+
selected.ambiguous = true;
|
|
3398
|
+
return selected;
|
|
3399
|
+
}
|
|
3400
|
+
return first.candidate;
|
|
3401
|
+
}
|
|
3402
|
+
async clearMigratedPlaintext(baseUrl2, kind, source, ambiguous = false) {
|
|
3403
|
+
if (!ambiguous) {
|
|
3404
|
+
await this.clearPlaintextSource(this.file, baseUrl2, kind);
|
|
3405
|
+
await this.clearPlaintextSource(this.legacy, baseUrl2, kind);
|
|
3406
|
+
return;
|
|
3407
|
+
}
|
|
3408
|
+
if (source === "file") {
|
|
3409
|
+
await this.clearPlaintextSource(this.file, baseUrl2, kind);
|
|
3410
|
+
return;
|
|
3411
|
+
}
|
|
3412
|
+
if (source === "legacy") {
|
|
3413
|
+
await this.clearPlaintextSource(this.legacy, baseUrl2, kind);
|
|
3414
|
+
}
|
|
3415
|
+
}
|
|
3416
|
+
async clearPlaintextSource(storage, baseUrl2, kind) {
|
|
3417
|
+
await this.clearBestEffort(() => kind === "tokens" ? storage.clearTokens(baseUrl2) : storage.clearClient(baseUrl2));
|
|
3418
|
+
}
|
|
3419
|
+
async clearBestEffort(fn) {
|
|
3420
|
+
try {
|
|
3421
|
+
await fn();
|
|
3422
|
+
return;
|
|
3423
|
+
} catch (error) {
|
|
3424
|
+
return error;
|
|
3425
|
+
}
|
|
3426
|
+
}
|
|
3427
|
+
toPolicyError(error) {
|
|
3428
|
+
if (!(error instanceof KeychainUnavailableError))
|
|
3429
|
+
return error;
|
|
3430
|
+
return new AuthStoragePolicyError(`System keychain is unavailable. ${createFileAuthStorageGuidance(this.configPath)}`);
|
|
3431
|
+
}
|
|
3432
|
+
warnKeychainExport() {
|
|
3433
|
+
if (this.warnedFileModeKeychainExport)
|
|
3434
|
+
return;
|
|
3435
|
+
this.warnedFileModeKeychainExport = true;
|
|
3436
|
+
this.onWarning("Warning: auth.storage=file is exporting existing keychain credentials to plaintext file storage.");
|
|
3437
|
+
}
|
|
3438
|
+
warnAmbiguousPlaintext() {
|
|
3439
|
+
if (this.warnedAmbiguousPlaintext)
|
|
3440
|
+
return;
|
|
3441
|
+
this.warnedAmbiguousPlaintext = true;
|
|
3442
|
+
this.onWarning("Warning: multiple plaintext auth entries exist with ambiguous timestamps; using the new config auth path and leaving the other entry intact.");
|
|
3443
|
+
}
|
|
3444
|
+
sameTokenData(a, b) {
|
|
3445
|
+
if (a === null || b === null)
|
|
3446
|
+
return a === b;
|
|
3447
|
+
return a.accessToken === b.accessToken && a.refreshToken === b.refreshToken && a.expiresAt === b.expiresAt && a.createdAt === b.createdAt;
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3450
|
+
// src/services/package-intelligence-service.ts
|
|
3451
|
+
import { z as z3 } from "zod";
|
|
3452
|
+
|
|
3453
|
+
// src/services/promote-version-not-found.ts
|
|
3454
|
+
function promoteGenericVersionNotFound(error, params) {
|
|
3455
|
+
if (!(error instanceof PackageIntelligenceBackendError))
|
|
3456
|
+
return error;
|
|
3457
|
+
if (error.graphqlCode !== undefined)
|
|
3458
|
+
return error;
|
|
3459
|
+
const requestedVersion = pickRequestedVersion(params);
|
|
3460
|
+
if (!requestedVersion)
|
|
3461
|
+
return error;
|
|
3462
|
+
if (!/no matching version/i.test(error.message))
|
|
3463
|
+
return error;
|
|
3464
|
+
const qualifiedName = synthesizeQualifiedName(params);
|
|
3465
|
+
return new PackageIntelligenceVersionNotFoundError(error.message, qualifiedName, requestedVersion, undefined);
|
|
3466
|
+
}
|
|
3467
|
+
function pickRequestedVersion(params) {
|
|
3468
|
+
if (params.version)
|
|
3469
|
+
return params.version;
|
|
3470
|
+
if (params.fromVersion)
|
|
3471
|
+
return params.fromVersion;
|
|
3472
|
+
if (params.toVersion)
|
|
3473
|
+
return params.toVersion;
|
|
3474
|
+
return;
|
|
3475
|
+
}
|
|
3476
|
+
function synthesizeQualifiedName(params) {
|
|
3477
|
+
if (!params.registry || !params.packageName)
|
|
3478
|
+
return;
|
|
3479
|
+
return `${params.registry.toLowerCase()}:${params.packageName}`;
|
|
3480
|
+
}
|
|
3481
|
+
|
|
2894
3482
|
// src/services/package-intelligence-service.ts
|
|
2895
3483
|
class PackageIntelligenceAccessError extends Error {
|
|
2896
3484
|
constructor(message) {
|
|
@@ -2975,63 +3563,63 @@ class PackageIntelligenceChangelogSourceNotFoundError extends Error {
|
|
|
2975
3563
|
this.name = "PackageIntelligenceChangelogSourceNotFoundError";
|
|
2976
3564
|
}
|
|
2977
3565
|
}
|
|
2978
|
-
var githubRepositorySchema =
|
|
2979
|
-
stargazersCount:
|
|
2980
|
-
forksCount:
|
|
2981
|
-
openIssuesCount:
|
|
2982
|
-
archived:
|
|
2983
|
-
language:
|
|
2984
|
-
topics:
|
|
2985
|
-
pushedAt:
|
|
3566
|
+
var githubRepositorySchema = z3.object({
|
|
3567
|
+
stargazersCount: z3.number().int().nullable().optional(),
|
|
3568
|
+
forksCount: z3.number().int().nullable().optional(),
|
|
3569
|
+
openIssuesCount: z3.number().int().nullable().optional(),
|
|
3570
|
+
archived: z3.boolean().nullable().optional(),
|
|
3571
|
+
language: z3.string().nullable().optional(),
|
|
3572
|
+
topics: z3.array(z3.string()).nullable().optional(),
|
|
3573
|
+
pushedAt: z3.string().nullable().optional()
|
|
2986
3574
|
}).nullable().optional();
|
|
2987
|
-
var packageIdentitySchema =
|
|
2988
|
-
name:
|
|
2989
|
-
registry:
|
|
2990
|
-
description:
|
|
2991
|
-
latestVersion:
|
|
2992
|
-
latestVersionPublishedAt:
|
|
2993
|
-
homepage:
|
|
2994
|
-
repositoryUrl:
|
|
2995
|
-
license:
|
|
2996
|
-
downloadsLastMonth:
|
|
2997
|
-
downloadsTotal:
|
|
3575
|
+
var packageIdentitySchema = z3.object({
|
|
3576
|
+
name: z3.string().nullable().optional(),
|
|
3577
|
+
registry: z3.string().nullable().optional(),
|
|
3578
|
+
description: z3.string().nullable().optional(),
|
|
3579
|
+
latestVersion: z3.string().nullable().optional(),
|
|
3580
|
+
latestVersionPublishedAt: z3.string().nullable().optional(),
|
|
3581
|
+
homepage: z3.string().nullable().optional(),
|
|
3582
|
+
repositoryUrl: z3.string().nullable().optional(),
|
|
3583
|
+
license: z3.string().nullable().optional(),
|
|
3584
|
+
downloadsLastMonth: z3.number().int().nullable().optional(),
|
|
3585
|
+
downloadsTotal: z3.number().int().nullable().optional(),
|
|
2998
3586
|
githubRepository: githubRepositorySchema
|
|
2999
3587
|
});
|
|
3000
|
-
var vulnerabilityOverviewSchema =
|
|
3001
|
-
osvId:
|
|
3002
|
-
summary:
|
|
3003
|
-
severityScore:
|
|
3004
|
-
publishedAt:
|
|
3588
|
+
var vulnerabilityOverviewSchema = z3.object({
|
|
3589
|
+
osvId: z3.string().nullable().optional(),
|
|
3590
|
+
summary: z3.string().nullable().optional(),
|
|
3591
|
+
severityScore: z3.number().nullable().optional(),
|
|
3592
|
+
publishedAt: z3.string().nullable().optional()
|
|
3005
3593
|
});
|
|
3006
|
-
var packageSecurityOverviewSchema =
|
|
3007
|
-
vulnerabilityCount:
|
|
3008
|
-
hasCurrentVulnerabilities:
|
|
3009
|
-
recentVulnerabilities:
|
|
3594
|
+
var packageSecurityOverviewSchema = z3.object({
|
|
3595
|
+
vulnerabilityCount: z3.number().int().nullable().optional(),
|
|
3596
|
+
hasCurrentVulnerabilities: z3.boolean().nullable().optional(),
|
|
3597
|
+
recentVulnerabilities: z3.array(vulnerabilityOverviewSchema).nullable().optional()
|
|
3010
3598
|
}).nullable().optional();
|
|
3011
|
-
var quickstartInfoSchema =
|
|
3012
|
-
installCommand:
|
|
3013
|
-
usageExample:
|
|
3599
|
+
var quickstartInfoSchema = z3.object({
|
|
3600
|
+
installCommand: z3.string().nullable().optional(),
|
|
3601
|
+
usageExample: z3.string().nullable().optional()
|
|
3014
3602
|
}).nullable().optional();
|
|
3015
|
-
var changelogEntrySchema =
|
|
3016
|
-
version:
|
|
3017
|
-
publishedAt:
|
|
3018
|
-
body:
|
|
3603
|
+
var changelogEntrySchema = z3.object({
|
|
3604
|
+
version: z3.string().nullable().optional(),
|
|
3605
|
+
publishedAt: z3.string().nullable().optional(),
|
|
3606
|
+
body: z3.string().nullable().optional()
|
|
3019
3607
|
});
|
|
3020
|
-
var packageSummaryResponseSchema =
|
|
3608
|
+
var packageSummaryResponseSchema = z3.object({
|
|
3021
3609
|
package: packageIdentitySchema.nullable().optional(),
|
|
3022
3610
|
security: packageSecurityOverviewSchema,
|
|
3023
3611
|
quickstart: quickstartInfoSchema,
|
|
3024
|
-
latestChangelogs:
|
|
3612
|
+
latestChangelogs: z3.array(changelogEntrySchema).nullable().optional()
|
|
3025
3613
|
});
|
|
3026
|
-
var graphQLErrorSchema2 =
|
|
3027
|
-
message:
|
|
3028
|
-
extensions:
|
|
3614
|
+
var graphQLErrorSchema2 = z3.object({
|
|
3615
|
+
message: z3.string(),
|
|
3616
|
+
extensions: z3.record(z3.string(), z3.unknown()).optional()
|
|
3029
3617
|
});
|
|
3030
|
-
var graphQLResponseSchema =
|
|
3031
|
-
data:
|
|
3618
|
+
var graphQLResponseSchema = z3.object({
|
|
3619
|
+
data: z3.object({
|
|
3032
3620
|
packageSummary: packageSummaryResponseSchema.nullable().optional()
|
|
3033
3621
|
}).nullable().optional(),
|
|
3034
|
-
errors:
|
|
3622
|
+
errors: z3.array(graphQLErrorSchema2).optional()
|
|
3035
3623
|
});
|
|
3036
3624
|
var PACKAGE_SUMMARY_QUERY = `
|
|
3037
3625
|
query PackageSummary($registry: Registry!, $name: String!) {
|
|
@@ -3078,39 +3666,55 @@ query PackageSummary($registry: Registry!, $name: String!) {
|
|
|
3078
3666
|
}
|
|
3079
3667
|
}
|
|
3080
3668
|
}`;
|
|
3081
|
-
var packageVersionIdentitySchema =
|
|
3082
|
-
name:
|
|
3083
|
-
registry:
|
|
3084
|
-
version:
|
|
3669
|
+
var packageVersionIdentitySchema = z3.object({
|
|
3670
|
+
name: z3.string().nullable().optional(),
|
|
3671
|
+
registry: z3.string().nullable().optional(),
|
|
3672
|
+
version: z3.string().nullable().optional()
|
|
3085
3673
|
});
|
|
3086
|
-
var vulnerabilityDetailSchema =
|
|
3087
|
-
osvId:
|
|
3088
|
-
summary:
|
|
3089
|
-
severityScore:
|
|
3090
|
-
severityType:
|
|
3091
|
-
affectedVersionRanges:
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3674
|
+
var vulnerabilityDetailSchema = z3.object({
|
|
3675
|
+
osvId: z3.string().nullable().optional(),
|
|
3676
|
+
summary: z3.string().nullable().optional(),
|
|
3677
|
+
severityScore: z3.number().nullable().optional(),
|
|
3678
|
+
severityType: z3.string().nullable().optional(),
|
|
3679
|
+
affectedVersionRanges: z3.array(z3.string()).nullable().optional(),
|
|
3680
|
+
affectedVersionRangesCount: z3.number().int(),
|
|
3681
|
+
affectedVersionRangesTruncated: z3.boolean(),
|
|
3682
|
+
fixedInVersions: z3.array(z3.string()).nullable().optional(),
|
|
3683
|
+
publishedAt: z3.string().nullable().optional(),
|
|
3684
|
+
modifiedAt: z3.string().nullable().optional(),
|
|
3685
|
+
withdrawnAt: z3.string().nullable().optional(),
|
|
3686
|
+
aliases: z3.array(z3.string()).nullable().optional(),
|
|
3687
|
+
isMalicious: z3.boolean().nullable().optional(),
|
|
3688
|
+
affectsInspectedVersion: z3.boolean(),
|
|
3689
|
+
matchedAffectedVersionRanges: z3.array(z3.string()),
|
|
3690
|
+
duplicateIds: z3.array(z3.string())
|
|
3691
|
+
});
|
|
3692
|
+
var pageInfoSchema = z3.object({
|
|
3693
|
+
hasNextPage: z3.boolean(),
|
|
3694
|
+
endCursor: z3.string().nullable().optional(),
|
|
3695
|
+
totalCount: z3.number().int()
|
|
3696
|
+
});
|
|
3697
|
+
var vulnerabilityAdvisoryPageSchema = z3.object({
|
|
3698
|
+
entries: z3.array(vulnerabilityDetailSchema),
|
|
3699
|
+
pageInfo: pageInfoSchema
|
|
3098
3700
|
});
|
|
3099
|
-
var vulnerabilitySecurityDetailsSchema =
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3701
|
+
var vulnerabilitySecurityDetailsSchema = z3.object({
|
|
3702
|
+
affectedVulnerabilityCount: z3.number().int(),
|
|
3703
|
+
nonAffectingVulnerabilityCount: z3.number().int(),
|
|
3704
|
+
allVulnerabilityCount: z3.number().int(),
|
|
3705
|
+
currentVersionAffected: z3.boolean().nullable().optional(),
|
|
3706
|
+
advisories: vulnerabilityAdvisoryPageSchema,
|
|
3707
|
+
upgradePaths: z3.array(z3.string()).nullable().optional()
|
|
3104
3708
|
}).nullable().optional();
|
|
3105
|
-
var vulnerabilityReportResponseSchema =
|
|
3709
|
+
var vulnerabilityReportResponseSchema = z3.object({
|
|
3106
3710
|
package: packageVersionIdentitySchema.nullable().optional(),
|
|
3107
3711
|
security: vulnerabilitySecurityDetailsSchema
|
|
3108
3712
|
});
|
|
3109
|
-
var vulnerabilitiesGraphQLResponseSchema =
|
|
3110
|
-
data:
|
|
3713
|
+
var vulnerabilitiesGraphQLResponseSchema = z3.object({
|
|
3714
|
+
data: z3.object({
|
|
3111
3715
|
packageVulnerabilities: vulnerabilityReportResponseSchema.nullable().optional()
|
|
3112
3716
|
}).nullable().optional(),
|
|
3113
|
-
errors:
|
|
3717
|
+
errors: z3.array(graphQLErrorSchema2).optional()
|
|
3114
3718
|
});
|
|
3115
3719
|
var PACKAGE_VULNERABILITIES_QUERY = `
|
|
3116
3720
|
query PackageVulnerabilities(
|
|
@@ -3119,6 +3723,7 @@ query PackageVulnerabilities(
|
|
|
3119
3723
|
$version: String
|
|
3120
3724
|
$minSeverity: Float
|
|
3121
3725
|
$includeWithdrawn: Boolean
|
|
3726
|
+
$after: String
|
|
3122
3727
|
) {
|
|
3123
3728
|
packageVulnerabilities(
|
|
3124
3729
|
registry: $registry
|
|
@@ -3133,110 +3738,124 @@ query PackageVulnerabilities(
|
|
|
3133
3738
|
version
|
|
3134
3739
|
}
|
|
3135
3740
|
security {
|
|
3136
|
-
|
|
3741
|
+
affectedVulnerabilityCount
|
|
3742
|
+
nonAffectingVulnerabilityCount
|
|
3743
|
+
allVulnerabilityCount
|
|
3137
3744
|
currentVersionAffected
|
|
3138
3745
|
upgradePaths
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3746
|
+
advisories(scope: AFFECTED, first: 100, after: $after) {
|
|
3747
|
+
entries {
|
|
3748
|
+
osvId
|
|
3749
|
+
summary
|
|
3750
|
+
severityScore
|
|
3751
|
+
severityType
|
|
3752
|
+
affectedVersionRanges
|
|
3753
|
+
affectedVersionRangesCount
|
|
3754
|
+
affectedVersionRangesTruncated
|
|
3755
|
+
fixedInVersions
|
|
3756
|
+
publishedAt
|
|
3757
|
+
modifiedAt
|
|
3758
|
+
withdrawnAt
|
|
3759
|
+
aliases
|
|
3760
|
+
isMalicious
|
|
3761
|
+
affectsInspectedVersion
|
|
3762
|
+
matchedAffectedVersionRanges
|
|
3763
|
+
duplicateIds
|
|
3764
|
+
}
|
|
3765
|
+
pageInfo {
|
|
3766
|
+
hasNextPage
|
|
3767
|
+
endCursor
|
|
3768
|
+
totalCount
|
|
3769
|
+
}
|
|
3151
3770
|
}
|
|
3152
3771
|
}
|
|
3153
3772
|
}
|
|
3154
3773
|
}`;
|
|
3155
|
-
var directDependencySchema =
|
|
3156
|
-
name:
|
|
3157
|
-
versionConstraint:
|
|
3158
|
-
type:
|
|
3774
|
+
var directDependencySchema = z3.object({
|
|
3775
|
+
name: z3.string().nullable().optional(),
|
|
3776
|
+
versionConstraint: z3.string().nullable().optional(),
|
|
3777
|
+
type: z3.string().nullable().optional()
|
|
3159
3778
|
});
|
|
3160
|
-
var dependencyGraphNodeSchema =
|
|
3161
|
-
registry:
|
|
3162
|
-
name:
|
|
3163
|
-
version:
|
|
3779
|
+
var dependencyGraphNodeSchema = z3.object({
|
|
3780
|
+
registry: z3.string(),
|
|
3781
|
+
name: z3.string(),
|
|
3782
|
+
version: z3.string().nullable().optional()
|
|
3164
3783
|
});
|
|
3165
|
-
var dependencyGraphEdgeSchema =
|
|
3166
|
-
fromIndex:
|
|
3167
|
-
toIndex:
|
|
3168
|
-
constraint:
|
|
3169
|
-
dependencyType:
|
|
3784
|
+
var dependencyGraphEdgeSchema = z3.object({
|
|
3785
|
+
fromIndex: z3.number().int().nullable().optional(),
|
|
3786
|
+
toIndex: z3.number().int(),
|
|
3787
|
+
constraint: z3.string().nullable().optional(),
|
|
3788
|
+
dependencyType: z3.string().nullable().optional()
|
|
3170
3789
|
});
|
|
3171
|
-
var dependencyGraphSchema =
|
|
3172
|
-
formatVersion:
|
|
3173
|
-
nodes:
|
|
3174
|
-
edges:
|
|
3790
|
+
var dependencyGraphSchema = z3.object({
|
|
3791
|
+
formatVersion: z3.number().int(),
|
|
3792
|
+
nodes: z3.array(dependencyGraphNodeSchema),
|
|
3793
|
+
edges: z3.array(dependencyGraphEdgeSchema)
|
|
3175
3794
|
});
|
|
3176
|
-
var dependencyConflictEdgeSchema =
|
|
3177
|
-
fromIndex:
|
|
3178
|
-
toIndex:
|
|
3179
|
-
versionConstraint:
|
|
3180
|
-
dependencyType:
|
|
3795
|
+
var dependencyConflictEdgeSchema = z3.object({
|
|
3796
|
+
fromIndex: z3.number().int().nullable().optional(),
|
|
3797
|
+
toIndex: z3.number().int(),
|
|
3798
|
+
versionConstraint: z3.string(),
|
|
3799
|
+
dependencyType: z3.string()
|
|
3181
3800
|
});
|
|
3182
|
-
var dependencyConflictSchema =
|
|
3183
|
-
packageName:
|
|
3184
|
-
requiredVersions:
|
|
3185
|
-
conflictingEdges:
|
|
3801
|
+
var dependencyConflictSchema = z3.object({
|
|
3802
|
+
packageName: z3.string(),
|
|
3803
|
+
requiredVersions: z3.array(z3.string()),
|
|
3804
|
+
conflictingEdges: z3.array(dependencyConflictEdgeSchema)
|
|
3186
3805
|
});
|
|
3187
|
-
var circularDependencyCycleSchema =
|
|
3188
|
-
cycleStart:
|
|
3189
|
-
circularPath:
|
|
3190
|
-
displayChain:
|
|
3806
|
+
var circularDependencyCycleSchema = z3.object({
|
|
3807
|
+
cycleStart: z3.string(),
|
|
3808
|
+
circularPath: z3.array(z3.string()),
|
|
3809
|
+
displayChain: z3.string()
|
|
3191
3810
|
});
|
|
3192
|
-
var environmentMarkerSchema =
|
|
3193
|
-
type:
|
|
3194
|
-
value:
|
|
3195
|
-
raw:
|
|
3811
|
+
var environmentMarkerSchema = z3.object({
|
|
3812
|
+
type: z3.string().nullable().optional(),
|
|
3813
|
+
value: z3.string().nullable().optional(),
|
|
3814
|
+
raw: z3.string().nullable().optional()
|
|
3196
3815
|
});
|
|
3197
|
-
var transitiveDependencySchema =
|
|
3198
|
-
totalEdges:
|
|
3199
|
-
uniquePackagesCount:
|
|
3200
|
-
uniqueDependencies:
|
|
3201
|
-
dependencyConflicts:
|
|
3202
|
-
circularDependencyCycles:
|
|
3816
|
+
var transitiveDependencySchema = z3.object({
|
|
3817
|
+
totalEdges: z3.number().int().nullable().optional(),
|
|
3818
|
+
uniquePackagesCount: z3.number().int().nullable().optional(),
|
|
3819
|
+
uniqueDependencies: z3.array(z3.string()).nullable().optional(),
|
|
3820
|
+
dependencyConflicts: z3.array(dependencyConflictSchema).nullable().optional(),
|
|
3821
|
+
circularDependencyCycles: z3.array(circularDependencyCycleSchema).nullable().optional(),
|
|
3203
3822
|
dependencyGraph: dependencyGraphSchema.nullable().optional()
|
|
3204
3823
|
}).nullable().optional();
|
|
3205
|
-
var dependencyBundleSchema =
|
|
3206
|
-
direct:
|
|
3824
|
+
var dependencyBundleSchema = z3.object({
|
|
3825
|
+
direct: z3.array(directDependencySchema).nullable().optional(),
|
|
3207
3826
|
transitive: transitiveDependencySchema
|
|
3208
3827
|
}).nullable().optional();
|
|
3209
|
-
var groupDependencySchema =
|
|
3210
|
-
name:
|
|
3211
|
-
constraint:
|
|
3828
|
+
var groupDependencySchema = z3.object({
|
|
3829
|
+
name: z3.string(),
|
|
3830
|
+
constraint: z3.string().nullable().optional()
|
|
3212
3831
|
});
|
|
3213
|
-
var dependencyGroupSchema =
|
|
3214
|
-
name:
|
|
3215
|
-
lifecycle:
|
|
3216
|
-
conditionType:
|
|
3217
|
-
conditionValue:
|
|
3218
|
-
selectionMode:
|
|
3219
|
-
exclusiveGroup:
|
|
3220
|
-
fallbackPriority:
|
|
3221
|
-
compatibleWith:
|
|
3222
|
-
defaultEnabled:
|
|
3223
|
-
dependencies:
|
|
3832
|
+
var dependencyGroupSchema = z3.object({
|
|
3833
|
+
name: z3.string(),
|
|
3834
|
+
lifecycle: z3.string(),
|
|
3835
|
+
conditionType: z3.string(),
|
|
3836
|
+
conditionValue: z3.string().nullable().optional(),
|
|
3837
|
+
selectionMode: z3.string(),
|
|
3838
|
+
exclusiveGroup: z3.string().nullable().optional(),
|
|
3839
|
+
fallbackPriority: z3.number().int().nullable().optional(),
|
|
3840
|
+
compatibleWith: z3.array(z3.string()).nullable().optional(),
|
|
3841
|
+
defaultEnabled: z3.boolean().nullable().optional(),
|
|
3842
|
+
dependencies: z3.array(groupDependencySchema)
|
|
3224
3843
|
});
|
|
3225
|
-
var dependencyGroupsInfoSchema =
|
|
3226
|
-
primaryGroup:
|
|
3227
|
-
environmentMarkers:
|
|
3228
|
-
groups:
|
|
3844
|
+
var dependencyGroupsInfoSchema = z3.object({
|
|
3845
|
+
primaryGroup: z3.string().nullable().optional(),
|
|
3846
|
+
environmentMarkers: z3.array(environmentMarkerSchema).nullable().optional(),
|
|
3847
|
+
groups: z3.array(dependencyGroupSchema)
|
|
3229
3848
|
}).nullable().optional();
|
|
3230
|
-
var dependencyReportResponseSchema =
|
|
3849
|
+
var dependencyReportResponseSchema = z3.object({
|
|
3231
3850
|
package: packageVersionIdentitySchema.nullable().optional(),
|
|
3232
3851
|
dependencies: dependencyBundleSchema,
|
|
3233
3852
|
dependencyGroups: dependencyGroupsInfoSchema
|
|
3234
3853
|
});
|
|
3235
|
-
var dependenciesGraphQLResponseSchema =
|
|
3236
|
-
data:
|
|
3854
|
+
var dependenciesGraphQLResponseSchema = z3.object({
|
|
3855
|
+
data: z3.object({
|
|
3237
3856
|
packageDependencies: dependencyReportResponseSchema.nullable().optional()
|
|
3238
3857
|
}).nullable().optional(),
|
|
3239
|
-
errors:
|
|
3858
|
+
errors: z3.array(graphQLErrorSchema2).optional()
|
|
3240
3859
|
});
|
|
3241
3860
|
var PACKAGE_DEPENDENCIES_QUERY = `
|
|
3242
3861
|
query PackageDependencies(
|
|
@@ -3330,32 +3949,32 @@ query PackageDependencies(
|
|
|
3330
3949
|
}
|
|
3331
3950
|
}
|
|
3332
3951
|
}`;
|
|
3333
|
-
var changelogPackageInfoSchema =
|
|
3334
|
-
name:
|
|
3335
|
-
registry:
|
|
3336
|
-
repoUrl:
|
|
3337
|
-
fromVersion:
|
|
3338
|
-
toVersion:
|
|
3339
|
-
limit:
|
|
3952
|
+
var changelogPackageInfoSchema = z3.object({
|
|
3953
|
+
name: z3.string().nullable().optional(),
|
|
3954
|
+
registry: z3.string().nullable().optional(),
|
|
3955
|
+
repoUrl: z3.string().nullable().optional(),
|
|
3956
|
+
fromVersion: z3.string().nullable().optional(),
|
|
3957
|
+
toVersion: z3.string().nullable().optional(),
|
|
3958
|
+
limit: z3.number().int().nullable().optional()
|
|
3340
3959
|
}).nullable().optional();
|
|
3341
|
-
var changelogEntryDetailSchema =
|
|
3342
|
-
version:
|
|
3343
|
-
normalizedVersion:
|
|
3344
|
-
body:
|
|
3345
|
-
htmlUrl:
|
|
3346
|
-
publishedAt:
|
|
3347
|
-
metadata:
|
|
3960
|
+
var changelogEntryDetailSchema = z3.object({
|
|
3961
|
+
version: z3.string().nullable().optional(),
|
|
3962
|
+
normalizedVersion: z3.string().nullable().optional(),
|
|
3963
|
+
body: z3.string().nullable().optional(),
|
|
3964
|
+
htmlUrl: z3.string().nullable().optional(),
|
|
3965
|
+
publishedAt: z3.string().nullable().optional(),
|
|
3966
|
+
metadata: z3.unknown().nullable().optional()
|
|
3348
3967
|
});
|
|
3349
|
-
var changelogReportResponseSchema =
|
|
3968
|
+
var changelogReportResponseSchema = z3.object({
|
|
3350
3969
|
package: changelogPackageInfoSchema,
|
|
3351
|
-
source:
|
|
3352
|
-
entries:
|
|
3970
|
+
source: z3.string().nullable().optional(),
|
|
3971
|
+
entries: z3.array(changelogEntryDetailSchema).nullable().optional()
|
|
3353
3972
|
});
|
|
3354
|
-
var changelogGraphQLResponseSchema =
|
|
3355
|
-
data:
|
|
3973
|
+
var changelogGraphQLResponseSchema = z3.object({
|
|
3974
|
+
data: z3.object({
|
|
3356
3975
|
packageChangelog: changelogReportResponseSchema.nullable().optional()
|
|
3357
3976
|
}).nullable().optional(),
|
|
3358
|
-
errors:
|
|
3977
|
+
errors: z3.array(graphQLErrorSchema2).optional()
|
|
3359
3978
|
});
|
|
3360
3979
|
var PACKAGE_CHANGELOG_QUERY = `
|
|
3361
3980
|
query PackageChangelog(
|
|
@@ -3395,72 +4014,72 @@ query PackageChangelog(
|
|
|
3395
4014
|
}
|
|
3396
4015
|
}
|
|
3397
4016
|
}`;
|
|
3398
|
-
var packageDocSourceKindSchema =
|
|
3399
|
-
var packageDocPageSummarySchema =
|
|
3400
|
-
id:
|
|
3401
|
-
title:
|
|
3402
|
-
slug:
|
|
3403
|
-
order:
|
|
3404
|
-
linkName:
|
|
3405
|
-
lastUpdatedAt:
|
|
4017
|
+
var packageDocSourceKindSchema = z3.enum(["CRAWLED", "REPOSITORY"]);
|
|
4018
|
+
var packageDocPageSummarySchema = z3.object({
|
|
4019
|
+
id: z3.string().nullable().optional(),
|
|
4020
|
+
title: z3.string().nullable().optional(),
|
|
4021
|
+
slug: z3.string().nullable().optional(),
|
|
4022
|
+
order: z3.number().int().nullable().optional(),
|
|
4023
|
+
linkName: z3.string().nullable().optional(),
|
|
4024
|
+
lastUpdatedAt: z3.string().nullable().optional(),
|
|
3406
4025
|
sourceKind: packageDocSourceKindSchema.nullable().optional(),
|
|
3407
|
-
sourceUrl:
|
|
3408
|
-
repoUrl:
|
|
3409
|
-
gitRef:
|
|
3410
|
-
requestedRef:
|
|
3411
|
-
filePath:
|
|
4026
|
+
sourceUrl: z3.string().nullable().optional(),
|
|
4027
|
+
repoUrl: z3.string().nullable().optional(),
|
|
4028
|
+
gitRef: z3.string().nullable().optional(),
|
|
4029
|
+
requestedRef: z3.string().nullable().optional(),
|
|
4030
|
+
filePath: z3.string().nullable().optional()
|
|
3412
4031
|
});
|
|
3413
|
-
var packageDocsPageInfoSchema =
|
|
3414
|
-
hasNextPage:
|
|
3415
|
-
endCursor:
|
|
3416
|
-
totalCount:
|
|
4032
|
+
var packageDocsPageInfoSchema = z3.object({
|
|
4033
|
+
hasNextPage: z3.boolean(),
|
|
4034
|
+
endCursor: z3.string().nullable().optional(),
|
|
4035
|
+
totalCount: z3.number().int().nullable().optional()
|
|
3417
4036
|
}).nullable().optional();
|
|
3418
|
-
var packageDocsListResponseSchema =
|
|
3419
|
-
registry:
|
|
3420
|
-
packageName:
|
|
3421
|
-
version:
|
|
3422
|
-
stale:
|
|
3423
|
-
pages:
|
|
4037
|
+
var packageDocsListResponseSchema = z3.object({
|
|
4038
|
+
registry: z3.string().nullable().optional(),
|
|
4039
|
+
packageName: z3.string().nullable().optional(),
|
|
4040
|
+
version: z3.string().nullable().optional(),
|
|
4041
|
+
stale: z3.boolean().nullable().optional(),
|
|
4042
|
+
pages: z3.array(packageDocPageSummarySchema).nullable().optional(),
|
|
3424
4043
|
pageInfo: packageDocsPageInfoSchema
|
|
3425
4044
|
});
|
|
3426
|
-
var packageDocSourceSchema =
|
|
3427
|
-
url:
|
|
3428
|
-
label:
|
|
4045
|
+
var packageDocSourceSchema = z3.object({
|
|
4046
|
+
url: z3.string().nullable().optional(),
|
|
4047
|
+
label: z3.string().nullable().optional()
|
|
3429
4048
|
}).nullable().optional();
|
|
3430
|
-
var packageDocPageSchema =
|
|
3431
|
-
id:
|
|
3432
|
-
title:
|
|
3433
|
-
content:
|
|
3434
|
-
contentFormat:
|
|
3435
|
-
breadcrumbs:
|
|
3436
|
-
linkName:
|
|
3437
|
-
lastUpdatedAt:
|
|
4049
|
+
var packageDocPageSchema = z3.object({
|
|
4050
|
+
id: z3.string().nullable().optional(),
|
|
4051
|
+
title: z3.string().nullable().optional(),
|
|
4052
|
+
content: z3.string().nullable().optional(),
|
|
4053
|
+
contentFormat: z3.string().nullable().optional(),
|
|
4054
|
+
breadcrumbs: z3.array(z3.string()).nullable().optional(),
|
|
4055
|
+
linkName: z3.string().nullable().optional(),
|
|
4056
|
+
lastUpdatedAt: z3.string().nullable().optional(),
|
|
3438
4057
|
sourceKind: packageDocSourceKindSchema.nullable().optional(),
|
|
3439
4058
|
source: packageDocSourceSchema,
|
|
3440
|
-
repoUrl:
|
|
3441
|
-
gitRef:
|
|
3442
|
-
requestedRef:
|
|
3443
|
-
filePath:
|
|
3444
|
-
baseUrl:
|
|
4059
|
+
repoUrl: z3.string().nullable().optional(),
|
|
4060
|
+
gitRef: z3.string().nullable().optional(),
|
|
4061
|
+
requestedRef: z3.string().nullable().optional(),
|
|
4062
|
+
filePath: z3.string().nullable().optional(),
|
|
4063
|
+
baseUrl: z3.string().nullable().optional()
|
|
3445
4064
|
}).nullable().optional();
|
|
3446
|
-
var packageDocResultResponseSchema =
|
|
3447
|
-
registry:
|
|
3448
|
-
packageName:
|
|
3449
|
-
version:
|
|
4065
|
+
var packageDocResultResponseSchema = z3.object({
|
|
4066
|
+
registry: z3.string().nullable().optional(),
|
|
4067
|
+
packageName: z3.string().nullable().optional(),
|
|
4068
|
+
version: z3.string().nullable().optional(),
|
|
3450
4069
|
sourceKind: packageDocSourceKindSchema.nullable().optional(),
|
|
3451
4070
|
page: packageDocPageSchema
|
|
3452
4071
|
});
|
|
3453
|
-
var packageDocsListGraphQLResponseSchema =
|
|
3454
|
-
data:
|
|
4072
|
+
var packageDocsListGraphQLResponseSchema = z3.object({
|
|
4073
|
+
data: z3.object({
|
|
3455
4074
|
listPackageDocs: packageDocsListResponseSchema.nullable().optional()
|
|
3456
4075
|
}).nullable().optional(),
|
|
3457
|
-
errors:
|
|
4076
|
+
errors: z3.array(graphQLErrorSchema2).optional()
|
|
3458
4077
|
});
|
|
3459
|
-
var packageDocReadGraphQLResponseSchema =
|
|
3460
|
-
data:
|
|
4078
|
+
var packageDocReadGraphQLResponseSchema = z3.object({
|
|
4079
|
+
data: z3.object({
|
|
3461
4080
|
getDocPage: packageDocResultResponseSchema.nullable().optional()
|
|
3462
4081
|
}).nullable().optional(),
|
|
3463
|
-
errors:
|
|
4082
|
+
errors: z3.array(graphQLErrorSchema2).optional()
|
|
3464
4083
|
});
|
|
3465
4084
|
var LIST_PACKAGE_DOCS_QUERY = `
|
|
3466
4085
|
query ListPackageDocs(
|
|
@@ -3602,6 +4221,9 @@ class PackageIntelligenceServiceImpl {
|
|
|
3602
4221
|
const extensions = getPrimaryExtensions2(errors);
|
|
3603
4222
|
const code = typeof extensions?.code === "string" ? extensions.code : undefined;
|
|
3604
4223
|
const retryable = typeof extensions?.retryable === "boolean" ? extensions.retryable : undefined;
|
|
4224
|
+
if (isClientUpdateRequiredGraphQLError({ message, code })) {
|
|
4225
|
+
return new ClientUpdateRequiredError;
|
|
4226
|
+
}
|
|
3605
4227
|
switch (code) {
|
|
3606
4228
|
case "NOT_FOUND":
|
|
3607
4229
|
case "PACKAGE_NOT_FOUND":
|
|
@@ -3692,6 +4314,56 @@ class PackageIntelligenceServiceImpl {
|
|
|
3692
4314
|
}));
|
|
3693
4315
|
}
|
|
3694
4316
|
async executePackageVulnerabilities(token, params) {
|
|
4317
|
+
let after = null;
|
|
4318
|
+
let firstPage;
|
|
4319
|
+
const entries = [];
|
|
4320
|
+
const seenCursors = new Set;
|
|
4321
|
+
do {
|
|
4322
|
+
const page = await this.fetchPackageVulnerabilitiesPage(token, params, after);
|
|
4323
|
+
if (!firstPage)
|
|
4324
|
+
firstPage = page;
|
|
4325
|
+
const advisoryPage = page.security?.advisories;
|
|
4326
|
+
if (!advisoryPage) {
|
|
4327
|
+
after = null;
|
|
4328
|
+
break;
|
|
4329
|
+
}
|
|
4330
|
+
entries.push(...advisoryPage.entries);
|
|
4331
|
+
if (advisoryPage.pageInfo.hasNextPage) {
|
|
4332
|
+
const nextCursor = advisoryPage.pageInfo.endCursor;
|
|
4333
|
+
if (!nextCursor) {
|
|
4334
|
+
throw new MalformedPackageIntelligenceResponseError("Vulnerability response pagination omitted next cursor.");
|
|
4335
|
+
}
|
|
4336
|
+
if (seenCursors.has(nextCursor)) {
|
|
4337
|
+
throw new MalformedPackageIntelligenceResponseError("Vulnerability response pagination repeated a cursor.");
|
|
4338
|
+
}
|
|
4339
|
+
seenCursors.add(nextCursor);
|
|
4340
|
+
after = nextCursor;
|
|
4341
|
+
} else {
|
|
4342
|
+
after = null;
|
|
4343
|
+
}
|
|
4344
|
+
} while (after !== null);
|
|
4345
|
+
if (!firstPage) {
|
|
4346
|
+
throw new MalformedPackageIntelligenceResponseError("Empty response from the package-intelligence service.");
|
|
4347
|
+
}
|
|
4348
|
+
if (firstPage.security) {
|
|
4349
|
+
const expectedCount = firstPage.security.advisories.pageInfo.totalCount;
|
|
4350
|
+
if (entries.length !== expectedCount) {
|
|
4351
|
+
throw new MalformedPackageIntelligenceResponseError("Vulnerability response pagination returned an incomplete advisory set.");
|
|
4352
|
+
}
|
|
4353
|
+
}
|
|
4354
|
+
const data = firstPage.security ? {
|
|
4355
|
+
...firstPage,
|
|
4356
|
+
security: {
|
|
4357
|
+
...firstPage.security,
|
|
4358
|
+
advisories: {
|
|
4359
|
+
...firstPage.security.advisories,
|
|
4360
|
+
entries
|
|
4361
|
+
}
|
|
4362
|
+
}
|
|
4363
|
+
} : firstPage;
|
|
4364
|
+
return this.normaliseVulnerabilityReport(data);
|
|
4365
|
+
}
|
|
4366
|
+
async fetchPackageVulnerabilitiesPage(token, params, after) {
|
|
3695
4367
|
let response;
|
|
3696
4368
|
try {
|
|
3697
4369
|
response = await postPkgseerGraphql({
|
|
@@ -3703,7 +4375,8 @@ class PackageIntelligenceServiceImpl {
|
|
|
3703
4375
|
name: params.packageName,
|
|
3704
4376
|
version: params.version,
|
|
3705
4377
|
minSeverity: params.minSeverity,
|
|
3706
|
-
includeWithdrawn: params.includeWithdrawn
|
|
4378
|
+
includeWithdrawn: params.includeWithdrawn,
|
|
4379
|
+
after
|
|
3707
4380
|
},
|
|
3708
4381
|
fetchFn: this.fetchFn
|
|
3709
4382
|
});
|
|
@@ -3727,7 +4400,7 @@ class PackageIntelligenceServiceImpl {
|
|
|
3727
4400
|
if (!data) {
|
|
3728
4401
|
throw new MalformedPackageIntelligenceResponseError("Empty response from the package-intelligence service.");
|
|
3729
4402
|
}
|
|
3730
|
-
return
|
|
4403
|
+
return data;
|
|
3731
4404
|
}
|
|
3732
4405
|
normaliseVulnerabilityReport(data) {
|
|
3733
4406
|
const name = data.package?.name ?? undefined;
|
|
@@ -3741,21 +4414,28 @@ class PackageIntelligenceServiceImpl {
|
|
|
3741
4414
|
registry: data.package?.registry ?? undefined
|
|
3742
4415
|
};
|
|
3743
4416
|
const security = data.security ? {
|
|
3744
|
-
|
|
4417
|
+
affectedVulnerabilityCount: data.security.affectedVulnerabilityCount,
|
|
4418
|
+
nonAffectingVulnerabilityCount: data.security.nonAffectingVulnerabilityCount,
|
|
4419
|
+
allVulnerabilityCount: data.security.allVulnerabilityCount,
|
|
3745
4420
|
currentVersionAffected: data.security.currentVersionAffected ?? undefined,
|
|
3746
|
-
vulnerabilities: data.security.
|
|
4421
|
+
vulnerabilities: data.security.advisories.entries.map((vuln) => ({
|
|
3747
4422
|
osvId: vuln.osvId ?? undefined,
|
|
3748
4423
|
summary: vuln.summary ?? undefined,
|
|
3749
4424
|
severityScore: vuln.severityScore ?? undefined,
|
|
3750
4425
|
severityType: vuln.severityType ?? undefined,
|
|
3751
4426
|
affectedVersionRanges: vuln.affectedVersionRanges ?? undefined,
|
|
4427
|
+
affectedVersionRangesCount: vuln.affectedVersionRangesCount,
|
|
4428
|
+
affectedVersionRangesTruncated: vuln.affectedVersionRangesTruncated,
|
|
3752
4429
|
fixedInVersions: vuln.fixedInVersions ?? undefined,
|
|
3753
4430
|
publishedAt: vuln.publishedAt ?? undefined,
|
|
3754
4431
|
modifiedAt: vuln.modifiedAt ?? undefined,
|
|
3755
4432
|
withdrawnAt: vuln.withdrawnAt ?? undefined,
|
|
3756
4433
|
aliases: vuln.aliases ?? undefined,
|
|
3757
|
-
isMalicious: vuln.isMalicious ?? undefined
|
|
3758
|
-
|
|
4434
|
+
isMalicious: vuln.isMalicious ?? undefined,
|
|
4435
|
+
affectsInspectedVersion: vuln.affectsInspectedVersion,
|
|
4436
|
+
matchedAffectedVersionRanges: vuln.matchedAffectedVersionRanges,
|
|
4437
|
+
duplicateIds: vuln.duplicateIds
|
|
4438
|
+
})),
|
|
3759
4439
|
upgradePaths: data.security.upgradePaths ?? undefined
|
|
3760
4440
|
} : undefined;
|
|
3761
4441
|
return {
|
|
@@ -3946,12 +4626,12 @@ class PackageIntelligenceServiceImpl {
|
|
|
3946
4626
|
return this.normaliseChangelogReport(data, params);
|
|
3947
4627
|
}
|
|
3948
4628
|
normaliseChangelogReport(data, params) {
|
|
3949
|
-
const source = data.source
|
|
3950
|
-
|
|
4629
|
+
const source = data.source && data.source.trim() ? data.source : undefined;
|
|
4630
|
+
const rawEntries = data.entries ?? [];
|
|
4631
|
+
if (!source && rawEntries.length === 0) {
|
|
3951
4632
|
const target = params.repoUrl ?? (params.registry && params.packageName ? `${params.registry.toLowerCase()}:${params.packageName}` : "package");
|
|
3952
4633
|
throw new PackageIntelligenceChangelogSourceNotFoundError(`No changelog source available for ${target} (tried GitHub Releases, CHANGELOG.md, and HexDocs).`);
|
|
3953
4634
|
}
|
|
3954
|
-
const rawEntries = data.entries ?? [];
|
|
3955
4635
|
const entries = rawEntries.map((entry) => ({
|
|
3956
4636
|
version: entry.version ?? undefined,
|
|
3957
4637
|
normalizedVersion: entry.normalizedVersion ?? undefined,
|
|
@@ -4292,37 +4972,428 @@ class TokenManager {
|
|
|
4292
4972
|
refreshToken: tokens.refreshToken
|
|
4293
4973
|
}));
|
|
4294
4974
|
} catch {
|
|
4975
|
+
const reloadedToken = await this.loadExternallyUpdatedToken(tokens);
|
|
4976
|
+
if (reloadedToken)
|
|
4977
|
+
return reloadedToken.accessToken;
|
|
4295
4978
|
const isExpired = tokens.expiresAt ? new Date >= new Date(tokens.expiresAt) : false;
|
|
4296
4979
|
if (isExpired) {
|
|
4980
|
+
const currentStoredTokens = await this.loadExternallyUpdatedToken(tokens);
|
|
4981
|
+
if (currentStoredTokens)
|
|
4982
|
+
return currentStoredTokens.accessToken;
|
|
4983
|
+
const cleared = await withTelemetrySpan("token-manager.clear-tokens-if-unchanged", () => this.authStorage.clearTokensIfUnchanged(this.mcpUrl, tokens));
|
|
4984
|
+
if (!cleared) {
|
|
4985
|
+
const currentToken = await this.authStorage.loadTokens(this.mcpUrl);
|
|
4986
|
+
this.cachedToken = currentToken;
|
|
4987
|
+
return currentToken?.accessToken;
|
|
4988
|
+
}
|
|
4297
4989
|
this.cachedToken = null;
|
|
4298
|
-
await withTelemetrySpan("token-manager.clear-tokens", () => this.authStorage.clearTokens(this.mcpUrl));
|
|
4299
4990
|
}
|
|
4300
4991
|
return;
|
|
4301
4992
|
}
|
|
4302
4993
|
const newTokenData = {
|
|
4303
4994
|
accessToken: response.accessToken,
|
|
4304
|
-
refreshToken: response.refreshToken,
|
|
4995
|
+
refreshToken: response.refreshToken ?? tokens.refreshToken,
|
|
4305
4996
|
expiresAt: new Date(Date.now() + response.expiresIn * 1000).toISOString(),
|
|
4306
4997
|
createdAt: new Date().toISOString()
|
|
4307
4998
|
};
|
|
4308
|
-
|
|
4999
|
+
const externallyUpdatedToken = await this.loadExternallyUpdatedToken(tokens, {
|
|
5000
|
+
treatMissingAsExternalUpdate: true
|
|
5001
|
+
});
|
|
5002
|
+
if (externallyUpdatedToken === null)
|
|
5003
|
+
return;
|
|
5004
|
+
if (externallyUpdatedToken)
|
|
5005
|
+
return externallyUpdatedToken.accessToken;
|
|
5006
|
+
const saved = await withTelemetrySpan("token-manager.save-tokens", () => this.authStorage.saveTokensIfUnchanged(this.mcpUrl, tokens, newTokenData));
|
|
5007
|
+
if (!saved) {
|
|
5008
|
+
const currentToken = await this.authStorage.loadTokens(this.mcpUrl);
|
|
5009
|
+
this.cachedToken = currentToken;
|
|
5010
|
+
return currentToken?.accessToken;
|
|
5011
|
+
}
|
|
4309
5012
|
this.cachedToken = newTokenData;
|
|
4310
5013
|
return response.accessToken;
|
|
4311
5014
|
});
|
|
4312
5015
|
}
|
|
5016
|
+
async loadExternallyUpdatedToken(failedTokens, options = {}) {
|
|
5017
|
+
const storedTokens = await withTelemetrySpan("token-manager.reload-tokens", () => this.authStorage.loadTokens(this.mcpUrl));
|
|
5018
|
+
if (!storedTokens) {
|
|
5019
|
+
if (options.treatMissingAsExternalUpdate)
|
|
5020
|
+
this.cachedToken = null;
|
|
5021
|
+
return options.treatMissingAsExternalUpdate ? null : undefined;
|
|
5022
|
+
}
|
|
5023
|
+
if (areSameTokenData(storedTokens, failedTokens))
|
|
5024
|
+
return;
|
|
5025
|
+
this.cachedToken = storedTokens;
|
|
5026
|
+
return storedTokens;
|
|
5027
|
+
}
|
|
4313
5028
|
}
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
5029
|
+
function areSameTokenData(a, b) {
|
|
5030
|
+
return a.accessToken === b.accessToken && a.refreshToken === b.refreshToken && a.expiresAt === b.expiresAt && a.createdAt === b.createdAt;
|
|
5031
|
+
}
|
|
5032
|
+
// src/services/update-check-service.ts
|
|
5033
|
+
import semver from "semver";
|
|
5034
|
+
var NPM_DIST_TAGS_URL = "https://registry.npmjs.org/-/package/githits/dist-tags";
|
|
5035
|
+
var NPM_PACKAGE_VERSION_URL = "https://registry.npmjs.org/githits";
|
|
5036
|
+
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
5037
|
+
var FETCH_TIMEOUT_MS = 1000;
|
|
5038
|
+
var DIR_MODE2 = 448;
|
|
5039
|
+
var UPDATE_COMMAND = "npm i -g githits@latest";
|
|
5040
|
+
var MAX_DEPRECATION_REASON_LENGTH = 200;
|
|
5041
|
+
|
|
5042
|
+
class NpmRegistryUpdateCheckService {
|
|
5043
|
+
currentVersion;
|
|
5044
|
+
fs;
|
|
5045
|
+
fetcher;
|
|
5046
|
+
env;
|
|
5047
|
+
now;
|
|
5048
|
+
checkIntervalMs;
|
|
5049
|
+
fetchTimeoutMs;
|
|
5050
|
+
configDir;
|
|
5051
|
+
cachePath;
|
|
5052
|
+
constructor(options) {
|
|
5053
|
+
this.currentVersion = options.currentVersion;
|
|
5054
|
+
this.fs = options.fileSystemService;
|
|
5055
|
+
this.fetcher = options.fetcher ?? fetch;
|
|
5056
|
+
this.env = options.env ?? process.env;
|
|
5057
|
+
this.now = options.now ?? (() => new Date);
|
|
5058
|
+
this.checkIntervalMs = options.checkIntervalMs ?? CHECK_INTERVAL_MS;
|
|
5059
|
+
this.fetchTimeoutMs = options.fetchTimeoutMs ?? FETCH_TIMEOUT_MS;
|
|
5060
|
+
this.configDir = this.fs.joinPath(resolveConfigHome(this.env, this.fs), "githits");
|
|
5061
|
+
this.cachePath = this.fs.joinPath(this.configDir, "update-check.json");
|
|
5062
|
+
}
|
|
5063
|
+
async checkForUpdate(signal) {
|
|
5064
|
+
const cache = await this.loadCache();
|
|
5065
|
+
const latestDue = !cache || this.isCheckDue(cache);
|
|
5066
|
+
const currentVersionStatusDue = this.isCurrentVersionStatusDue(cache?.currentVersionStatus);
|
|
5067
|
+
const currentVersionStatus = await this.refreshCurrentVersionStatusIfDue(cache?.currentVersionStatus, signal);
|
|
5068
|
+
const currentVersionStatusChanged = currentVersionStatusDue && !sameCurrentVersionStatus(currentVersionStatus, cache?.currentVersionStatus);
|
|
5069
|
+
if (cache && !latestDue) {
|
|
5070
|
+
if (currentVersionStatusChanged) {
|
|
5071
|
+
await this.saveCache({
|
|
5072
|
+
...cache,
|
|
5073
|
+
currentVersionStatus
|
|
5074
|
+
});
|
|
5075
|
+
}
|
|
5076
|
+
return this.noticeFromLatest(cache.latestVersion);
|
|
5077
|
+
}
|
|
5078
|
+
const latestVersion = await this.fetchLatestVersion(signal);
|
|
5079
|
+
if (!latestVersion) {
|
|
5080
|
+
if (currentVersionStatusChanged) {
|
|
5081
|
+
await this.saveCache({
|
|
5082
|
+
...cache,
|
|
5083
|
+
currentVersionStatus
|
|
5084
|
+
});
|
|
5085
|
+
}
|
|
5086
|
+
return this.noticeFromLatest(cache?.latestVersion);
|
|
5087
|
+
}
|
|
5088
|
+
await this.saveCache({
|
|
5089
|
+
checkedAt: this.now().toISOString(),
|
|
5090
|
+
latestVersion,
|
|
5091
|
+
currentVersionStatus
|
|
4325
5092
|
});
|
|
5093
|
+
return this.noticeFromLatest(latestVersion);
|
|
5094
|
+
}
|
|
5095
|
+
async refreshRequiredUpdateStatus(signal) {
|
|
5096
|
+
const cache = await this.loadCache();
|
|
5097
|
+
const currentVersionStatusDue = this.isCurrentVersionStatusDue(cache?.currentVersionStatus);
|
|
5098
|
+
const currentVersionStatus = await this.refreshCurrentVersionStatusIfDue(cache?.currentVersionStatus, signal);
|
|
5099
|
+
if (currentVersionStatusDue && !sameCurrentVersionStatus(currentVersionStatus, cache?.currentVersionStatus)) {
|
|
5100
|
+
await this.saveCache({
|
|
5101
|
+
...cache,
|
|
5102
|
+
currentVersionStatus
|
|
5103
|
+
});
|
|
5104
|
+
}
|
|
5105
|
+
}
|
|
5106
|
+
async getRequiredUpdateNotice() {
|
|
5107
|
+
const cache = await this.loadCache();
|
|
5108
|
+
const status = cache?.currentVersionStatus;
|
|
5109
|
+
if (!status || status.version !== this.currentVersion || !status.deprecatedReason) {
|
|
5110
|
+
return;
|
|
5111
|
+
}
|
|
5112
|
+
return {
|
|
5113
|
+
currentVersion: this.currentVersion,
|
|
5114
|
+
...cache.latestVersion ? { latestKnownVersion: cache.latestVersion } : {},
|
|
5115
|
+
reason: status.deprecatedReason,
|
|
5116
|
+
updateCommand: formatUpdateCommand(this.env)
|
|
5117
|
+
};
|
|
5118
|
+
}
|
|
5119
|
+
noticeFromLatest(latestVersion) {
|
|
5120
|
+
if (!latestVersion || !semver.valid(latestVersion) || !semver.valid(this.currentVersion) || !semver.gt(latestVersion, this.currentVersion)) {
|
|
5121
|
+
return;
|
|
5122
|
+
}
|
|
5123
|
+
return {
|
|
5124
|
+
currentVersion: this.currentVersion,
|
|
5125
|
+
latestVersion,
|
|
5126
|
+
updateCommand: UPDATE_COMMAND
|
|
5127
|
+
};
|
|
5128
|
+
}
|
|
5129
|
+
isCheckDue(cache) {
|
|
5130
|
+
if (!cache.checkedAt || !cache.latestVersion) {
|
|
5131
|
+
return true;
|
|
5132
|
+
}
|
|
5133
|
+
const checkedAtMs = Date.parse(cache.checkedAt);
|
|
5134
|
+
if (Number.isNaN(checkedAtMs)) {
|
|
5135
|
+
return true;
|
|
5136
|
+
}
|
|
5137
|
+
return this.now().getTime() - checkedAtMs >= this.checkIntervalMs;
|
|
5138
|
+
}
|
|
5139
|
+
isCurrentVersionStatusDue(status) {
|
|
5140
|
+
if (!status || status.version !== this.currentVersion) {
|
|
5141
|
+
return true;
|
|
5142
|
+
}
|
|
5143
|
+
const checkedAtMs = Date.parse(status.checkedAt);
|
|
5144
|
+
if (Number.isNaN(checkedAtMs)) {
|
|
5145
|
+
return true;
|
|
5146
|
+
}
|
|
5147
|
+
return this.now().getTime() - checkedAtMs >= this.checkIntervalMs;
|
|
5148
|
+
}
|
|
5149
|
+
async refreshCurrentVersionStatusIfDue(cached, signal) {
|
|
5150
|
+
const reusableCached = cached?.version === this.currentVersion ? cached : undefined;
|
|
5151
|
+
if (!this.isCurrentVersionStatusDue(reusableCached)) {
|
|
5152
|
+
return reusableCached;
|
|
5153
|
+
}
|
|
5154
|
+
const remote = await this.fetchCurrentVersionStatus(signal);
|
|
5155
|
+
if (!remote) {
|
|
5156
|
+
return reusableCached;
|
|
5157
|
+
}
|
|
5158
|
+
return remote;
|
|
5159
|
+
}
|
|
5160
|
+
async fetchLatestVersion(signal) {
|
|
5161
|
+
try {
|
|
5162
|
+
const timeoutSignal = AbortSignal.timeout(this.fetchTimeoutMs);
|
|
5163
|
+
const response = await this.fetcher(NPM_DIST_TAGS_URL, {
|
|
5164
|
+
signal: signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal
|
|
5165
|
+
});
|
|
5166
|
+
if (!response.ok) {
|
|
5167
|
+
return;
|
|
5168
|
+
}
|
|
5169
|
+
const body = await response.json();
|
|
5170
|
+
if (!body || typeof body !== "object" || typeof body.latest !== "string") {
|
|
5171
|
+
return;
|
|
5172
|
+
}
|
|
5173
|
+
const latest = body.latest;
|
|
5174
|
+
return semver.valid(latest) ? latest : undefined;
|
|
5175
|
+
} catch {
|
|
5176
|
+
return;
|
|
5177
|
+
}
|
|
5178
|
+
}
|
|
5179
|
+
async fetchCurrentVersionStatus(signal) {
|
|
5180
|
+
try {
|
|
5181
|
+
const timeoutSignal = AbortSignal.timeout(this.fetchTimeoutMs);
|
|
5182
|
+
const response = await this.fetcher(`${NPM_PACKAGE_VERSION_URL}/${this.currentVersion}`, {
|
|
5183
|
+
signal: signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal
|
|
5184
|
+
});
|
|
5185
|
+
if (!response.ok) {
|
|
5186
|
+
return;
|
|
5187
|
+
}
|
|
5188
|
+
const body = await response.json();
|
|
5189
|
+
if (!body || typeof body !== "object") {
|
|
5190
|
+
return;
|
|
5191
|
+
}
|
|
5192
|
+
const rawDeprecated = body.deprecated;
|
|
5193
|
+
const deprecatedReason = typeof rawDeprecated === "string" ? sanitizeDeprecationReason(rawDeprecated) : undefined;
|
|
5194
|
+
return {
|
|
5195
|
+
version: this.currentVersion,
|
|
5196
|
+
checkedAt: this.now().toISOString(),
|
|
5197
|
+
...deprecatedReason ? { deprecatedReason } : {}
|
|
5198
|
+
};
|
|
5199
|
+
} catch {
|
|
5200
|
+
return;
|
|
5201
|
+
}
|
|
5202
|
+
}
|
|
5203
|
+
async loadCache() {
|
|
5204
|
+
try {
|
|
5205
|
+
if (!await this.fs.exists(this.cachePath)) {
|
|
5206
|
+
return;
|
|
5207
|
+
}
|
|
5208
|
+
const raw = await this.fs.readFile(this.cachePath);
|
|
5209
|
+
const parsed = JSON.parse(raw);
|
|
5210
|
+
const currentVersionStatus = parseCurrentVersionStatus(parsed.currentVersionStatus);
|
|
5211
|
+
const hasLatest = typeof parsed.checkedAt === "string" && typeof parsed.latestVersion === "string";
|
|
5212
|
+
if (!hasLatest && !currentVersionStatus) {
|
|
5213
|
+
return;
|
|
5214
|
+
}
|
|
5215
|
+
return {
|
|
5216
|
+
...hasLatest ? {
|
|
5217
|
+
checkedAt: parsed.checkedAt,
|
|
5218
|
+
latestVersion: parsed.latestVersion
|
|
5219
|
+
} : {},
|
|
5220
|
+
currentVersionStatus
|
|
5221
|
+
};
|
|
5222
|
+
} catch {
|
|
5223
|
+
return;
|
|
5224
|
+
}
|
|
5225
|
+
}
|
|
5226
|
+
async saveCache(cache) {
|
|
5227
|
+
try {
|
|
5228
|
+
await this.fs.ensureDir(this.configDir, DIR_MODE2);
|
|
5229
|
+
if (typeof this.fs.atomicWriteFile === "function") {
|
|
5230
|
+
await this.fs.atomicWriteFile(this.cachePath, `${JSON.stringify(cache, null, 2)}
|
|
5231
|
+
`);
|
|
5232
|
+
return;
|
|
5233
|
+
}
|
|
5234
|
+
await this.fs.writeFile(this.cachePath, `${JSON.stringify(cache, null, 2)}
|
|
5235
|
+
`, 384);
|
|
5236
|
+
} catch {}
|
|
5237
|
+
}
|
|
5238
|
+
}
|
|
5239
|
+
function resolveConfigHome(env, fs) {
|
|
5240
|
+
const xdgConfigHome = env.XDG_CONFIG_HOME?.trim();
|
|
5241
|
+
if (xdgConfigHome) {
|
|
5242
|
+
return xdgConfigHome;
|
|
5243
|
+
}
|
|
5244
|
+
return fs.joinPath(fs.getHomeDir(), ".config");
|
|
5245
|
+
}
|
|
5246
|
+
function shouldRunUpdateCheck(input) {
|
|
5247
|
+
if (input.stderrIsTTY !== true) {
|
|
5248
|
+
return false;
|
|
5249
|
+
}
|
|
5250
|
+
const env = input.env ?? process.env;
|
|
5251
|
+
if (env.CI || env.GITHITS_DISABLE_UPDATE_CHECK) {
|
|
5252
|
+
return false;
|
|
5253
|
+
}
|
|
5254
|
+
if (isHelpOrVersionInvocation(input.args)) {
|
|
5255
|
+
return false;
|
|
5256
|
+
}
|
|
5257
|
+
if (isLikelyEphemeralPackageRunner(env)) {
|
|
5258
|
+
return false;
|
|
5259
|
+
}
|
|
5260
|
+
if (isMcpStdioInvocation(input.args, input.stdinIsTTY === true, input.stdoutIsTTY === true)) {
|
|
5261
|
+
return false;
|
|
5262
|
+
}
|
|
5263
|
+
return true;
|
|
5264
|
+
}
|
|
5265
|
+
function shouldRunRequiredUpdateEnforcement(input) {
|
|
5266
|
+
if (isHelpOrVersionInvocation(input.args)) {
|
|
5267
|
+
return false;
|
|
5268
|
+
}
|
|
5269
|
+
const env = input.env ?? process.env;
|
|
5270
|
+
if (isLikelyEphemeralPackageRunner(env)) {
|
|
5271
|
+
return false;
|
|
5272
|
+
}
|
|
5273
|
+
return true;
|
|
5274
|
+
}
|
|
5275
|
+
function formatUpdateNotice(notice) {
|
|
5276
|
+
return `Update available: githits ${notice.currentVersion} -> ${notice.latestVersion}
|
|
5277
|
+
Run: ${notice.updateCommand}`;
|
|
5278
|
+
}
|
|
5279
|
+
function formatRequiredUpdateNotice(notice) {
|
|
5280
|
+
const lines = [
|
|
5281
|
+
`Update required: ${notice.reason}`,
|
|
5282
|
+
"",
|
|
5283
|
+
`Installed githits ${notice.currentVersion} is no longer supported.`
|
|
5284
|
+
];
|
|
5285
|
+
if (notice.latestKnownVersion) {
|
|
5286
|
+
lines.push(`Latest known version: ${notice.latestKnownVersion}`);
|
|
5287
|
+
}
|
|
5288
|
+
lines.push("Update with:", ` ${notice.updateCommand}`);
|
|
5289
|
+
return [...lines].join(`
|
|
5290
|
+
`);
|
|
5291
|
+
}
|
|
5292
|
+
function formatUpdateCommand(env = process.env) {
|
|
5293
|
+
const userAgent = env.npm_config_user_agent ?? "";
|
|
5294
|
+
const execPath = env.npm_execpath ?? "";
|
|
5295
|
+
const signal = `${userAgent} ${execPath}`.toLowerCase();
|
|
5296
|
+
if (signal.includes("pnpm")) {
|
|
5297
|
+
return "pnpm add -g githits@latest";
|
|
5298
|
+
}
|
|
5299
|
+
if (signal.includes("yarn")) {
|
|
5300
|
+
return "yarn global add githits@latest";
|
|
5301
|
+
}
|
|
5302
|
+
if (signal.includes("bun")) {
|
|
5303
|
+
return "bun add -g githits@latest";
|
|
5304
|
+
}
|
|
5305
|
+
return UPDATE_COMMAND;
|
|
5306
|
+
}
|
|
5307
|
+
function parseCurrentVersionStatus(value) {
|
|
5308
|
+
if (!value || typeof value !== "object") {
|
|
5309
|
+
return;
|
|
5310
|
+
}
|
|
5311
|
+
const status = value;
|
|
5312
|
+
if (typeof status.version !== "string") {
|
|
5313
|
+
return;
|
|
5314
|
+
}
|
|
5315
|
+
if (typeof status.checkedAt !== "string") {
|
|
5316
|
+
return;
|
|
5317
|
+
}
|
|
5318
|
+
const deprecatedReason = typeof status.deprecatedReason === "string" ? sanitizeDeprecationReason(status.deprecatedReason) : undefined;
|
|
5319
|
+
return {
|
|
5320
|
+
version: status.version,
|
|
5321
|
+
checkedAt: status.checkedAt,
|
|
5322
|
+
...deprecatedReason ? { deprecatedReason } : {}
|
|
5323
|
+
};
|
|
5324
|
+
}
|
|
5325
|
+
function sameCurrentVersionStatus(left, right) {
|
|
5326
|
+
return left?.version === right?.version && left?.checkedAt === right?.checkedAt && left?.deprecatedReason === right?.deprecatedReason;
|
|
5327
|
+
}
|
|
5328
|
+
function sanitizeDeprecationReason(value) {
|
|
5329
|
+
const sanitized = Array.from(value).map((character) => isControlCharacter(character) ? " " : character).join("").replace(/\s+/g, " ").trim().slice(0, MAX_DEPRECATION_REASON_LENGTH).trim();
|
|
5330
|
+
return sanitized.length > 0 ? sanitized : undefined;
|
|
5331
|
+
}
|
|
5332
|
+
function isControlCharacter(value) {
|
|
5333
|
+
const code = value.charCodeAt(0);
|
|
5334
|
+
return code <= 31 || code >= 127 && code <= 159;
|
|
5335
|
+
}
|
|
5336
|
+
function isHelpOrVersionInvocation(args) {
|
|
5337
|
+
return args.length === 0 || args[0] === "help" || args.includes("--help") || args.includes("-h") || args.includes("--version") || args.includes("-V");
|
|
5338
|
+
}
|
|
5339
|
+
function isLikelyEphemeralPackageRunner(env) {
|
|
5340
|
+
const lifecycleEvent = env.npm_lifecycle_event;
|
|
5341
|
+
if (lifecycleEvent === "npx" || lifecycleEvent === "bunx") {
|
|
5342
|
+
return true;
|
|
5343
|
+
}
|
|
5344
|
+
const userAgent = env.npm_config_user_agent ?? "";
|
|
5345
|
+
return env.npm_command === "exec" && (userAgent.startsWith("npm/") || userAgent.startsWith("bun/"));
|
|
5346
|
+
}
|
|
5347
|
+
function isMcpStdioInvocation(args, stdinIsTTY, stdoutIsTTY) {
|
|
5348
|
+
const firstTokenIndex = args.findIndex((arg) => !arg.startsWith("-"));
|
|
5349
|
+
if (firstTokenIndex === -1 || args[firstTokenIndex] !== "mcp") {
|
|
5350
|
+
return false;
|
|
5351
|
+
}
|
|
5352
|
+
const remainingArgs = args.slice(firstTokenIndex + 1);
|
|
5353
|
+
return remainingArgs.includes("start") || !stdinIsTTY || !stdoutIsTTY;
|
|
5354
|
+
}
|
|
5355
|
+
// src/container.ts
|
|
5356
|
+
async function createAuthStorage(fileSystemService) {
|
|
5357
|
+
return withTelemetrySpan("container.create-auth-storage", async () => {
|
|
5358
|
+
const authConfig = await loadAuthConfig(fileSystemService);
|
|
5359
|
+
return createAuthStorageForMode(fileSystemService, authConfig.storage, authConfig.configPath);
|
|
5360
|
+
});
|
|
5361
|
+
}
|
|
5362
|
+
function createAuthStorageForMode(fileSystemService, mode, configPath = "your GitHits config.toml") {
|
|
5363
|
+
const fileStorage = new ModeAwareFileAuthStorage(new AuthStorageImpl(fileSystemService, getAuthFileStorageDir(fileSystemService)), mode, configPath);
|
|
5364
|
+
const legacyStorage = new AuthStorageImpl(fileSystemService, getLegacyAuthStorageDir(fileSystemService));
|
|
5365
|
+
const rawKeyring = new KeyringServiceImpl;
|
|
5366
|
+
const keyring = process.platform === "win32" ? new ChunkingKeyringService(rawKeyring, WINDOWS_MAX_ENTRY_SIZE) : rawKeyring;
|
|
5367
|
+
const keychainStorage = new KeychainAuthStorage(keyring);
|
|
5368
|
+
return new LockedAuthStorage(new MigratingAuthStorage(keychainStorage, fileStorage, legacyStorage, mode, configPath, (message) => console.error(message)), fileSystemService);
|
|
5369
|
+
}
|
|
5370
|
+
async function createAuthCommandDependencies() {
|
|
5371
|
+
return withTelemetrySpan("container.create-auth-command", async () => {
|
|
5372
|
+
const fileSystemService = new FileSystemServiceImpl;
|
|
5373
|
+
return {
|
|
5374
|
+
authStorage: await createAuthStorage(fileSystemService),
|
|
5375
|
+
authService: new AuthServiceImpl,
|
|
5376
|
+
browserService: new BrowserServiceImpl,
|
|
5377
|
+
fileSystemService,
|
|
5378
|
+
mcpUrl: getMcpUrl(),
|
|
5379
|
+
apiUrl: getApiUrl(),
|
|
5380
|
+
envApiToken: getEnvApiToken()
|
|
5381
|
+
};
|
|
5382
|
+
});
|
|
5383
|
+
}
|
|
5384
|
+
async function createAuthStatusDependencies() {
|
|
5385
|
+
return withTelemetrySpan("container.create-auth-status", async () => {
|
|
5386
|
+
const fileSystemService = new FileSystemServiceImpl;
|
|
5387
|
+
const envApiToken = getEnvApiToken();
|
|
5388
|
+
return {
|
|
5389
|
+
authStorage: envApiToken ? createAuthStorageForMode(fileSystemService, "keychain") : await createAuthStorage(fileSystemService),
|
|
5390
|
+
authService: new AuthServiceImpl,
|
|
5391
|
+
browserService: new BrowserServiceImpl,
|
|
5392
|
+
fileSystemService,
|
|
5393
|
+
mcpUrl: getMcpUrl(),
|
|
5394
|
+
apiUrl: getApiUrl(),
|
|
5395
|
+
envApiToken
|
|
5396
|
+
};
|
|
4326
5397
|
});
|
|
4327
5398
|
}
|
|
4328
5399
|
function createStaticTokenProvider(token) {
|
|
@@ -4338,18 +5409,17 @@ async function createContainer() {
|
|
|
4338
5409
|
const mcpUrl = getMcpUrl();
|
|
4339
5410
|
const apiUrl = getApiUrl();
|
|
4340
5411
|
const codeNavigationUrl = getCodeNavigationUrl();
|
|
4341
|
-
const codeNavigationCliOverrideEnabled = isCodeNavigationCliOverrideEnabled();
|
|
4342
5412
|
const fileSystemService = new FileSystemServiceImpl;
|
|
4343
|
-
const authStorage = createAuthStorage(fileSystemService);
|
|
4344
5413
|
const authService = new AuthServiceImpl;
|
|
4345
5414
|
const browserService = new BrowserServiceImpl;
|
|
4346
5415
|
const envToken = getEnvApiToken();
|
|
4347
5416
|
if (envToken) {
|
|
5417
|
+
const authStorage2 = createAuthStorageForMode(fileSystemService, "keychain");
|
|
4348
5418
|
const tokenProvider = createStaticTokenProvider(envToken);
|
|
4349
|
-
const codeNavigationService2 =
|
|
4350
|
-
const packageIntelligenceService2 =
|
|
5419
|
+
const codeNavigationService2 = new CodeNavigationServiceImpl(codeNavigationUrl, tokenProvider);
|
|
5420
|
+
const packageIntelligenceService2 = new PackageIntelligenceServiceImpl(codeNavigationUrl, tokenProvider);
|
|
4351
5421
|
return {
|
|
4352
|
-
authStorage,
|
|
5422
|
+
authStorage: authStorage2,
|
|
4353
5423
|
authService,
|
|
4354
5424
|
browserService,
|
|
4355
5425
|
fileSystemService,
|
|
@@ -4358,18 +5428,17 @@ async function createContainer() {
|
|
|
4358
5428
|
apiToken: envToken,
|
|
4359
5429
|
hasValidToken: true,
|
|
4360
5430
|
envApiToken: envToken,
|
|
4361
|
-
codeNavigationCapability: getCodeNavigationCapability(envToken),
|
|
4362
|
-
codeNavigationCliOverrideEnabled,
|
|
4363
5431
|
codeNavigationUrl,
|
|
4364
5432
|
codeNavigationService: codeNavigationService2,
|
|
4365
5433
|
packageIntelligenceService: packageIntelligenceService2,
|
|
4366
5434
|
githitsService: new GitHitsServiceImpl(apiUrl, envToken)
|
|
4367
5435
|
};
|
|
4368
5436
|
}
|
|
5437
|
+
const authStorage = await createAuthStorage(fileSystemService);
|
|
4369
5438
|
const tokenManager = new TokenManager({ authService, authStorage, mcpUrl });
|
|
4370
5439
|
const apiToken = await withTelemetrySpan("container.token.get", () => tokenManager.getToken());
|
|
4371
|
-
const codeNavigationService =
|
|
4372
|
-
const packageIntelligenceService =
|
|
5440
|
+
const codeNavigationService = new CodeNavigationServiceImpl(codeNavigationUrl, tokenManager);
|
|
5441
|
+
const packageIntelligenceService = new PackageIntelligenceServiceImpl(codeNavigationUrl, tokenManager);
|
|
4373
5442
|
return {
|
|
4374
5443
|
authStorage,
|
|
4375
5444
|
authService,
|
|
@@ -4380,8 +5449,6 @@ async function createContainer() {
|
|
|
4380
5449
|
apiToken,
|
|
4381
5450
|
hasValidToken: apiToken !== undefined,
|
|
4382
5451
|
envApiToken: undefined,
|
|
4383
|
-
codeNavigationCapability: getCodeNavigationCapability(apiToken),
|
|
4384
|
-
codeNavigationCliOverrideEnabled,
|
|
4385
5452
|
codeNavigationUrl,
|
|
4386
5453
|
codeNavigationService,
|
|
4387
5454
|
packageIntelligenceService,
|
|
@@ -4389,48 +5456,5 @@ async function createContainer() {
|
|
|
4389
5456
|
};
|
|
4390
5457
|
});
|
|
4391
5458
|
}
|
|
4392
|
-
async function resolveStartupCodeNavigationCapability() {
|
|
4393
|
-
const state = await resolveStartupCodeNavigationRegistrationState();
|
|
4394
|
-
return state.capability;
|
|
4395
|
-
}
|
|
4396
|
-
async function resolveStartupCodeNavigationRegistrationState() {
|
|
4397
|
-
return withTelemetrySpan("startup.resolve-code-nav-registration-state", async () => {
|
|
4398
|
-
const envToken = getEnvApiToken();
|
|
4399
|
-
if (envToken) {
|
|
4400
|
-
return {
|
|
4401
|
-
capability: getCodeNavigationCapability(envToken),
|
|
4402
|
-
expiredStoredAuth: false
|
|
4403
|
-
};
|
|
4404
|
-
}
|
|
4405
|
-
const tokens = await loadStartupTokens(getMcpUrl());
|
|
4406
|
-
if (tokens?.expiresAt && new Date(tokens.expiresAt) < new Date) {
|
|
4407
|
-
return { capability: "unknown", expiredStoredAuth: true };
|
|
4408
|
-
}
|
|
4409
|
-
return {
|
|
4410
|
-
capability: getCodeNavigationCapability(tokens?.accessToken),
|
|
4411
|
-
expiredStoredAuth: false
|
|
4412
|
-
};
|
|
4413
|
-
});
|
|
4414
|
-
}
|
|
4415
|
-
async function loadStartupTokens(mcpUrl) {
|
|
4416
|
-
return withTelemetrySpan("startup.load-tokens", async () => {
|
|
4417
|
-
const fileSystemService = new FileSystemServiceImpl;
|
|
4418
|
-
const fileStorage = new AuthStorageImpl(fileSystemService);
|
|
4419
|
-
try {
|
|
4420
|
-
const rawKeyring = new KeyringServiceImpl;
|
|
4421
|
-
const keyring = process.platform === "win32" ? new ChunkingKeyringService(rawKeyring, WINDOWS_MAX_ENTRY_SIZE) : rawKeyring;
|
|
4422
|
-
const keychainStorage = new KeychainAuthStorage(keyring);
|
|
4423
|
-
const keychainTokens = await keychainStorage.loadTokens(mcpUrl);
|
|
4424
|
-
if (keychainTokens) {
|
|
4425
|
-
return keychainTokens;
|
|
4426
|
-
}
|
|
4427
|
-
} catch (error) {
|
|
4428
|
-
if (!(error instanceof KeychainUnavailableError)) {
|
|
4429
|
-
throw error;
|
|
4430
|
-
}
|
|
4431
|
-
}
|
|
4432
|
-
return fileStorage.loadTokens(mcpUrl);
|
|
4433
|
-
});
|
|
4434
|
-
}
|
|
4435
5459
|
|
|
4436
|
-
export {
|
|
5460
|
+
export { AuthConfigError, CLIENT_UPDATE_REQUIRED_REASON, ClientUpdateRequiredError, debugLog, setMcpClientVersionProvider, setClientMode, isTelemetryEnabled, withTelemetrySpan, startTelemetrySpan, endTelemetrySpan, flushTelemetry, AuthenticationError, CodeNavigationAccessError, CodeNavigationGraphQLError, CodeNavigationIndexingError, CodeNavigationUnresolvableError, MalformedCodeNavigationResponseError, CodeNavigationTargetNotFoundError, CodeNavigationFileNotFoundError, CodeNavigationVersionNotFoundError, CodeNavigationValidationError, CodeNavigationFeatureFlagRequiredError, CodeNavigationNetworkError, CodeNavigationBackendError, getCodeNavigationUrl, ExecServiceImpl, FileSystemServiceImpl, AuthStorageLockTimeoutError, AuthStoragePolicyError, PackageIntelligenceAccessError, PackageIntelligenceFeatureFlagRequiredError, PackageIntelligenceNetworkError, PackageIntelligenceBackendError, PackageIntelligenceGraphQLError, PackageIntelligenceTargetNotFoundError, PackageIntelligenceValidationError, PackageIntelligenceVersionNotFoundError, MalformedPackageIntelligenceResponseError, PackageIntelligenceChangelogSourceNotFoundError, PromptServiceImpl, refreshExpiredToken, NpmRegistryUpdateCheckService, shouldRunUpdateCheck, shouldRunRequiredUpdateEnforcement, formatUpdateNotice, formatRequiredUpdateNotice, createAuthCommandDependencies, createAuthStatusDependencies, createContainer };
|