inup 1.4.3 → 1.4.4

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 CHANGED
@@ -1,14 +1,14 @@
1
- # inup
1
+ # 🚀 inup
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/inup?logo=npm&logoColor=%23CB3837&style=for-the-badge&color=crimson)](https://www.npmjs.com/package/inup)
4
4
  [![Downloads](https://img.shields.io/npm/dm/inup?style=for-the-badge&color=646CFF&logoColor=white)](https://www.npmjs.com/package/inup)
5
5
  [![Total downloads](https://img.shields.io/npm/dt/inup?style=for-the-badge&color=informational)](https://www.npmjs.com/package/inup)
6
6
 
7
- Interactive upgrade for your dependencies. Works with npm, yarn, pnpm, and bun.
7
+ Upgrade your dependencies interactively. Works with npm, yarn, pnpm, and bun.
8
8
 
9
9
  ![Interactive Upgrade Demo](docs/demo/interactive-upgrade.gif)
10
10
 
11
- ## Install
11
+ ## 🚀 Usage
12
12
 
13
13
  ```bash
14
14
  npx inup
@@ -20,24 +20,17 @@ Or install globally:
20
20
  npm install -g inup
21
21
  ```
22
22
 
23
- ## Usage
24
-
25
- ```bash
26
- npx inup
27
- ```
28
-
29
23
  That's it. The tool scans your project, finds outdated packages, and lets you pick what to upgrade.
30
24
 
31
- ## Features
25
+ ## 💡 Why inup?
32
26
 
33
- - Auto-detects package manager (npm, yarn, pnpm, bun)
34
- - Works with monorepos and workspaces
35
- - Batch upgrades with keyboard shortcuts
36
- - Search packages with `/`
37
- - Multiple themes (press `t`)
38
- - Package info modal (press `i`)
27
+ - **Inclusive by Default**: We load Dev, Peer, and Optional dependencies automatically. No more restarting the tool because you forgot a `--peer` flag.
28
+ - **Live Toggles**: Toggle dependency types (`d`, `p`, `o`) on the fly without exiting.
29
+ - **Zero Config**: Auto-detects your package manager.
30
+ - **Monorepo Ready**: Seamlessly handles workspaces.
31
+ - **Modern UX**: Search with `/`, view package details with `i`, and swap themes with `t`.
39
32
 
40
- ## Keyboard Shortcuts
33
+ ## ⌨️ Keyboard Shortcuts
41
34
 
42
35
  - `↑/↓` - Navigate packages
43
36
  - `←/→` - Select version (current, patch, minor, major)
@@ -50,18 +43,22 @@ That's it. The tool scans your project, finds outdated packages, and lets you pi
50
43
  - `i` - View package info
51
44
  - `Enter` - Confirm and upgrade
52
45
 
53
- ## Options
46
+ ## ⚙️ Options
54
47
 
55
48
  ```bash
56
49
  inup [options]
57
50
 
58
51
  -d, --dir <path> Run in specific directory
59
52
  -e, --exclude <patterns> Skip directories (comma-separated regex)
60
- -p, --peer Include peer dependencies
61
- -o, --optional Include optional dependencies
62
53
  --package-manager <name> Force package manager (npm, yarn, pnpm, bun)
63
54
  ```
64
55
 
65
- ## License
56
+ ## 🔒 Privacy
57
+
58
+ We don't track anything. Ever.
59
+
60
+ The only network requests made are to the npm registry and jsDelivr CDN to fetch package version data. That's it.
61
+
62
+ ## 📄 License
66
63
 
67
64
  MIT
@@ -88,19 +88,11 @@ class PackageDetector {
88
88
  }
89
89
  }
90
90
  const allPackageData = config_1.DEFAULT_REGISTRY === 'jsdelivr'
91
- ? await (0, services_1.getAllPackageDataFromJsdelivr)(packageNames, currentVersions, (currentPackage, completed, total) => {
92
- const percentage = Math.round((completed / total) * 100);
93
- const truncatedPackage = currentPackage.length > 40
94
- ? currentPackage.substring(0, 37) + '...'
95
- : currentPackage;
96
- this.showProgress(`🌐 Fetching ${percentage}% (${truncatedPackage})`);
91
+ ? await (0, services_1.getAllPackageDataFromJsdelivr)(packageNames, currentVersions, (_currentPackage, completed, total) => {
92
+ this.showProgress(`🌐 Checking versions... (${completed}/${total} packages)`);
97
93
  })
98
- : await (0, services_1.getAllPackageData)(packageNames, (currentPackage, completed, total) => {
99
- const percentage = Math.round((completed / total) * 100);
100
- const truncatedPackage = currentPackage.length > 40
101
- ? currentPackage.substring(0, 37) + '...'
102
- : currentPackage;
103
- this.showProgress(`🌐 Fetching ${percentage}% (${truncatedPackage})`);
94
+ : await (0, services_1.getAllPackageData)(packageNames, (_currentPackage, completed, total) => {
95
+ this.showProgress(`🌐 Checking versions... (${completed}/${total} packages)`);
104
96
  });
105
97
  try {
106
98
  for (const dep of allDeps) {
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.changelogFetcher = exports.ChangelogFetcher = void 0;
4
+ const constants_1 = require("../config/constants");
4
5
  /**
5
6
  * Fetches package metadata from npm registry
6
7
  * Includes description, repository info, and basic metadata
@@ -69,12 +70,13 @@ class ChangelogFetcher {
69
70
  }
70
71
  }
71
72
  /**
72
- * Fetch data from npm registry
73
- * Returns the package data from the registry
73
+ * Fetch data from jsdelivr CDN
74
+ * Returns the package data by fetching package.json directly from jsdelivr
74
75
  */
75
76
  async fetchFromRegistry(packageName) {
76
77
  try {
77
- const response = await fetch(`https://registry.npmjs.org/${encodeURIComponent(packageName)}`, {
78
+ // Fetch package.json directly from jsdelivr CDN (resolves to latest automatically)
79
+ const response = await fetch(`${constants_1.JSDELIVR_CDN_URL}/${encodeURIComponent(packageName)}@latest/package.json`, {
78
80
  method: 'GET',
79
81
  headers: {
80
82
  accept: 'application/json',
@@ -83,20 +85,15 @@ class ChangelogFetcher {
83
85
  if (!response.ok) {
84
86
  return null;
85
87
  }
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;
88
+ const pkgData = (await response.json());
92
89
  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),
90
+ description: pkgData.description,
91
+ homepage: pkgData.homepage,
92
+ repository: pkgData.repository,
93
+ bugs: pkgData.bugs,
94
+ keywords: (pkgData.keywords || []),
95
+ author: pkgData.author,
96
+ license: pkgData.license,
100
97
  };
101
98
  }
102
99
  catch {
@@ -49,6 +49,9 @@ const jsdelivrPool = new undici_1.Pool('https://cdn.jsdelivr.net', {
49
49
  keepAliveMaxTimeout: config_1.REQUEST_TIMEOUT, // Maximum keep-alive timeout
50
50
  connectTimeout: config_1.REQUEST_TIMEOUT, // 60 seconds connect timeout
51
51
  });
52
+ // Batch configuration for progressive loading
53
+ const BATCH_SIZE = 5;
54
+ const BATCH_TIMEOUT_MS = 500;
52
55
  const packageCache = new Map();
53
56
  /**
54
57
  * Fetches package.json from jsdelivr CDN for a specific version tag using undici pool.
@@ -86,23 +89,51 @@ async function fetchPackageJsonFromJsdelivr(packageName, versionTag) {
86
89
  /**
87
90
  * Fetches package version data from jsdelivr CDN for multiple packages.
88
91
  * Uses undici connection pool for blazing fast performance with connection reuse.
89
- * Falls back to npm registry in batches if jsdelivr doesn't have packages.
92
+ * Falls back to npm registry immediately when jsdelivr fails (interleaved, not sequential).
93
+ * Supports batched callbacks for progressive UI updates.
90
94
  * @param packageNames - Array of package names to fetch
91
95
  * @param currentVersions - Optional map of package names to their current versions
92
96
  * @param onProgress - Optional progress callback
97
+ * @param onBatchReady - Optional callback for batch updates (fires every BATCH_SIZE packages or BATCH_TIMEOUT_MS)
93
98
  * @returns Map of package names to their version data
94
99
  */
95
- async function getAllPackageDataFromJsdelivr(packageNames, currentVersions, onProgress) {
100
+ async function getAllPackageDataFromJsdelivr(packageNames, currentVersions, onProgress, onBatchReady) {
96
101
  const packageData = new Map();
97
102
  if (packageNames.length === 0) {
98
103
  return packageData;
99
104
  }
100
105
  const total = packageNames.length;
101
106
  let completedCount = 0;
102
- // Track packages that need npm fallback (not found on jsDelivr)
103
- const failedPackages = [];
104
- // Fire all jsDelivr requests simultaneously - undici pool handles concurrency internally
105
- const allPromises = packageNames.map(async (packageName) => {
107
+ // Batch buffer for progressive updates
108
+ let batchBuffer = [];
109
+ let batchTimer = null;
110
+ // Helper to flush the current batch
111
+ const flushBatch = () => {
112
+ if (batchBuffer.length > 0 && onBatchReady) {
113
+ onBatchReady([...batchBuffer]);
114
+ batchBuffer = [];
115
+ }
116
+ if (batchTimer) {
117
+ clearTimeout(batchTimer);
118
+ batchTimer = null;
119
+ }
120
+ };
121
+ // Helper to add package to batch and flush if needed
122
+ const addToBatch = (packageName, data) => {
123
+ if (onBatchReady) {
124
+ batchBuffer.push({ name: packageName, data });
125
+ // Flush if batch is full
126
+ if (batchBuffer.length >= BATCH_SIZE) {
127
+ flushBatch();
128
+ }
129
+ else if (!batchTimer) {
130
+ // Set timer to flush batch after timeout
131
+ batchTimer = setTimeout(flushBatch, BATCH_TIMEOUT_MS);
132
+ }
133
+ }
134
+ };
135
+ // Process individual package fetch with immediate npm fallback on failure
136
+ const fetchPackageWithFallback = async (packageName) => {
106
137
  const currentVersion = currentVersions?.get(packageName);
107
138
  // Try to get from cache first
108
139
  const cached = packageCache.get(packageName);
@@ -112,6 +143,7 @@ async function getAllPackageDataFromJsdelivr(packageNames, currentVersions, onPr
112
143
  if (onProgress) {
113
144
  onProgress(packageName, completedCount, total);
114
145
  }
146
+ addToBatch(packageName, cached.data);
115
147
  return;
116
148
  }
117
149
  try {
@@ -131,8 +163,21 @@ async function getAllPackageDataFromJsdelivr(packageNames, currentVersions, onPr
131
163
  const latestResult = results[0];
132
164
  const majorResult = results[1];
133
165
  if (!latestResult) {
134
- // Package not on jsDelivr, mark for npm fallback
135
- failedPackages.push(packageName);
166
+ // Package not on jsDelivr, immediately try npm fallback
167
+ const npmData = await (0, npm_registry_1.getAllPackageData)([packageName]);
168
+ const result = npmData.get(packageName);
169
+ if (result) {
170
+ packageData.set(packageName, result);
171
+ packageCache.set(packageName, {
172
+ data: result,
173
+ timestamp: Date.now(),
174
+ });
175
+ addToBatch(packageName, result);
176
+ }
177
+ completedCount++;
178
+ if (onProgress) {
179
+ onProgress(packageName, completedCount, total);
180
+ }
136
181
  return;
137
182
  }
138
183
  const latestVersion = latestResult.version;
@@ -155,31 +200,35 @@ async function getAllPackageDataFromJsdelivr(packageNames, currentVersions, onPr
155
200
  if (onProgress) {
156
201
  onProgress(packageName, completedCount, total);
157
202
  }
203
+ addToBatch(packageName, result);
158
204
  }
159
205
  catch (error) {
160
- // On error, mark for npm fallback
161
- failedPackages.push(packageName);
162
- }
163
- });
164
- // Wait for all jsDelivr requests to complete
165
- await Promise.all(allPromises);
166
- // Batch fetch all failed packages from npm registry in one call
167
- if (failedPackages.length > 0) {
168
- const npmData = await (0, npm_registry_1.getAllPackageData)(failedPackages, (pkg, completed, npmTotal) => {
206
+ // On error, immediately try npm fallback
207
+ try {
208
+ const npmData = await (0, npm_registry_1.getAllPackageData)([packageName]);
209
+ const result = npmData.get(packageName);
210
+ if (result) {
211
+ packageData.set(packageName, result);
212
+ packageCache.set(packageName, {
213
+ data: result,
214
+ timestamp: Date.now(),
215
+ });
216
+ addToBatch(packageName, result);
217
+ }
218
+ }
219
+ catch (npmError) {
220
+ // If both fail, just continue
221
+ }
169
222
  completedCount++;
170
223
  if (onProgress) {
171
- onProgress(pkg, completedCount, total);
224
+ onProgress(packageName, completedCount, total);
172
225
  }
173
- });
174
- // Merge npm data into results and cache it
175
- for (const [packageName, data] of npmData.entries()) {
176
- packageData.set(packageName, data);
177
- packageCache.set(packageName, {
178
- data,
179
- timestamp: Date.now(),
180
- });
181
226
  }
182
- }
227
+ };
228
+ // Fire all requests simultaneously - they handle fallback internally and immediately
229
+ await Promise.all(packageNames.map(fetchPackageWithFallback));
230
+ // Flush any remaining batch items
231
+ flushBatch();
183
232
  // Clear the progress line and show completion time if no custom progress handler
184
233
  if (!onProgress) {
185
234
  process.stdout.write('\r' + ' '.repeat(80) + '\r');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inup",
3
- "version": "1.4.3",
3
+ "version": "1.4.4",
4
4
  "description": "Interactive CLI tool for upgrading dependencies with ease. Auto-detects and works with npm, yarn, pnpm, and bun. Inspired by yarn upgrade-interactive. Supports monorepos, workspaces, and batch upgrades.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {