inup 1.5.5 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -10
- package/dist/cli.js +53 -31
- package/dist/config/constants.js +4 -6
- package/dist/config/package-meta.js +10 -0
- package/dist/config/project-config.js +11 -1
- package/dist/core/package-detector.js +37 -5
- package/dist/core/upgrade-runner.js +8 -10
- package/dist/core/upgrader.js +15 -11
- package/dist/features/changelog/clients/github-client.js +5 -6
- package/dist/features/changelog/services/changelog-service.js +2 -4
- package/dist/features/changelog/services/package-metadata-service.js +7 -23
- package/dist/features/changelog/services/release-notes-service.js +4 -29
- package/dist/features/debug/services/performance-tracker.js +6 -8
- package/dist/features/headless/headless-runner.js +53 -0
- package/dist/features/headless/index.js +27 -0
- package/dist/features/headless/report.js +64 -0
- package/dist/features/headless/types.js +6 -0
- package/dist/features/headless/vulnerability-audit.js +106 -0
- package/dist/index.js +1 -2
- package/dist/interactive-ui.js +15 -606
- package/dist/services/background-audit.js +3 -5
- package/dist/services/cache-manager.js +5 -7
- package/dist/services/http/inflight.js +22 -0
- package/dist/services/http/retry.js +30 -0
- package/dist/services/index.js +0 -1
- package/dist/services/npm-registry.js +20 -97
- package/dist/services/package-manager-detector.js +6 -3
- package/dist/services/persistent-cache.js +8 -13
- package/dist/types/domain.js +3 -0
- package/dist/types/streaming.js +3 -0
- package/dist/types/ui.js +3 -0
- package/dist/types.js +17 -0
- package/dist/ui/controllers/package-info-modal-controller.js +22 -31
- package/dist/ui/controllers/vulnerability-audit-controller.js +17 -8
- package/dist/ui/index.js +3 -0
- package/dist/ui/input-handler.js +58 -75
- package/dist/ui/keymap.js +208 -0
- package/dist/ui/modal/package-info-sections/release-notes.js +161 -0
- package/dist/ui/modal/package-info-sections/sections.js +174 -0
- package/dist/ui/modal/package-info-sections/text.js +75 -0
- package/dist/ui/modal/package-info-sections.js +15 -369
- package/dist/ui/modal/package-info.js +1 -1
- package/dist/ui/presenters/health.js +24 -0
- package/dist/ui/renderer/help-modal.js +75 -0
- package/dist/ui/renderer/index.js +2 -5
- package/dist/ui/renderer/package-list/interface.js +184 -0
- package/dist/ui/renderer/package-list/rows.js +177 -0
- package/dist/ui/renderer/package-list.js +15 -455
- package/dist/ui/session/action-dispatcher.js +233 -0
- package/dist/ui/session/index.js +13 -0
- package/dist/ui/session/interactive-session.js +280 -0
- package/dist/ui/session/selection-state-builder.js +149 -0
- package/dist/ui/state/filter-manager.js +17 -6
- package/dist/ui/state/modal-manager.js +35 -0
- package/dist/ui/state/navigation-manager.js +33 -4
- package/dist/ui/state/state-manager.js +68 -3
- package/dist/ui/state/theme-manager.js +1 -0
- package/dist/ui/themes-colors.js +16 -4
- package/dist/ui/themes.js +11 -19
- package/dist/ui/utils/cursor.js +12 -7
- package/dist/ui/utils/index.js +6 -1
- package/dist/ui/utils/text.js +3 -2
- package/dist/ui/utils/version.js +60 -86
- package/dist/utils/color.js +38 -0
- package/dist/utils/config.js +13 -1
- package/dist/utils/engines.js +63 -0
- package/dist/utils/filesystem/io.js +103 -0
- package/dist/utils/filesystem/paths.js +19 -0
- package/dist/utils/filesystem/scan.js +280 -0
- package/dist/utils/filesystem.js +17 -335
- package/dist/utils/index.js +3 -0
- package/dist/utils/manifest.js +35 -0
- package/dist/utils/version.js +38 -1
- package/package.json +8 -7
- package/dist/services/jsdelivr-registry.js +0 -395
|
@@ -3,11 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.BackgroundAuditTracker = void 0;
|
|
4
4
|
const utils_1 = require("../utils");
|
|
5
5
|
class BackgroundAuditTracker {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
this.completed = new Set();
|
|
10
|
-
}
|
|
6
|
+
pending = new Map();
|
|
7
|
+
inFlight = new Set();
|
|
8
|
+
completed = new Set();
|
|
11
9
|
enqueue(packages) {
|
|
12
10
|
let added = 0;
|
|
13
11
|
for (const pkg of packages) {
|
|
@@ -3,13 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.packageCache = exports.CacheManager = void 0;
|
|
4
4
|
const config_1 = require("../config");
|
|
5
5
|
const persistent_cache_1 = require("./persistent-cache");
|
|
6
|
-
|
|
7
|
-
* Unified cache manager that handles both in-memory and persistent disk caching.
|
|
8
|
-
* Consolidates caching logic used across registry services.
|
|
9
|
-
*/
|
|
6
|
+
// Single TTL policy for both memory and disk.
|
|
10
7
|
class CacheManager {
|
|
8
|
+
memoryCache = new Map();
|
|
9
|
+
ttl;
|
|
11
10
|
constructor(ttl = config_1.CACHE_TTL) {
|
|
12
|
-
this.memoryCache = new Map();
|
|
13
11
|
this.ttl = ttl;
|
|
14
12
|
}
|
|
15
13
|
/**
|
|
@@ -24,11 +22,11 @@ class CacheManager {
|
|
|
24
22
|
}
|
|
25
23
|
// Check persistent disk cache (survives restarts)
|
|
26
24
|
const diskCached = persistent_cache_1.persistentCache.get(key);
|
|
27
|
-
if (diskCached) {
|
|
25
|
+
if (diskCached && Date.now() - diskCached.timestamp < this.ttl) {
|
|
28
26
|
// Populate in-memory cache for subsequent accesses
|
|
29
27
|
this.memoryCache.set(key, {
|
|
30
28
|
data: diskCached,
|
|
31
|
-
timestamp:
|
|
29
|
+
timestamp: diskCached.timestamp,
|
|
32
30
|
});
|
|
33
31
|
return diskCached;
|
|
34
32
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InflightMap = void 0;
|
|
4
|
+
class InflightMap {
|
|
5
|
+
map = new Map();
|
|
6
|
+
async dedupe(key, fn) {
|
|
7
|
+
const existing = this.map.get(key);
|
|
8
|
+
if (existing) {
|
|
9
|
+
return await existing;
|
|
10
|
+
}
|
|
11
|
+
const promise = fn().finally(() => {
|
|
12
|
+
this.map.delete(key);
|
|
13
|
+
});
|
|
14
|
+
this.map.set(key, promise);
|
|
15
|
+
return await promise;
|
|
16
|
+
}
|
|
17
|
+
clear() {
|
|
18
|
+
this.map.clear();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.InflightMap = InflightMap;
|
|
22
|
+
//# sourceMappingURL=inflight.js.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isTransientNetworkError = exports.isRetryableStatus = exports.sleep = void 0;
|
|
4
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
5
|
+
exports.sleep = sleep;
|
|
6
|
+
const isRetryableStatus = (statusCode) => statusCode === 408 || statusCode === 429 || statusCode >= 500;
|
|
7
|
+
exports.isRetryableStatus = isRetryableStatus;
|
|
8
|
+
const isTransientNetworkError = (error) => {
|
|
9
|
+
if (!(error instanceof Error)) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
const maybeCode = error.code;
|
|
13
|
+
return (error.name === 'AbortError' ||
|
|
14
|
+
error.name === 'HeadersTimeoutError' ||
|
|
15
|
+
error.name === 'BodyTimeoutError' ||
|
|
16
|
+
error.name === 'ConnectTimeoutError' ||
|
|
17
|
+
error.name === 'SocketError' ||
|
|
18
|
+
maybeCode === 'UND_ERR_HEADERS_TIMEOUT' ||
|
|
19
|
+
maybeCode === 'UND_ERR_BODY_TIMEOUT' ||
|
|
20
|
+
maybeCode === 'UND_ERR_CONNECT_TIMEOUT' ||
|
|
21
|
+
maybeCode === 'UND_ERR_SOCKET' ||
|
|
22
|
+
maybeCode === 'ENOTFOUND' ||
|
|
23
|
+
maybeCode === 'EAI_AGAIN' ||
|
|
24
|
+
maybeCode === 'ECONNRESET' ||
|
|
25
|
+
maybeCode === 'ECONNREFUSED' ||
|
|
26
|
+
maybeCode === 'ETIMEDOUT' ||
|
|
27
|
+
maybeCode === 'EPIPE');
|
|
28
|
+
};
|
|
29
|
+
exports.isTransientNetworkError = isTransientNetworkError;
|
|
30
|
+
//# sourceMappingURL=retry.js.map
|
package/dist/services/index.js
CHANGED
|
@@ -18,7 +18,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
18
18
|
};
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
20
|
__exportStar(require("./npm-registry"), exports);
|
|
21
|
-
__exportStar(require("./jsdelivr-registry"), exports);
|
|
22
21
|
__exportStar(require("../features/changelog"), exports);
|
|
23
22
|
__exportStar(require("./version-checker"), exports);
|
|
24
23
|
__exportStar(require("./vulnerability-checker"), exports);
|
|
@@ -1,42 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
3
|
exports.fetchPackageVersions = fetchPackageVersions;
|
|
37
4
|
exports.clearPackageCache = clearPackageCache;
|
|
38
5
|
exports.closeRegistryPool = closeRegistryPool;
|
|
39
|
-
const semver = __importStar(require("semver"));
|
|
40
6
|
const undici_1 = require("undici");
|
|
41
7
|
const node_zlib_1 = require("node:zlib");
|
|
42
8
|
const node_util_1 = require("node:util");
|
|
@@ -44,8 +10,10 @@ const gunzipAsync = (0, node_util_1.promisify)(node_zlib_1.gunzip);
|
|
|
44
10
|
const inflateAsync = (0, node_util_1.promisify)(node_zlib_1.inflate);
|
|
45
11
|
const brotliDecompressAsync = (0, node_util_1.promisify)(node_zlib_1.brotliDecompress);
|
|
46
12
|
const config_1 = require("../config");
|
|
47
|
-
const
|
|
48
|
-
const
|
|
13
|
+
const version_1 = require("../utils/version");
|
|
14
|
+
const retry_1 = require("./http/retry");
|
|
15
|
+
const inflight_1 = require("./http/inflight");
|
|
16
|
+
const inFlightLookups = new inflight_1.InflightMap();
|
|
49
17
|
const registryOrigin = new URL(config_1.NPM_REGISTRY_URL).origin;
|
|
50
18
|
const registryPathPrefix = new URL(config_1.NPM_REGISTRY_URL).pathname.replace(/\/$/, '');
|
|
51
19
|
// Few connections + many requests per connection = maximum keep-alive reuse.
|
|
@@ -54,60 +22,18 @@ const registryPathPrefix = new URL(config_1.NPM_REGISTRY_URL).pathname.replace(/
|
|
|
54
22
|
const registryPool = new undici_1.Pool(registryOrigin, {
|
|
55
23
|
connections: 6,
|
|
56
24
|
pipelining: 1,
|
|
57
|
-
keepAliveTimeout:
|
|
58
|
-
keepAliveMaxTimeout:
|
|
25
|
+
keepAliveTimeout: 30_000,
|
|
26
|
+
keepAliveMaxTimeout: 600_000,
|
|
59
27
|
headersTimeout: 0,
|
|
60
28
|
bodyTimeout: 0,
|
|
61
|
-
connectTimeout:
|
|
29
|
+
connectTimeout: 15_000,
|
|
62
30
|
allowH2: false,
|
|
63
31
|
});
|
|
64
32
|
const MAX_REGISTRY_ATTEMPTS = 3;
|
|
65
33
|
const RETRY_BACKOFF_MS = [500, 1500, 3000];
|
|
66
|
-
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
67
|
-
const isRetryableStatus = (statusCode) => statusCode === 408 || statusCode === 429 || statusCode >= 500;
|
|
68
|
-
const isTransientNetworkError = (error) => {
|
|
69
|
-
if (!(error instanceof Error)) {
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
const maybeCode = error.code;
|
|
73
|
-
return (error.name === 'AbortError' ||
|
|
74
|
-
error.name === 'HeadersTimeoutError' ||
|
|
75
|
-
error.name === 'BodyTimeoutError' ||
|
|
76
|
-
error.name === 'ConnectTimeoutError' ||
|
|
77
|
-
error.name === 'SocketError' ||
|
|
78
|
-
maybeCode === 'UND_ERR_HEADERS_TIMEOUT' ||
|
|
79
|
-
maybeCode === 'UND_ERR_BODY_TIMEOUT' ||
|
|
80
|
-
maybeCode === 'UND_ERR_CONNECT_TIMEOUT' ||
|
|
81
|
-
maybeCode === 'UND_ERR_SOCKET' ||
|
|
82
|
-
maybeCode === 'ENOTFOUND' ||
|
|
83
|
-
maybeCode === 'EAI_AGAIN' ||
|
|
84
|
-
maybeCode === 'ECONNRESET' ||
|
|
85
|
-
maybeCode === 'ECONNREFUSED' ||
|
|
86
|
-
maybeCode === 'ETIMEDOUT' ||
|
|
87
|
-
maybeCode === 'EPIPE');
|
|
88
|
-
};
|
|
89
|
-
const fetchFromJsdelivrFallback = async (packageName, currentVersion) => {
|
|
90
|
-
const jsdelivrData = await (0, jsdelivr_registry_1.getAllPackageDataFromJsdelivr)([packageName], currentVersion ? new Map([[packageName, currentVersion]]) : undefined);
|
|
91
|
-
return jsdelivrData.get(packageName) ?? { latestVersion: 'unknown', allVersions: [] };
|
|
92
|
-
};
|
|
93
34
|
async function getFreshPackageData(packageName, currentVersion) {
|
|
94
35
|
const cacheKey = `${packageName}@${currentVersion ?? ''}`;
|
|
95
|
-
|
|
96
|
-
if (inFlight) {
|
|
97
|
-
return await inFlight;
|
|
98
|
-
}
|
|
99
|
-
const lookupPromise = fetchPackageFromRegistryWithFallback(packageName, currentVersion).finally(() => {
|
|
100
|
-
inFlightLookups.delete(cacheKey);
|
|
101
|
-
});
|
|
102
|
-
inFlightLookups.set(cacheKey, lookupPromise);
|
|
103
|
-
return await lookupPromise;
|
|
104
|
-
}
|
|
105
|
-
function parseVersions(raw) {
|
|
106
|
-
const data = JSON.parse(raw);
|
|
107
|
-
const allVersions = Object.keys(data.versions || {}).filter((v) => /^[0-9]+\.[0-9]+\.[0-9]+$/.test(v));
|
|
108
|
-
const sortedVersions = allVersions.sort(semver.rcompare);
|
|
109
|
-
const latestVersion = sortedVersions.length > 0 ? sortedVersions[0] : 'unknown';
|
|
110
|
-
return { latestVersion, allVersions };
|
|
36
|
+
return inFlightLookups.dedupe(cacheKey, () => fetchPackageFromRegistry(packageName));
|
|
111
37
|
}
|
|
112
38
|
const encodeRegistryPath = (packageName) => {
|
|
113
39
|
const encodedName = packageName.startsWith('@')
|
|
@@ -130,7 +56,7 @@ async function attemptRegistryFetch(path) {
|
|
|
130
56
|
});
|
|
131
57
|
if (statusCode < 200 || statusCode >= 300) {
|
|
132
58
|
await body.dump().catch(() => undefined);
|
|
133
|
-
if (isRetryableStatus(statusCode)) {
|
|
59
|
+
if ((0, retry_1.isRetryableStatus)(statusCode)) {
|
|
134
60
|
return { kind: 'retryable' };
|
|
135
61
|
}
|
|
136
62
|
return { kind: 'not-found' };
|
|
@@ -153,10 +79,10 @@ async function attemptRegistryFetch(path) {
|
|
|
153
79
|
else {
|
|
154
80
|
decoded = raw;
|
|
155
81
|
}
|
|
156
|
-
return { kind: 'success', data: parseVersions(decoded.toString('utf8')) };
|
|
82
|
+
return { kind: 'success', data: (0, version_1.parseVersions)(decoded.toString('utf8')) };
|
|
157
83
|
}
|
|
158
84
|
catch (error) {
|
|
159
|
-
if (isTransientNetworkError(error)) {
|
|
85
|
+
if ((0, retry_1.isTransientNetworkError)(error)) {
|
|
160
86
|
return { kind: 'transient' };
|
|
161
87
|
}
|
|
162
88
|
// Unknown error: treat as transient so we try the fallback rather than
|
|
@@ -174,24 +100,20 @@ async function fetchFromRegistryWithRetries(path) {
|
|
|
174
100
|
lastOutcome = outcome;
|
|
175
101
|
if (attempt < MAX_REGISTRY_ATTEMPTS - 1) {
|
|
176
102
|
const backoff = RETRY_BACKOFF_MS[Math.min(attempt, RETRY_BACKOFF_MS.length - 1)];
|
|
177
|
-
await sleep(backoff);
|
|
103
|
+
await (0, retry_1.sleep)(backoff);
|
|
178
104
|
}
|
|
179
105
|
}
|
|
180
106
|
return lastOutcome;
|
|
181
107
|
}
|
|
182
|
-
async function
|
|
108
|
+
async function fetchPackageFromRegistry(packageName) {
|
|
183
109
|
const path = encodeRegistryPath(packageName);
|
|
184
110
|
const outcome = await fetchFromRegistryWithRetries(path);
|
|
185
111
|
if (outcome.kind === 'success') {
|
|
186
112
|
return outcome.data;
|
|
187
113
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
191
|
-
// Only reach here after exhausted retries against real errors — try jsdelivr
|
|
192
|
-
// as last-resort safety net so we don't silently return 'unknown'.
|
|
193
|
-
const fallback = await fetchFromJsdelivrFallback(packageName, currentVersion).catch(() => null);
|
|
194
|
-
return fallback ?? { latestVersion: 'unknown', allVersions: [] };
|
|
114
|
+
// Not found, or exhausted retries against real errors: report unavailable.
|
|
115
|
+
// The registry is the single source of truth — there is no secondary fetch.
|
|
116
|
+
return { latestVersion: 'unknown', allVersions: [] };
|
|
195
117
|
}
|
|
196
118
|
/**
|
|
197
119
|
* Fetches version data for a list of packages from the npm registry.
|
|
@@ -201,9 +123,10 @@ async function fetchPackageFromRegistryWithFallback(packageName, currentVersion)
|
|
|
201
123
|
* It doesn't interact with batch size — batches exist only to group
|
|
202
124
|
* emissions for the UI.
|
|
203
125
|
* - No per-request timeouts: slow responses are allowed to finish. Real
|
|
204
|
-
* network errors are retried with exponential backoff; after
|
|
205
|
-
*
|
|
206
|
-
* dropped due to
|
|
126
|
+
* network errors are retried with exponential backoff; after the retry
|
|
127
|
+
* budget is exhausted the package is reported as unavailable
|
|
128
|
+
* (`latestVersion: 'unknown'`). A result is never silently dropped due to
|
|
129
|
+
* slowness.
|
|
207
130
|
*
|
|
208
131
|
* Callbacks:
|
|
209
132
|
* - `onBatchReady` fires once a whole emission batch has resolved, in
|
|
@@ -56,8 +56,8 @@ class PackageManagerDetector {
|
|
|
56
56
|
if (fromLockFile) {
|
|
57
57
|
return fromLockFile;
|
|
58
58
|
}
|
|
59
|
-
// 3. Fallback to npm
|
|
60
|
-
console.
|
|
59
|
+
// 3. Fallback to npm. Warn on stderr so it never corrupts --json output on stdout.
|
|
60
|
+
console.error(chalk_1.default.yellow('⚠️ No package manager detected. Defaulting to npm. Consider adding a "packageManager" field to your package.json.'));
|
|
61
61
|
return PACKAGE_MANAGERS.npm;
|
|
62
62
|
}
|
|
63
63
|
/**
|
|
@@ -92,6 +92,8 @@ class PackageManagerDetector {
|
|
|
92
92
|
const lockFileChecks = [
|
|
93
93
|
{ pm: PACKAGE_MANAGERS.pnpm, path: (0, path_1.join)(cwd, 'pnpm-lock.yaml') },
|
|
94
94
|
{ pm: PACKAGE_MANAGERS.bun, path: (0, path_1.join)(cwd, 'bun.lockb') },
|
|
95
|
+
// Bun >= 1.2 writes a text `bun.lock` instead of the binary `bun.lockb`.
|
|
96
|
+
{ pm: PACKAGE_MANAGERS.bun, path: (0, path_1.join)(cwd, 'bun.lock') },
|
|
95
97
|
{ pm: PACKAGE_MANAGERS.yarn, path: (0, path_1.join)(cwd, 'yarn.lock') },
|
|
96
98
|
{ pm: PACKAGE_MANAGERS.npm, path: (0, path_1.join)(cwd, 'package-lock.json') },
|
|
97
99
|
];
|
|
@@ -107,7 +109,8 @@ class PackageManagerDetector {
|
|
|
107
109
|
}
|
|
108
110
|
// If multiple lock files, use most recently modified
|
|
109
111
|
if (existingLocks.length > 1) {
|
|
110
|
-
|
|
112
|
+
// stderr so it never corrupts --json output on stdout.
|
|
113
|
+
console.error(chalk_1.default.yellow('⚠️ Multiple lock files detected. Using most recently modified. Consider cleaning up unused lock files.'));
|
|
111
114
|
existingLocks.sort((a, b) => b.mtime - a.mtime);
|
|
112
115
|
}
|
|
113
116
|
return existingLocks[0].pm;
|
|
@@ -7,21 +7,22 @@ exports.persistentCache = void 0;
|
|
|
7
7
|
const fs_1 = require("fs");
|
|
8
8
|
const path_1 = require("path");
|
|
9
9
|
const env_paths_1 = __importDefault(require("env-paths"));
|
|
10
|
-
|
|
11
|
-
const DISK_CACHE_TTL = 24 * 60 * 60 * 1000;
|
|
10
|
+
const config_1 = require("../config");
|
|
12
11
|
// Maximum cache size (number of packages)
|
|
13
12
|
const MAX_CACHE_ENTRIES = 5000;
|
|
14
13
|
// Cache file format version (increment when structure changes)
|
|
15
|
-
const CACHE_VERSION =
|
|
14
|
+
const CACHE_VERSION = 2;
|
|
16
15
|
/**
|
|
17
16
|
* Persistent cache manager for package registry data.
|
|
18
17
|
* Stores cache on disk for fast repeated runs across CLI invocations.
|
|
19
18
|
*/
|
|
20
19
|
class PersistentCacheManager {
|
|
20
|
+
cacheDir;
|
|
21
|
+
indexPath;
|
|
22
|
+
index = null;
|
|
23
|
+
dirty = false;
|
|
21
24
|
constructor() {
|
|
22
|
-
|
|
23
|
-
this.dirty = false;
|
|
24
|
-
const paths = (0, env_paths_1.default)('inup');
|
|
25
|
+
const paths = (0, env_paths_1.default)(config_1.PACKAGE_NAME);
|
|
25
26
|
this.cacheDir = (0, path_1.join)(paths.cache, 'registry');
|
|
26
27
|
this.indexPath = (0, path_1.join)(this.cacheDir, 'index.json');
|
|
27
28
|
}
|
|
@@ -93,13 +94,6 @@ class PersistentCacheManager {
|
|
|
93
94
|
if (!entry) {
|
|
94
95
|
return null;
|
|
95
96
|
}
|
|
96
|
-
// Check TTL
|
|
97
|
-
if (Date.now() - entry.timestamp > DISK_CACHE_TTL) {
|
|
98
|
-
// Expired, remove from index
|
|
99
|
-
delete index.entries[packageName];
|
|
100
|
-
this.dirty = true;
|
|
101
|
-
return null;
|
|
102
|
-
}
|
|
103
97
|
// Read the actual cache file
|
|
104
98
|
try {
|
|
105
99
|
const filePath = (0, path_1.join)(this.cacheDir, entry.file);
|
|
@@ -113,6 +107,7 @@ class PersistentCacheManager {
|
|
|
113
107
|
return {
|
|
114
108
|
latestVersion: cached.latestVersion,
|
|
115
109
|
allVersions: cached.allVersions,
|
|
110
|
+
timestamp: entry.timestamp,
|
|
116
111
|
};
|
|
117
112
|
}
|
|
118
113
|
catch {
|
package/dist/types/ui.js
ADDED
package/dist/types.js
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types/domain"), exports);
|
|
18
|
+
__exportStar(require("./types/ui"), exports);
|
|
19
|
+
__exportStar(require("./types/streaming"), exports);
|
|
3
20
|
//# sourceMappingURL=types.js.map
|
|
@@ -38,12 +38,10 @@ const semver = __importStar(require("semver"));
|
|
|
38
38
|
const services_1 = require("../../services");
|
|
39
39
|
const RELEASE_NOTES_LOAD_DEBOUNCE_MS = 120;
|
|
40
40
|
class PackageInfoModalController {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
this.resolveDebouncedLoad = null;
|
|
46
|
-
}
|
|
41
|
+
abortController = null;
|
|
42
|
+
pendingReleaseNotesVersion = null;
|
|
43
|
+
releaseNotesDebounceTimer = null;
|
|
44
|
+
resolveDebouncedLoad = null;
|
|
47
45
|
/**
|
|
48
46
|
* Cancel any in-flight hydrate/release-notes fetches.
|
|
49
47
|
* Safe to call multiple times or when nothing is in flight.
|
|
@@ -68,32 +66,11 @@ class PackageInfoModalController {
|
|
|
68
66
|
if (!metadata) {
|
|
69
67
|
return null;
|
|
70
68
|
}
|
|
71
|
-
const result = {
|
|
72
|
-
description: metadata.description,
|
|
73
|
-
homepage: metadata.homepage,
|
|
74
|
-
repository: metadata.releaseNotes,
|
|
75
|
-
weeklyDownloads: metadata.weeklyDownloads,
|
|
76
|
-
author: metadata.author,
|
|
77
|
-
license: metadata.license,
|
|
78
|
-
};
|
|
79
|
-
state.description = result.description;
|
|
80
|
-
state.homepage = result.homepage;
|
|
81
|
-
state.repository = result.repository;
|
|
82
|
-
state.weeklyDownloads = result.weeklyDownloads;
|
|
83
|
-
state.author = result.author;
|
|
84
|
-
state.license = result.license;
|
|
85
69
|
// Compute the version range for release notes
|
|
86
70
|
const targetVersion = state.selectedOption === 'range' ? state.rangeVersion : state.latestVersion;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
else {
|
|
91
|
-
// No allVersions available — just show the target version
|
|
92
|
-
state.releaseNotesVersions = [targetVersion];
|
|
93
|
-
}
|
|
94
|
-
state.releaseNotesLoaded = new Map();
|
|
95
|
-
state.releaseNotesViewIndex = 0;
|
|
96
|
-
state.releaseNotesLoadingVersion = undefined;
|
|
71
|
+
const releaseNotesVersions = state.allVersions && state.allVersions.length > 0
|
|
72
|
+
? this.buildReleaseNotesVersionQueue(state.allVersions, state.currentVersion, targetVersion)
|
|
73
|
+
: [targetVersion];
|
|
97
74
|
this.pendingReleaseNotesVersion = null;
|
|
98
75
|
if (this.releaseNotesDebounceTimer) {
|
|
99
76
|
clearTimeout(this.releaseNotesDebounceTimer);
|
|
@@ -101,7 +78,21 @@ class PackageInfoModalController {
|
|
|
101
78
|
}
|
|
102
79
|
this.resolveDebouncedLoad?.(false);
|
|
103
80
|
this.resolveDebouncedLoad = null;
|
|
104
|
-
return
|
|
81
|
+
return {
|
|
82
|
+
name: state.name,
|
|
83
|
+
patch: {
|
|
84
|
+
description: metadata.description,
|
|
85
|
+
homepage: metadata.homepage,
|
|
86
|
+
repository: metadata.releaseNotes,
|
|
87
|
+
weeklyDownloads: metadata.weeklyDownloads,
|
|
88
|
+
author: metadata.author,
|
|
89
|
+
license: metadata.license,
|
|
90
|
+
releaseNotesVersions,
|
|
91
|
+
releaseNotesLoaded: new Map(),
|
|
92
|
+
releaseNotesViewIndex: 0,
|
|
93
|
+
releaseNotesLoadingVersion: undefined,
|
|
94
|
+
},
|
|
95
|
+
};
|
|
105
96
|
}
|
|
106
97
|
/**
|
|
107
98
|
* Load release notes for a specific version by index.
|
|
@@ -4,11 +4,9 @@ exports.VulnerabilityAuditController = void 0;
|
|
|
4
4
|
const services_1 = require("../../services");
|
|
5
5
|
const vulnerability_1 = require("../presenters/vulnerability");
|
|
6
6
|
class VulnerabilityAuditController {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
this.drainPromise = null;
|
|
11
|
-
}
|
|
7
|
+
tracker = new services_1.BackgroundAuditTracker();
|
|
8
|
+
cache = new Map();
|
|
9
|
+
drainPromise = null;
|
|
12
10
|
getCachedSummary(packageName, currentVersionSpecifier, type) {
|
|
13
11
|
return this.cache.get(this.getCacheKey(packageName, currentVersionSpecifier, type));
|
|
14
12
|
}
|
|
@@ -25,16 +23,18 @@ class VulnerabilityAuditController {
|
|
|
25
23
|
this.drain(selectionStates, onUpdate);
|
|
26
24
|
}
|
|
27
25
|
}
|
|
28
|
-
drain(selectionStates, onUpdate) {
|
|
26
|
+
async drain(selectionStates, onUpdate) {
|
|
29
27
|
if (this.drainPromise) {
|
|
30
|
-
return;
|
|
28
|
+
return [];
|
|
31
29
|
}
|
|
30
|
+
const allUpdates = [];
|
|
32
31
|
this.drainPromise = (async () => {
|
|
33
32
|
while (true) {
|
|
34
33
|
const batch = this.tracker.reserveNextBatch(20);
|
|
35
34
|
if (batch.packageNames.length === 0) {
|
|
36
35
|
break;
|
|
37
36
|
}
|
|
37
|
+
const batchUpdates = [];
|
|
38
38
|
try {
|
|
39
39
|
const vulnerabilityData = await (0, services_1.fetchVulnerabilities)(batch.packages);
|
|
40
40
|
const batchNames = new Set(batch.packageNames);
|
|
@@ -55,8 +55,8 @@ class VulnerabilityAuditController {
|
|
|
55
55
|
url: item.url,
|
|
56
56
|
})), vulnerability.highestSeverity);
|
|
57
57
|
const merged = (0, vulnerability_1.mergeVulnerabilitySummary)(state.vulnerability, summary);
|
|
58
|
-
state.vulnerability = merged;
|
|
59
58
|
this.cache.set(this.getCacheKey(state.name, state.currentVersionSpecifier, state.type), merged);
|
|
59
|
+
batchUpdates.push({ name: state.name, patch: { vulnerability: merged } });
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
catch {
|
|
@@ -64,6 +64,13 @@ class VulnerabilityAuditController {
|
|
|
64
64
|
}
|
|
65
65
|
finally {
|
|
66
66
|
this.tracker.markCompleted(batch.packageNames);
|
|
67
|
+
for (const update of batchUpdates) {
|
|
68
|
+
for (const state of selectionStates) {
|
|
69
|
+
if (state.name === update.name)
|
|
70
|
+
Object.assign(state, update.patch);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
allUpdates.push(...batchUpdates);
|
|
67
74
|
onUpdate?.();
|
|
68
75
|
}
|
|
69
76
|
}
|
|
@@ -73,6 +80,8 @@ class VulnerabilityAuditController {
|
|
|
73
80
|
this.drain(selectionStates, onUpdate);
|
|
74
81
|
}
|
|
75
82
|
});
|
|
83
|
+
await this.drainPromise;
|
|
84
|
+
return allUpdates;
|
|
76
85
|
}
|
|
77
86
|
getCacheKey(packageName, currentVersionSpecifier, type) {
|
|
78
87
|
return `${packageName}@${currentVersionSpecifier}@${type}`;
|
package/dist/ui/index.js
CHANGED
|
@@ -21,4 +21,7 @@ __exportStar(require("./modal"), exports);
|
|
|
21
21
|
__exportStar(require("./presenters"), exports);
|
|
22
22
|
__exportStar(require("./controllers"), exports);
|
|
23
23
|
__exportStar(require("./input-handler"), exports);
|
|
24
|
+
__exportStar(require("./keymap"), exports);
|
|
25
|
+
__exportStar(require("./themes"), exports);
|
|
26
|
+
__exportStar(require("./themes-colors"), exports);
|
|
24
27
|
//# sourceMappingURL=index.js.map
|