inup 1.4.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 +142 -0
- package/dist/cli.js +109 -0
- package/dist/constants.js +28 -0
- package/dist/core/index.js +23 -0
- package/dist/core/package-detector.js +182 -0
- package/dist/core/upgrade-runner.js +135 -0
- package/dist/core/upgrader.js +139 -0
- package/dist/index.js +10 -0
- package/dist/interactive-ui.js +411 -0
- package/dist/services/changelog-fetcher.js +193 -0
- package/dist/services/index.js +24 -0
- package/dist/services/jsdelivr-registry.js +232 -0
- package/dist/services/npm-registry.js +145 -0
- package/dist/services/package-manager-detector.js +172 -0
- package/dist/services/version-checker.js +92 -0
- package/dist/types.js +3 -0
- package/dist/ui/index.js +13 -0
- package/dist/ui/input-handler.js +112 -0
- package/dist/ui/renderer/confirmation.js +34 -0
- package/dist/ui/renderer/index.js +77 -0
- package/dist/ui/renderer/modal.js +184 -0
- package/dist/ui/renderer/package-list.js +243 -0
- package/dist/ui/state.js +250 -0
- package/dist/ui/utils.js +66 -0
- package/dist/utils/exec.js +38 -0
- package/dist/utils/filesystem.js +225 -0
- package/dist/utils/index.js +28 -0
- package/dist/utils/version.js +130 -0
- package/package.json +73 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.changelogFetcher = exports.ChangelogFetcher = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Fetches package metadata from npm registry
|
|
6
|
+
* Includes description, repository info, and basic metadata
|
|
7
|
+
*/
|
|
8
|
+
class ChangelogFetcher {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.cache = new Map();
|
|
11
|
+
this.failureCache = new Set(); // Track packages that failed to fetch
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Fetch package metadata from npm registry
|
|
15
|
+
* Uses a cached approach to avoid repeated requests
|
|
16
|
+
*/
|
|
17
|
+
async fetchPackageMetadata(packageName) {
|
|
18
|
+
// Check if we already have this in cache
|
|
19
|
+
if (this.cache.has(packageName)) {
|
|
20
|
+
return this.cache.get(packageName);
|
|
21
|
+
}
|
|
22
|
+
// Check if we already failed to fetch this
|
|
23
|
+
if (this.failureCache.has(packageName)) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
// Fetch from npm registry
|
|
28
|
+
const response = await this.fetchFromRegistry(packageName);
|
|
29
|
+
if (!response) {
|
|
30
|
+
this.failureCache.add(packageName);
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const repositoryUrl = this.extractRepositoryUrl(response.repository?.url || '');
|
|
34
|
+
const npmUrl = `https://www.npmjs.com/package/${encodeURIComponent(packageName)}`;
|
|
35
|
+
const issuesUrl = repositoryUrl ? `${repositoryUrl}/issues` : undefined;
|
|
36
|
+
const metadata = {
|
|
37
|
+
description: response.description || 'No description available',
|
|
38
|
+
homepage: response.homepage,
|
|
39
|
+
repository: response.repository,
|
|
40
|
+
bugs: response.bugs,
|
|
41
|
+
keywords: response.keywords || [],
|
|
42
|
+
author: response.author?.name || response.author,
|
|
43
|
+
license: response.license,
|
|
44
|
+
repositoryUrl,
|
|
45
|
+
npmUrl,
|
|
46
|
+
issuesUrl,
|
|
47
|
+
};
|
|
48
|
+
// Try to extract release notes/changelog info
|
|
49
|
+
if (repositoryUrl) {
|
|
50
|
+
metadata.releaseNotes = `${repositoryUrl}/releases`;
|
|
51
|
+
}
|
|
52
|
+
// Try to get weekly download count
|
|
53
|
+
try {
|
|
54
|
+
const downloadsData = await this.fetchDownloadStats(packageName);
|
|
55
|
+
if (downloadsData) {
|
|
56
|
+
metadata.weeklyDownloads = downloadsData.downloads;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Ignore download stats errors - optional data
|
|
61
|
+
}
|
|
62
|
+
this.cache.set(packageName, metadata);
|
|
63
|
+
return metadata;
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
// Cache the failure to avoid retrying
|
|
67
|
+
this.failureCache.add(packageName);
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Fetch data from npm registry
|
|
73
|
+
* Returns the package data from the registry
|
|
74
|
+
*/
|
|
75
|
+
async fetchFromRegistry(packageName) {
|
|
76
|
+
try {
|
|
77
|
+
const response = await fetch(`https://registry.npmjs.org/${encodeURIComponent(packageName)}`, {
|
|
78
|
+
method: 'GET',
|
|
79
|
+
headers: {
|
|
80
|
+
accept: 'application/json',
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
if (!response.ok) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const data = (await response.json());
|
|
87
|
+
// Get the latest version data
|
|
88
|
+
const distTags = data['dist-tags'];
|
|
89
|
+
const latestVersion = distTags?.latest;
|
|
90
|
+
const versions = data.versions;
|
|
91
|
+
const latestPackageData = latestVersion ? versions?.[latestVersion] : undefined;
|
|
92
|
+
return {
|
|
93
|
+
description: data.description,
|
|
94
|
+
homepage: (data.homepage || latestPackageData?.homepage),
|
|
95
|
+
repository: (data.repository || latestPackageData?.repository),
|
|
96
|
+
bugs: (data.bugs || latestPackageData?.bugs),
|
|
97
|
+
keywords: (data.keywords || []),
|
|
98
|
+
author: (data.author || latestPackageData?.author),
|
|
99
|
+
license: (data.license || latestPackageData?.license),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Extract GitHub URL from repository URL for easier access to releases
|
|
108
|
+
*/
|
|
109
|
+
extractRepositoryUrl(repoUrl) {
|
|
110
|
+
if (!repoUrl)
|
|
111
|
+
return '';
|
|
112
|
+
// Handle various repository URL formats
|
|
113
|
+
// git+https://github.com/user/repo.git -> https://github.com/user/repo/releases
|
|
114
|
+
// https://github.com/user/repo.git -> https://github.com/user/repo/releases
|
|
115
|
+
// github:user/repo -> https://github.com/user/repo/releases
|
|
116
|
+
let cleanUrl = repoUrl
|
|
117
|
+
.replace(/^git\+/, '') // Remove git+ prefix
|
|
118
|
+
.replace(/\.git$/, '') // Remove .git suffix
|
|
119
|
+
.replace(/^github:/, 'https://github.com/'); // Convert github: format
|
|
120
|
+
// Ensure it's a proper URL
|
|
121
|
+
if (!cleanUrl.startsWith('http')) {
|
|
122
|
+
cleanUrl = 'https://github.com/' + cleanUrl;
|
|
123
|
+
}
|
|
124
|
+
return cleanUrl;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Fetch weekly download statistics from npm
|
|
128
|
+
*/
|
|
129
|
+
async fetchDownloadStats(packageName) {
|
|
130
|
+
try {
|
|
131
|
+
const response = await fetch(`https://api.npmjs.org/downloads/point/last-week/${encodeURIComponent(packageName)}`, {
|
|
132
|
+
method: 'GET',
|
|
133
|
+
headers: {
|
|
134
|
+
accept: 'application/json',
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
if (!response.ok) {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
const data = (await response.json());
|
|
141
|
+
return {
|
|
142
|
+
downloads: data.downloads || 0,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Get repository release URL for a package
|
|
151
|
+
*/
|
|
152
|
+
getRepositoryReleaseUrl(packageName, version) {
|
|
153
|
+
const metadata = this.cache.get(packageName);
|
|
154
|
+
if (!metadata || !metadata.releaseNotes) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
return `${metadata.releaseNotes}/releases/tag/v${version}`;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Cache package metadata directly (used by utils to avoid duplicate fetches)
|
|
161
|
+
*/
|
|
162
|
+
cacheMetadata(packageName, rawData) {
|
|
163
|
+
const repositoryUrl = this.extractRepositoryUrl(rawData.repository?.url || '');
|
|
164
|
+
const npmUrl = `https://www.npmjs.com/package/${encodeURIComponent(packageName)}`;
|
|
165
|
+
const issuesUrl = repositoryUrl ? `${repositoryUrl}/issues` : undefined;
|
|
166
|
+
const metadata = {
|
|
167
|
+
description: rawData.description || 'No description available',
|
|
168
|
+
homepage: rawData.homepage,
|
|
169
|
+
repository: rawData.repository,
|
|
170
|
+
bugs: rawData.bugs,
|
|
171
|
+
keywords: rawData.keywords || [],
|
|
172
|
+
author: rawData.author?.name || rawData.author,
|
|
173
|
+
license: rawData.license,
|
|
174
|
+
repositoryUrl,
|
|
175
|
+
npmUrl,
|
|
176
|
+
issuesUrl,
|
|
177
|
+
};
|
|
178
|
+
if (repositoryUrl) {
|
|
179
|
+
metadata.releaseNotes = `${repositoryUrl}/releases`;
|
|
180
|
+
}
|
|
181
|
+
this.cache.set(packageName, metadata);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Clear the cache (useful for testing)
|
|
185
|
+
*/
|
|
186
|
+
clearCache() {
|
|
187
|
+
this.cache.clear();
|
|
188
|
+
this.failureCache.clear();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
exports.ChangelogFetcher = ChangelogFetcher;
|
|
192
|
+
exports.changelogFetcher = new ChangelogFetcher();
|
|
193
|
+
//# sourceMappingURL=changelog-fetcher.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* External service integrations
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
17
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
__exportStar(require("./npm-registry"), exports);
|
|
21
|
+
__exportStar(require("./jsdelivr-registry"), exports);
|
|
22
|
+
__exportStar(require("./changelog-fetcher"), exports);
|
|
23
|
+
__exportStar(require("./version-checker"), exports);
|
|
24
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,232 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.getAllPackageDataFromJsdelivr = getAllPackageDataFromJsdelivr;
|
|
37
|
+
exports.clearJsdelivrPackageCache = clearJsdelivrPackageCache;
|
|
38
|
+
exports.closeJsdelivrPool = closeJsdelivrPool;
|
|
39
|
+
const undici_1 = require("undici");
|
|
40
|
+
const semver = __importStar(require("semver"));
|
|
41
|
+
const constants_1 = require("../constants");
|
|
42
|
+
const npm_registry_1 = require("./npm-registry");
|
|
43
|
+
// Create a persistent connection pool for jsDelivr CDN with optimal settings
|
|
44
|
+
// This enables connection reuse and HTTP/1.1 keep-alive for blazing fast requests
|
|
45
|
+
const jsdelivrPool = new undici_1.Pool('https://cdn.jsdelivr.net', {
|
|
46
|
+
connections: constants_1.MAX_CONCURRENT_REQUESTS, // Maximum concurrent connections
|
|
47
|
+
pipelining: 10, // Enable request pipelining for even better performance
|
|
48
|
+
keepAliveTimeout: 60000, // Keep connections alive for 60 seconds
|
|
49
|
+
keepAliveMaxTimeout: 600000, // Maximum keep-alive timeout
|
|
50
|
+
});
|
|
51
|
+
const packageCache = new Map();
|
|
52
|
+
/**
|
|
53
|
+
* Fetches package.json from jsdelivr CDN for a specific version tag using undici pool.
|
|
54
|
+
* Uses connection pooling and keep-alive for maximum performance.
|
|
55
|
+
* @param packageName - The npm package name
|
|
56
|
+
* @param versionTag - The version tag (e.g., '14', 'latest')
|
|
57
|
+
* @returns The package.json content or null if not found
|
|
58
|
+
*/
|
|
59
|
+
async function fetchPackageJsonFromJsdelivr(packageName, versionTag) {
|
|
60
|
+
try {
|
|
61
|
+
const url = `${constants_1.JSDELIVR_CDN_URL}/${encodeURIComponent(packageName)}@${versionTag}/package.json`;
|
|
62
|
+
const { statusCode, body } = await (0, undici_1.request)(url, {
|
|
63
|
+
dispatcher: jsdelivrPool,
|
|
64
|
+
method: 'GET',
|
|
65
|
+
headers: {
|
|
66
|
+
accept: 'application/json',
|
|
67
|
+
},
|
|
68
|
+
headersTimeout: constants_1.REQUEST_TIMEOUT,
|
|
69
|
+
bodyTimeout: constants_1.REQUEST_TIMEOUT,
|
|
70
|
+
});
|
|
71
|
+
if (statusCode !== 200) {
|
|
72
|
+
// Consume body to prevent memory leaks
|
|
73
|
+
await body.text();
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
const text = await body.text();
|
|
77
|
+
const data = JSON.parse(text);
|
|
78
|
+
return data.version ? { version: data.version } : null;
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
console.error(`Error fetching from jsdelivr for package: ${packageName}@${versionTag}`, error);
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Fetches package data from jsdelivr CDN with fallback to npm registry.
|
|
87
|
+
* Makes simultaneous requests for @latest and @major version.
|
|
88
|
+
* @param packageName - The npm package name
|
|
89
|
+
* @param currentVersion - The current version to extract major from (optional)
|
|
90
|
+
* @returns Package data with latest version and all versions
|
|
91
|
+
*/
|
|
92
|
+
async function fetchPackageFromJsdelivr(packageName, currentVersion) {
|
|
93
|
+
// Check cache first
|
|
94
|
+
const cached = packageCache.get(packageName);
|
|
95
|
+
if (cached && Date.now() - cached.timestamp < constants_1.CACHE_TTL) {
|
|
96
|
+
return cached.data;
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
// 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
|
+
const majorVersion = currentVersion
|
|
102
|
+
? semver.major(semver.coerce(currentVersion) || '0.0.0').toString()
|
|
103
|
+
: null;
|
|
104
|
+
// Prepare requests: always fetch @latest, and @major if we have a current version
|
|
105
|
+
const requests = [
|
|
106
|
+
fetchPackageJsonFromJsdelivr(packageName, 'latest'),
|
|
107
|
+
];
|
|
108
|
+
if (majorVersion) {
|
|
109
|
+
requests.push(fetchPackageJsonFromJsdelivr(packageName, majorVersion));
|
|
110
|
+
}
|
|
111
|
+
// Execute all requests simultaneously
|
|
112
|
+
const results = await Promise.all(requests);
|
|
113
|
+
const latestResult = results[0];
|
|
114
|
+
const majorResult = results[1];
|
|
115
|
+
if (!latestResult) {
|
|
116
|
+
// jsdelivr doesn't have this package, fallback to npm registry
|
|
117
|
+
const npmData = await (0, npm_registry_1.getAllPackageData)([packageName]);
|
|
118
|
+
const data = npmData.get(packageName) || { latestVersion: 'unknown', allVersions: [] };
|
|
119
|
+
// Cache the result
|
|
120
|
+
packageCache.set(packageName, {
|
|
121
|
+
data,
|
|
122
|
+
timestamp: Date.now(),
|
|
123
|
+
});
|
|
124
|
+
return data;
|
|
125
|
+
}
|
|
126
|
+
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
|
+
const allVersions = [latestVersion];
|
|
155
|
+
// Add the current version if it's valid and not already in the list
|
|
156
|
+
if (currentVersion && semver.valid(currentVersion)) {
|
|
157
|
+
const coerced = semver.coerce(currentVersion);
|
|
158
|
+
if (coerced && !allVersions.includes(coerced.version)) {
|
|
159
|
+
allVersions.push(coerced.version);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const result = {
|
|
163
|
+
latestVersion,
|
|
164
|
+
allVersions: allVersions.sort(semver.rcompare),
|
|
165
|
+
};
|
|
166
|
+
// Cache the result
|
|
167
|
+
packageCache.set(packageName, {
|
|
168
|
+
data: result,
|
|
169
|
+
timestamp: Date.now(),
|
|
170
|
+
});
|
|
171
|
+
return result;
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
// Fallback to npm registry on any error
|
|
175
|
+
const npmData = await (0, npm_registry_1.getAllPackageData)([packageName]);
|
|
176
|
+
const data = npmData.get(packageName) || { latestVersion: 'unknown', allVersions: [] };
|
|
177
|
+
// Cache the result
|
|
178
|
+
packageCache.set(packageName, {
|
|
179
|
+
data,
|
|
180
|
+
timestamp: Date.now(),
|
|
181
|
+
});
|
|
182
|
+
return data;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Fetches package version data from jsdelivr CDN for multiple packages.
|
|
187
|
+
* Uses undici connection pool for blazing fast performance with connection reuse.
|
|
188
|
+
* Falls back to npm registry if jsdelivr doesn't have the package.
|
|
189
|
+
* @param packageNames - Array of package names to fetch
|
|
190
|
+
* @param currentVersions - Optional map of package names to their current versions
|
|
191
|
+
* @param onProgress - Optional progress callback
|
|
192
|
+
* @returns Map of package names to their version data
|
|
193
|
+
*/
|
|
194
|
+
async function getAllPackageDataFromJsdelivr(packageNames, currentVersions, onProgress) {
|
|
195
|
+
const packageData = new Map();
|
|
196
|
+
if (packageNames.length === 0) {
|
|
197
|
+
return packageData;
|
|
198
|
+
}
|
|
199
|
+
const total = packageNames.length;
|
|
200
|
+
let completedCount = 0;
|
|
201
|
+
// Fire all requests simultaneously - undici pool handles concurrency internally
|
|
202
|
+
// No need for p-limit - the pool's connection limit controls concurrency
|
|
203
|
+
const allPromises = packageNames.map(async (packageName) => {
|
|
204
|
+
const currentVersion = currentVersions?.get(packageName);
|
|
205
|
+
const data = await fetchPackageFromJsdelivr(packageName, currentVersion);
|
|
206
|
+
packageData.set(packageName, data);
|
|
207
|
+
completedCount++;
|
|
208
|
+
if (onProgress) {
|
|
209
|
+
onProgress(packageName, completedCount, total);
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
// Wait for all requests to complete
|
|
213
|
+
await Promise.all(allPromises);
|
|
214
|
+
// Clear the progress line and show completion time if no custom progress handler
|
|
215
|
+
if (!onProgress) {
|
|
216
|
+
process.stdout.write('\r' + ' '.repeat(80) + '\r');
|
|
217
|
+
}
|
|
218
|
+
return packageData;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Clear the package cache (useful for testing)
|
|
222
|
+
*/
|
|
223
|
+
function clearJsdelivrPackageCache() {
|
|
224
|
+
packageCache.clear();
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Close the jsDelivr connection pool (useful for graceful shutdown)
|
|
228
|
+
*/
|
|
229
|
+
async function closeJsdelivrPool() {
|
|
230
|
+
await jsdelivrPool.close();
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=jsdelivr-registry.js.map
|
|
@@ -0,0 +1,145 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.getAllPackageData = getAllPackageData;
|
|
37
|
+
exports.clearPackageCache = clearPackageCache;
|
|
38
|
+
exports.closeNpmPool = closeNpmPool;
|
|
39
|
+
const undici_1 = require("undici");
|
|
40
|
+
const semver = __importStar(require("semver"));
|
|
41
|
+
const constants_1 = require("../constants");
|
|
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
|
+
});
|
|
50
|
+
const packageCache = new Map();
|
|
51
|
+
/**
|
|
52
|
+
* Fetches package data from npm registry with caching using undici pool.
|
|
53
|
+
* Uses connection pooling and keep-alive for maximum performance.
|
|
54
|
+
*/
|
|
55
|
+
async function fetchPackageFromRegistry(packageName) {
|
|
56
|
+
// Check cache first
|
|
57
|
+
const cached = packageCache.get(packageName);
|
|
58
|
+
if (cached && Date.now() - cached.timestamp < constants_1.CACHE_TTL) {
|
|
59
|
+
return cached.data;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const url = `${constants_1.NPM_REGISTRY_URL}/${encodeURIComponent(packageName)}`;
|
|
63
|
+
const { statusCode, body } = await (0, undici_1.request)(url, {
|
|
64
|
+
dispatcher: npmPool,
|
|
65
|
+
method: 'GET',
|
|
66
|
+
headers: {
|
|
67
|
+
accept: 'application/vnd.npm.install-v1+json',
|
|
68
|
+
},
|
|
69
|
+
headersTimeout: constants_1.REQUEST_TIMEOUT,
|
|
70
|
+
bodyTimeout: constants_1.REQUEST_TIMEOUT,
|
|
71
|
+
});
|
|
72
|
+
if (statusCode !== 200) {
|
|
73
|
+
// Consume body to prevent memory leaks
|
|
74
|
+
await body.text();
|
|
75
|
+
throw new Error(`HTTP ${statusCode}`);
|
|
76
|
+
}
|
|
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
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
// Return fallback data for failed packages
|
|
100
|
+
return { latestVersion: 'unknown', allVersions: [] };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Fetches package version data from npm registry for multiple packages.
|
|
105
|
+
* Uses undici connection pool for blazing fast performance with connection reuse.
|
|
106
|
+
* Only returns valid semantic versions (X.Y.Z format, excluding pre-releases).
|
|
107
|
+
*/
|
|
108
|
+
async function getAllPackageData(packageNames, onProgress) {
|
|
109
|
+
const packageData = new Map();
|
|
110
|
+
if (packageNames.length === 0) {
|
|
111
|
+
return packageData;
|
|
112
|
+
}
|
|
113
|
+
const total = packageNames.length;
|
|
114
|
+
let completedCount = 0;
|
|
115
|
+
// Fire all requests simultaneously - undici pool handles concurrency internally
|
|
116
|
+
// No need for p-limit - the pool's connection limit controls concurrency
|
|
117
|
+
const allPromises = packageNames.map(async (packageName) => {
|
|
118
|
+
const data = await fetchPackageFromRegistry(packageName);
|
|
119
|
+
packageData.set(packageName, data);
|
|
120
|
+
completedCount++;
|
|
121
|
+
if (onProgress) {
|
|
122
|
+
onProgress(packageName, completedCount, total);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
// Wait for all requests to complete
|
|
126
|
+
await Promise.all(allPromises);
|
|
127
|
+
// Clear the progress line and show completion time if no custom progress handler
|
|
128
|
+
if (!onProgress) {
|
|
129
|
+
process.stdout.write('\r' + ' '.repeat(80) + '\r');
|
|
130
|
+
}
|
|
131
|
+
return packageData;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Clear the package cache (useful for testing)
|
|
135
|
+
*/
|
|
136
|
+
function clearPackageCache() {
|
|
137
|
+
packageCache.clear();
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Close the npm registry connection pool (useful for graceful shutdown)
|
|
141
|
+
*/
|
|
142
|
+
async function closeNpmPool() {
|
|
143
|
+
await npmPool.close();
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=npm-registry.js.map
|