fast-npm-meta 1.4.2 → 1.5.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/dist/cli.mjs +62 -35
- package/dist/index.mjs +61 -31
- package/package.json +8 -3
- package/skills/fast-npm-meta/SKILL.md +1 -2
package/dist/cli.mjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import process$1 from "node:process";
|
|
3
|
-
|
|
4
3
|
//#region ../node_modules/.pnpm/cac@7.0.0/node_modules/cac/dist/index.js
|
|
5
4
|
function toArr(any) {
|
|
6
5
|
return any == null ? [] : Array.isArray(any) ? any : [any];
|
|
@@ -618,11 +617,9 @@ var CAC = class extends EventTarget {
|
|
|
618
617
|
* @param name The program name to display in help and version message
|
|
619
618
|
*/
|
|
620
619
|
const cac = (name = "") => new CAC(name);
|
|
621
|
-
|
|
622
620
|
//#endregion
|
|
623
621
|
//#region package.json
|
|
624
|
-
var version = "1.
|
|
625
|
-
|
|
622
|
+
var version = "1.5.1";
|
|
626
623
|
//#endregion
|
|
627
624
|
//#region ../node_modules/.pnpm/is-network-error@1.3.0/node_modules/is-network-error/index.js
|
|
628
625
|
const objectToString = Object.prototype.toString;
|
|
@@ -645,9 +642,8 @@ function isNetworkError(error) {
|
|
|
645
642
|
if (message.startsWith("error sending request for url")) return true;
|
|
646
643
|
return errorMessages.has(message);
|
|
647
644
|
}
|
|
648
|
-
|
|
649
645
|
//#endregion
|
|
650
|
-
//#region ../node_modules/.pnpm/p-retry@
|
|
646
|
+
//#region ../node_modules/.pnpm/p-retry@8.0.0/node_modules/p-retry/index.js
|
|
651
647
|
function validateRetries(retries) {
|
|
652
648
|
if (typeof retries === "number") {
|
|
653
649
|
if (retries < 0) throw new TypeError("Expected `retries` to be a non-negative number.");
|
|
@@ -660,6 +656,10 @@ function validateNumberOption(name, value, { min = 0, allowInfinity = false } =
|
|
|
660
656
|
if (!allowInfinity && !Number.isFinite(value)) throw new TypeError(`Expected \`${name}\` to be a finite number.`);
|
|
661
657
|
if (value < min) throw new TypeError(`Expected \`${name}\` to be \u2265 ${min}.`);
|
|
662
658
|
}
|
|
659
|
+
function validateFunctionOption(name, value) {
|
|
660
|
+
if (value === void 0) return;
|
|
661
|
+
if (typeof value !== "function") throw new TypeError(`Expected \`${name}\` to be a function.`);
|
|
662
|
+
}
|
|
663
663
|
var AbortError = class extends Error {
|
|
664
664
|
constructor(message) {
|
|
665
665
|
super();
|
|
@@ -685,48 +685,69 @@ function calculateRemainingTime(start, max) {
|
|
|
685
685
|
if (!Number.isFinite(max)) return max;
|
|
686
686
|
return max - (performance.now() - start);
|
|
687
687
|
}
|
|
688
|
+
async function delayForRetry(delay, options) {
|
|
689
|
+
if (delay <= 0) return;
|
|
690
|
+
await new Promise((resolve, reject) => {
|
|
691
|
+
const onAbort = () => {
|
|
692
|
+
clearTimeout(timeoutToken);
|
|
693
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
694
|
+
reject(options.signal.reason);
|
|
695
|
+
};
|
|
696
|
+
const timeoutToken = setTimeout(() => {
|
|
697
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
698
|
+
resolve();
|
|
699
|
+
}, delay);
|
|
700
|
+
if (options.unref) timeoutToken.unref?.();
|
|
701
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
702
|
+
});
|
|
703
|
+
}
|
|
688
704
|
async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTime, options }) {
|
|
689
705
|
const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new TypeError(`Non-error was thrown: "${error}". You should only throw errors.`);
|
|
690
706
|
if (normalizedError instanceof AbortError) throw normalizedError.originalError;
|
|
691
707
|
const retriesLeft = Number.isFinite(options.retries) ? Math.max(0, options.retries - retriesConsumed) : options.retries;
|
|
692
708
|
const maxRetryTime = options.maxRetryTime ?? Number.POSITIVE_INFINITY;
|
|
709
|
+
const delayTime = calculateDelay(retriesConsumed, options);
|
|
710
|
+
if (calculateRemainingTime(startTime, maxRetryTime) <= 0) {
|
|
711
|
+
const context = Object.freeze({
|
|
712
|
+
error: normalizedError,
|
|
713
|
+
attemptNumber,
|
|
714
|
+
retriesLeft,
|
|
715
|
+
retriesConsumed,
|
|
716
|
+
retryDelay: 0
|
|
717
|
+
});
|
|
718
|
+
await options.onFailedAttempt(context);
|
|
719
|
+
throw normalizedError;
|
|
720
|
+
}
|
|
721
|
+
const consumeRetryContext = Object.freeze({
|
|
722
|
+
error: normalizedError,
|
|
723
|
+
attemptNumber,
|
|
724
|
+
retriesLeft,
|
|
725
|
+
retriesConsumed,
|
|
726
|
+
retryDelay: retriesLeft > 0 ? delayTime : 0
|
|
727
|
+
});
|
|
728
|
+
const consumeRetry = await options.shouldConsumeRetry(consumeRetryContext);
|
|
729
|
+
const effectiveDelay = consumeRetry && retriesLeft > 0 ? delayTime : 0;
|
|
693
730
|
const context = Object.freeze({
|
|
694
731
|
error: normalizedError,
|
|
695
732
|
attemptNumber,
|
|
696
733
|
retriesLeft,
|
|
697
|
-
retriesConsumed
|
|
734
|
+
retriesConsumed,
|
|
735
|
+
retryDelay: effectiveDelay
|
|
698
736
|
});
|
|
699
737
|
await options.onFailedAttempt(context);
|
|
700
738
|
if (calculateRemainingTime(startTime, maxRetryTime) <= 0) throw normalizedError;
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
if (remainingTime <= 0 || retriesLeft <= 0) throw normalizedError;
|
|
704
|
-
if (normalizedError instanceof TypeError && !isNetworkError(normalizedError)) {
|
|
705
|
-
if (consumeRetry) throw normalizedError;
|
|
706
|
-
options.signal?.throwIfAborted();
|
|
707
|
-
return false;
|
|
708
|
-
}
|
|
739
|
+
if (calculateRemainingTime(startTime, maxRetryTime) <= 0 || retriesLeft <= 0) throw normalizedError;
|
|
740
|
+
if (normalizedError instanceof TypeError && !isNetworkError(normalizedError)) throw normalizedError;
|
|
709
741
|
if (!await options.shouldRetry(context)) throw normalizedError;
|
|
742
|
+
const remainingTimeAfterShouldRetry = calculateRemainingTime(startTime, maxRetryTime);
|
|
743
|
+
if (remainingTimeAfterShouldRetry <= 0) throw normalizedError;
|
|
710
744
|
if (!consumeRetry) {
|
|
711
745
|
options.signal?.throwIfAborted();
|
|
712
746
|
return false;
|
|
713
747
|
}
|
|
714
|
-
const
|
|
715
|
-
const finalDelay = Math.min(delayTime, remainingTime);
|
|
748
|
+
const finalDelay = Math.min(effectiveDelay, remainingTimeAfterShouldRetry);
|
|
716
749
|
options.signal?.throwIfAborted();
|
|
717
|
-
|
|
718
|
-
const onAbort = () => {
|
|
719
|
-
clearTimeout(timeoutToken);
|
|
720
|
-
options.signal?.removeEventListener("abort", onAbort);
|
|
721
|
-
reject(options.signal.reason);
|
|
722
|
-
};
|
|
723
|
-
const timeoutToken = setTimeout(() => {
|
|
724
|
-
options.signal?.removeEventListener("abort", onAbort);
|
|
725
|
-
resolve();
|
|
726
|
-
}, finalDelay);
|
|
727
|
-
if (options.unref) timeoutToken.unref?.();
|
|
728
|
-
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
729
|
-
});
|
|
750
|
+
await delayForRetry(finalDelay, options);
|
|
730
751
|
options.signal?.throwIfAborted();
|
|
731
752
|
return true;
|
|
732
753
|
}
|
|
@@ -743,6 +764,9 @@ async function pRetry(input, options = {}) {
|
|
|
743
764
|
options.onFailedAttempt ??= () => {};
|
|
744
765
|
options.shouldRetry ??= () => true;
|
|
745
766
|
options.shouldConsumeRetry ??= () => true;
|
|
767
|
+
validateFunctionOption("onFailedAttempt", options.onFailedAttempt);
|
|
768
|
+
validateFunctionOption("shouldRetry", options.shouldRetry);
|
|
769
|
+
validateFunctionOption("shouldConsumeRetry", options.shouldConsumeRetry);
|
|
746
770
|
validateNumberOption("factor", options.factor, {
|
|
747
771
|
min: 0,
|
|
748
772
|
allowInfinity: false
|
|
@@ -783,7 +807,6 @@ async function pRetry(input, options = {}) {
|
|
|
783
807
|
}
|
|
784
808
|
throw new Error("Retry attempts exhausted without throwing an error.");
|
|
785
809
|
}
|
|
786
|
-
|
|
787
810
|
//#endregion
|
|
788
811
|
//#region src/api.ts
|
|
789
812
|
const defaultRetryOptions = {
|
|
@@ -793,7 +816,13 @@ const defaultRetryOptions = {
|
|
|
793
816
|
maxTimeout: Infinity,
|
|
794
817
|
randomize: false
|
|
795
818
|
};
|
|
796
|
-
const defaultOptions = {
|
|
819
|
+
const defaultOptions = {
|
|
820
|
+
/**
|
|
821
|
+
* API endpoint for fetching package versions
|
|
822
|
+
*
|
|
823
|
+
* @default 'https://npm.antfu.dev/'
|
|
824
|
+
*/
|
|
825
|
+
apiEndpoint: "https://npm.antfu.dev/" };
|
|
797
826
|
async function getLatestVersionBatch(packages, options = {}) {
|
|
798
827
|
const { apiEndpoint = defaultOptions.apiEndpoint, fetch: fetchApi = fetch, throw: throwError = true, retry = defaultRetryOptions } = options;
|
|
799
828
|
let query = [
|
|
@@ -835,7 +864,6 @@ function toArray(data) {
|
|
|
835
864
|
if (Array.isArray(data)) return data;
|
|
836
865
|
return [data];
|
|
837
866
|
}
|
|
838
|
-
|
|
839
867
|
//#endregion
|
|
840
868
|
//#region src/cli.ts
|
|
841
869
|
const cli = cac("fast-npm-meta");
|
|
@@ -874,6 +902,5 @@ cli.command("full <...pkgs>", "Get full package metadata (versions list, dist-ta
|
|
|
874
902
|
cli.help();
|
|
875
903
|
cli.version(version);
|
|
876
904
|
cli.parse();
|
|
877
|
-
|
|
878
905
|
//#endregion
|
|
879
|
-
export {
|
|
906
|
+
export {};
|
package/dist/index.mjs
CHANGED
|
@@ -19,9 +19,8 @@ function isNetworkError(error) {
|
|
|
19
19
|
if (message.startsWith("error sending request for url")) return true;
|
|
20
20
|
return errorMessages.has(message);
|
|
21
21
|
}
|
|
22
|
-
|
|
23
22
|
//#endregion
|
|
24
|
-
//#region ../node_modules/.pnpm/p-retry@
|
|
23
|
+
//#region ../node_modules/.pnpm/p-retry@8.0.0/node_modules/p-retry/index.js
|
|
25
24
|
function validateRetries(retries) {
|
|
26
25
|
if (typeof retries === "number") {
|
|
27
26
|
if (retries < 0) throw new TypeError("Expected `retries` to be a non-negative number.");
|
|
@@ -34,6 +33,10 @@ function validateNumberOption(name, value, { min = 0, allowInfinity = false } =
|
|
|
34
33
|
if (!allowInfinity && !Number.isFinite(value)) throw new TypeError(`Expected \`${name}\` to be a finite number.`);
|
|
35
34
|
if (value < min) throw new TypeError(`Expected \`${name}\` to be \u2265 ${min}.`);
|
|
36
35
|
}
|
|
36
|
+
function validateFunctionOption(name, value) {
|
|
37
|
+
if (value === void 0) return;
|
|
38
|
+
if (typeof value !== "function") throw new TypeError(`Expected \`${name}\` to be a function.`);
|
|
39
|
+
}
|
|
37
40
|
var AbortError = class extends Error {
|
|
38
41
|
constructor(message) {
|
|
39
42
|
super();
|
|
@@ -59,48 +62,69 @@ function calculateRemainingTime(start, max) {
|
|
|
59
62
|
if (!Number.isFinite(max)) return max;
|
|
60
63
|
return max - (performance.now() - start);
|
|
61
64
|
}
|
|
65
|
+
async function delayForRetry(delay, options) {
|
|
66
|
+
if (delay <= 0) return;
|
|
67
|
+
await new Promise((resolve, reject) => {
|
|
68
|
+
const onAbort = () => {
|
|
69
|
+
clearTimeout(timeoutToken);
|
|
70
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
71
|
+
reject(options.signal.reason);
|
|
72
|
+
};
|
|
73
|
+
const timeoutToken = setTimeout(() => {
|
|
74
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
75
|
+
resolve();
|
|
76
|
+
}, delay);
|
|
77
|
+
if (options.unref) timeoutToken.unref?.();
|
|
78
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
79
|
+
});
|
|
80
|
+
}
|
|
62
81
|
async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTime, options }) {
|
|
63
82
|
const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new TypeError(`Non-error was thrown: "${error}". You should only throw errors.`);
|
|
64
83
|
if (normalizedError instanceof AbortError) throw normalizedError.originalError;
|
|
65
84
|
const retriesLeft = Number.isFinite(options.retries) ? Math.max(0, options.retries - retriesConsumed) : options.retries;
|
|
66
85
|
const maxRetryTime = options.maxRetryTime ?? Number.POSITIVE_INFINITY;
|
|
86
|
+
const delayTime = calculateDelay(retriesConsumed, options);
|
|
87
|
+
if (calculateRemainingTime(startTime, maxRetryTime) <= 0) {
|
|
88
|
+
const context = Object.freeze({
|
|
89
|
+
error: normalizedError,
|
|
90
|
+
attemptNumber,
|
|
91
|
+
retriesLeft,
|
|
92
|
+
retriesConsumed,
|
|
93
|
+
retryDelay: 0
|
|
94
|
+
});
|
|
95
|
+
await options.onFailedAttempt(context);
|
|
96
|
+
throw normalizedError;
|
|
97
|
+
}
|
|
98
|
+
const consumeRetryContext = Object.freeze({
|
|
99
|
+
error: normalizedError,
|
|
100
|
+
attemptNumber,
|
|
101
|
+
retriesLeft,
|
|
102
|
+
retriesConsumed,
|
|
103
|
+
retryDelay: retriesLeft > 0 ? delayTime : 0
|
|
104
|
+
});
|
|
105
|
+
const consumeRetry = await options.shouldConsumeRetry(consumeRetryContext);
|
|
106
|
+
const effectiveDelay = consumeRetry && retriesLeft > 0 ? delayTime : 0;
|
|
67
107
|
const context = Object.freeze({
|
|
68
108
|
error: normalizedError,
|
|
69
109
|
attemptNumber,
|
|
70
110
|
retriesLeft,
|
|
71
|
-
retriesConsumed
|
|
111
|
+
retriesConsumed,
|
|
112
|
+
retryDelay: effectiveDelay
|
|
72
113
|
});
|
|
73
114
|
await options.onFailedAttempt(context);
|
|
74
115
|
if (calculateRemainingTime(startTime, maxRetryTime) <= 0) throw normalizedError;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if (remainingTime <= 0 || retriesLeft <= 0) throw normalizedError;
|
|
78
|
-
if (normalizedError instanceof TypeError && !isNetworkError(normalizedError)) {
|
|
79
|
-
if (consumeRetry) throw normalizedError;
|
|
80
|
-
options.signal?.throwIfAborted();
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
116
|
+
if (calculateRemainingTime(startTime, maxRetryTime) <= 0 || retriesLeft <= 0) throw normalizedError;
|
|
117
|
+
if (normalizedError instanceof TypeError && !isNetworkError(normalizedError)) throw normalizedError;
|
|
83
118
|
if (!await options.shouldRetry(context)) throw normalizedError;
|
|
119
|
+
const remainingTimeAfterShouldRetry = calculateRemainingTime(startTime, maxRetryTime);
|
|
120
|
+
if (remainingTimeAfterShouldRetry <= 0) throw normalizedError;
|
|
84
121
|
if (!consumeRetry) {
|
|
85
122
|
options.signal?.throwIfAborted();
|
|
86
123
|
return false;
|
|
87
124
|
}
|
|
88
|
-
const
|
|
89
|
-
const finalDelay = Math.min(delayTime, remainingTime);
|
|
125
|
+
const finalDelay = Math.min(effectiveDelay, remainingTimeAfterShouldRetry);
|
|
90
126
|
options.signal?.throwIfAborted();
|
|
91
|
-
|
|
92
|
-
const onAbort = () => {
|
|
93
|
-
clearTimeout(timeoutToken);
|
|
94
|
-
options.signal?.removeEventListener("abort", onAbort);
|
|
95
|
-
reject(options.signal.reason);
|
|
96
|
-
};
|
|
97
|
-
const timeoutToken = setTimeout(() => {
|
|
98
|
-
options.signal?.removeEventListener("abort", onAbort);
|
|
99
|
-
resolve();
|
|
100
|
-
}, finalDelay);
|
|
101
|
-
if (options.unref) timeoutToken.unref?.();
|
|
102
|
-
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
103
|
-
});
|
|
127
|
+
await delayForRetry(finalDelay, options);
|
|
104
128
|
options.signal?.throwIfAborted();
|
|
105
129
|
return true;
|
|
106
130
|
}
|
|
@@ -117,6 +141,9 @@ async function pRetry(input, options = {}) {
|
|
|
117
141
|
options.onFailedAttempt ??= () => {};
|
|
118
142
|
options.shouldRetry ??= () => true;
|
|
119
143
|
options.shouldConsumeRetry ??= () => true;
|
|
144
|
+
validateFunctionOption("onFailedAttempt", options.onFailedAttempt);
|
|
145
|
+
validateFunctionOption("shouldRetry", options.shouldRetry);
|
|
146
|
+
validateFunctionOption("shouldConsumeRetry", options.shouldConsumeRetry);
|
|
120
147
|
validateNumberOption("factor", options.factor, {
|
|
121
148
|
min: 0,
|
|
122
149
|
allowInfinity: false
|
|
@@ -157,7 +184,6 @@ async function pRetry(input, options = {}) {
|
|
|
157
184
|
}
|
|
158
185
|
throw new Error("Retry attempts exhausted without throwing an error.");
|
|
159
186
|
}
|
|
160
|
-
|
|
161
187
|
//#endregion
|
|
162
188
|
//#region src/api.ts
|
|
163
189
|
const defaultRetryOptions = {
|
|
@@ -167,7 +193,13 @@ const defaultRetryOptions = {
|
|
|
167
193
|
maxTimeout: Infinity,
|
|
168
194
|
randomize: false
|
|
169
195
|
};
|
|
170
|
-
const defaultOptions = {
|
|
196
|
+
const defaultOptions = {
|
|
197
|
+
/**
|
|
198
|
+
* API endpoint for fetching package versions
|
|
199
|
+
*
|
|
200
|
+
* @default 'https://npm.antfu.dev/'
|
|
201
|
+
*/
|
|
202
|
+
apiEndpoint: "https://npm.antfu.dev/" };
|
|
171
203
|
async function getLatestVersionBatch(packages, options = {}) {
|
|
172
204
|
const { apiEndpoint = defaultOptions.apiEndpoint, fetch: fetchApi = fetch, throw: throwError = true, retry = defaultRetryOptions } = options;
|
|
173
205
|
let query = [
|
|
@@ -217,7 +249,6 @@ function toArray(data) {
|
|
|
217
249
|
if (Array.isArray(data)) return data;
|
|
218
250
|
return [data];
|
|
219
251
|
}
|
|
220
|
-
|
|
221
252
|
//#endregion
|
|
222
253
|
//#region src/helpers.ts
|
|
223
254
|
const NPM_REGISTRY = "https://registry.npmjs.org/";
|
|
@@ -234,6 +265,5 @@ function pickRegistry(scope, npmConfigs, defaultRegistry = NPM_REGISTRY) {
|
|
|
234
265
|
if (!registry) registry = npmConfigs.registry || defaultRegistry;
|
|
235
266
|
return registry;
|
|
236
267
|
}
|
|
237
|
-
|
|
238
268
|
//#endregion
|
|
239
|
-
export { NPM_REGISTRY, defaultOptions, getLatestVersion, getLatestVersionBatch, getVersions, getVersionsBatch, pickRegistry };
|
|
269
|
+
export { NPM_REGISTRY, defaultOptions, getLatestVersion, getLatestVersionBatch, getVersions, getVersionsBatch, pickRegistry };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fast-npm-meta",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.5.1",
|
|
5
5
|
"description": "Get npm package metadata",
|
|
6
6
|
"author": "Anthony Fu <anthonyfu117@hotmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -28,8 +28,13 @@
|
|
|
28
28
|
],
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"cac": "^7.0.0",
|
|
31
|
-
"p-retry": "^
|
|
32
|
-
"tsdown": "^0.
|
|
31
|
+
"p-retry": "^8.0.0",
|
|
32
|
+
"tsdown": "^0.21.10"
|
|
33
|
+
},
|
|
34
|
+
"inlinedDependencies": {
|
|
35
|
+
"cac": "7.0.0",
|
|
36
|
+
"is-network-error": "1.3.0",
|
|
37
|
+
"p-retry": "8.0.0"
|
|
33
38
|
},
|
|
34
39
|
"scripts": {
|
|
35
40
|
"build": "tsdown",
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: fast-npm-meta
|
|
3
|
-
description:
|
|
4
|
-
license: MIT
|
|
3
|
+
description: Queries npm package metadata via the fast-npm-meta CLI — resolves package versions, dist-tags, publish dates, engine requirements, and version range specifiers. Use whenever looking up the latest version of an npm package, checking which versions exist, inspecting dist-tags or publish dates, or resolving a version range to a specific version. Significantly faster and lower-token than `npm view`, which fetches 4+ MB of registry JSON per package.
|
|
5
4
|
---
|
|
6
5
|
|
|
7
6
|
# fast-npm-meta CLI
|