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 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.4.2";
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@7.1.1/node_modules/p-retry/index.js
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
- const consumeRetry = await options.shouldConsumeRetry(context);
702
- const remainingTime = calculateRemainingTime(startTime, maxRetryTime);
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 delayTime = calculateDelay(retriesConsumed, options);
715
- const finalDelay = Math.min(delayTime, remainingTime);
748
+ const finalDelay = Math.min(effectiveDelay, remainingTimeAfterShouldRetry);
716
749
  options.signal?.throwIfAborted();
717
- if (finalDelay > 0) await new Promise((resolve, reject) => {
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 = { apiEndpoint: "https://npm.antfu.dev/" };
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@7.1.1/node_modules/p-retry/index.js
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
- const consumeRetry = await options.shouldConsumeRetry(context);
76
- const remainingTime = calculateRemainingTime(startTime, maxRetryTime);
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 delayTime = calculateDelay(retriesConsumed, options);
89
- const finalDelay = Math.min(delayTime, remainingTime);
125
+ const finalDelay = Math.min(effectiveDelay, remainingTimeAfterShouldRetry);
90
126
  options.signal?.throwIfAborted();
91
- if (finalDelay > 0) await new Promise((resolve, reject) => {
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 = { apiEndpoint: "https://npm.antfu.dev/" };
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.2",
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": "^7.1.1",
32
- "tsdown": "^0.20.3"
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: Get npm package metadata
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