inup 1.4.0 → 1.4.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/README.md +9 -0
- package/dist/{constants.js → config/constants.js} +8 -3
- package/dist/config/index.js +18 -0
- package/dist/core/package-detector.js +17 -6
- package/dist/interactive-ui.js +41 -22
- package/dist/services/jsdelivr-registry.js +24 -44
- package/dist/services/npm-registry.js +45 -57
- package/dist/services/version-checker.js +2 -2
- package/dist/ui/index.js +5 -1
- package/dist/ui/input-handler.js +71 -3
- package/dist/ui/renderer/index.js +2 -2
- package/dist/ui/renderer/package-list.js +105 -41
- package/dist/ui/state/filter-manager.js +48 -0
- package/dist/ui/state/index.js +12 -0
- package/dist/ui/state/modal-manager.js +45 -0
- package/dist/ui/state/navigation-manager.js +154 -0
- package/dist/ui/state/state-manager.js +215 -0
- package/dist/ui/utils/cursor.js +33 -0
- package/dist/ui/utils/index.js +8 -0
- package/dist/ui/{utils.js → utils/version.js} +1 -1
- package/dist/utils/version.js +11 -6
- package/package.json +2 -2
- package/dist/ui/state.js +0 -250
package/README.md
CHANGED
|
@@ -59,6 +59,15 @@ inup
|
|
|
59
59
|
|
|
60
60
|
The tool will scan your entire workspace (including monorepos), find outdated packages, and let you choose which ones to upgrade interactively.
|
|
61
61
|
|
|
62
|
+
### Interactive Features
|
|
63
|
+
|
|
64
|
+
- **Search**: Press `/` to search for a specific package by name
|
|
65
|
+
- **Navigate**: Use arrow keys to move between packages
|
|
66
|
+
- **Select Version**: Use `Left` and `Right` arrow keys to cycle through available versions (default, minor, patch, major)
|
|
67
|
+
- **Select All Minor**: Press `m` to select all minor updates
|
|
68
|
+
- **Package Info**: Press `i` to view detailed information about the selected package
|
|
69
|
+
- **Exit Search**: Press `Esc` to exit search mode
|
|
70
|
+
|
|
62
71
|
### Command line options
|
|
63
72
|
|
|
64
73
|
- `-d, --dir <directory>`: Run in a specific directory (default: current directory)
|
|
@@ -3,12 +3,17 @@
|
|
|
3
3
|
* Constants for npm registry queries and configuration
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.WORKSPACE_FILES = exports.LOCK_FILES = exports.REQUEST_TIMEOUT = exports.CACHE_TTL = exports.MAX_CONCURRENT_REQUESTS = exports.JSDELIVR_CDN_URL = exports.NPM_REGISTRY_URL = void 0;
|
|
6
|
+
exports.WORKSPACE_FILES = exports.LOCK_FILES = exports.DEFAULT_REGISTRY = exports.REQUEST_TIMEOUT = exports.CACHE_TTL = exports.MAX_CONCURRENT_REQUESTS = exports.JSDELIVR_CDN_URL = exports.NPM_REGISTRY_URL = void 0;
|
|
7
7
|
exports.NPM_REGISTRY_URL = 'https://registry.npmjs.org';
|
|
8
8
|
exports.JSDELIVR_CDN_URL = 'https://cdn.jsdelivr.net/npm';
|
|
9
|
-
exports.MAX_CONCURRENT_REQUESTS =
|
|
9
|
+
exports.MAX_CONCURRENT_REQUESTS = 150;
|
|
10
10
|
exports.CACHE_TTL = 5 * 60 * 1000; // 5 minutes in milliseconds
|
|
11
|
-
exports.REQUEST_TIMEOUT =
|
|
11
|
+
exports.REQUEST_TIMEOUT = 60000; // 60 seconds in milliseconds
|
|
12
|
+
/**
|
|
13
|
+
* Registry selection: 'jsdelivr' for fast CDN lookups, 'npm' for direct npm registry
|
|
14
|
+
* Set to 'npm' to use npm registry by default instead of jsdelivr
|
|
15
|
+
*/
|
|
16
|
+
exports.DEFAULT_REGISTRY = 'jsdelivr';
|
|
12
17
|
/**
|
|
13
18
|
* Package manager lock files
|
|
14
19
|
*/
|
|
@@ -0,0 +1,18 @@
|
|
|
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
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./constants"), exports);
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -37,6 +37,7 @@ exports.PackageDetector = void 0;
|
|
|
37
37
|
const semver = __importStar(require("semver"));
|
|
38
38
|
const utils_1 = require("../utils");
|
|
39
39
|
const services_1 = require("../services");
|
|
40
|
+
const config_1 = require("../config");
|
|
40
41
|
class PackageDetector {
|
|
41
42
|
constructor(options) {
|
|
42
43
|
this.packageJsonPath = null;
|
|
@@ -80,7 +81,7 @@ class PackageDetector {
|
|
|
80
81
|
}
|
|
81
82
|
}
|
|
82
83
|
const packageNames = Array.from(uniquePackageNames);
|
|
83
|
-
// Step 4: Fetch all package data in one call per package
|
|
84
|
+
// Step 4: Fetch all package data in one call per package
|
|
84
85
|
// Create a map of package names to their current versions for major version optimization
|
|
85
86
|
const currentVersions = new Map();
|
|
86
87
|
for (const dep of allDeps) {
|
|
@@ -89,11 +90,21 @@ class PackageDetector {
|
|
|
89
90
|
currentVersions.set(dep.name, dep.version);
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
|
-
const allPackageData =
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
const allPackageData = config_1.DEFAULT_REGISTRY === 'jsdelivr'
|
|
94
|
+
? await (0, services_1.getAllPackageDataFromJsdelivr)(packageNames, currentVersions, (currentPackage, completed, total) => {
|
|
95
|
+
const percentage = Math.round((completed / total) * 100);
|
|
96
|
+
const truncatedPackage = currentPackage.length > 40
|
|
97
|
+
? currentPackage.substring(0, 37) + '...'
|
|
98
|
+
: currentPackage;
|
|
99
|
+
this.showProgress(`🌐 Fetching ${percentage}% (${truncatedPackage})`);
|
|
100
|
+
})
|
|
101
|
+
: await (0, services_1.getAllPackageData)(packageNames, (currentPackage, completed, total) => {
|
|
102
|
+
const percentage = Math.round((completed / total) * 100);
|
|
103
|
+
const truncatedPackage = currentPackage.length > 40
|
|
104
|
+
? currentPackage.substring(0, 37) + '...'
|
|
105
|
+
: currentPackage;
|
|
106
|
+
this.showProgress(`🌐 Fetching ${percentage}% (${truncatedPackage})`);
|
|
107
|
+
});
|
|
97
108
|
try {
|
|
98
109
|
for (const dep of allDeps) {
|
|
99
110
|
try {
|
package/dist/interactive-ui.js
CHANGED
|
@@ -80,15 +80,15 @@ class InteractiveUI {
|
|
|
80
80
|
// Build label describing which types are shown
|
|
81
81
|
const types = [];
|
|
82
82
|
if (options.includePeerDeps)
|
|
83
|
-
types.push('Peer
|
|
83
|
+
types.push('Peer Deps');
|
|
84
84
|
if (options.includeOptionalDeps)
|
|
85
|
-
types.push('Optional
|
|
85
|
+
types.push('Optional Deps');
|
|
86
86
|
dependencyTypeLabel = types.join(' & ');
|
|
87
87
|
}
|
|
88
88
|
else {
|
|
89
89
|
// Default: show only regular dependencies and devDependencies
|
|
90
90
|
filteredPackages = outdatedPackages.filter((pkg) => pkg.type === 'dependencies' || pkg.type === 'devDependencies');
|
|
91
|
-
dependencyTypeLabel = '
|
|
91
|
+
dependencyTypeLabel = 'Deps & Dev Deps';
|
|
92
92
|
}
|
|
93
93
|
if (filteredPackages.length === 0) {
|
|
94
94
|
return [];
|
|
@@ -186,47 +186,48 @@ class InteractiveUI {
|
|
|
186
186
|
stateManager.setRenderableItems([]);
|
|
187
187
|
const handleAction = (action) => {
|
|
188
188
|
const uiState = stateManager.getUIState();
|
|
189
|
+
const filteredStates = stateManager.getFilteredStates(states);
|
|
189
190
|
switch (action.type) {
|
|
190
191
|
case 'navigate_up':
|
|
191
192
|
if (!uiState.showInfoModal) {
|
|
192
|
-
stateManager.navigateUp(
|
|
193
|
+
stateManager.navigateUp(filteredStates.length);
|
|
193
194
|
}
|
|
194
195
|
break;
|
|
195
196
|
case 'navigate_down':
|
|
196
197
|
if (!uiState.showInfoModal) {
|
|
197
|
-
stateManager.navigateDown(
|
|
198
|
+
stateManager.navigateDown(filteredStates.length);
|
|
198
199
|
}
|
|
199
200
|
break;
|
|
200
201
|
case 'select_left':
|
|
201
202
|
if (!uiState.showInfoModal) {
|
|
202
|
-
stateManager.updateSelection(
|
|
203
|
+
stateManager.updateSelection(filteredStates, 'left');
|
|
203
204
|
}
|
|
204
205
|
break;
|
|
205
206
|
case 'select_right':
|
|
206
207
|
if (!uiState.showInfoModal) {
|
|
207
|
-
stateManager.updateSelection(
|
|
208
|
+
stateManager.updateSelection(filteredStates, 'right');
|
|
208
209
|
}
|
|
209
210
|
break;
|
|
210
211
|
case 'bulk_select_minor':
|
|
211
212
|
if (!uiState.showInfoModal) {
|
|
212
|
-
stateManager.bulkSelectMinor(
|
|
213
|
+
stateManager.bulkSelectMinor(filteredStates);
|
|
213
214
|
}
|
|
214
215
|
break;
|
|
215
216
|
case 'bulk_select_latest':
|
|
216
217
|
if (!uiState.showInfoModal) {
|
|
217
|
-
stateManager.bulkSelectLatest(
|
|
218
|
+
stateManager.bulkSelectLatest(filteredStates);
|
|
218
219
|
}
|
|
219
220
|
break;
|
|
220
221
|
case 'bulk_unselect_all':
|
|
221
222
|
if (!uiState.showInfoModal) {
|
|
222
|
-
stateManager.bulkUnselectAll(
|
|
223
|
+
stateManager.bulkUnselectAll(filteredStates);
|
|
223
224
|
}
|
|
224
225
|
break;
|
|
225
226
|
case 'toggle_info_modal':
|
|
226
227
|
if (!uiState.showInfoModal) {
|
|
227
228
|
// Opening modal - load package info asynchronously
|
|
228
229
|
stateManager.toggleInfoModal();
|
|
229
|
-
const currentState =
|
|
230
|
+
const currentState = filteredStates[uiState.currentRow];
|
|
230
231
|
stateManager.setModalLoading(true);
|
|
231
232
|
renderInterface();
|
|
232
233
|
// Fetch metadata asynchronously
|
|
@@ -249,6 +250,20 @@ class InteractiveUI {
|
|
|
249
250
|
renderInterface();
|
|
250
251
|
}
|
|
251
252
|
break;
|
|
253
|
+
case 'enter_filter_mode':
|
|
254
|
+
stateManager.enterFilterMode();
|
|
255
|
+
break;
|
|
256
|
+
case 'exit_filter_mode':
|
|
257
|
+
stateManager.exitFilterMode();
|
|
258
|
+
break;
|
|
259
|
+
case 'filter_input':
|
|
260
|
+
stateManager.appendToFilterQuery(action.char);
|
|
261
|
+
// Re-calculate filtered states after input
|
|
262
|
+
break;
|
|
263
|
+
case 'filter_backspace':
|
|
264
|
+
stateManager.deleteFromFilterQuery();
|
|
265
|
+
// Re-calculate filtered states after backspace
|
|
266
|
+
break;
|
|
252
267
|
case 'resize':
|
|
253
268
|
const heightChanged = stateManager.updateTerminalHeight(action.height);
|
|
254
269
|
if (heightChanged) {
|
|
@@ -269,6 +284,7 @@ class InteractiveUI {
|
|
|
269
284
|
}
|
|
270
285
|
};
|
|
271
286
|
const handleConfirm = (selectedStates) => {
|
|
287
|
+
ui_1.CursorUtils.show();
|
|
272
288
|
// Clean up listeners
|
|
273
289
|
if (process.stdin.setRawMode) {
|
|
274
290
|
process.stdin.setRawMode(false);
|
|
@@ -279,6 +295,7 @@ class InteractiveUI {
|
|
|
279
295
|
resolve(selectedStates);
|
|
280
296
|
};
|
|
281
297
|
const handleCancel = () => {
|
|
298
|
+
ui_1.CursorUtils.show();
|
|
282
299
|
// Clean up listeners
|
|
283
300
|
if (process.stdin.setRawMode) {
|
|
284
301
|
process.stdin.setRawMode(false);
|
|
@@ -291,16 +308,17 @@ class InteractiveUI {
|
|
|
291
308
|
const inputHandler = new ui_1.InputHandler(stateManager, handleAction, handleConfirm, handleCancel);
|
|
292
309
|
const renderInterface = () => {
|
|
293
310
|
const uiState = stateManager.getUIState();
|
|
294
|
-
|
|
311
|
+
const filteredStates = stateManager.getFilteredStates(states);
|
|
312
|
+
if (uiState.forceFullRender) {
|
|
295
313
|
console.clear();
|
|
314
|
+
ui_1.CursorUtils.hide();
|
|
296
315
|
}
|
|
297
316
|
else {
|
|
298
|
-
|
|
299
|
-
process.stdout.write('\x1b[H');
|
|
317
|
+
ui_1.CursorUtils.moveToHome();
|
|
300
318
|
}
|
|
301
319
|
// If modal is open, render only the modal with header/footer
|
|
302
|
-
if (uiState.showInfoModal && uiState.infoModalRow >= 0 && uiState.infoModalRow <
|
|
303
|
-
const selectedState =
|
|
320
|
+
if (uiState.showInfoModal && uiState.infoModalRow >= 0 && uiState.infoModalRow < filteredStates.length) {
|
|
321
|
+
const selectedState = filteredStates[uiState.infoModalRow];
|
|
304
322
|
const terminalWidth = process.stdout.columns || 80;
|
|
305
323
|
const terminalHeight = this.getTerminalHeight();
|
|
306
324
|
// Render header
|
|
@@ -323,20 +341,20 @@ class InteractiveUI {
|
|
|
323
341
|
modalLines.forEach((line) => console.log(line));
|
|
324
342
|
}
|
|
325
343
|
// Clear any remaining lines from previous render
|
|
326
|
-
|
|
344
|
+
ui_1.CursorUtils.clearToEndOfScreen();
|
|
327
345
|
stateManager.markRendered([]);
|
|
328
346
|
}
|
|
329
347
|
else {
|
|
330
348
|
// Normal list view (flat rendering - no grouping)
|
|
331
|
-
const lines = this.renderer.renderInterface(
|
|
349
|
+
const lines = this.renderer.renderInterface(filteredStates, uiState.currentRow, uiState.scrollOffset, uiState.maxVisibleItems, uiState.forceFullRender, [], // No renderable items - use flat rendering
|
|
332
350
|
dependencyTypeLabel, // Show which dependency type we're upgrading
|
|
333
|
-
this.packageManager // Pass package manager info for header
|
|
334
|
-
);
|
|
351
|
+
this.packageManager, // Pass package manager info for header
|
|
352
|
+
uiState.filterMode, uiState.filterQuery, states.length);
|
|
335
353
|
// Print all lines
|
|
336
354
|
lines.forEach((line) => console.log(line));
|
|
337
355
|
// Clear any remaining lines from previous render
|
|
338
|
-
if (!uiState.
|
|
339
|
-
|
|
356
|
+
if (!uiState.forceFullRender) {
|
|
357
|
+
ui_1.CursorUtils.clearToEndOfScreen();
|
|
340
358
|
}
|
|
341
359
|
stateManager.markRendered(lines);
|
|
342
360
|
}
|
|
@@ -387,6 +405,7 @@ class InteractiveUI {
|
|
|
387
405
|
if (process.stdin.setRawMode) {
|
|
388
406
|
process.stdin.setRawMode(true);
|
|
389
407
|
}
|
|
408
|
+
ui_1.CursorUtils.hide();
|
|
390
409
|
process.stdin.resume();
|
|
391
410
|
process.stdin.on('keypress', (str, key) => inputHandler.handleKeypress(str, key));
|
|
392
411
|
}
|
|
@@ -38,15 +38,16 @@ exports.clearJsdelivrPackageCache = clearJsdelivrPackageCache;
|
|
|
38
38
|
exports.closeJsdelivrPool = closeJsdelivrPool;
|
|
39
39
|
const undici_1 = require("undici");
|
|
40
40
|
const semver = __importStar(require("semver"));
|
|
41
|
-
const
|
|
41
|
+
const config_1 = require("../config");
|
|
42
42
|
const npm_registry_1 = require("./npm-registry");
|
|
43
43
|
// Create a persistent connection pool for jsDelivr CDN with optimal settings
|
|
44
44
|
// This enables connection reuse and HTTP/1.1 keep-alive for blazing fast requests
|
|
45
45
|
const jsdelivrPool = new undici_1.Pool('https://cdn.jsdelivr.net', {
|
|
46
|
-
connections:
|
|
46
|
+
connections: config_1.MAX_CONCURRENT_REQUESTS, // Maximum concurrent connections
|
|
47
47
|
pipelining: 10, // Enable request pipelining for even better performance
|
|
48
|
-
keepAliveTimeout:
|
|
49
|
-
keepAliveMaxTimeout:
|
|
48
|
+
keepAliveTimeout: config_1.REQUEST_TIMEOUT, // Keep connections alive for 60 seconds
|
|
49
|
+
keepAliveMaxTimeout: config_1.REQUEST_TIMEOUT, // Maximum keep-alive timeout
|
|
50
|
+
connectTimeout: config_1.REQUEST_TIMEOUT, // 60 seconds connect timeout
|
|
50
51
|
});
|
|
51
52
|
const packageCache = new Map();
|
|
52
53
|
/**
|
|
@@ -58,15 +59,15 @@ const packageCache = new Map();
|
|
|
58
59
|
*/
|
|
59
60
|
async function fetchPackageJsonFromJsdelivr(packageName, versionTag) {
|
|
60
61
|
try {
|
|
61
|
-
const url = `${
|
|
62
|
+
const url = `${config_1.JSDELIVR_CDN_URL}/${encodeURIComponent(packageName)}@${versionTag}/package.json`;
|
|
62
63
|
const { statusCode, body } = await (0, undici_1.request)(url, {
|
|
63
64
|
dispatcher: jsdelivrPool,
|
|
64
65
|
method: 'GET',
|
|
65
66
|
headers: {
|
|
66
67
|
accept: 'application/json',
|
|
67
68
|
},
|
|
68
|
-
headersTimeout:
|
|
69
|
-
bodyTimeout:
|
|
69
|
+
headersTimeout: config_1.REQUEST_TIMEOUT,
|
|
70
|
+
bodyTimeout: config_1.REQUEST_TIMEOUT,
|
|
70
71
|
});
|
|
71
72
|
if (statusCode !== 200) {
|
|
72
73
|
// Consume body to prevent memory leaks
|
|
@@ -84,7 +85,7 @@ async function fetchPackageJsonFromJsdelivr(packageName, versionTag) {
|
|
|
84
85
|
}
|
|
85
86
|
/**
|
|
86
87
|
* Fetches package data from jsdelivr CDN with fallback to npm registry.
|
|
87
|
-
* Makes simultaneous requests for @latest
|
|
88
|
+
* Makes simultaneous requests for @latest, @major version, and current version.
|
|
88
89
|
* @param packageName - The npm package name
|
|
89
90
|
* @param currentVersion - The current version to extract major from (optional)
|
|
90
91
|
* @returns Package data with latest version and all versions
|
|
@@ -92,26 +93,31 @@ async function fetchPackageJsonFromJsdelivr(packageName, versionTag) {
|
|
|
92
93
|
async function fetchPackageFromJsdelivr(packageName, currentVersion) {
|
|
93
94
|
// Check cache first
|
|
94
95
|
const cached = packageCache.get(packageName);
|
|
95
|
-
if (cached && Date.now() - cached.timestamp <
|
|
96
|
+
if (cached && Date.now() - cached.timestamp < config_1.CACHE_TTL) {
|
|
96
97
|
return cached.data;
|
|
97
98
|
}
|
|
98
99
|
try {
|
|
100
|
+
// Coerce the current version in case it's a range like ^1.1.5
|
|
101
|
+
const coercedVersion = currentVersion ? semver.coerce(currentVersion)?.version : null;
|
|
99
102
|
// Determine major version from current version if provided
|
|
100
|
-
// Need to coerce the version first in case it's a range like ^1.1.5
|
|
101
103
|
const majorVersion = currentVersion
|
|
102
104
|
? semver.major(semver.coerce(currentVersion) || '0.0.0').toString()
|
|
103
105
|
: null;
|
|
104
|
-
// Prepare requests: always fetch @latest,
|
|
106
|
+
// Prepare requests: always fetch @latest, @major if we have a current version, and @currentVersion
|
|
105
107
|
const requests = [
|
|
106
108
|
fetchPackageJsonFromJsdelivr(packageName, 'latest'),
|
|
107
109
|
];
|
|
108
110
|
if (majorVersion) {
|
|
109
111
|
requests.push(fetchPackageJsonFromJsdelivr(packageName, majorVersion));
|
|
110
112
|
}
|
|
113
|
+
if (coercedVersion) {
|
|
114
|
+
requests.push(fetchPackageJsonFromJsdelivr(packageName, coercedVersion));
|
|
115
|
+
}
|
|
111
116
|
// Execute all requests simultaneously
|
|
112
117
|
const results = await Promise.all(requests);
|
|
113
118
|
const latestResult = results[0];
|
|
114
119
|
const majorResult = results[1];
|
|
120
|
+
const currentResult = results[2];
|
|
115
121
|
if (!latestResult) {
|
|
116
122
|
// jsdelivr doesn't have this package, fallback to npm registry
|
|
117
123
|
const npmData = await (0, npm_registry_1.getAllPackageData)([packageName]);
|
|
@@ -124,40 +130,14 @@ async function fetchPackageFromJsdelivr(packageName, currentVersion) {
|
|
|
124
130
|
return data;
|
|
125
131
|
}
|
|
126
132
|
const latestVersion = latestResult.version;
|
|
127
|
-
// If we have a major version result, we can build a minimal version list
|
|
128
|
-
// This is much faster than fetching all versions from npm
|
|
129
|
-
if (majorResult) {
|
|
130
|
-
const allVersions = [latestVersion];
|
|
131
|
-
// Add the major version result if different from latest
|
|
132
|
-
if (majorResult.version !== latestVersion) {
|
|
133
|
-
allVersions.push(majorResult.version);
|
|
134
|
-
}
|
|
135
|
-
// Add the current version if it's valid and not already in the list
|
|
136
|
-
if (currentVersion && semver.valid(currentVersion)) {
|
|
137
|
-
const coerced = semver.coerce(currentVersion);
|
|
138
|
-
if (coerced && !allVersions.includes(coerced.version)) {
|
|
139
|
-
allVersions.push(coerced.version);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
const result = {
|
|
143
|
-
latestVersion,
|
|
144
|
-
allVersions: allVersions.sort(semver.rcompare),
|
|
145
|
-
};
|
|
146
|
-
// Cache the result
|
|
147
|
-
packageCache.set(packageName, {
|
|
148
|
-
data: result,
|
|
149
|
-
timestamp: Date.now(),
|
|
150
|
-
});
|
|
151
|
-
return result;
|
|
152
|
-
}
|
|
153
|
-
// No major version provided, just return latest with minimal version list
|
|
154
133
|
const allVersions = [latestVersion];
|
|
155
|
-
// Add the
|
|
156
|
-
if (
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
134
|
+
// Add the major version result if different from latest
|
|
135
|
+
if (majorResult && majorResult.version !== latestVersion) {
|
|
136
|
+
allVersions.push(majorResult.version);
|
|
137
|
+
}
|
|
138
|
+
// Add the current version result if different from latest and major
|
|
139
|
+
if (currentResult && !allVersions.includes(currentResult.version)) {
|
|
140
|
+
allVersions.push(currentResult.version);
|
|
161
141
|
}
|
|
162
142
|
const result = {
|
|
163
143
|
latestVersion,
|
|
@@ -35,65 +35,59 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.getAllPackageData = getAllPackageData;
|
|
37
37
|
exports.clearPackageCache = clearPackageCache;
|
|
38
|
-
exports.closeNpmPool = closeNpmPool;
|
|
39
|
-
const undici_1 = require("undici");
|
|
40
38
|
const semver = __importStar(require("semver"));
|
|
41
|
-
const
|
|
42
|
-
// Create a persistent connection pool for npm registry with optimal settings
|
|
43
|
-
// This enables connection reuse and HTTP/1.1 keep-alive for blazing fast requests
|
|
44
|
-
const npmPool = new undici_1.Pool('https://registry.npmjs.org', {
|
|
45
|
-
connections: constants_1.MAX_CONCURRENT_REQUESTS, // Maximum concurrent connections
|
|
46
|
-
pipelining: 10, // Enable request pipelining for even better performance
|
|
47
|
-
keepAliveTimeout: 60000, // Keep connections alive for 60 seconds
|
|
48
|
-
keepAliveMaxTimeout: 600000, // Maximum keep-alive timeout
|
|
49
|
-
});
|
|
39
|
+
const config_1 = require("../config");
|
|
50
40
|
const packageCache = new Map();
|
|
51
41
|
/**
|
|
52
|
-
* Fetches package data from npm registry with caching using
|
|
53
|
-
*
|
|
42
|
+
* Fetches package data from npm registry with caching using native fetch.
|
|
43
|
+
* Includes timeout support for slow connections.
|
|
54
44
|
*/
|
|
55
45
|
async function fetchPackageFromRegistry(packageName) {
|
|
56
46
|
// Check cache first
|
|
57
47
|
const cached = packageCache.get(packageName);
|
|
58
|
-
if (cached && Date.now() - cached.timestamp <
|
|
48
|
+
if (cached && Date.now() - cached.timestamp < config_1.CACHE_TTL) {
|
|
59
49
|
return cached.data;
|
|
60
50
|
}
|
|
61
51
|
try {
|
|
62
|
-
const url = `${
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
52
|
+
const url = `${config_1.NPM_REGISTRY_URL}/${encodeURIComponent(packageName)}`;
|
|
53
|
+
const controller = new AbortController();
|
|
54
|
+
const timeoutId = setTimeout(() => controller.abort(), config_1.REQUEST_TIMEOUT);
|
|
55
|
+
try {
|
|
56
|
+
const response = await fetch(url, {
|
|
57
|
+
method: 'GET',
|
|
58
|
+
headers: {
|
|
59
|
+
accept: 'application/vnd.npm.install-v1+json',
|
|
60
|
+
},
|
|
61
|
+
signal: controller.signal,
|
|
62
|
+
});
|
|
63
|
+
clearTimeout(timeoutId);
|
|
64
|
+
if (!response.ok) {
|
|
65
|
+
throw new Error(`HTTP ${response.status}`);
|
|
66
|
+
}
|
|
67
|
+
const text = await response.text();
|
|
68
|
+
const data = JSON.parse(text);
|
|
69
|
+
// Extract versions and filter to valid semver (X.Y.Z format, no pre-releases)
|
|
70
|
+
const allVersions = Object.keys(data.versions || {}).filter((version) => {
|
|
71
|
+
// Match only X.Y.Z format (no pre-release, no build metadata)
|
|
72
|
+
return /^[0-9]+\.[0-9]+\.[0-9]+$/.test(version);
|
|
73
|
+
});
|
|
74
|
+
// Sort versions to find the latest
|
|
75
|
+
const sortedVersions = allVersions.sort(semver.rcompare);
|
|
76
|
+
const latestVersion = sortedVersions.length > 0 ? sortedVersions[0] : 'unknown';
|
|
77
|
+
const result = {
|
|
78
|
+
latestVersion,
|
|
79
|
+
allVersions,
|
|
80
|
+
};
|
|
81
|
+
// Cache the result
|
|
82
|
+
packageCache.set(packageName, {
|
|
83
|
+
data: result,
|
|
84
|
+
timestamp: Date.now(),
|
|
85
|
+
});
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
clearTimeout(timeoutId);
|
|
76
90
|
}
|
|
77
|
-
const text = await body.text();
|
|
78
|
-
const data = JSON.parse(text);
|
|
79
|
-
// Extract versions and filter to valid semver (X.Y.Z format, no pre-releases)
|
|
80
|
-
const allVersions = Object.keys(data.versions || {}).filter((version) => {
|
|
81
|
-
// Match only X.Y.Z format (no pre-release, no build metadata)
|
|
82
|
-
return /^[0-9]+\.[0-9]+\.[0-9]+$/.test(version);
|
|
83
|
-
});
|
|
84
|
-
// Sort versions to find the latest
|
|
85
|
-
const sortedVersions = allVersions.sort(semver.rcompare);
|
|
86
|
-
const latestVersion = sortedVersions.length > 0 ? sortedVersions[0] : 'unknown';
|
|
87
|
-
const result = {
|
|
88
|
-
latestVersion,
|
|
89
|
-
allVersions,
|
|
90
|
-
};
|
|
91
|
-
// Cache the result
|
|
92
|
-
packageCache.set(packageName, {
|
|
93
|
-
data: result,
|
|
94
|
-
timestamp: Date.now(),
|
|
95
|
-
});
|
|
96
|
-
return result;
|
|
97
91
|
}
|
|
98
92
|
catch (error) {
|
|
99
93
|
// Return fallback data for failed packages
|
|
@@ -102,7 +96,7 @@ async function fetchPackageFromRegistry(packageName) {
|
|
|
102
96
|
}
|
|
103
97
|
/**
|
|
104
98
|
* Fetches package version data from npm registry for multiple packages.
|
|
105
|
-
* Uses
|
|
99
|
+
* Uses native fetch with timeout support for reliable performance.
|
|
106
100
|
* Only returns valid semantic versions (X.Y.Z format, excluding pre-releases).
|
|
107
101
|
*/
|
|
108
102
|
async function getAllPackageData(packageNames, onProgress) {
|
|
@@ -112,8 +106,8 @@ async function getAllPackageData(packageNames, onProgress) {
|
|
|
112
106
|
}
|
|
113
107
|
const total = packageNames.length;
|
|
114
108
|
let completedCount = 0;
|
|
115
|
-
// Fire all requests simultaneously
|
|
116
|
-
//
|
|
109
|
+
// Fire all requests simultaneously
|
|
110
|
+
// Concurrency is handled naturally by the event loop with fetch
|
|
117
111
|
const allPromises = packageNames.map(async (packageName) => {
|
|
118
112
|
const data = await fetchPackageFromRegistry(packageName);
|
|
119
113
|
packageData.set(packageName, data);
|
|
@@ -136,10 +130,4 @@ async function getAllPackageData(packageNames, onProgress) {
|
|
|
136
130
|
function clearPackageCache() {
|
|
137
131
|
packageCache.clear();
|
|
138
132
|
}
|
|
139
|
-
/**
|
|
140
|
-
* Close the npm registry connection pool (useful for graceful shutdown)
|
|
141
|
-
*/
|
|
142
|
-
async function closeNpmPool() {
|
|
143
|
-
await npmPool.close();
|
|
144
|
-
}
|
|
145
133
|
//# sourceMappingURL=npm-registry.js.map
|
|
@@ -37,7 +37,7 @@ exports.checkForUpdate = checkForUpdate;
|
|
|
37
37
|
exports.checkForUpdateAsync = checkForUpdateAsync;
|
|
38
38
|
const child_process_1 = require("child_process");
|
|
39
39
|
const semver = __importStar(require("semver"));
|
|
40
|
-
const
|
|
40
|
+
const config_1 = require("../config");
|
|
41
41
|
/**
|
|
42
42
|
* Check if the current package version is outdated compared to npm registry
|
|
43
43
|
*/
|
|
@@ -46,7 +46,7 @@ async function checkForUpdate(packageName, currentVersion) {
|
|
|
46
46
|
// Use npm view to get the latest version from registry
|
|
47
47
|
const result = (0, child_process_1.execSync)(`npm view ${packageName} version`, {
|
|
48
48
|
encoding: 'utf-8',
|
|
49
|
-
timeout:
|
|
49
|
+
timeout: config_1.REQUEST_TIMEOUT,
|
|
50
50
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
51
51
|
});
|
|
52
52
|
const latestVersion = result.trim();
|
package/dist/ui/index.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ConfirmationInputHandler = exports.InputHandler = exports.UIRenderer = exports.StateManager = exports.VersionUtils = void 0;
|
|
3
|
+
exports.ConfirmationInputHandler = exports.InputHandler = exports.UIRenderer = exports.FilterManager = exports.ModalManager = exports.NavigationManager = exports.StateManager = exports.CursorUtils = exports.VersionUtils = void 0;
|
|
4
4
|
var utils_1 = require("./utils");
|
|
5
5
|
Object.defineProperty(exports, "VersionUtils", { enumerable: true, get: function () { return utils_1.VersionUtils; } });
|
|
6
|
+
Object.defineProperty(exports, "CursorUtils", { enumerable: true, get: function () { return utils_1.CursorUtils; } });
|
|
6
7
|
var state_1 = require("./state");
|
|
7
8
|
Object.defineProperty(exports, "StateManager", { enumerable: true, get: function () { return state_1.StateManager; } });
|
|
9
|
+
Object.defineProperty(exports, "NavigationManager", { enumerable: true, get: function () { return state_1.NavigationManager; } });
|
|
10
|
+
Object.defineProperty(exports, "ModalManager", { enumerable: true, get: function () { return state_1.ModalManager; } });
|
|
11
|
+
Object.defineProperty(exports, "FilterManager", { enumerable: true, get: function () { return state_1.FilterManager; } });
|
|
8
12
|
var index_1 = require("./renderer/index");
|
|
9
13
|
Object.defineProperty(exports, "UIRenderer", { enumerable: true, get: function () { return index_1.UIRenderer; } });
|
|
10
14
|
var input_handler_1 = require("./input-handler");
|